Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions SPECS/ntp/CVE-2026-63379.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
From 87e8e44fa774e9677b089b1a5114ee68aefa1636 Mon Sep 17 00:00:00 2001
From: Nick Mathewson <nickm@torproject.org>
Date: Fri, 26 Jun 2026 11:04:48 -0400
Subject: [PATCH] http: Discard trailers.

Previously, we would insert any trailers directly into the header
list. But this was incorrect, since trailers are not supposed to be
treated as normal headers. This behavior could lead to conflicting
interpretation between HTTP servers and proxies, and enable
different kinds of attacks.

Fixes GHSA-2gmv-p5m7-98p6.

Reported by @sebastianosrt.

Tracking: X13.
Upstream Patch reference: https://github.com/libevent/libevent/commit/87e8e44fa774e9677b089b1a5114ee68aefa1636.patch
---
sntp/libevent/http.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/sntp/libevent/http.c b/sntp/libevent/http.c
index 04f089b..e96ce0b 100644
--- a/sntp/libevent/http.c
+++ b/sntp/libevent/http.c
@@ -181,6 +181,10 @@ static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *, int
static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri);
+static enum message_read_status evhttp_parse_headers_impl_(
+ struct evhttp_request *req,
+ struct evbuffer *buffer,
+ struct evkeyvalq *headers);
static int evhttp_associate_new_request_with_connection(
struct evhttp_connection *evcon);
static void evhttp_connection_start_detectclose(
@@ -997,8 +1001,10 @@ static void
evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
{
struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
+ struct evkeyvalq tmp_headers;
+ TAILQ_INIT(&tmp_headers);

- switch (evhttp_parse_headers_(req, buf)) {
+ switch (evhttp_parse_headers_impl_(req, buf, &tmp_headers)) {
case DATA_CORRUPTED:
case DATA_TOO_LONG:
evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
@@ -1012,6 +1018,8 @@ evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
default:
break;
}
+
+ evhttp_clear_headers(&tmp_headers);
}

static void
@@ -2092,14 +2100,17 @@ evhttp_append_to_last_header(struct evkeyvalq *headers, char *line)
return (0);
}

-enum message_read_status
-evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
+/* As `evhttp_parse_headers_`, but put any headers we find into `headers`. */
+static enum message_read_status
+evhttp_parse_headers_impl_(
+ struct evhttp_request *req,
+ struct evbuffer *buffer,
+ struct evkeyvalq *headers)
{
enum message_read_status errcode = DATA_CORRUPTED;
char *line;
enum message_read_status status = MORE_DATA_EXPECTED;

- struct evkeyvalq* headers = req->input_headers;
size_t len;
while ((line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF))
!= NULL) {
@@ -2155,6 +2166,13 @@ evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
return (errcode);
}

+
+enum message_read_status
+evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer *buffer)
+{
+ return evhttp_parse_headers_impl_(req, buffer, req->input_headers);
+}
+
static int
evhttp_get_body_length(struct evhttp_request *req)
{
--
2.43.0

93 changes: 93 additions & 0 deletions SPECS/ntp/CVE-2026-63381.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
From 5cb95ba2f804f8aff46f88d58391c71e1251cd1c Mon Sep 17 00:00:00 2001
From: Alexis <alexis.challande@trailofbits.com>
Date: Tue, 9 Jun 2026 15:09:05 +0200
Subject: [PATCH] Fix a dangling pointer in evbuffer_add_buffer_reference.

If `evbuffer_add_buffer_reference` was called to add a reference to
an empty buffer, the resulting code would produce dangling pointers
that could later lead to a use-after-free.

Fixes GHSA-c2pj-cg4r-88c8.

Tracking: X8.
Upstream Patch reference: https://github.com/libevent/libevent/commit/5cb95ba2f804f8aff46f88d58391c71e1251cd1c.patch
---
sntp/libevent/buffer.c | 7 +++++-
sntp/libevent/test/regress_buffer.c | 35 +++++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/sntp/libevent/buffer.c b/sntp/libevent/buffer.c
index 3524b35..f68f31c 100644
--- a/sntp/libevent/buffer.c
+++ b/sntp/libevent/buffer.c
@@ -1038,8 +1038,13 @@ evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf)

if (out_total_len == 0) {
/* There might be an empty chain at the start of outbuf; free
- * it. */
+ * it. Reset the chain pointers afterwards so the subsequent
+ * APPEND_CHAIN_MULTICAST does not dereference the freed chain
+ * through outbuf->first / last_with_datap. */
evbuffer_free_all_chains(outbuf->first);
+ outbuf->first = NULL;
+ outbuf->last = NULL;
+ outbuf->last_with_datap = &outbuf->first;
}
APPEND_CHAIN_MULTICAST(outbuf, inbuf);

diff --git a/sntp/libevent/test/regress_buffer.c b/sntp/libevent/test/regress_buffer.c
index f259b92..e1dc9bd 100644
--- a/sntp/libevent/test/regress_buffer.c
+++ b/sntp/libevent/test/regress_buffer.c
@@ -2227,6 +2227,40 @@ end:
evbuffer_free(buf2);
}

+static void
+test_evbuffer_multicast_empty_chain(void *ptr)
+{
+ const char chunk[] = "If you have found the answer to such a problem";
+ size_t len = strlen(chunk);
+
+ struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+ buf1 = evbuffer_new();
+ tt_assert(buf1);
+ buf2 = evbuffer_new();
+ tt_assert(buf2);
+
+ evbuffer_add_reference(buf2, "", 0, NULL, NULL);
+ evbuffer_validate(buf2);
+ tt_int_op(evbuffer_get_length(buf2), ==, 0);
+
+ evbuffer_add(buf1, chunk, len);
+ evbuffer_validate(buf1);
+
+ tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
+ evbuffer_validate(buf2);
+ tt_int_op(evbuffer_get_length(buf2), ==, len);
+
+ tt_assert(!strncmp((char *)evbuffer_pullup(buf2, -1), chunk, len));
+ evbuffer_validate(buf2);
+
+end:
+ if (buf1)
+ evbuffer_free(buf1);
+ if (buf2)
+ evbuffer_free(buf2);
+}
+
static void
check_prepend(struct evbuffer *buffer,
const struct evbuffer_cb_info *cbinfo,
@@ -2830,6 +2864,7 @@ struct testcase_t evbuffer_testcases[] = {
{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
{ "multicast", test_evbuffer_multicast, 0, NULL, NULL },
{ "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL },
+ { "multicast_empty_chain", test_evbuffer_multicast_empty_chain, TT_FORK, NULL, NULL },
{ "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
{ "empty_reference_prepend", test_evbuffer_empty_reference_prepend, TT_FORK, NULL, NULL },
{ "empty_reference_prepend_buffer", test_evbuffer_empty_reference_prepend_buffer, TT_FORK, NULL, NULL },
--
2.43.0

Loading
Loading