Since GitHub or GitLab support the v2 protocol, you can get into these kind of deadlock with said v2.
Before Git 2.28 (Q3 2020), the on-the-wire protocol v2 easily falls into a deadlock between the remote-curl
helper and the fetch-pack
process when the server side prematurely throws an error and disconnects.
The communication has been updated to make it more robust.
See commit b0df0c1, commit 0181b60, commit 74b082a, commit 101736a, commit dde72f9 (19 May 2020), and commit 04cc91a, commit 51ca7f8 (18 May 2020) by Denton Liu (Denton-L
).
(Merged by Junio C Hamano -- gitster
-- in commit b37fd14, 09 Jun 2020)
Reported-by: Force Charlie
Helped-by: Jeff King
Signed-off-by: Denton Liu
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.
(Hence your issue)
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.
So your case should not happen anymore with Git 2.28: if the clone has to fail, it will do so explicitily instead of staying "frozen" forever.
Note: with Git 2.33 (Q3 2021), the error message has been updated.
See commit 8232a0f (08 Jul 2021) by Denton Liu (Denton-L
).
(Merged by Junio C Hamano -- gitster
-- in commit 1e893a1, 28 Jul 2021)
pkt-line
: replace "stateless separator" with "response end"
Signed-off-by: Denton Liu
In 0181b60 (pkt-line
: define PACKET_READ_RESPONSE_END, 2020-05-19, Git v2.28.0-rc0 -- merge listed in batch #2) (pkt-line: define PACKET_READ_RESPONSE_END
2020-05-19), the Response End packet was defined for Git's network protocol.
When the patch was sent, it included an oversight where the error messages referenced "stateless separator
", the work-in-progress name, over "response end
", the final name chosen.
Correct these error messages by having them correctly reference a "response end
" packet.