]> git.ipfire.org Git - thirdparty/git.git/commitdiff
apply: check git diffs for invalid file modes
authorRené Scharfe <l.s.r@web.de>
Tue, 27 Jun 2017 17:03:47 +0000 (19:03 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 27 Jun 2017 17:59:38 +0000 (10:59 -0700)
An empty string as mode specification is accepted silently by git apply,
as Vegard Nossum found out using AFL.  It's interpreted as zero.  Reject
such bogus file modes, and only accept ones consisting exclusively of
octal digits.

Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Rene Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
apply.c
t/t4129-apply-samemode.sh

diff --git a/apply.c b/apply.c
index 1c0bcd737ee339832eaaaf38e26c21cd6036c5fe..4b689d9bf721815f472cddc64eaa8e5be7a1ab8d 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -1011,20 +1011,27 @@ static int gitdiff_newname(struct apply_state *state,
                                   DIFF_NEW_NAME);
 }
 
+static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
+{
+       char *end;
+       *mode = strtoul(line, &end, 8);
+       if (end == line || !isspace(*end))
+               return error(_("invalid mode on line %d: %s"), linenr, line);
+       return 0;
+}
+
 static int gitdiff_oldmode(struct apply_state *state,
                           const char *line,
                           struct patch *patch)
 {
-       patch->old_mode = strtoul(line, NULL, 8);
-       return 0;
+       return parse_mode_line(line, state->linenr, &patch->old_mode);
 }
 
 static int gitdiff_newmode(struct apply_state *state,
                           const char *line,
                           struct patch *patch)
 {
-       patch->new_mode = strtoul(line, NULL, 8);
-       return 0;
+       return parse_mode_line(line, state->linenr, &patch->new_mode);
 }
 
 static int gitdiff_delete(struct apply_state *state,
@@ -1138,7 +1145,7 @@ static int gitdiff_index(struct apply_state *state,
        memcpy(patch->new_sha1_prefix, line, len);
        patch->new_sha1_prefix[len] = 0;
        if (*ptr == ' ')
-               patch->old_mode = strtoul(ptr+1, NULL, 8);
+               return gitdiff_oldmode(state, ptr + 1, patch);
        return 0;
 }
 
index c268298eaf5672c649ca3e4815dc4f43d71efece..5cdd76dfa726d32226b1dd625d21d6280125afb7 100755 (executable)
@@ -13,7 +13,9 @@ test_expect_success setup '
        echo modified >file &&
        git diff --stat -p >patch-0.txt &&
        chmod +x file &&
-       git diff --stat -p >patch-1.txt
+       git diff --stat -p >patch-1.txt &&
+       sed "s/^\(new mode \).*/\1/" <patch-1.txt >patch-empty-mode.txt &&
+       sed "s/^\(new mode \).*/\1garbage/" <patch-1.txt >patch-bogus-mode.txt
 '
 
 test_expect_success FILEMODE 'same mode (no index)' '
@@ -59,4 +61,16 @@ test_expect_success FILEMODE 'mode update (index only)' '
        git ls-files -s file | grep "^100755"
 '
 
+test_expect_success FILEMODE 'empty mode is rejected' '
+       git reset --hard &&
+       test_must_fail git apply patch-empty-mode.txt 2>err &&
+       test_i18ngrep "invalid mode" err
+'
+
+test_expect_success FILEMODE 'bogus mode is rejected' '
+       git reset --hard &&
+       test_must_fail git apply patch-bogus-mode.txt 2>err &&
+       test_i18ngrep "invalid mode" err
+'
+
 test_done