148 lines
7.1 KiB
Diff
148 lines
7.1 KiB
Diff
From f6e0b9f38987ad5e47bab551f8760b70689a5905 Mon Sep 17 00:00:00 2001
|
|
From: Patrick Steinhardt <ps@pks.im>
|
|
Date: Thu, 1 Dec 2022 15:46:34 +0100
|
|
Subject: [PATCH] pretty: fix out-of-bounds read when parsing invalid padding
|
|
format
|
|
|
|
An out-of-bounds read can be triggered when parsing an incomplete
|
|
padding format string passed via `--pretty=format` or in Git archives
|
|
when files are marked with the `export-subst` gitattribute.
|
|
|
|
This bug exists since we have introduced support for truncating output
|
|
via the `trunc` keyword a7f01c6b4d (pretty: support truncating in %>, %<
|
|
and %><, 2013-04-19). Before this commit, we used to find the end of the
|
|
formatting string by using strchr(3P). This function returns a `NULL`
|
|
pointer in case the character in question wasn't found. The subsequent
|
|
check whether any character was found thus simply checked the returned
|
|
pointer. After the commit we switched to strcspn(3P) though, which only
|
|
returns the offset to the first found character or to the trailing NUL
|
|
byte. As the end pointer is now computed by adding the offset to the
|
|
start pointer it won't be `NULL` anymore, and as a consequence the check
|
|
doesn't do anything anymore.
|
|
|
|
The out-of-bounds data that is being read can in fact end up in the
|
|
formatted string. As a consequence, it is possible to leak memory
|
|
contents either by calling git-log(1) or via git-archive(1) when any of
|
|
the archived files is marked with the `export-subst` gitattribute.
|
|
|
|
==10888==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000398 at pc 0x7f0356047cb2 bp 0x7fff3ffb95d0 sp 0x7fff3ffb8d78
|
|
READ of size 1 at 0x602000000398 thread T0
|
|
#0 0x7f0356047cb1 in __interceptor_strchrnul /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:725
|
|
#1 0x563b7cec9a43 in strbuf_expand strbuf.c:417
|
|
#2 0x563b7cda7060 in repo_format_commit_message pretty.c:1869
|
|
#3 0x563b7cda8d0f in pretty_print_commit pretty.c:2161
|
|
#4 0x563b7cca04c8 in show_log log-tree.c:781
|
|
#5 0x563b7cca36ba in log_tree_commit log-tree.c:1117
|
|
#6 0x563b7c927ed5 in cmd_log_walk_no_free builtin/log.c:508
|
|
#7 0x563b7c92835b in cmd_log_walk builtin/log.c:549
|
|
#8 0x563b7c92b1a2 in cmd_log builtin/log.c:883
|
|
#9 0x563b7c802993 in run_builtin git.c:466
|
|
#10 0x563b7c803397 in handle_builtin git.c:721
|
|
#11 0x563b7c803b07 in run_argv git.c:788
|
|
#12 0x563b7c8048a7 in cmd_main git.c:923
|
|
#13 0x563b7ca99682 in main common-main.c:57
|
|
#14 0x7f0355e3c28f (/usr/lib/libc.so.6+0x2328f)
|
|
#15 0x7f0355e3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
|
|
#16 0x563b7c7fe0e4 in _start ../sysdeps/x86_64/start.S:115
|
|
|
|
0x602000000398 is located 0 bytes to the right of 8-byte region [0x602000000390,0x602000000398)
|
|
allocated by thread T0 here:
|
|
#0 0x7f0356072faa in __interceptor_strdup /usr/src/debug/gcc/libsanitizer/asan/asan_interceptors.cpp:439
|
|
#1 0x563b7cf7317c in xstrdup wrapper.c:39
|
|
#2 0x563b7cd9a06a in save_user_format pretty.c:40
|
|
#3 0x563b7cd9b3e5 in get_commit_format pretty.c:173
|
|
#4 0x563b7ce54ea0 in handle_revision_opt revision.c:2456
|
|
#5 0x563b7ce597c9 in setup_revisions revision.c:2850
|
|
#6 0x563b7c9269e0 in cmd_log_init_finish builtin/log.c:269
|
|
#7 0x563b7c927362 in cmd_log_init builtin/log.c:348
|
|
#8 0x563b7c92b193 in cmd_log builtin/log.c:882
|
|
#9 0x563b7c802993 in run_builtin git.c:466
|
|
#10 0x563b7c803397 in handle_builtin git.c:721
|
|
#11 0x563b7c803b07 in run_argv git.c:788
|
|
#12 0x563b7c8048a7 in cmd_main git.c:923
|
|
#13 0x563b7ca99682 in main common-main.c:57
|
|
#14 0x7f0355e3c28f (/usr/lib/libc.so.6+0x2328f)
|
|
#15 0x7f0355e3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
|
|
#16 0x563b7c7fe0e4 in _start ../sysdeps/x86_64/start.S:115
|
|
|
|
SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/src/debug/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:725 in __interceptor_strchrnul
|
|
Shadow bytes around the buggy address:
|
|
0x0c047fff8020: fa fa fd fd fa fa 00 06 fa fa 05 fa fa fa fd fd
|
|
0x0c047fff8030: fa fa 00 02 fa fa 06 fa fa fa 05 fa fa fa fd fd
|
|
0x0c047fff8040: fa fa 00 07 fa fa 03 fa fa fa fd fd fa fa 00 00
|
|
0x0c047fff8050: fa fa 00 01 fa fa fd fd fa fa 00 00 fa fa 00 01
|
|
0x0c047fff8060: fa fa 00 06 fa fa 00 06 fa fa 05 fa fa fa 05 fa
|
|
=>0x0c047fff8070: fa fa 00[fa]fa fa fd fa fa fa fd fd fa fa fd fd
|
|
0x0c047fff8080: fa fa fd fd fa fa 00 00 fa fa 00 fa fa fa fd fa
|
|
0x0c047fff8090: fa fa fd fd fa fa 00 00 fa fa fa fa fa fa fa fa
|
|
0x0c047fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff80b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
0x0c047fff80c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
|
|
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
|
|
==10888==ABORTING
|
|
|
|
Fix this bug by checking whether `end` points at the trailing NUL byte.
|
|
Add a test which catches this out-of-bounds read and which demonstrates
|
|
that we used to write out-of-bounds data into the formatted message.
|
|
|
|
Reported-by: Markus Vervier <markus.vervier@x41-dsec.de>
|
|
Original-patch-by: Markus Vervier <markus.vervier@x41-dsec.de>
|
|
Signed-off-by: Patrick Steinhardt <ps@pks.im>
|
|
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
|
---
|
|
pretty.c | 2 +-
|
|
t/t4205-log-pretty-formats.sh | 6 ++++++
|
|
2 files changed, 7 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/pretty.c b/pretty.c
|
|
index 692a6382a1..d55b88607a 100644
|
|
--- a/pretty.c
|
|
+++ b/pretty.c
|
|
@@ -1041,7 +1041,7 @@ static size_t parse_padding_placeholder(const char *placeholder,
|
|
const char *end = start + strcspn(start, ",)");
|
|
char *next;
|
|
int width;
|
|
- if (!end || end == start)
|
|
+ if (!*end || end == start)
|
|
return 0;
|
|
width = strtol(start, &next, 10);
|
|
if (next == start || width == 0)
|
|
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
|
|
index 126dc20f23..cdde37d325 100755
|
|
--- a/t/t4205-log-pretty-formats.sh
|
|
+++ b/t/t4205-log-pretty-formats.sh
|
|
@@ -873,6 +873,12 @@ test_expect_success 'log --pretty with space stealing' '
|
|
test_cmp expect actual
|
|
'
|
|
|
|
+test_expect_success 'log --pretty with invalid padding format' '
|
|
+ printf "%s%%<(20" "$(git rev-parse HEAD)" >expect &&
|
|
+ git log -1 --pretty="format:%H%<(20" >actual &&
|
|
+ test_cmp expect actual
|
|
+'
|
|
+
|
|
test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
|
|
# We only assert that this command does not crash. This needs to be
|
|
# executed with the address sanitizer to demonstrate failure.
|
|
--
|
|
2.27.0
|
|
|