summaryrefslogtreecommitdiffstats
path: root/http.c
diff options
context:
space:
mode:
authorJeff King <peff@peff.net>2024-09-25 00:01:09 +0200
committerJunio C Hamano <gitster@pobox.com>2024-09-25 19:24:55 +0200
commita1bc3c88de1526c83882143b2e47400f7e3ee4b2 (patch)
tree506081f350f856df1334447ad0571ad736bc22d8 /http.c
parenthttp: fix leak when redacting cookies from curl trace (diff)
downloadgit-a1bc3c88de1526c83882143b2e47400f7e3ee4b2.tar.xz
git-a1bc3c88de1526c83882143b2e47400f7e3ee4b2.zip
http: fix leak of http_object_request struct
The new_http_object_request() function allocates a struct on the heap, along with some fields inside the struct. But the matching function to clean it up, release_http_object_request(), only frees the interior fields without freeing the struct itself, causing a leak. The related http_pack_request new/release pair gets this right, and at first glance we should be able to do the same thing and just add a single free() call. But there's a catch. These http_object_request structs are typically embedded in the object_request struct of http-walker.c. And when we clean up that parent struct, it sanity-checks the embedded struct to make sure we are not leaking descriptors. Which means a use-after-free if we simply free() the embedded struct. I have no idea how valuable that sanity-check is, or whether it can simply be deleted. This all goes back to 5424bc557f (http*: add helper methods for fetching objects (loose), 2009-06-06). But the obvious way to make it all work is to be sure we set the pointer to NULL after freeing it (and our freeing process closes the descriptor, so we know there is no leak). To make sure we do that consistently, we'll switch the pointer we take in release_http_object_request() to a pointer-to-pointer, and we'll set it to NULL ourselves. And then the compiler can help us find each caller which needs to be updated. Most cases will just pass "&obj_req->req", which will obviously do the right thing. In a few cases, like http-push's finish_request(), we are working with a copy of the pointer, so we don't NULL the original. But it's OK because the next step is to free the struct containing the original pointer anyway. This lets us mark t5551 as leak-free. Ironically this is the "smart" http test, and the leak here only affects dumb http. But there's a single dumb-http invocation in there. The full dumb tests are in t5550, which still has some more leaks. This also makes t5559 leak-free, as it's just an HTTP/2 variant of t5551. But we don't need to mark it as such, since it inherits the flag from t5551. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'http.c')
-rw-r--r--http.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/http.c b/http.c
index cc136408c0..d0242ffb50 100644
--- a/http.c
+++ b/http.c
@@ -2816,15 +2816,17 @@ int finish_http_object_request(struct http_object_request *freq)
return freq->rename;
}
-void abort_http_object_request(struct http_object_request *freq)
+void abort_http_object_request(struct http_object_request **freq_p)
{
+ struct http_object_request *freq = *freq_p;
unlink_or_warn(freq->tmpfile.buf);
- release_http_object_request(freq);
+ release_http_object_request(freq_p);
}
-void release_http_object_request(struct http_object_request *freq)
+void release_http_object_request(struct http_object_request **freq_p)
{
+ struct http_object_request *freq = *freq_p;
if (freq->localfile != -1) {
close(freq->localfile);
freq->localfile = -1;
@@ -2838,4 +2840,7 @@ void release_http_object_request(struct http_object_request *freq)
}
curl_slist_free_all(freq->headers);
strbuf_release(&freq->tmpfile);
+
+ free(freq);
+ *freq_p = NULL;
}