vcs-svn: avoid hangs from corrupt deltas
A corrupt Subversion-format delta can request reads past the end of the preimage. Set sliding_view::max_off so such corruption is caught when it appears rather than blocking in an impossible-to-fulfill read() when input is coming from a socket or pipe. Inspired-by: Ramkumar Ramachandra <artagnon@gmail.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Jonathan Nieder committed
May 27, 2011 at 05:44 UTC
3ac10b2e3fd6d858621f796160d251ad34affc20
2 files changed
+46
-9
t/t9010-svn-fe.sh
+37
-3
@@ -18,12 +18,13 @@ reinit_git () {
18
19
try_dump () {
20
input=$1 &&
21
- maybe_fail=${2:+test_$2} &&
21
+ maybe_fail_svnfe=${2:+test_$2} &&
22
+ maybe_fail_fi=${3:+test_$3} &&
23
24
{
24
- $maybe_fail test-svn-fe "$input" >stream 3<backflow &
25
+ $maybe_fail_svnfe test-svn-fe "$input" >stream 3<backflow &
26
} &&
26
- git fast-import --cat-blob-fd=3 <stream 3>backflow &&
27
+ $maybe_fail_fi git fast-import --cat-blob-fd=3 <stream 3>backflow &&
28
wait $!
29
}
30
@@ -1047,6 +1048,39 @@ test_expect_success PIPE 'deltas need not consume the whole preimage' '
1048
test_cmp expect.3 actual.3
1049
'
1050
1051
+test_expect_success PIPE 'no hang for delta trying to read past end of preimage' '
1052
+ reinit_git &&
1053
+ {
1054
+ # COPY 1
1055
+ printf "SVNQ%b%b" "Q\001\001\002Q" "\001Q" |
1056
+ q_to_nul
1057
+ } >greedy.delta &&
1058
+ {
1059
+ cat <<-\EOF &&
1060
+ SVN-fs-dump-format-version: 3
1061
+
1062
+ Revision-number: 1
1063
+ Prop-content-length: 10
1064
+ Content-length: 10
1065
+
1066
+ PROPS-END
1067
+
1068
+ Node-path: bootstrap
1069
+ Node-kind: file
1070
+ Node-action: add
1071
+ Text-delta: true
1072
+ Prop-content-length: 10
1073
+ EOF
1074
+ echo Text-content-length: $(wc -c <greedy.delta) &&
1075
+ echo Content-length: $((10 + $(wc -c <greedy.delta))) &&
1076
+ echo &&
1077
+ echo PROPS-END &&
1078
+ cat greedy.delta &&
1079
+ echo
1080
+ } >greedydelta.dump &&
1081
+ try_dump greedydelta.dump must_fail might_fail
1082
+'
1083
+
1084
test_expect_success 'set up svn repo' '
1085
svnconf=$PWD/svnconf &&
1086
mkdir -p "$svnconf" &&
vcs-svn/fast_export.c
+9
-6
@@ -198,8 +198,7 @@ static long apply_delta(off_t len, struct line_buffer *input,
198
const char *old_data, uint32_t old_mode)
199
{
200
long ret;
201
- off_t preimage_len = 0;
202
- struct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer, -1);
201
+ struct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer, 0);
202
FILE *out;
203
204
if (init_postimage() || !(out = buffer_tmpfile_rewind(&postimage)))
@@ -211,19 +210,23 @@ static long apply_delta(off_t len, struct line_buffer *input,
210
printf("cat-blob %s\n", old_data);
211
fflush(stdout);
212
response = get_response_line();
214
- if (parse_cat_response_line(response, &preimage_len))
213
+ if (parse_cat_response_line(response, &preimage.max_off))
214
die("invalid cat-blob response: %s", response);
215
+ check_preimage_overflow(preimage.max_off, 1);
216
}
217
if (old_mode == REPO_MODE_LNK) {
218
strbuf_addstr(&preimage.buf, "link ");
219
- check_preimage_overflow(preimage_len, strlen("link "));
220
- preimage_len += strlen("link ");
219
+ check_preimage_overflow(preimage.max_off, strlen("link "));
220
+ preimage.max_off += strlen("link ");
221
+ check_preimage_overflow(preimage.max_off, 1);
222
}
223
if (svndiff0_apply(input, len, &preimage, out))
224
die("cannot apply delta");
225
if (old_data) {
226
/* Read the remainder of preimage and trailing newline. */
226
- if (move_window(&preimage, preimage_len, 1))
227
+ assert(!signed_add_overflows(preimage.max_off, 1));
228
+ preimage.max_off++; /* room for newline */
229
+ if (move_window(&preimage, preimage.max_off - 1, 1))
230
die("cannot seek to end of input");
231
if (preimage.buf.buf[0] != '\n')
232
die("missing newline after cat-blob response");