Skip to content
Snippets Groups Projects

daemon/http: fix memleak if http_write_pkt() fails

Merged Tomas Krizek requested to merge doh-on-write-leak into master
+ 21
6
/*
*
* Copyright (C) 2020 CZ.NIC, z.s.p.o
*
* Initial Author: Jan Hák <jan.hak@nic.cz>
@@ -424,7 +425,6 @@ static void on_pkt_write(struct http_data *data, int status)
return;
data->on_write(data->req, status);
free(data);
}
@@ -589,22 +589,33 @@ static int http_send_response(nghttp2_session *h2, int32_t stream_id,
MAKE_NV("cache-control", 13, max_age, max_age_len),
};
ret = nghttp2_submit_response(h2, stream_id, hdrs, sizeof(hdrs)/sizeof(*hdrs), prov);
ret = nghttp2_session_set_stream_user_data(h2, stream_id, (void*)data);
if (ret != 0) {
kr_log_verbose("[http] nghttp2_submit_response failed: %s\n", nghttp2_strerror(ret));
kr_log_verbose("[http] failed to set stream user data: %s\n", nghttp2_strerror(ret));
free(data);
return kr_error(EIO);
}
ret = nghttp2_session_set_stream_user_data(h2, stream_id, (void*)data);
ret = nghttp2_submit_response(h2, stream_id, hdrs, sizeof(hdrs)/sizeof(*hdrs), prov);
if (ret != 0) {
kr_log_verbose("[http] failed to set stream user data: %s\n", nghttp2_strerror(ret));
kr_log_verbose("[http] nghttp2_submit_response failed: %s\n", nghttp2_strerror(ret));
nghttp2_session_set_stream_user_data(h2, stream_id, NULL); // just in case
free(data);
return kr_error(EIO);
}
ret = nghttp2_session_send(h2);
if(ret < 0) {
kr_log_verbose("[http] nghttp2_session_send failed: %s\n", nghttp2_strerror(ret));
return kr_error(EIO);
/* At this point, there was an error in some nghttp2 callback. The on_pkt_write()
* callback which also calls free(data) may or may not have been called. Therefore,
* we must guarantee it will have been called by explicitly closing the stream.
* Afterwards, we have no option but to pretend this function was a success. If we
* returned an error, qr_task_send() logic would lead to a double-free because
* on_write() was already called. */
nghttp2_submit_rst_stream(h2, NGHTTP2_FLAG_NONE, stream_id, NGHTTP2_INTERNAL_ERROR);
return 0;
}
return 0;
@@ -612,6 +623,10 @@ static int http_send_response(nghttp2_session *h2, int32_t stream_id,
/*
* Send HTTP/2 stream data created from packet's wire buffer.
*
* If this function returns an error, the on_write() callback isn't (and
* musn't be!) called, since such errors are handled in an upper layer - in
* qr_task_step() in daemon/worker.
*/
static int http_write_pkt(nghttp2_session *h2, knot_pkt_t *pkt, int32_t stream_id,
uv_write_t *req, uv_write_cb on_write)
Loading