From 8262715b8eb157497ec1ee1cfcef778d526b2336 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 3 Oct 2017 19:30:40 -0400 Subject: [PATCH 1/3] path.c: fix uninitialized memory access In cleanup_path we're passing in a char array, run a memcmp on it, and run through it without ever checking if something is in the array in the first place. This can lead us to access uninitialized memory, for example in t5541-http-push-smart.sh test 7, when run under valgrind: ==4423== Conditional jump or move depends on uninitialised value(s) ==4423== at 0x242FA9: cleanup_path (path.c:35) ==4423== by 0x242FA9: mkpath (path.c:456) ==4423== by 0x256CC7: refname_match (refs.c:364) ==4423== by 0x26C181: count_refspec_match (remote.c:1015) ==4423== by 0x26C181: match_explicit_lhs (remote.c:1126) ==4423== by 0x26C181: check_push_refs (remote.c:1409) ==4423== by 0x2ABB4D: transport_push (transport.c:870) ==4423== by 0x186703: push_with_options (push.c:332) ==4423== by 0x18746D: do_push (push.c:409) ==4423== by 0x18746D: cmd_push (push.c:566) ==4423== by 0x1183E0: run_builtin (git.c:352) ==4423== by 0x11973E: handle_builtin (git.c:539) ==4423== by 0x11973E: run_argv (git.c:593) ==4423== by 0x11973E: main (git.c:698) ==4423== Uninitialised value was created by a heap allocation ==4423== at 0x4C2CD8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4423== by 0x4C2F195: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4423== by 0x2C196B: xrealloc (wrapper.c:137) ==4423== by 0x29A30B: strbuf_grow (strbuf.c:66) ==4423== by 0x29A30B: strbuf_vaddf (strbuf.c:277) ==4423== by 0x242F9F: mkpath (path.c:454) ==4423== by 0x256CC7: refname_match (refs.c:364) ==4423== by 0x26C181: count_refspec_match (remote.c:1015) ==4423== by 0x26C181: match_explicit_lhs (remote.c:1126) ==4423== by 0x26C181: check_push_refs (remote.c:1409) ==4423== by 0x2ABB4D: transport_push (transport.c:870) ==4423== by 0x186703: push_with_options (push.c:332) ==4423== by 0x18746D: do_push (push.c:409) ==4423== by 0x18746D: cmd_push (push.c:566) ==4423== by 0x1183E0: run_builtin (git.c:352) ==4423== by 0x11973E: handle_builtin (git.c:539) ==4423== by 0x11973E: run_argv (git.c:593) ==4423== by 0x11973E: main (git.c:698) ==4423== Avoid this by using skip_prefix(), which knows not to go beyond the end of the string. Reported-by: Thomas Gummerer Signed-off-by: Jeff King Reviewed-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- path.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/path.c b/path.c index e50d2befcf..2fecf854fe 100644 --- a/path.c +++ b/path.c @@ -33,11 +33,10 @@ static struct strbuf *get_pathname(void) return sb; } -static char *cleanup_path(char *path) +static const char *cleanup_path(const char *path) { /* Clean it up */ - if (!memcmp(path, "./", 2)) { - path += 2; + if (skip_prefix(path, "./", &path)) { while (*path == '/') path++; } @@ -46,7 +45,7 @@ static char *cleanup_path(char *path) static void strbuf_cleanup_path(struct strbuf *sb) { - char *path = cleanup_path(sb->buf); + const char *path = cleanup_path(sb->buf); if (path > sb->buf) strbuf_remove(sb, 0, path - sb->buf); } @@ -63,7 +62,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...) strlcpy(buf, bad_path, n); return buf; } - return cleanup_path(buf); + return (char *)cleanup_path(buf); } static int dir_prefix(const char *buf, const char *dir) From 51bfb734df43dc2d9ddbc7234a8723a7b1cfb322 Mon Sep 17 00:00:00 2001 From: Thomas Gummerer Date: Tue, 3 Oct 2017 20:57:12 +0100 Subject: [PATCH 2/3] http-push: fix construction of hex value from path The get_oid_hex_from_objpath takes care of creating a oid from a pathname. It does this by memcpy'ing the first two bytes of the path to the "hex" string, then skipping the '/', and then copying the rest of the path to the "hex" string. Currently it fails to increase the pointer to the hex string, so the second memcpy invocation just mashes over what was copied in the first one, and leaves the last two bytes in the string uninitialized. This breaks valgrind in t5540, although the test passes without valgrind: ==5490== Use of uninitialised value of size 8 ==5490== at 0x13C6B5: hexval (cache.h:1238) ==5490== by 0x13C6DB: hex2chr (cache.h:1247) ==5490== by 0x13C734: get_sha1_hex (hex.c:42) ==5490== by 0x13C78E: get_oid_hex (hex.c:53) ==5490== by 0x118BDA: get_oid_hex_from_objpath (http-push.c:1023) ==5490== by 0x118C92: process_ls_object (http-push.c:1038) ==5490== by 0x118E5B: handle_remote_ls_ctx (http-push.c:1077) ==5490== by 0x118227: xml_end_tag (http-push.c:815) ==5490== by 0x50C1448: ??? (in /usr/lib/libexpat.so.1.6.6) ==5490== by 0x50C221B: ??? (in /usr/lib/libexpat.so.1.6.6) ==5490== by 0x50BFBF2: ??? (in /usr/lib/libexpat.so.1.6.6) ==5490== by 0x50C0B24: ??? (in /usr/lib/libexpat.so.1.6.6) ==5490== Uninitialised value was created by a stack allocation ==5490== at 0x118B63: get_oid_hex_from_objpath (http-push.c:1012) ==5490== Fix this by correctly incrementing the pointer to the "hex" variable, so the first two bytes are left untouched by the memcpy call, and the last two bytes are correctly initialized. Signed-off-by: Thomas Gummerer Signed-off-by: Junio C Hamano --- http-push.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http-push.c b/http-push.c index c91f40a610..df969609be 100644 --- a/http-push.c +++ b/http-push.c @@ -1017,7 +1017,7 @@ static int get_oid_hex_from_objpath(const char *path, struct object_id *oid) memcpy(hex, path, 2); path += 2; path++; /* skip '/' */ - memcpy(hex, path, GIT_SHA1_HEXSZ - 2); + memcpy(hex + 2, path, GIT_SHA1_HEXSZ - 2); return get_oid_hex(hex, oid); } From 2944a94c6b74d3941f63d1f4eee5bdfbbf5cd400 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 3 Oct 2017 22:24:57 +0200 Subject: [PATCH 3/3] sub-process: use child_process.args instead of child_process.argv Currently the argv is only allocated on the stack, and then assigned to process->argv. When the start_subprocess function goes out of scope, the local argv variable is eliminated from the stack, but the pointer is still kept around in process->argv. Much later when we try to access the same process->argv in finish_command, this leads us to access a memory location that no longer contains what we want. As argv0 is only used for printing errors, this is not easily noticed in normal git operations. However when running t0021-conversion.sh through valgrind, valgrind rightfully complains: ==21024== Invalid read of size 8 ==21024== at 0x2ACF64: finish_command (run-command.c:869) ==21024== by 0x2D6B18: subprocess_exit_handler (sub-process.c:72) ==21024== by 0x2AB41E: cleanup_children (run-command.c:45) ==21024== by 0x2AB526: cleanup_children_on_exit (run-command.c:81) ==21024== by 0x54AD487: __run_exit_handlers (in /usr/lib/libc-2.26.so) ==21024== by 0x54AD4D9: exit (in /usr/lib/libc-2.26.so) ==21024== by 0x11A9EF: handle_builtin (git.c:550) ==21024== by 0x11ABCC: run_argv (git.c:602) ==21024== by 0x11AD8E: cmd_main (git.c:679) ==21024== by 0x1BF125: main (common-main.c:43) ==21024== Address 0x1ffeffec00 is on thread 1's stack ==21024== 1504 bytes below stack pointer ==21024== These days, the child_process structure has its own args array, and the standard way to set up its argv[] is to use that one, instead of assigning to process->argv to point at an array that is outside. Use that facility automatically fixes this issue. Reported-by: Thomas Gummerer Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- sub-process.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sub-process.c b/sub-process.c index fcc4832c14..648b3a3943 100644 --- a/sub-process.c +++ b/sub-process.c @@ -74,13 +74,12 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co { int err; struct child_process *process; - const char *argv[] = { cmd, NULL }; entry->cmd = cmd; process = &entry->process; child_process_init(process); - process->argv = argv; + argv_array_push(&process->args, cmd); process->use_shell = 1; process->in = -1; process->out = -1;