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");