]> git.ipfire.org Git - thirdparty/git.git/commitdiff
pretty: restrict input lengths for padding and wrapping formats
authorPatrick Steinhardt <ps@pks.im>
Thu, 1 Dec 2022 14:47:23 +0000 (15:47 +0100)
committerJunio C Hamano <gitster@pobox.com>
Fri, 9 Dec 2022 05:26:21 +0000 (14:26 +0900)
Both the padding and wrapping formatting directives allow the caller to
specify an integer that ultimately leads to us adding this many chars to
the result buffer. As a consequence, it is trivial to e.g. allocate 2GB
of RAM via a single formatting directive and cause resource exhaustion
on the machine executing this logic. Furthermore, it is debatable
whether there are any sane usecases that require the user to pad data to
2GB boundaries or to indent wrapped data by 2GB.

Restrict the input sizes to 16 kilobytes at a maximum to limit the
amount of bytes that can be requested by the user. This is not meant
as a fix because there are ways to trivially amplify the amount of
data we generate via formatting directives; the real protection is
achieved by the changes in previous steps to catch and avoid integer
wraparound that causes us to under-allocate and access beyond the
end of allocated memory reagions. But having such a limit
significantly helps fuzzing the pretty format, because the fuzzer is
otherwise quite fast to run out-of-memory as it discovers these
formatters.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
pretty.c
t/t4205-log-pretty-formats.sh

index aae6e792bc43097a72f9a62ed6b1a1cd852157e5..e2285572c49b8eb9dcf219d95dc43da1f3f2e5fa 100644 (file)
--- a/pretty.c
+++ b/pretty.c
 #include "gpg-interface.h"
 #include "trailer.h"
 
+/*
+ * The limit for formatting directives, which enable the caller to append
+ * arbitrarily many bytes to the formatted buffer. This includes padding
+ * and wrapping formatters.
+ */
+#define FORMATTING_LIMIT (16 * 1024)
+
 static char *user_format;
 static struct cmt_fmt_map {
        const char *name;
@@ -1046,6 +1053,15 @@ static size_t parse_padding_placeholder(const char *placeholder,
                if (!*end || end == start)
                        return 0;
                width = strtol(start, &next, 10);
+
+               /*
+                * We need to limit the amount of padding, or otherwise this
+                * would allow the user to pad the buffer by arbitrarily many
+                * bytes and thus cause resource exhaustion.
+                */
+               if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT)
+                       return 0;
+
                if (next == start || width == 0)
                        return 0;
                if (width < 0) {
@@ -1205,6 +1221,16 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                                if (*next != ')')
                                        return 0;
                        }
+
+                       /*
+                        * We need to limit the format here as it allows the
+                        * user to prepend arbitrarily many bytes to the buffer
+                        * when rewrapping.
+                        */
+                       if (width > FORMATTING_LIMIT ||
+                           indent1 > FORMATTING_LIMIT ||
+                           indent2 > FORMATTING_LIMIT)
+                               return 0;
                        rewrap_message_tail(sb, c, width, indent1, indent2);
                        return end - placeholder + 1;
                } else
index 5c5b56596e81a733cc10b1cb5ddd730809ae43c1..84c61dfc48977f9f4e26890545beb8d5e651d259 100755 (executable)
@@ -888,15 +888,21 @@ test_expect_success 'log --pretty with magical wrapping directives' '
 '
 
 test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping directive' '
-       cat >expect <<-EOF &&
-       fatal: number too large to represent as int on this platform: 2147483649
-       EOF
-       test_must_fail git log -1 --pretty="format:%w(2147483649,1,1)%d" 2>error &&
-       test_cmp expect error &&
-       test_must_fail git log -1 --pretty="format:%w(1,2147483649,1)%d" 2>error &&
-       test_cmp expect error &&
-       test_must_fail git log -1 --pretty="format:%w(1,1,2147483649)%d" 2>error &&
-       test_cmp expect error
+       printf "%%w(2147483649,1,1)0" >expect &&
+       git log -1 --pretty="format:%w(2147483649,1,1)%x30" >actual &&
+       test_cmp expect actual &&
+       printf "%%w(1,2147483649,1)0" >expect &&
+       git log -1 --pretty="format:%w(1,2147483649,1)%x30" >actual &&
+       test_cmp expect actual &&
+       printf "%%w(1,1,2147483649)0" >expect &&
+       git log -1 --pretty="format:%w(1,1,2147483649)%x30" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing padding directive' '
+       printf "%%<(2147483649)0" >expect &&
+       git log -1 --pretty="format:%<(2147483649)%x30" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'log --pretty with padding and preceding control chars' '