git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 5/6] remote-curl: error on incomplete packet

From
Denton Liu <liu.denton@gmail.com>
Date
May 13, 2020, 18:04 UTC
Message-ID
<3ed7cf87aaa40ee66b20aa929d89d28fefcec312.1589393036.git.liu.denton@gmail.com>
In-Reply-To
<cover.1589393036.git.liu.denton@gmail.com>

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 with a partially written packet, remote-curl will blindly send the partially written packet before waiting on more input from fetch-pack. Meanwhile, fetch-pack will read the partial packet and continue reading, expecting more input. This results in a deadlock between the two processes.

Instead of blindly forwarding packets, inspect each packet to ensure that it is a full packet, erroring out if a partial packet is sent.

Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
Notes:
    Unfortunately, I'm not really sure how to test this.
 remote-curl.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/remote-curl.c b/remote-curl.c
index da3e07184a..8b740354e5 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -682,6 +682,8 @@ static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp)
 struct rpc_in_data {
 	struct rpc_state *rpc;
 	struct active_request_slot *slot;
+	struct strbuf len_buf;
+	int remaining;
 };
 
 /*
@@ -692,6 +694,7 @@ static size_t rpc_in(char *ptr, size_t eltsize,
 		size_t nmemb, void *buffer_)
 {
 	size_t size = eltsize * nmemb;
+	size_t unwritten = size;
 	struct rpc_in_data *data = buffer_;
 	long response_code;
 
@@ -702,7 +705,42 @@ static size_t rpc_in(char *ptr, size_t eltsize,
 		return size;
 	if (size)
 		data->rpc->any_written = 1;
-	write_or_die(data->rpc->in, ptr, size);
+
+	while (unwritten) {
+		if (!data->remaining) {
+			int digits_remaining = 4 - data->len_buf.len;
+			if (digits_remaining > unwritten)
+				digits_remaining = unwritten;
+			strbuf_add(&data->len_buf, ptr, digits_remaining);
+			ptr += digits_remaining;
+			unwritten -= digits_remaining;
+
+			if (data->len_buf.len == 4) {
+				data->remaining = packet_length(data->len_buf.buf);
+				if (data->remaining < 0) {
+					die(_("remote-curl: bad line length character: %.4s"), data->len_buf.buf);
+				} else if (data->remaining <= 1) {
+					data->remaining = 0;
+				} else if (data->remaining < 4) {
+					die(_("remote-curl: bad line length %d"), data->remaining);
+				} else {
+					data->remaining -= 4;
+				}
+				write_or_die(data->rpc->in, data->len_buf.buf, 4);
+				strbuf_reset(&data->len_buf);
+			}
+		}
+
+		if (data->remaining) {
+			int remaining = data->remaining;
+			if (remaining > unwritten)
+				remaining = unwritten;
+			write_or_die(data->rpc->in, ptr, remaining);
+			ptr += remaining;
+			unwritten -= remaining;
+			data->remaining -= remaining;
+		}
+	}
 	return size;
 }
 
@@ -920,6 +958,8 @@ static int post_rpc(struct rpc_state *rpc, int flush_received)
 	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
 	rpc_in_data.rpc = rpc;
 	rpc_in_data.slot = slot;
+	strbuf_init(&rpc_in_data.len_buf, 4);
+	rpc_in_data.remaining = 0;
 	curl_easy_setopt(slot->curl, CURLOPT_FILE, &rpc_in_data);
 	curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
 
@@ -936,6 +976,9 @@ static int post_rpc(struct rpc_state *rpc, int flush_received)
 	if (!rpc->any_written)
 		err = -1;
 
+	if (rpc_in_data.remaining)
+		err = error(_("%d bytes are still expected"), rpc_in_data.remaining);
+
 	curl_slist_free_all(headers);
 	free(gzip_body);
 	return err;
-- 
2.26.2.706.g87896c9627
Previous: Jeff KingNext: Jeff King
Message 12 of 62 in “remote-curl: partial fix for a deadlock with stateless rpc”
  1. 0/6 remote-curl: partial fix for a deadlock with stateless rpcDenton Liu, May 13, 2020
  2. 1/6 remote-curl: fix typoDenton Liu, May 13, 2020
  3. 2/6 remote-curl: remove label indentationDenton Liu, May 13, 2020
  4. 3/6 transport: combine common cases with a fallthroughDenton Liu, May 13, 2020
  5. Eric SunshineMay 13, 2020
  6. Denton LiuMay 18, 2020
  7. Eric SunshineMay 18, 2020
  8. 4/6 pkt-line: extern packet_length()Denton Liu, May 13, 2020
  9. Eric SunshineMay 13, 2020
  10. Jeff KingMay 15, 2020
  11. Jeff KingMay 15, 2020
  12. 5/6 remote-curl: error on incomplete packetDenton Liu, May 13, 2020
  13. Jeff KingMay 15, 2020
  14. Denton LiuMay 18, 2020
  15. Jeff KingMay 18, 2020
  16. 6/6 remote-curl: ensure last packet is a flushDenton Liu, May 13, 2020
  17. Denton LiuMay 15, 2020
  18. Jeff KingMay 15, 2020
  19. Junio C HamanoMay 18, 2020
  20. Jeff KingMay 18, 2020
  21. Jeff KingMay 18, 2020
  22. 0/7 remote-curl: fix deadlocks when remote server disconnectsDenton Liu, May 18, 2020
  23. 1/7 remote-curl: fix typoDenton Liu, May 18, 2020
  24. 2/7 remote-curl: remove label indentationDenton Liu, May 18, 2020
  25. Junio C HamanoMay 18, 2020
  26. 4/7 pkt-line: extern packet_length()Denton Liu, May 18, 2020
  27. Jeff KingMay 18, 2020
  28. Eric SunshineMay 18, 2020
  29. Jeff KingMay 18, 2020
  30. Junio C HamanoMay 18, 2020
  31. 3/7 transport: extract common fetch_pack() callDenton Liu, May 18, 2020
  32. Junio C HamanoMay 18, 2020
  33. 6/7 pkt-line: PACKET_READ_RESPONSE_ENDDenton Liu, May 18, 2020
  34. 7/7 stateless-connect: send response end packetDenton Liu, May 18, 2020
  35. Jeff KingMay 18, 2020
  36. Denton LiuMay 18, 2020
  37. Jeff KingMay 18, 2020
  38. 5/7 remote-curl: error on incomplete packetDenton Liu, May 18, 2020
  39. Jeff KingMay 18, 2020
  40. Denton LiuMay 18, 2020
  41. Jeff KingMay 18, 2020
  42. Denton LiuMay 18, 2020
  43. Jeff KingMay 18, 2020
  44. Junio C HamanoMay 18, 2020
  45. Jeff KingMay 19, 2020
  46. Junio C HamanoMay 18, 2020
  47. 0/7 remote-curl: fix deadlocks when remote server disconnectsDenton Liu, May 19, 2020
  48. 1/7 remote-curl: fix typoDenton Liu, May 19, 2020
  49. 2/7 remote-curl: remove label indentationDenton Liu, May 19, 2020
  50. 3/7 transport: extract common fetch_pack() callDenton Liu, May 19, 2020
  51. 4/7 pkt-line: extern packet_length()Denton Liu, May 19, 2020
  52. Eric SunshineMay 19, 2020
  53. 6/7 pkt-line: define PACKET_READ_RESPONSE_ENDDenton Liu, May 19, 2020
  54. 5/7 remote-curl: error on incomplete packetDenton Liu, May 19, 2020
  55. 7/7 stateless-connect: send response end packetDenton Liu, May 19, 2020
  56. Jeff KingMay 19, 2020
  57. Denton LiuMay 19, 2020
  58. 8/7 fixup! pkt-line: extern packet_length()Denton Liu, May 19, 2020
  59. 9/9 fixup! remote-curl: error on incomplete packetDenton Liu, May 22, 2020
  60. Jeff KingMay 22, 2020
  61. Denton LiuMay 22, 2020
  62. Jeff KingMay 22, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.