]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'ps/attr-limits' into maint-2.32
authorJunio C Hamano <gitster@pobox.com>
Fri, 9 Dec 2022 08:03:49 +0000 (17:03 +0900)
committerJunio C Hamano <gitster@pobox.com>
Fri, 9 Dec 2022 08:03:49 +0000 (17:03 +0900)
1  2 
attr.c
attr.h
t/t0003-attributes.sh

diff --cc attr.c
index 9e897e43f53196c238d152822f54b37b3ce91288,f9316d14baf835ee498722a4dc26bd9bd56a8efd..d7b8f60e7b414db9bf3f398183d1de851367164f
--- 1/attr.c
--- 2/attr.c
+++ b/attr.c
@@@ -335,10 -331,9 +335,9 @@@ static const char *parse_attr(const cha
  }
  
  static struct match_attr *parse_attr_line(const char *line, const char *src,
 -                                        int lineno, int macro_ok)
 +                                        int lineno, unsigned flags)
  {
-       int namelen;
-       int num_attr, i;
+       size_t namelen, num_attr, i;
        const char *cp, *name, *states;
        struct match_attr *res = NULL;
        int is_macro;
@@@ -661,11 -661,11 +665,11 @@@ static void handle_attr_line(struct att
  {
        struct match_attr *a;
  
 -      a = parse_attr_line(line, src, lineno, macro_ok);
 +      a = parse_attr_line(line, src, lineno, flags);
        if (!a)
                return;
-       ALLOC_GROW(res->attrs, res->num_matches + 1, res->alloc);
-       res->attrs[res->num_matches++] = a;
+       ALLOC_GROW_BY(res->attrs, res->num_matches, 1, res->alloc);
+       res->attrs[res->num_matches - 1] = a;
  }
  
  static struct attr_stack *read_attr_from_array(const char **list)
@@@ -703,33 -702,39 +707,45 @@@ void git_attr_set_direction(enum git_at
        direction = new_direction;
  }
  
 -static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
 +static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
  {
 -      FILE *fp = fopen_or_warn(path, "r");
+       struct strbuf buf = STRBUF_INIT;
 +      int fd;
 +      FILE *fp;
        struct attr_stack *res;
-       char buf[2048];
        int lineno = 0;
 -      int fd;
+       struct stat st;
  
 -      if (!fp)
 -              return NULL;
 +      if (flags & READ_ATTR_NOFOLLOW)
 +              fd = open_nofollow(path, O_RDONLY);
 +      else
 +              fd = open(path, O_RDONLY);
  
 -      fd = fileno(fp);
 +      if (fd < 0) {
 +              warn_on_fopen_errors(path);
 +              return NULL;
 +      }
 +      fp = xfdopen(fd, "r");
+       if (fstat(fd, &st)) {
+               warning_errno(_("cannot fstat gitattributes file '%s'"), path);
+               fclose(fp);
+               return NULL;
+       }
+       if (st.st_size >= ATTR_MAX_FILE_SIZE) {
+               warning(_("ignoring overly large gitattributes file '%s'"), path);
+               fclose(fp);
+               return NULL;
+       }
  
        CALLOC_ARRAY(res, 1);
-       while (fgets(buf, sizeof(buf), fp)) {
-               char *bufp = buf;
-               if (!lineno)
-                       skip_utf8_bom(&bufp, strlen(bufp));
-               handle_attr_line(res, bufp, path, ++lineno, flags);
+       while (strbuf_getline(&buf, fp) != EOF) {
+               if (!lineno && starts_with(buf.buf, utf8_bom))
+                       strbuf_remove(&buf, 0, strlen(utf8_bom));
 -              handle_attr_line(res, buf.buf, path, ++lineno, macro_ok);
++              handle_attr_line(res, buf.buf, path, ++lineno, flags);
        }
        fclose(fp);
+       strbuf_release(&buf);
        return res;
  }
  
@@@ -744,11 -750,15 +761,15 @@@ static struct attr_stack *read_attr_fro
        if (!istate)
                return NULL;
  
-       buf = read_blob_data_from_index(istate, path, NULL);
+       buf = read_blob_data_from_index(istate, path, &size);
        if (!buf)
                return NULL;
+       if (size >= ATTR_MAX_FILE_SIZE) {
+               warning(_("ignoring overly large gitattributes blob '%s'"), path);
+               return NULL;
+       }
  
 -      res = xcalloc(1, sizeof(*res));
 +      CALLOC_ARRAY(res, 1);
        for (sp = buf; *sp; ) {
                char *ep;
                int more;
diff --cc attr.h
Simple merge
index 1e4c672b84aa366de04969b3c3f073c1f02ce92f,9d9aa2855d226feed852bfe968d8d1a27fcf447e..89d5a0f67fa87d62ea9907a6f11990712b852857
@@@ -342,31 -339,63 +342,90 @@@ test_expect_success 'query binary macr
        test_cmp expect actual
  '
  
 +test_expect_success SYMLINKS 'set up symlink tests' '
 +      echo "* test" >attr &&
 +      rm -f .gitattributes
 +'
 +
 +test_expect_success SYMLINKS 'symlinks respected in core.attributesFile' '
 +      test_when_finished "rm symlink" &&
 +      ln -s attr symlink &&
 +      test_config core.attributesFile "$(pwd)/symlink" &&
 +      attr_check file set
 +'
 +
 +test_expect_success SYMLINKS 'symlinks respected in info/attributes' '
 +      test_when_finished "rm .git/info/attributes" &&
 +      ln -s ../../attr .git/info/attributes &&
 +      attr_check file set
 +'
 +
 +test_expect_success SYMLINKS 'symlinks not respected in-tree' '
 +      test_when_finished "rm -rf .gitattributes subdir" &&
 +      ln -s attr .gitattributes &&
 +      mkdir subdir &&
 +      ln -s ../attr subdir/.gitattributes &&
 +      attr_check_basic subdir/file unspecified &&
 +      test_i18ngrep "unable to access.*gitattributes" err
 +'
 +
+ test_expect_success 'large attributes line ignored in tree' '
+       test_when_finished "rm .gitattributes" &&
+       printf "path %02043d" 1 >.gitattributes &&
+       git check-attr --all path >actual 2>err &&
+       echo "warning: ignoring overly long attributes line 1" >expect &&
+       test_cmp expect err &&
+       test_must_be_empty actual
+ '
+ test_expect_success 'large attributes line ignores trailing content in tree' '
+       test_when_finished "rm .gitattributes" &&
+       # older versions of Git broke lines at 2048 bytes; the 2045 bytes
+       # of 0-padding here is accounting for the three bytes of "a 1", which
+       # would knock "trailing" to the "next" line, where it would be
+       # erroneously parsed.
+       printf "a %02045dtrailing attribute\n" 1 >.gitattributes &&
+       git check-attr --all trailing >actual 2>err &&
+       echo "warning: ignoring overly long attributes line 1" >expect &&
+       test_cmp expect err &&
+       test_must_be_empty actual
+ '
+ test_expect_success EXPENSIVE 'large attributes file ignored in tree' '
+       test_when_finished "rm .gitattributes" &&
+       dd if=/dev/zero of=.gitattributes bs=101M count=1 2>/dev/null &&
+       git check-attr --all path >/dev/null 2>err &&
+       echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect &&
+       test_cmp expect err
+ '
+ test_expect_success 'large attributes line ignored in index' '
+       test_when_finished "git update-index --remove .gitattributes" &&
+       blob=$(printf "path %02043d" 1 | git hash-object -w --stdin) &&
+       git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+       git check-attr --cached --all path >actual 2>err &&
+       echo "warning: ignoring overly long attributes line 1" >expect &&
+       test_cmp expect err &&
+       test_must_be_empty actual
+ '
+ test_expect_success 'large attributes line ignores trailing content in index' '
+       test_when_finished "git update-index --remove .gitattributes" &&
+       blob=$(printf "a %02045dtrailing attribute\n" 1 | git hash-object -w --stdin) &&
+       git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+       git check-attr --cached --all trailing >actual 2>err &&
+       echo "warning: ignoring overly long attributes line 1" >expect &&
+       test_cmp expect err &&
+       test_must_be_empty actual
+ '
+ test_expect_success EXPENSIVE 'large attributes file ignored in index' '
+       test_when_finished "git update-index --remove .gitattributes" &&
+       blob=$(dd if=/dev/zero bs=101M count=1 2>/dev/null | git hash-object -w --stdin) &&
+       git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+       git check-attr --cached --all path >/dev/null 2>err &&
+       echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect &&
+       test_cmp expect err
+ '
  test_done