aboutsummaryrefslogtreecommitdiffstats
path: root/remote-curl.c
diff options
context:
space:
mode:
authorDenton Liu <liu.denton@gmail.com>2020-05-19 06:54:00 -0400
committerJunio C Hamano <gitster@pobox.com>2020-05-24 16:26:00 -0700
commitb0df0c16ead4c5512d506dcbbdf31194d992803c (patch)
treec2a5f0b8bfb8fd410c5b3b1217202d8f91e3df39 /remote-curl.c
parent0181b600a6deb66a346dbcbe8300cf9e2467ebbb (diff)
downloadgit-b0df0c16ead4c5512d506dcbbdf31194d992803c.tar.gz
stateless-connect: send response end packet
Currently, remote-curl acts as a proxy and blindly forwards packets between an HTTP server and fetch-pack. In the case of a stateless RPC connection where the connection is terminated before the transaction is complete, remote-curl will blindly forward the packets before waiting on more input from fetch-pack. Meanwhile, fetch-pack will read the transaction and continue reading, expecting more input to continue the transaction. This results in a deadlock between the two processes. This can be seen in the following command which does not terminate: $ git -c protocol.version=2 clone https://github.com/git/git.git --shallow-since=20151012 Cloning into 'git'... whereas the v1 version does terminate as expected: $ git -c protocol.version=1 clone https://github.com/git/git.git --shallow-since=20151012 Cloning into 'git'... fatal: the remote end hung up unexpectedly Instead of blindly forwarding packets, make remote-curl insert a response end packet after proxying the responses from the remote server when using stateless_connect(). On the RPC client side, ensure that each response ends as described. A separate control packet is chosen because we need to be able to differentiate between what the remote server sends and remote-curl's control packets. By ensuring in the remote-curl code that a server cannot send response end packets, we prevent a malicious server from being able to perform a denial of service attack in which they spoof a response end packet and cause the described deadlock to happen. Reported-by: Force Charlie <charlieio@outlook.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Denton Liu <liu.denton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'remote-curl.c')
-rw-r--r--remote-curl.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/remote-curl.c b/remote-curl.c
index d02cb547e9..75532a8bae 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -703,6 +703,8 @@ static void check_pktline(struct check_pktline_state *state, const char *ptr, si
state->remaining = packet_length(state->len_buf);
if (state->remaining < 0) {
die(_("remote-curl: bad line length character: %.4s"), state->len_buf);
+ } else if (state->remaining == 2) {
+ die(_("remote-curl: unexpected response end packet"));
} else if (state->remaining < 4) {
state->remaining = 0;
} else {
@@ -991,6 +993,9 @@ retry:
if (rpc_in_data.pktline_state.remaining)
err = error(_("%d bytes of body are still expected"), rpc_in_data.pktline_state.remaining);
+ if (stateless_connect)
+ packet_response_end(rpc->in);
+
curl_slist_free_all(headers);
free(gzip_body);
return err;