diff options
author | Andrzej Hunt <ajrhunt@google.com> | 2021-03-15 16:39:23 +0000 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2021-03-17 10:00:20 -0700 |
commit | 097ea2c8486e9fc8c6c11bad8688434edeeda3f2 (patch) | |
tree | fef7231efd63627cdcc676e9fb73e053a487e287 | |
parent | fsmonitor: refactor initialization of fsmonitor_last_update token (diff) | |
download | tgif-097ea2c8486e9fc8c6c11bad8688434edeeda3f2.tar.xz |
fsmonitor: avoid global-buffer-overflow READ when checking trivial response
query_result can be be an empty strbuf (STRBUF_INIT) - in that case
trying to read 3 bytes triggers a buffer overflow read (as
query_result.buf = '\0').
Therefore we need to check query_result's length before trying to read 3
bytes.
This overflow was introduced in:
940b94f35c (fsmonitor: log invocation of FSMonitor hook to trace2, 2021-02-03)
It was found when running the test-suite against ASAN, and can be most
easily reproduced with the following command:
make GIT_TEST_OPTS="-v" DEFAULT_TEST_TARGET="t7519-status-fsmonitor.sh" \
SANITIZE=address DEVELOPER=1 test
==2235==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000019e6e5e at pc 0x00000043745c bp 0x7fffd382c520 sp 0x7fffd382bcc8
READ of size 3 at 0x0000019e6e5e thread T0
#0 0x43745b in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long) /home/abuild/rpmbuild/BUILD/llvm-11.0.0.src/build/../projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:842:7
#1 0x43786d in bcmp /home/abuild/rpmbuild/BUILD/llvm-11.0.0.src/build/../projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:887:10
#2 0x80b146 in fsmonitor_is_trivial_response /home/ahunt/oss-fuzz/git/fsmonitor.c:192:10
#3 0x80b146 in query_fsmonitor /home/ahunt/oss-fuzz/git/fsmonitor.c:175:7
#4 0x80a749 in refresh_fsmonitor /home/ahunt/oss-fuzz/git/fsmonitor.c:267:21
#5 0x80bad1 in tweak_fsmonitor /home/ahunt/oss-fuzz/git/fsmonitor.c:429:4
#6 0x90f040 in read_index_from /home/ahunt/oss-fuzz/git/read-cache.c:2321:3
#7 0x8e5d08 in repo_read_index_preload /home/ahunt/oss-fuzz/git/preload-index.c:164:15
#8 0x52dd45 in prepare_index /home/ahunt/oss-fuzz/git/builtin/commit.c:363:6
#9 0x52a188 in cmd_commit /home/ahunt/oss-fuzz/git/builtin/commit.c:1588:15
#10 0x4ce77e in run_builtin /home/ahunt/oss-fuzz/git/git.c:453:11
#11 0x4ccb18 in handle_builtin /home/ahunt/oss-fuzz/git/git.c:704:3
#12 0x4cb01c in run_argv /home/ahunt/oss-fuzz/git/git.c:771:4
#13 0x4cb01c in cmd_main /home/ahunt/oss-fuzz/git/git.c:902:19
#14 0x6aca8d in main /home/ahunt/oss-fuzz/git/common-main.c:52:11
#15 0x7fb027bf5349 in __libc_start_main (/lib64/libc.so.6+0x24349)
#16 0x4206b9 in _start /home/abuild/rpmbuild/BUILD/glibc-2.26/csu/../sysdeps/x86_64/start.S:120
0x0000019e6e5e is located 2 bytes to the left of global variable 'strbuf_slopbuf' defined in 'strbuf.c:51:6' (0x19e6e60) of size 1
'strbuf_slopbuf' is ascii string ''
0x0000019e6e5e is located 126 bytes to the right of global variable 'signals' defined in 'sigchain.c:11:31' (0x19e6be0) of size 512
SUMMARY: AddressSanitizer: global-buffer-overflow /home/abuild/rpmbuild/BUILD/llvm-11.0.0.src/build/../projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:842:7 in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long)
Shadow bytes around the buggy address:
0x000080334d70: f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
0x000080334d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x000080334d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x000080334da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x000080334db0: 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9
=>0x000080334dc0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9[f9]01 f9 f9 f9
0x000080334dd0: f9 f9 f9 f9 03 f9 f9 f9 f9 f9 f9 f9 02 f9 f9 f9
0x000080334de0: f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 04 f9 f9 f9
0x000080334df0: f9 f9 f9 f9 01 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
0x000080334e00: f9 f9 f9 f9 00 00 00 00 f9 f9 f9 f9 01 f9 f9 f9
0x000080334e10: f9 f9 f9 f9 04 f9 f9 f9 f9 f9 f9 f9 00 f9 f9 f9
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
Signed-off-by: Andrzej Hunt <ajrhunt@google.com>
Acked-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | fsmonitor.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/fsmonitor.c b/fsmonitor.c index e12214b300..fb8d789740 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -184,10 +184,10 @@ static int query_fsmonitor(int version, const char *last_update, struct strbuf * int fsmonitor_is_trivial_response(const struct strbuf *query_result) { static char trivial_response[3] = { '\0', '/', '\0' }; - int is_trivial = !memcmp(trivial_response, - &query_result->buf[query_result->len - 3], 3); - return is_trivial; + return query_result->len >= 3 && + !memcmp(trivial_response, + &query_result->buf[query_result->len - 3], 3); } static void fsmonitor_refresh_callback(struct index_state *istate, char *name) |