apply: check git diffs for invalid file modes
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>
René Scharfe committed
Jun 27, 2017 at 19:03 UTC
44e5471a8d8ec5f04058220f8b91513b5b5accaa
2 files changed
+27
-6
apply.c
+12
-5
@@ -1011,20 +1011,27 @@ static int gitdiff_newname(struct apply_state *state,
1011
DIFF_NEW_NAME);
1012
}
1013
1014
+static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
1015
+{
1016
+ char *end;
1017
+ *mode = strtoul(line, &end, 8);
1018
+ if (end == line || !isspace(*end))
1019
+ return error(_("invalid mode on line %d: %s"), linenr, line);
1020
+ return 0;
1021
+}
1022
+
1023
static int gitdiff_oldmode(struct apply_state *state,
1024
const char *line,
1025
struct patch *patch)
1026
{
1018
- patch->old_mode = strtoul(line, NULL, 8);
1019
- return 0;
1027
+ return parse_mode_line(line, state->linenr, &patch->old_mode);
1028
}
1029
1030
static int gitdiff_newmode(struct apply_state *state,
1031
const char *line,
1032
struct patch *patch)
1033
{
1026
- patch->new_mode = strtoul(line, NULL, 8);
1027
- return 0;
1034
+ return parse_mode_line(line, state->linenr, &patch->new_mode);
1035
}
1036
1037
static int gitdiff_delete(struct apply_state *state,
@@ -1138,7 +1145,7 @@ static int gitdiff_index(struct apply_state *state,
1145
memcpy(patch->new_sha1_prefix, line, len);
1146
patch->new_sha1_prefix[len] = 0;
1147
if (*ptr == ' ')
1141
- patch->old_mode = strtoul(ptr+1, NULL, 8);
1148
+ return gitdiff_oldmode(state, ptr + 1, patch);
1149
return 0;
1150
}
1151
t/t4129-apply-samemode.sh
+15
-1
@@ -13,7 +13,9 @@ test_expect_success setup '
13
echo modified >file &&
14
git diff --stat -p >patch-0.txt &&
15
chmod +x file &&
16
- git diff --stat -p >patch-1.txt
16
+ git diff --stat -p >patch-1.txt &&
17
+ sed "s/^\(new mode \).*/\1/" <patch-1.txt >patch-empty-mode.txt &&
18
+ sed "s/^\(new mode \).*/\1garbage/" <patch-1.txt >patch-bogus-mode.txt
19
'
20
21
test_expect_success FILEMODE 'same mode (no index)' '
@@ -59,4 +61,16 @@ test_expect_success FILEMODE 'mode update (index only)' '
61
git ls-files -s file | grep "^100755"
62
'
63
64
+test_expect_success FILEMODE 'empty mode is rejected' '
65
+ git reset --hard &&
66
+ test_must_fail git apply patch-empty-mode.txt 2>err &&
67
+ test_i18ngrep "invalid mode" err
68
+'
69
+
70
+test_expect_success FILEMODE 'bogus mode is rejected' '
71
+ git reset --hard &&
72
+ test_must_fail git apply patch-bogus-mode.txt 2>err &&
73
+ test_i18ngrep "invalid mode" err
74
+'
75
+
76
test_done