From 16749b8dd2cd2d3ab693ac7ebe110e57cf054005 Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Thu, 5 Sep 2019 18:04:55 -0400 Subject: commit-graph.c: handle commit parsing errors To write a commit graph chunk, 'write_graph_chunk_data()' takes a list of commits to write and parses each one before writing the necessary data, and continuing on to the next commit in the list. Since the majority of these commits are not parsed ahead of time (an exception is made for the *last* commit in the list, which is parsed early within 'copy_oids_to_commits'), it is possible that calling 'parse_commit_no_graph()' on them may return an error. Failing to catch these errors before de-referencing later calls can result in a undefined memory access and a SIGSEGV. One such example of this is 'get_commit_tree_oid()', which expects a parsed object as its input (in this case, the commit-graph code passes '*list'). If '*list' causes a parse error, the subsequent call will fail. Prevent such an issue by checking the return value of 'parse_commit_no_graph()' to avoid passing an unparsed object to a function which expects a parsed object, thus preventing a segfault. It is worth noting that this fix is really skirting around the issue in object.c's 'parse_object()', which makes it difficult to tell how corrupt an object is without digging into it. Presumably one could change the meaning of 'parse_object' returns, but this would require adjusting each callsite accordingly. Instead of that, add an additional check to the object parsed. Signed-off-by: Taylor Blau Signed-off-by: Junio C Hamano --- commit-graph.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'commit-graph.c') diff --git a/commit-graph.c b/commit-graph.c index f2888c203b..6aa6998ecd 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -843,7 +843,9 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len, uint32_t packedDate[2]; display_progress(ctx->progress, ++ctx->progress_cnt); - parse_commit_no_graph(*list); + if (parse_commit_no_graph(*list)) + die(_("unable to parse commit %s"), + oid_to_hex(&(*list)->object.oid)); hashwrite(f, get_commit_tree_oid(*list)->hash, hash_len); parent = (*list)->parents; -- cgit v1.2.3 From 806278dead57766bf000af62dcb8892ee3a24956 Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Thu, 5 Sep 2019 18:04:57 -0400 Subject: commit-graph.c: handle corrupt/missing trees Apply similar treatment as in the previous commit to handle an unchecked call to 'get_commit_tree_oid()'. Previously, a NULL return value from this function would be immediately dereferenced with '->hash', and then cause a segfault. Before dereferencing to access the 'hash' member, check the return value of 'get_commit_tree_oid()' to make sure that it is not NULL. To make this check correct, a related change is also needed in 'commit.c', which is to check the return value of 'get_commit_tree' before taking its address. If 'get_commit_tree' returns NULL, we encounter an undefined behavior when taking the address of the return value of 'get_commit_tree' and then taking '->object.oid'. (On my system, this is memory address 0x8, which is obviously wrong). Fix this by making sure that 'get_commit_tree' returns something non-NULL before digging through a structure that is not there, thus preventing a segfault down the line in the commit graph code. Signed-off-by: Taylor Blau Signed-off-by: Junio C Hamano --- commit-graph.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'commit-graph.c') diff --git a/commit-graph.c b/commit-graph.c index 6aa6998ecd..cea1b37493 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -839,6 +839,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len, while (list < last) { struct commit_list *parent; + struct object_id *tree; int edge_value; uint32_t packedDate[2]; display_progress(ctx->progress, ++ctx->progress_cnt); @@ -846,7 +847,11 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len, if (parse_commit_no_graph(*list)) die(_("unable to parse commit %s"), oid_to_hex(&(*list)->object.oid)); - hashwrite(f, get_commit_tree_oid(*list)->hash, hash_len); + tree = get_commit_tree_oid(*list); + if (!tree) + die(_("unable to get tree for %s"), + oid_to_hex(&(*list)->object.oid)); + hashwrite(f, tree->hash, hash_len); parent = (*list)->parents; -- cgit v1.2.3