Skip to content

Commit fc7ae9c

Browse files
committed
Merge branch 'nd/hash-object-sanity'
* nd/hash-object-sanity: Make hash-object more robust against malformed objects Conflicts: cache.h
2 parents 99f45c2 + c879daa commit fc7ae9c

File tree

5 files changed

+63
-10
lines changed

5 files changed

+63
-10
lines changed

builtin/hash-object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ static void hash_fd(int fd, const char *type, int write_object, const char *path
1515
struct stat st;
1616
unsigned char sha1[20];
1717
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))
1919
die(write_object
2020
? "Unable to add %s to database"
2121
: "Unable to hash %s", path);

cache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ struct pathspec {
516516
extern int init_pathspec(struct pathspec *, const char **);
517517
extern void free_pathspec(struct pathspec *);
518518
extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
519-
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
519+
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);
520520
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
521521
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
522522

read-cache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
9292

9393
if (fd >= 0) {
9494
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))
9696
match = hashcmp(sha1, ce->sha1);
9797
/* index_fd() closed the file descriptor already */
9898
}

sha1_file.c

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "commit.h"
1414
#include "tag.h"
1515
#include "tree.h"
16+
#include "tree-walk.h"
1617
#include "refs.h"
1718
#include "pack-revindex.h"
1819
#include "sha1-lookup.h"
@@ -2479,8 +2480,37 @@ int has_sha1_file(const unsigned char *sha1)
24792480
return has_loose_object(sha1);
24802481
}
24812482

2483+
static void check_tree(const void *buf, size_t size)
2484+
{
2485+
struct tree_desc desc;
2486+
struct name_entry entry;
2487+
2488+
init_tree_desc(&desc, buf, size);
2489+
while (tree_entry(&desc, &entry))
2490+
/* do nothing
2491+
* tree_entry() will die() on malformed entries */
2492+
;
2493+
}
2494+
2495+
static void check_commit(const void *buf, size_t size)
2496+
{
2497+
struct commit c;
2498+
memset(&c, 0, sizeof(c));
2499+
if (parse_commit_buffer(&c, buf, size))
2500+
die("corrupt commit");
2501+
}
2502+
2503+
static void check_tag(const void *buf, size_t size)
2504+
{
2505+
struct tag t;
2506+
memset(&t, 0, sizeof(t));
2507+
if (parse_tag_buffer(&t, buf, size))
2508+
die("corrupt tag");
2509+
}
2510+
24822511
static int index_mem(unsigned char *sha1, void *buf, size_t size,
2483-
int write_object, enum object_type type, const char *path)
2512+
int write_object, enum object_type type,
2513+
const char *path, int format_check)
24842514
{
24852515
int ret, re_allocated = 0;
24862516

@@ -2498,6 +2528,14 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
24982528
re_allocated = 1;
24992529
}
25002530
}
2531+
if (format_check) {
2532+
if (type == OBJ_TREE)
2533+
check_tree(buf, size);
2534+
if (type == OBJ_COMMIT)
2535+
check_commit(buf, size);
2536+
if (type == OBJ_TAG)
2537+
check_tag(buf, size);
2538+
}
25012539

25022540
if (write_object)
25032541
ret = write_sha1_file(buf, size, typename(type), sha1);
@@ -2511,7 +2549,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
25112549
#define SMALL_FILE_SIZE (32*1024)
25122550

25132551
int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
2514-
enum object_type type, const char *path)
2552+
enum object_type type, const char *path, int format_check)
25152553
{
25162554
int ret;
25172555
size_t size = xsize_t(st->st_size);
@@ -2520,23 +2558,25 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
25202558
struct strbuf sbuf = STRBUF_INIT;
25212559
if (strbuf_read(&sbuf, fd, 4096) >= 0)
25222560
ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object,
2523-
type, path);
2561+
type, path, format_check);
25242562
else
25252563
ret = -1;
25262564
strbuf_release(&sbuf);
25272565
} else if (!size) {
2528-
ret = index_mem(sha1, NULL, size, write_object, type, path);
2566+
ret = index_mem(sha1, NULL, size, write_object, type, path,
2567+
format_check);
25292568
} else if (size <= SMALL_FILE_SIZE) {
25302569
char *buf = xmalloc(size);
25312570
if (size == read_in_full(fd, buf, size))
25322571
ret = index_mem(sha1, buf, size, write_object, type,
2533-
path);
2572+
path, format_check);
25342573
else
25352574
ret = error("short read %s", strerror(errno));
25362575
free(buf);
25372576
} else {
25382577
void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
2539-
ret = index_mem(sha1, buf, size, write_object, type, path);
2578+
ret = index_mem(sha1, buf, size, write_object, type, path,
2579+
format_check);
25402580
munmap(buf, size);
25412581
}
25422582
close(fd);
@@ -2554,7 +2594,7 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
25542594
if (fd < 0)
25552595
return error("open(\"%s\"): %s", path,
25562596
strerror(errno));
2557-
if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path) < 0)
2597+
if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path, 0) < 0)
25582598
return error("%s: failed to insert into database",
25592599
path);
25602600
break;

t/t1007-hash-object.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,17 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do
188188
pop_repo
189189
done
190190

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+
191204
test_done

0 commit comments

Comments
 (0)