@matheusbsbs / matheus-bagliano / commits / c879daa237
Fork 0

Make hash-object more robust against malformed objects

Commits, trees and tags have structure. Don't let users feed git with malformed ones. Sooner or later git will die() when encountering them. Note that this patch does not check semantics. A tree that points to non-existent objects is perfectly OK (and should be so, users may choose to add commit first, then its associated tree for example). Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Feb 5, 2011 at 17:52 UTC c879daa23729547fb28aa7e8783c5e4e619a9e7c
5 files changed +63 -10
builtin/hash-object.c
+1 -1
@@ -15,7 +15,7 @@ static void hash_fd(int fd, const char *type, int write_object, const char *path
15 struct stat st;
16 unsigned char sha1[20];
17 if (fstat(fd, &st) < 0 ||
18 - index_fd(sha1, fd, &st, write_object, type_from_string(type), path))
18 + index_fd(sha1, fd, &st, write_object, type_from_string(type), path, 1))
19 die(write_object
20 ? "Unable to add %s to database"
21 : "Unable to hash %s", path);
cache.h
+1 -1
@@ -501,7 +501,7 @@ extern int ie_match_stat(const struct index_state *, struct cache_entry *, struc
501 extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
502
503 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
504 -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
504 +extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path, int format_check);
505 extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
506 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
507
read-cache.c
+1 -1
@@ -92,7 +92,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
92
93 if (fd >= 0) {
94 unsigned char sha1[20];
95 - if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name))
95 + if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name, 0))
96 match = hashcmp(sha1, ce->sha1);
97 /* index_fd() closed the file descriptor already */
98 }
sha1_file.c
+47 -7
@@ -13,6 +13,7 @@
13 #include "commit.h"
14 #include "tag.h"
15 #include "tree.h"
16 +#include "tree-walk.h"
17 #include "refs.h"
18 #include "pack-revindex.h"
19 #include "sha1-lookup.h"
@@ -2471,8 +2472,37 @@ int has_sha1_file(const unsigned char *sha1)
2472 return has_loose_object(sha1);
2473 }
2474
2475 +static void check_tree(const void *buf, size_t size)
2476 +{
2477 + struct tree_desc desc;
2478 + struct name_entry entry;
2479 +
2480 + init_tree_desc(&desc, buf, size);
2481 + while (tree_entry(&desc, &entry))
2482 + /* do nothing
2483 + * tree_entry() will die() on malformed entries */
2484 + ;
2485 +}
2486 +
2487 +static void check_commit(const void *buf, size_t size)
2488 +{
2489 + struct commit c;
2490 + memset(&c, 0, sizeof(c));
2491 + if (parse_commit_buffer(&c, buf, size))
2492 + die("corrupt commit");
2493 +}
2494 +
2495 +static void check_tag(const void *buf, size_t size)
2496 +{
2497 + struct tag t;
2498 + memset(&t, 0, sizeof(t));
2499 + if (parse_tag_buffer(&t, buf, size))
2500 + die("corrupt tag");
2501 +}
2502 +
2503 static int index_mem(unsigned char *sha1, void *buf, size_t size,
2475 - int write_object, enum object_type type, const char *path)
2504 + int write_object, enum object_type type,
2505 + const char *path, int format_check)
2506 {
2507 int ret, re_allocated = 0;
2508
@@ -2490,6 +2520,14 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
2520 re_allocated = 1;
2521 }
2522 }
2523 + if (format_check) {
2524 + if (type == OBJ_TREE)
2525 + check_tree(buf, size);
2526 + if (type == OBJ_COMMIT)
2527 + check_commit(buf, size);
2528 + if (type == OBJ_TAG)
2529 + check_tag(buf, size);
2530 + }
2531
2532 if (write_object)
2533 ret = write_sha1_file(buf, size, typename(type), sha1);
@@ -2503,7 +2541,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
2541 #define SMALL_FILE_SIZE (32*1024)
2542
2543 int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
2506 - enum object_type type, const char *path)
2544 + enum object_type type, const char *path, int format_check)
2545 {
2546 int ret;
2547 size_t size = xsize_t(st->st_size);
@@ -2512,23 +2550,25 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
2550 struct strbuf sbuf = STRBUF_INIT;
2551 if (strbuf_read(&sbuf, fd, 4096) >= 0)
2552 ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object,
2515 - type, path);
2553 + type, path, format_check);
2554 else
2555 ret = -1;
2556 strbuf_release(&sbuf);
2557 } else if (!size) {
2520 - ret = index_mem(sha1, NULL, size, write_object, type, path);
2558 + ret = index_mem(sha1, NULL, size, write_object, type, path,
2559 + format_check);
2560 } else if (size <= SMALL_FILE_SIZE) {
2561 char *buf = xmalloc(size);
2562 if (size == read_in_full(fd, buf, size))
2563 ret = index_mem(sha1, buf, size, write_object, type,
2525 - path);
2564 + path, format_check);
2565 else
2566 ret = error("short read %s", strerror(errno));
2567 free(buf);
2568 } else {
2569 void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
2531 - ret = index_mem(sha1, buf, size, write_object, type, path);
2570 + ret = index_mem(sha1, buf, size, write_object, type, path,
2571 + format_check);
2572 munmap(buf, size);
2573 }
2574 close(fd);
@@ -2546,7 +2586,7 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
2586 if (fd < 0)
2587 return error("open(\"%s\"): %s", path,
2588 strerror(errno));
2549 - if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path) < 0)
2589 + if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path, 0) < 0)
2590 return error("%s: failed to insert into database",
2591 path);
2592 break;
t/t1007-hash-object.sh
+13
@@ -188,4 +188,17 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do
188 pop_repo
189 done
190
191 +test_expect_success 'corrupt tree' '
192 + echo abc >malformed-tree
193 + test_must_fail git hash-object -t tree malformed-tree
194 +'
195 +
196 +test_expect_success 'corrupt commit' '
197 + test_must_fail git hash-object -t commit --stdin </dev/null
198 +'
199 +
200 +test_expect_success 'corrupt tag' '
201 + test_must_fail git hash-object -t tag --stdin </dev/null
202 +'
203 +
204 test_done