{"thread":{"id":"62306","subject":"[PATCH 0/3] fuzz: port OSS-Fuzz tests back to Git","startedAt":"2024-10-10T21:11:58Z","lastAt":"2024-10-14T21:04:17Z","messageCount":13,"participants":["Josh Steadmon","Junio C Hamano","Oswald Buddenhagen"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"504745","messageId":"cover.1728594659.git.steadmon@google.com","threadId":"62306","inReplyTo":null,"subject":"[PATCH 0/3] fuzz: port OSS-Fuzz tests back to Git","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-10T21:11:52Z","receivedAt":"2024-10-10T21:11:58Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"Git's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nOSS-Fuzz's recommended setup is for tests to live in the repository of\nthe code they test and to be built along with other tests [1].\n\nPort some of these tests back to the Git project, so that they can be\nbuilt and tested during our normal development workflow and CI, and as\nsuch avoid future bitrot.\n\n[1] https://google.github.io/oss-fuzz/advanced-topics/ideal-integration/\n\n\nEric Sesterhenn (3):\n  fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz\n  fuzz: port fuzz-parse-attr-line from OSS-Fuzz\n  fuzz: port fuzz-url-decode-mem from OSS-Fuzz\n\n Makefile                                   |  3 ++\n attr.c                                     | 38 +------------------\n attr.h                                     | 43 ++++++++++++++++++++++\n ci/run-build-and-minimal-fuzzers.sh        | 15 +++++++-\n oss-fuzz/.gitignore                        |  3 ++\n oss-fuzz/fuzz-credential-from-url-gently.c | 32 ++++++++++++++++\n oss-fuzz/fuzz-parse-attr-line.c            | 39 ++++++++++++++++++++\n oss-fuzz/fuzz-url-decode-mem.c             | 43 ++++++++++++++++++++++\n 8 files changed, 177 insertions(+), 39 deletions(-)\n create mode 100644 oss-fuzz/fuzz-credential-from-url-gently.c\n create mode 100644 oss-fuzz/fuzz-parse-attr-line.c\n create mode 100644 oss-fuzz/fuzz-url-decode-mem.c\n\n\nbase-commit: 159f2d50e75c17382c9f4eb7cbda671a6fa612d1\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"},{"id":"504746","messageId":"625b8d607ed2c95e396e7794616d9f290f23d15c.1728594659.git.steadmon@google.com","threadId":"62306","inReplyTo":"cover.1728594659.git.steadmon@google.com","subject":"[PATCH 1/3] fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-10T21:11:53Z","receivedAt":"2024-10-10T21:12:00Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"From: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>\n\nGit's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nPort one of these tests back to the Git project:\nfuzz-credential-from-url-gently\n\nThis test was originally written by Eric Sesterhenn as part of a\nsecurity audit of Git [2]. It was then contributed to the OSS-Fuzz repo\nin commit c58ac4492 (Git fuzzing: uncomment the existing and add new\ntargets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon)\nhave verified with both Eric and Jaroslav that they're OK with moving\nthis test to the Git project.\n\n[1] https://github.com/google/oss-fuzz\n[2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf\n\nCo-authored-by: Jaroslav Lobačevski <jarlob@gmail.com>\nCo-authored-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Josh Steadmon <steadmon@google.com>\n---\n Makefile                                   |  1 +\n ci/run-build-and-minimal-fuzzers.sh        | 13 +++++++--\n oss-fuzz/.gitignore                        |  1 +\n oss-fuzz/fuzz-credential-from-url-gently.c | 32 ++++++++++++++++++++++\n 4 files changed, 45 insertions(+), 2 deletions(-)\n create mode 100644 oss-fuzz/fuzz-credential-from-url-gently.c\n\ndiff --git a/Makefile b/Makefile\nindex e298c8b55e..3ce391062f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2378,6 +2378,7 @@ endif\n FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o\n FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n FUZZ_OBJS += oss-fuzz/fuzz-config.o\n+FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o\n FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\ndiff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh\nindex af8065f349..d9d3ad23c7 100755\n--- a/ci/run-build-and-minimal-fuzzers.sh\n+++ b/ci/run-build-and-minimal-fuzzers.sh\n@@ -13,8 +13,17 @@ group \"Build fuzzers\" make \\\n \tLIB_FUZZING_ENGINE=\"-fsanitize=fuzzer,address\" \\\n \tfuzz-all\n \n-for fuzzer in commit-graph config date pack-headers pack-idx ; do\n+fuzzers=\"\n+commit-graph \\\n+config \\\n+credential-from-url-gently \\\n+date \\\n+pack-headers \\\n+pack-idx \\\n+\"\n+\n+for fuzzer in $fuzzers ; do\n \tbegin_group \"fuzz-$fuzzer\"\n-\t./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n+\techo ./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n \tend_group \"fuzz-$fuzzer\"\n done\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex a877c11f42..2cfc845b20 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -1,5 +1,6 @@\n fuzz-commit-graph\n fuzz-config\n+fuzz-credential-from-url-gently\n fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\ndiff --git a/oss-fuzz/fuzz-credential-from-url-gently.c b/oss-fuzz/fuzz-credential-from-url-gently.c\nnew file mode 100644\nindex 0000000000..c872f9ad2d\n--- /dev/null\n+++ b/oss-fuzz/fuzz-credential-from-url-gently.c\n@@ -0,0 +1,32 @@\n+#include \"git-compat-util.h\"\n+#include <stddef.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include \"credential.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tstruct credential c;\n+\tchar *buf;\n+\n+\tbuf = malloc(size + 1);\n+\tif (!buf)\n+\t\treturn 0;\n+\n+\tmemcpy(buf, data, size);\n+\tbuf[size] = 0;\n+\n+\t// start fuzzing\n+\tcredential_init(&c);\n+\tcredential_from_url_gently(&c, buf, 1);\n+\n+\t// cleanup\n+\tcredential_clear(&c);\n+\tfree(buf);\n+\n+\treturn 0;\n+}\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"},{"id":"504747","messageId":"770fe27c67638c315daf03412d0ce935d5e9bee5.1728594659.git.steadmon@google.com","threadId":"62306","inReplyTo":"cover.1728594659.git.steadmon@google.com","subject":"[PATCH 2/3] fuzz: port fuzz-parse-attr-line from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-10T21:11:54Z","receivedAt":"2024-10-10T21:12:02Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"From: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>\n\nGit's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nPort one of these tests back to the Git project:\nfuzz-parse-attr-line\n\nThis test was originally written by Eric Sesterhenn as part of a\nsecurity audit of Git [2]. It was then contributed to the OSS-Fuzz repo\nin commit c58ac4492 (Git fuzzing: uncomment the existing and add new\ntargets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon)\nhave verified with both Eric and Jaroslav that they're OK with moving\nthis test to the Git project.\n\n[1] https://github.com/google/oss-fuzz\n[2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf\n\nCo-authored-by: Jaroslav Lobačevski <jarlob@gmail.com>\nCo-authored-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Josh Steadmon <steadmon@google.com>\n---\n Makefile                            |  1 +\n attr.c                              | 38 +------------------------\n attr.h                              | 43 +++++++++++++++++++++++++++++\n ci/run-build-and-minimal-fuzzers.sh |  1 +\n oss-fuzz/.gitignore                 |  1 +\n oss-fuzz/fuzz-parse-attr-line.c     | 39 ++++++++++++++++++++++++++\n 6 files changed, 86 insertions(+), 37 deletions(-)\n create mode 100644 oss-fuzz/fuzz-parse-attr-line.c\n\ndiff --git a/Makefile b/Makefile\nindex 3ce391062f..141e194bf5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2382,6 +2382,7 @@ FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o\n FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n+FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o\n .PHONY: fuzz-objs\n fuzz-objs: $(FUZZ_OBJS)\n \ndiff --git a/attr.c b/attr.c\nindex 06b5b5e55e..f7898285c5 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -259,42 +259,6 @@ const struct git_attr *git_attr(const char *name)\n \treturn git_attr_internal(name, strlen(name));\n }\n \n-/* What does a matched pattern decide? */\n-struct attr_state {\n-\tconst struct git_attr *attr;\n-\tconst char *setto;\n-};\n-\n-struct pattern {\n-\tconst char *pattern;\n-\tint patternlen;\n-\tint nowildcardlen;\n-\tunsigned flags;\t\t/* PATTERN_FLAG_* */\n-};\n-\n-/*\n- * One rule, as from a .gitattributes file.\n- *\n- * If is_macro is true, then u.attr is a pointer to the git_attr being\n- * defined.\n- *\n- * If is_macro is false, then u.pat is the filename pattern to which the\n- * rule applies.\n- *\n- * In either case, num_attr is the number of attributes affected by\n- * this rule, and state is an array listing them.  The attributes are\n- * listed as they appear in the file (macros unexpanded).\n- */\n-struct match_attr {\n-\tunion {\n-\t\tstruct pattern pat;\n-\t\tconst struct git_attr *attr;\n-\t} u;\n-\tchar is_macro;\n-\tsize_t num_attr;\n-\tstruct attr_state state[FLEX_ARRAY];\n-};\n-\n static const char blank[] = \" \\t\\r\\n\";\n \n /* Flags usable in read_attr() and parse_attr_line() family of functions. */\n@@ -353,7 +317,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,\n \treturn ep + strspn(ep, blank);\n }\n \n-static struct match_attr *parse_attr_line(const char *line, const char *src,\n+struct match_attr *parse_attr_line(const char *line, const char *src,\n \t\t\t\t\t  int lineno, unsigned flags)\n {\n \tsize_t namelen, num_attr, i;\ndiff --git a/attr.h b/attr.h\nindex bb33b60880..2319ef31e3 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -240,4 +240,47 @@ int git_attr_system_is_enabled(void);\n \n extern char *git_attr_tree;\n \n+/*\n+ * Exposed for fuzz-testing only.\n+ */\n+\n+/* What does a matched pattern decide? */\n+struct attr_state {\n+\tconst struct git_attr *attr;\n+\tconst char *setto;\n+};\n+\n+struct pattern {\n+\tconst char *pattern;\n+\tint patternlen;\n+\tint nowildcardlen;\n+\tunsigned flags;\t\t/* PATTERN_FLAG_* */\n+};\n+\n+/*\n+ * One rule, as from a .gitattributes file.\n+ *\n+ * If is_macro is true, then u.attr is a pointer to the git_attr being\n+ * defined.\n+ *\n+ * If is_macro is false, then u.pat is the filename pattern to which the\n+ * rule applies.\n+ *\n+ * In either case, num_attr is the number of attributes affected by\n+ * this rule, and state is an array listing them.  The attributes are\n+ * listed as they appear in the file (macros unexpanded).\n+ */\n+struct match_attr {\n+\tunion {\n+\t\tstruct pattern pat;\n+\t\tconst struct git_attr *attr;\n+\t} u;\n+\tchar is_macro;\n+\tsize_t num_attr;\n+\tstruct attr_state state[FLEX_ARRAY];\n+};\n+\n+struct match_attr *parse_attr_line(const char *line, const char *src,\n+\t\t\t\t\t  int lineno, unsigned flags);\n+\n #endif /* ATTR_H */\ndiff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh\nindex d9d3ad23c7..60fe8b0dfc 100755\n--- a/ci/run-build-and-minimal-fuzzers.sh\n+++ b/ci/run-build-and-minimal-fuzzers.sh\n@@ -20,6 +20,7 @@ credential-from-url-gently \\\n date \\\n pack-headers \\\n pack-idx \\\n+parse-attr-line \\\n \"\n \n for fuzzer in $fuzzers ; do\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex 2cfc845b20..ec185f061c 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -4,3 +4,4 @@ fuzz-credential-from-url-gently\n fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\n+fuzz-parse-attr-line\ndiff --git a/oss-fuzz/fuzz-parse-attr-line.c b/oss-fuzz/fuzz-parse-attr-line.c\nnew file mode 100644\nindex 0000000000..45a4c4e53c\n--- /dev/null\n+++ b/oss-fuzz/fuzz-parse-attr-line.c\n@@ -0,0 +1,39 @@\n+#include \"git-compat-util.h\"\n+#include <stddef.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include \"attr.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tstruct match_attr *res;\n+\tchar *buf;\n+\n+\tbuf = malloc(size + 1);\n+\tif (!buf)\n+\t\treturn 0;\n+\n+\tmemcpy(buf, data, size);\n+\tbuf[size] = 0;\n+\n+\tres = parse_attr_line(buf, \"dummy\", 0, 0);\n+\n+\tif (res) {\n+\t\tint j;\n+\t\tfor (j = 0; j < res->num_attr; j++) {\n+\t\t\tconst char *setto = res->state[j].setto;\n+\t\t\tif (ATTR_TRUE(setto) || ATTR_FALSE(setto) ||\n+\t\t\t\tATTR_UNSET(setto))\n+\t\t\t\t;\n+\t\t\telse\n+\t\t\t\tfree((char *)setto);\n+\t\t}\n+\t\tfree(res);\n+\t}\n+\tfree(buf);\n+\n+\treturn 0;\n+}\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"},{"id":"504748","messageId":"4c9813313ccb620f2ac176ef9fe9223113523c75.1728594659.git.steadmon@google.com","threadId":"62306","inReplyTo":"cover.1728594659.git.steadmon@google.com","subject":"[PATCH 3/3] fuzz: port fuzz-url-decode-mem from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-10T21:11:55Z","receivedAt":"2024-10-10T21:12:04Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"From: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>\n\nGit's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nPort one of these tests back to the Git project:\nfuzz-url-decode-mem\n\nThis test was originally written by Eric Sesterhenn as part of a\nsecurity audit of Git [2]. It was then contributed to the OSS-Fuzz repo\nin commit c58ac4492 (Git fuzzing: uncomment the existing and add new\ntargets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon)\nhave verified with both Eric and Jaroslav that they're OK with moving\nthis test to the Git project.\n\n[1] https://github.com/google/oss-fuzz\n[2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf\n\nCo-authored-by: Jaroslav Lobačevski <jarlob@gmail.com>\nCo-authored-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Josh Steadmon <steadmon@google.com>\n---\n Makefile                            |  1 +\n ci/run-build-and-minimal-fuzzers.sh |  1 +\n oss-fuzz/.gitignore                 |  1 +\n oss-fuzz/fuzz-url-decode-mem.c      | 43 +++++++++++++++++++++++++++++\n 4 files changed, 46 insertions(+)\n create mode 100644 oss-fuzz/fuzz-url-decode-mem.c\n\ndiff --git a/Makefile b/Makefile\nindex 141e194bf5..2cd7a6e003 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2383,6 +2383,7 @@ FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o\n+FUZZ_OBJS += oss-fuzz/fuzz-url-decode-mem.o\n .PHONY: fuzz-objs\n fuzz-objs: $(FUZZ_OBJS)\n \ndiff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh\nindex 60fe8b0dfc..08c556c818 100755\n--- a/ci/run-build-and-minimal-fuzzers.sh\n+++ b/ci/run-build-and-minimal-fuzzers.sh\n@@ -21,6 +21,7 @@ date \\\n pack-headers \\\n pack-idx \\\n parse-attr-line \\\n+url-decode-mem \\\n \"\n \n for fuzzer in $fuzzers ; do\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex ec185f061c..f2d74de457 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -5,3 +5,4 @@ fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\n fuzz-parse-attr-line\n+fuzz-url-decode-mem\ndiff --git a/oss-fuzz/fuzz-url-decode-mem.c b/oss-fuzz/fuzz-url-decode-mem.c\nnew file mode 100644\nindex 0000000000..2342aa993b\n--- /dev/null\n+++ b/oss-fuzz/fuzz-url-decode-mem.c\n@@ -0,0 +1,43 @@\n+#include \"git-compat-util.h\"\n+#include <stddef.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include \"url.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tchar *buf;\n+\tchar *r;\n+\tconst char *pbuf;\n+\n+\tbuf = malloc(size + 1);\n+\tif (!buf)\n+\t\treturn 0;\n+\n+\tmemcpy(buf, data, size);\n+\tbuf[size] = 0;\n+\n+\t// start fuzzing\n+\tr = url_decode(buf);\n+\tfree(r);\n+\n+\tr = url_percent_decode(buf);\n+\tfree(r);\n+\n+\tpbuf = (const char*) buf;\n+\tr = url_decode_parameter_name(&pbuf);\n+\tfree(r);\n+\n+\tpbuf = (const char*) buf;\n+\tr = url_decode_parameter_value(&pbuf);\n+\tfree(r);\n+\n+\t// cleanup\n+\tfree(buf);\n+\n+\treturn 0;\n+}\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"},{"id":"504756","messageId":"xmqq4j5jk5h0.fsf@gitster.g","threadId":"62306","inReplyTo":"cover.1728594659.git.steadmon@google.com","subject":"Re: [PATCH 0/3] fuzz: port OSS-Fuzz tests back to Git","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-10-10T21:34:03Z","receivedAt":"2024-10-10T21:34:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Josh Steadmon <steadmon@google.com> writes:\n\n> Git's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\n> additional fuzz tests have been contributed directly to OSS-Fuzz;\n> however, these tests are vulnerable to bitrot because they are not built\n> during Git's CI runs, and thus breaking changes are much less likely to\n> be noticed by Git contributors.\n>\n> OSS-Fuzz's recommended setup is for tests to live in the repository of\n> the code they test and to be built along with other tests [1].\n>\n> Port some of these tests back to the Git project, so that they can be\n> built and tested during our normal development workflow and CI, and as\n> such avoid future bitrot.\n>\n> [1] https://google.github.io/oss-fuzz/advanced-topics/ideal-integration/\n\nThanks!  Very much appreciated.\n\n> Eric Sesterhenn (3):\n>   fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz\n>   fuzz: port fuzz-parse-attr-line from OSS-Fuzz\n>   fuzz: port fuzz-url-decode-mem from OSS-Fuzz\n>\n>  Makefile                                   |  3 ++\n>  attr.c                                     | 38 +------------------\n>  attr.h                                     | 43 ++++++++++++++++++++++\n>  ci/run-build-and-minimal-fuzzers.sh        | 15 +++++++-\n>  oss-fuzz/.gitignore                        |  3 ++\n>  oss-fuzz/fuzz-credential-from-url-gently.c | 32 ++++++++++++++++\n>  oss-fuzz/fuzz-parse-attr-line.c            | 39 ++++++++++++++++++++\n>  oss-fuzz/fuzz-url-decode-mem.c             | 43 ++++++++++++++++++++++\n>  8 files changed, 177 insertions(+), 39 deletions(-)\n>  create mode 100644 oss-fuzz/fuzz-credential-from-url-gently.c\n>  create mode 100644 oss-fuzz/fuzz-parse-attr-line.c\n>  create mode 100644 oss-fuzz/fuzz-url-decode-mem.c\n>\n>\n> base-commit: 159f2d50e75c17382c9f4eb7cbda671a6fa612d1\n"},{"id":"504830","messageId":"ZwjsK-uprX0eUAl5@ugly","threadId":"62306","inReplyTo":"625b8d607ed2c95e396e7794616d9f290f23d15c.1728594659.git.steadmon@google.com","subject":"Re: [PATCH 1/3] fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz","fromName":"Oswald Buddenhagen","fromEmail":"oswald.buddenhagen@gmx.de","sentAt":"2024-10-11T09:13:15Z","receivedAt":"2024-10-11T09:13:23Z","isPatch":true,"sender":{"key":"oswald.buddenhagen@gmx.de","avatar":"https://avatars.githubusercontent.com/u/812380?v=4"},"body":"just some nits:\n\nOn Thu, Oct 10, 2024 at 02:11:53PM -0700, Josh Steadmon wrote:\n>+++ b/ci/run-build-and-minimal-fuzzers.sh\n>+fuzzers=\"\n>+commit-graph \\\n>+config \\\n>+credential-from-url-gently \\\n>+date \\\n>+pack-headers \\\n>+pack-idx \\\n>+\"\nthe trailing space-backslashes can be left out, which would make the\ncode less noisy. then the variable would contain linebreaks instead of\nspaces, which the for loop would be just fine with (as $IFS contains\nLF).\n\n>+for fuzzer in $fuzzers ; do\n>\nthe space before the semicolon seems excessive.\n\n>+++ b/oss-fuzz/fuzz-credential-from-url-gently.c\n>+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n>+\nare these seemingly redundant prototypes meant to suppress compiler\nwarnings?\n\n>+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n>+{\n"},{"id":"504847","messageId":"xmqqjzeeha1o.fsf@gitster.g","threadId":"62306","inReplyTo":"ZwjsK-uprX0eUAl5@ugly","subject":"Re: [PATCH 1/3] fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-10-11T16:35:47Z","receivedAt":"2024-10-11T16:35:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Oswald Buddenhagen <oswald.buddenhagen@gmx.de> writes:\n\n> just some nits:\n>\n> On Thu, Oct 10, 2024 at 02:11:53PM -0700, Josh Steadmon wrote:\n>>+++ b/ci/run-build-and-minimal-fuzzers.sh\n>>+fuzzers=\"\n>>+commit-graph \\\n>>...\n>>+pack-idx \\\n>>+\"\n> the trailing space-backslashes can be left out, which would make the\n> code less noisy. then the variable would contain linebreaks instead of\n> spaces, which the for loop would be just fine with (as $IFS contains\n> LF).\n\nPerfect.\n\nThanks.\n"},{"id":"505051","messageId":"qno6z2tvnx44qvcz3s3klldpshszfw3d6zk5io6chsg4mz7t4v@c7hfalghw56u","threadId":"62306","inReplyTo":"ZwjsK-uprX0eUAl5@ugly","subject":"Re: [PATCH 1/3] fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-14T20:35:03Z","receivedAt":"2024-10-14T20:35:09Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"On 2024.10.11 11:13, Oswald Buddenhagen wrote:\n> just some nits:\n> \n> On Thu, Oct 10, 2024 at 02:11:53PM -0700, Josh Steadmon wrote:\n> > +++ b/ci/run-build-and-minimal-fuzzers.sh\n> > +fuzzers=\"\n> > +commit-graph \\\n> > +config \\\n> > +credential-from-url-gently \\\n> > +date \\\n> > +pack-headers \\\n> > +pack-idx \\\n> > +\"\n> the trailing space-backslashes can be left out, which would make the\n> code less noisy. then the variable would contain linebreaks instead of\n> spaces, which the for loop would be just fine with (as $IFS contains\n> LF).\n\nFixed in V2.\n\n> > +for fuzzer in $fuzzers ; do\n> > \n> the space before the semicolon seems excessive.\n\nFixed in V2.\n\n> > +++ b/oss-fuzz/fuzz-credential-from-url-gently.c\n> > +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n> > +\n> are these seemingly redundant prototypes meant to suppress compiler\n> warnings?\n\nYes, unfortunately we get complaints without them.\n\n> > +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n> > +{\n\nThanks for the review!\n"},{"id":"505052","messageId":"dulefctj55gna2kkxohggxwhhgot2sp73flbnx2rf2bucq6ewj@tpvobir5g63n","threadId":"62306","inReplyTo":"625b8d607ed2c95e396e7794616d9f290f23d15c.1728594659.git.steadmon@google.com","subject":"Re: [PATCH 1/3] fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-14T20:43:24Z","receivedAt":"2024-10-14T20:43:30Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"On 2024.10.10 14:11, Josh Steadmon wrote:\n> diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh\n> index af8065f349..d9d3ad23c7 100755\n> --- a/ci/run-build-and-minimal-fuzzers.sh\n> +++ b/ci/run-build-and-minimal-fuzzers.sh\n> @@ -13,8 +13,17 @@ group \"Build fuzzers\" make \\\n>  \tLIB_FUZZING_ENGINE=\"-fsanitize=fuzzer,address\" \\\n>  \tfuzz-all\n>  \n> -for fuzzer in commit-graph config date pack-headers pack-idx ; do\n> +fuzzers=\"\n> +commit-graph \\\n> +config \\\n> +credential-from-url-gently \\\n> +date \\\n> +pack-headers \\\n> +pack-idx \\\n> +\"\n> +\n> +for fuzzer in $fuzzers ; do\n>  \tbegin_group \"fuzz-$fuzzer\"\n> -\t./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n> +\techo ./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n>  \tend_group \"fuzz-$fuzzer\"\n>  done\n\nI'm not sure how this \"echo\" got into the diff here, but I've removed it\nin V2.\n"},{"id":"505060","messageId":"cover.1728939687.git.steadmon@google.com","threadId":"62306","inReplyTo":"cover.1728594659.git.steadmon@google.com","subject":"[PATCH v2 0/3] fuzz: port OSS-Fuzz tests back to Git","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-14T21:04:07Z","receivedAt":"2024-10-14T21:04:12Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"Git's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nOSS-Fuzz's recommended setup is for tests to live in the repository of\nthe code they test and to be built along with other tests [1].\n\nPort some of these tests back to the Git project, so that they can be\nbuilt and tested during our normal development workflow and CI, and as\nsuch avoid future bitrot.\n\n[1] https://google.github.io/oss-fuzz/advanced-topics/ideal-integration/\n\nChanges in V2:\n* Remove an errant `echo` in ci/run-build-and-minimal-fuzzers.sh\n* Fix some style nits in ci/run-build-and-minimal-fuzzers.sh\n* Fix whitespace errors in attr.{h,c}\n\n\nEric Sesterhenn (3):\n  fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz\n  fuzz: port fuzz-parse-attr-line from OSS-Fuzz\n  fuzz: port fuzz-url-decode-mem from OSS-Fuzz\n\n Makefile                                   |  3 ++\n attr.c                                     | 40 +-------------------\n attr.h                                     | 43 ++++++++++++++++++++++\n ci/run-build-and-minimal-fuzzers.sh        | 13 ++++++-\n oss-fuzz/.gitignore                        |  3 ++\n oss-fuzz/fuzz-credential-from-url-gently.c | 32 ++++++++++++++++\n oss-fuzz/fuzz-parse-attr-line.c            | 39 ++++++++++++++++++++\n oss-fuzz/fuzz-url-decode-mem.c             | 43 ++++++++++++++++++++++\n 8 files changed, 177 insertions(+), 39 deletions(-)\n create mode 100644 oss-fuzz/fuzz-credential-from-url-gently.c\n create mode 100644 oss-fuzz/fuzz-parse-attr-line.c\n create mode 100644 oss-fuzz/fuzz-url-decode-mem.c\n\nRange-diff against v1:\n1:  625b8d607e ! 1:  04225dd421 fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz\n    @@ ci/run-build-and-minimal-fuzzers.sh: group \"Build fuzzers\" make \\\n      \n     -for fuzzer in commit-graph config date pack-headers pack-idx ; do\n     +fuzzers=\"\n    -+commit-graph \\\n    -+config \\\n    -+credential-from-url-gently \\\n    -+date \\\n    -+pack-headers \\\n    -+pack-idx \\\n    ++commit-graph\n    ++config\n    ++credential-from-url-gently\n    ++date\n    ++pack-headers\n    ++pack-idx\n     +\"\n     +\n    -+for fuzzer in $fuzzers ; do\n    ++for fuzzer in $fuzzers; do\n      \tbegin_group \"fuzz-$fuzzer\"\n    --\t./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n    -+\techo ./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n    + \t./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n      \tend_group \"fuzz-$fuzzer\"\n    - done\n     \n      ## oss-fuzz/.gitignore ##\n     @@\n2:  770fe27c67 ! 2:  16c6573190 fuzz: port fuzz-parse-attr-line from OSS-Fuzz\n    @@ attr.c: static const char *parse_attr(const char *src, int lineno, const char *c\n      }\n      \n     -static struct match_attr *parse_attr_line(const char *line, const char *src,\n    +-\t\t\t\t\t  int lineno, unsigned flags)\n     +struct match_attr *parse_attr_line(const char *line, const char *src,\n    - \t\t\t\t\t  int lineno, unsigned flags)\n    ++\t\t\t\t   int lineno, unsigned flags)\n      {\n      \tsize_t namelen, num_attr, i;\n    + \tconst char *cp, *name, *states;\n     \n      ## attr.h ##\n     @@ attr.h: int git_attr_system_is_enabled(void);\n    @@ attr.h: int git_attr_system_is_enabled(void);\n     +};\n     +\n     +struct match_attr *parse_attr_line(const char *line, const char *src,\n    -+\t\t\t\t\t  int lineno, unsigned flags);\n    ++\t\t\t\t   int lineno, unsigned flags);\n     +\n      #endif /* ATTR_H */\n     \n      ## ci/run-build-and-minimal-fuzzers.sh ##\n    -@@ ci/run-build-and-minimal-fuzzers.sh: credential-from-url-gently \\\n    - date \\\n    - pack-headers \\\n    - pack-idx \\\n    -+parse-attr-line \\\n    +@@ ci/run-build-and-minimal-fuzzers.sh: credential-from-url-gently\n    + date\n    + pack-headers\n    + pack-idx\n    ++parse-attr-line\n      \"\n      \n    - for fuzzer in $fuzzers ; do\n    + for fuzzer in $fuzzers; do\n     \n      ## oss-fuzz/.gitignore ##\n     @@ oss-fuzz/.gitignore: fuzz-credential-from-url-gently\n3:  4c9813313c ! 3:  ec6b5eed71 fuzz: port fuzz-url-decode-mem from OSS-Fuzz\n    @@ Makefile: FUZZ_OBJS += oss-fuzz/fuzz-date.o\n      \n     \n      ## ci/run-build-and-minimal-fuzzers.sh ##\n    -@@ ci/run-build-and-minimal-fuzzers.sh: date \\\n    - pack-headers \\\n    - pack-idx \\\n    - parse-attr-line \\\n    -+url-decode-mem \\\n    +@@ ci/run-build-and-minimal-fuzzers.sh: date\n    + pack-headers\n    + pack-idx\n    + parse-attr-line\n    ++url-decode-mem\n      \"\n      \n    - for fuzzer in $fuzzers ; do\n    + for fuzzer in $fuzzers; do\n     \n      ## oss-fuzz/.gitignore ##\n     @@ oss-fuzz/.gitignore: fuzz-date\n\nbase-commit: 159f2d50e75c17382c9f4eb7cbda671a6fa612d1\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"},{"id":"505061","messageId":"04225dd4214cf79256805055f1c52012e62b8e8b.1728939687.git.steadmon@google.com","threadId":"62306","inReplyTo":"cover.1728939687.git.steadmon@google.com","subject":"[PATCH v2 1/3] fuzz: port fuzz-credential-from-url-gently from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-14T21:04:08Z","receivedAt":"2024-10-14T21:04:14Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"From: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>\n\nGit's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nPort one of these tests back to the Git project:\nfuzz-credential-from-url-gently\n\nThis test was originally written by Eric Sesterhenn as part of a\nsecurity audit of Git [2]. It was then contributed to the OSS-Fuzz repo\nin commit c58ac4492 (Git fuzzing: uncomment the existing and add new\ntargets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon)\nhave verified with both Eric and Jaroslav that they're OK with moving\nthis test to the Git project.\n\n[1] https://github.com/google/oss-fuzz\n[2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf\n\nCo-authored-by: Jaroslav Lobačevski <jarlob@gmail.com>\nCo-authored-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Josh Steadmon <steadmon@google.com>\n---\n Makefile                                   |  1 +\n ci/run-build-and-minimal-fuzzers.sh        | 11 +++++++-\n oss-fuzz/.gitignore                        |  1 +\n oss-fuzz/fuzz-credential-from-url-gently.c | 32 ++++++++++++++++++++++\n 4 files changed, 44 insertions(+), 1 deletion(-)\n create mode 100644 oss-fuzz/fuzz-credential-from-url-gently.c\n\ndiff --git a/Makefile b/Makefile\nindex e298c8b55e..3ce391062f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2378,6 +2378,7 @@ endif\n FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o\n FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o\n FUZZ_OBJS += oss-fuzz/fuzz-config.o\n+FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o\n FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\ndiff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh\nindex af8065f349..631796ab8b 100755\n--- a/ci/run-build-and-minimal-fuzzers.sh\n+++ b/ci/run-build-and-minimal-fuzzers.sh\n@@ -13,7 +13,16 @@ group \"Build fuzzers\" make \\\n \tLIB_FUZZING_ENGINE=\"-fsanitize=fuzzer,address\" \\\n \tfuzz-all\n \n-for fuzzer in commit-graph config date pack-headers pack-idx ; do\n+fuzzers=\"\n+commit-graph\n+config\n+credential-from-url-gently\n+date\n+pack-headers\n+pack-idx\n+\"\n+\n+for fuzzer in $fuzzers; do\n \tbegin_group \"fuzz-$fuzzer\"\n \t./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1\n \tend_group \"fuzz-$fuzzer\"\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex a877c11f42..2cfc845b20 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -1,5 +1,6 @@\n fuzz-commit-graph\n fuzz-config\n+fuzz-credential-from-url-gently\n fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\ndiff --git a/oss-fuzz/fuzz-credential-from-url-gently.c b/oss-fuzz/fuzz-credential-from-url-gently.c\nnew file mode 100644\nindex 0000000000..c872f9ad2d\n--- /dev/null\n+++ b/oss-fuzz/fuzz-credential-from-url-gently.c\n@@ -0,0 +1,32 @@\n+#include \"git-compat-util.h\"\n+#include <stddef.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include \"credential.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tstruct credential c;\n+\tchar *buf;\n+\n+\tbuf = malloc(size + 1);\n+\tif (!buf)\n+\t\treturn 0;\n+\n+\tmemcpy(buf, data, size);\n+\tbuf[size] = 0;\n+\n+\t// start fuzzing\n+\tcredential_init(&c);\n+\tcredential_from_url_gently(&c, buf, 1);\n+\n+\t// cleanup\n+\tcredential_clear(&c);\n+\tfree(buf);\n+\n+\treturn 0;\n+}\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"},{"id":"505062","messageId":"16c6573190e0289eb1f38330796177fb1a066804.1728939687.git.steadmon@google.com","threadId":"62306","inReplyTo":"cover.1728939687.git.steadmon@google.com","subject":"[PATCH v2 2/3] fuzz: port fuzz-parse-attr-line from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-14T21:04:09Z","receivedAt":"2024-10-14T21:04:15Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"From: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>\n\nGit's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nPort one of these tests back to the Git project:\nfuzz-parse-attr-line\n\nThis test was originally written by Eric Sesterhenn as part of a\nsecurity audit of Git [2]. It was then contributed to the OSS-Fuzz repo\nin commit c58ac4492 (Git fuzzing: uncomment the existing and add new\ntargets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon)\nhave verified with both Eric and Jaroslav that they're OK with moving\nthis test to the Git project.\n\n[1] https://github.com/google/oss-fuzz\n[2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf\n\nCo-authored-by: Jaroslav Lobačevski <jarlob@gmail.com>\nCo-authored-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Josh Steadmon <steadmon@google.com>\n---\n Makefile                            |  1 +\n attr.c                              | 40 ++-------------------------\n attr.h                              | 43 +++++++++++++++++++++++++++++\n ci/run-build-and-minimal-fuzzers.sh |  1 +\n oss-fuzz/.gitignore                 |  1 +\n oss-fuzz/fuzz-parse-attr-line.c     | 39 ++++++++++++++++++++++++++\n 6 files changed, 87 insertions(+), 38 deletions(-)\n create mode 100644 oss-fuzz/fuzz-parse-attr-line.c\n\ndiff --git a/Makefile b/Makefile\nindex 3ce391062f..141e194bf5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2382,6 +2382,7 @@ FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o\n FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n+FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o\n .PHONY: fuzz-objs\n fuzz-objs: $(FUZZ_OBJS)\n \ndiff --git a/attr.c b/attr.c\nindex 06b5b5e55e..b0073c5277 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -259,42 +259,6 @@ const struct git_attr *git_attr(const char *name)\n \treturn git_attr_internal(name, strlen(name));\n }\n \n-/* What does a matched pattern decide? */\n-struct attr_state {\n-\tconst struct git_attr *attr;\n-\tconst char *setto;\n-};\n-\n-struct pattern {\n-\tconst char *pattern;\n-\tint patternlen;\n-\tint nowildcardlen;\n-\tunsigned flags;\t\t/* PATTERN_FLAG_* */\n-};\n-\n-/*\n- * One rule, as from a .gitattributes file.\n- *\n- * If is_macro is true, then u.attr is a pointer to the git_attr being\n- * defined.\n- *\n- * If is_macro is false, then u.pat is the filename pattern to which the\n- * rule applies.\n- *\n- * In either case, num_attr is the number of attributes affected by\n- * this rule, and state is an array listing them.  The attributes are\n- * listed as they appear in the file (macros unexpanded).\n- */\n-struct match_attr {\n-\tunion {\n-\t\tstruct pattern pat;\n-\t\tconst struct git_attr *attr;\n-\t} u;\n-\tchar is_macro;\n-\tsize_t num_attr;\n-\tstruct attr_state state[FLEX_ARRAY];\n-};\n-\n static const char blank[] = \" \\t\\r\\n\";\n \n /* Flags usable in read_attr() and parse_attr_line() family of functions. */\n@@ -353,8 +317,8 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,\n \treturn ep + strspn(ep, blank);\n }\n \n-static struct match_attr *parse_attr_line(const char *line, const char *src,\n-\t\t\t\t\t  int lineno, unsigned flags)\n+struct match_attr *parse_attr_line(const char *line, const char *src,\n+\t\t\t\t   int lineno, unsigned flags)\n {\n \tsize_t namelen, num_attr, i;\n \tconst char *cp, *name, *states;\ndiff --git a/attr.h b/attr.h\nindex bb33b60880..a04a521092 100644\n--- a/attr.h\n+++ b/attr.h\n@@ -240,4 +240,47 @@ int git_attr_system_is_enabled(void);\n \n extern char *git_attr_tree;\n \n+/*\n+ * Exposed for fuzz-testing only.\n+ */\n+\n+/* What does a matched pattern decide? */\n+struct attr_state {\n+\tconst struct git_attr *attr;\n+\tconst char *setto;\n+};\n+\n+struct pattern {\n+\tconst char *pattern;\n+\tint patternlen;\n+\tint nowildcardlen;\n+\tunsigned flags;\t\t/* PATTERN_FLAG_* */\n+};\n+\n+/*\n+ * One rule, as from a .gitattributes file.\n+ *\n+ * If is_macro is true, then u.attr is a pointer to the git_attr being\n+ * defined.\n+ *\n+ * If is_macro is false, then u.pat is the filename pattern to which the\n+ * rule applies.\n+ *\n+ * In either case, num_attr is the number of attributes affected by\n+ * this rule, and state is an array listing them.  The attributes are\n+ * listed as they appear in the file (macros unexpanded).\n+ */\n+struct match_attr {\n+\tunion {\n+\t\tstruct pattern pat;\n+\t\tconst struct git_attr *attr;\n+\t} u;\n+\tchar is_macro;\n+\tsize_t num_attr;\n+\tstruct attr_state state[FLEX_ARRAY];\n+};\n+\n+struct match_attr *parse_attr_line(const char *line, const char *src,\n+\t\t\t\t   int lineno, unsigned flags);\n+\n #endif /* ATTR_H */\ndiff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh\nindex 631796ab8b..13c85320d6 100755\n--- a/ci/run-build-and-minimal-fuzzers.sh\n+++ b/ci/run-build-and-minimal-fuzzers.sh\n@@ -20,6 +20,7 @@ credential-from-url-gently\n date\n pack-headers\n pack-idx\n+parse-attr-line\n \"\n \n for fuzzer in $fuzzers; do\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex 2cfc845b20..ec185f061c 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -4,3 +4,4 @@ fuzz-credential-from-url-gently\n fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\n+fuzz-parse-attr-line\ndiff --git a/oss-fuzz/fuzz-parse-attr-line.c b/oss-fuzz/fuzz-parse-attr-line.c\nnew file mode 100644\nindex 0000000000..45a4c4e53c\n--- /dev/null\n+++ b/oss-fuzz/fuzz-parse-attr-line.c\n@@ -0,0 +1,39 @@\n+#include \"git-compat-util.h\"\n+#include <stddef.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include \"attr.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tstruct match_attr *res;\n+\tchar *buf;\n+\n+\tbuf = malloc(size + 1);\n+\tif (!buf)\n+\t\treturn 0;\n+\n+\tmemcpy(buf, data, size);\n+\tbuf[size] = 0;\n+\n+\tres = parse_attr_line(buf, \"dummy\", 0, 0);\n+\n+\tif (res) {\n+\t\tint j;\n+\t\tfor (j = 0; j < res->num_attr; j++) {\n+\t\t\tconst char *setto = res->state[j].setto;\n+\t\t\tif (ATTR_TRUE(setto) || ATTR_FALSE(setto) ||\n+\t\t\t\tATTR_UNSET(setto))\n+\t\t\t\t;\n+\t\t\telse\n+\t\t\t\tfree((char *)setto);\n+\t\t}\n+\t\tfree(res);\n+\t}\n+\tfree(buf);\n+\n+\treturn 0;\n+}\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"},{"id":"505063","messageId":"ec6b5eed712e89c31e0d3348fffa04ea2100ef6c.1728939687.git.steadmon@google.com","threadId":"62306","inReplyTo":"cover.1728939687.git.steadmon@google.com","subject":"[PATCH v2 3/3] fuzz: port fuzz-url-decode-mem from OSS-Fuzz","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2024-10-14T21:04:10Z","receivedAt":"2024-10-14T21:04:17Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"From: Eric Sesterhenn <eric.sesterhenn@x41-dsec.de>\n\nGit's fuzz tests are run continuously as part of OSS-Fuzz [1]. Several\nadditional fuzz tests have been contributed directly to OSS-Fuzz;\nhowever, these tests are vulnerable to bitrot because they are not built\nduring Git's CI runs, and thus breaking changes are much less likely to\nbe noticed by Git contributors.\n\nPort one of these tests back to the Git project:\nfuzz-url-decode-mem\n\nThis test was originally written by Eric Sesterhenn as part of a\nsecurity audit of Git [2]. It was then contributed to the OSS-Fuzz repo\nin commit c58ac4492 (Git fuzzing: uncomment the existing and add new\ntargets. (#11486), 2024-02-21) by Jaroslav Lobačevski. I (Josh Steadmon)\nhave verified with both Eric and Jaroslav that they're OK with moving\nthis test to the Git project.\n\n[1] https://github.com/google/oss-fuzz\n[2] https://ostif.org/wp-content/uploads/2023/01/X41-OSTIF-Gitlab-Git-Security-Audit-20230117-public.pdf\n\nCo-authored-by: Jaroslav Lobačevski <jarlob@gmail.com>\nCo-authored-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Josh Steadmon <steadmon@google.com>\n---\n Makefile                            |  1 +\n ci/run-build-and-minimal-fuzzers.sh |  1 +\n oss-fuzz/.gitignore                 |  1 +\n oss-fuzz/fuzz-url-decode-mem.c      | 43 +++++++++++++++++++++++++++++\n 4 files changed, 46 insertions(+)\n create mode 100644 oss-fuzz/fuzz-url-decode-mem.c\n\ndiff --git a/Makefile b/Makefile\nindex 141e194bf5..2cd7a6e003 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -2383,6 +2383,7 @@ FUZZ_OBJS += oss-fuzz/fuzz-date.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o\n FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o\n FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o\n+FUZZ_OBJS += oss-fuzz/fuzz-url-decode-mem.o\n .PHONY: fuzz-objs\n fuzz-objs: $(FUZZ_OBJS)\n \ndiff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh\nindex 13c85320d6..e7b97952e7 100755\n--- a/ci/run-build-and-minimal-fuzzers.sh\n+++ b/ci/run-build-and-minimal-fuzzers.sh\n@@ -21,6 +21,7 @@ date\n pack-headers\n pack-idx\n parse-attr-line\n+url-decode-mem\n \"\n \n for fuzzer in $fuzzers; do\ndiff --git a/oss-fuzz/.gitignore b/oss-fuzz/.gitignore\nindex ec185f061c..f2d74de457 100644\n--- a/oss-fuzz/.gitignore\n+++ b/oss-fuzz/.gitignore\n@@ -5,3 +5,4 @@ fuzz-date\n fuzz-pack-headers\n fuzz-pack-idx\n fuzz-parse-attr-line\n+fuzz-url-decode-mem\ndiff --git a/oss-fuzz/fuzz-url-decode-mem.c b/oss-fuzz/fuzz-url-decode-mem.c\nnew file mode 100644\nindex 0000000000..2342aa993b\n--- /dev/null\n+++ b/oss-fuzz/fuzz-url-decode-mem.c\n@@ -0,0 +1,43 @@\n+#include \"git-compat-util.h\"\n+#include <stddef.h>\n+#include <stdlib.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <stdio.h>\n+#include \"url.h\"\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n+\n+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n+{\n+\tchar *buf;\n+\tchar *r;\n+\tconst char *pbuf;\n+\n+\tbuf = malloc(size + 1);\n+\tif (!buf)\n+\t\treturn 0;\n+\n+\tmemcpy(buf, data, size);\n+\tbuf[size] = 0;\n+\n+\t// start fuzzing\n+\tr = url_decode(buf);\n+\tfree(r);\n+\n+\tr = url_percent_decode(buf);\n+\tfree(r);\n+\n+\tpbuf = (const char*) buf;\n+\tr = url_decode_parameter_name(&pbuf);\n+\tfree(r);\n+\n+\tpbuf = (const char*) buf;\n+\tr = url_decode_parameter_value(&pbuf);\n+\tfree(r);\n+\n+\t// cleanup\n+\tfree(buf);\n+\n+\treturn 0;\n+}\n-- \n2.47.0.rc1.288.g06298d1525-goog\n\n"}]}