diff --git a/SPECS/ntp/CVE-2026-63379.patch b/SPECS/ntp/CVE-2026-63379.patch new file mode 100644 index 00000000000..11b25d48ab7 --- /dev/null +++ b/SPECS/ntp/CVE-2026-63379.patch @@ -0,0 +1,95 @@ +From 87e8e44fa774e9677b089b1a5114ee68aefa1636 Mon Sep 17 00:00:00 2001 +From: Nick Mathewson +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 + diff --git a/SPECS/ntp/CVE-2026-63381.patch b/SPECS/ntp/CVE-2026-63381.patch new file mode 100644 index 00000000000..ee82ad10d74 --- /dev/null +++ b/SPECS/ntp/CVE-2026-63381.patch @@ -0,0 +1,93 @@ +From 5cb95ba2f804f8aff46f88d58391c71e1251cd1c Mon Sep 17 00:00:00 2001 +From: Alexis +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 + diff --git a/SPECS/ntp/CVE-2026-63382.patch b/SPECS/ntp/CVE-2026-63382.patch new file mode 100644 index 00000000000..67171b8a1f9 --- /dev/null +++ b/SPECS/ntp/CVE-2026-63382.patch @@ -0,0 +1,343 @@ +From ac38703b2d312200c4f967f02936af0118d384a0 Mon Sep 17 00:00:00 2001 +From: Nick Mathewson +Date: Fri, 26 Jun 2026 10:37:46 -0400 +Subject: [PATCH] http: Tighten acceptable headers to prevent request + smuggling. + +Previously, we accepted a wider variety of combinations of +Content-Length and Transfer-Encoding, and we didn't parse +Transfer-Encoding according to the full rules of the relevant RFC. +This made evhttp interpret these headers in a +non-standards-compliant way that had the potential to differ from +a more compliant proxy or HTTP server. Thus, when used _as_ an +HTTP proxy, evhttp had the potential to enable http smuggling +attacks. + +Fixes GHSA-q39v-w2g7-gr8j. + +Originally reported by @xclow3n; and then by @kodareef5, +@nstaller0490, @AsafMeizneer, and @yaotushaozhu (in that order). + +(Note that this fix assumes that we have _also_ disabled support for +CR and LF in header lines.) + +Tracking: X12. +Upstream Patch reference: +https://github.com/libevent/libevent/commit/ac38703b2d312200c4f967f02936af0118d384a0.patch +& https://github.com/libevent/libevent/commit/10abb34b8dc3e1184de315dd261ce4b77563cda6.patch +--- + sntp/libevent/http-internal.h | 14 +++ + sntp/libevent/http.c | 165 ++++++++++++++++++++++++++++-- + sntp/libevent/test/regress_http.c | 39 +++++++ + 3 files changed, 211 insertions(+), 7 deletions(-) + +diff --git a/sntp/libevent/http-internal.h b/sntp/libevent/http-internal.h +index feaf436..4d52504 100644 +--- a/sntp/libevent/http-internal.h ++++ b/sntp/libevent/http-internal.h +@@ -185,6 +185,20 @@ EVENT2_EXPORT_SYMBOL + void evhttp_connection_fail_(struct evhttp_connection *, + enum evhttp_request_error error); + ++enum evhttp_transfer_encoding_header_status { ++ /* This Transfer-Encoding line was invalid. ++ * (We consider all "chunked" encodings invalid except those at the end ++ * of the sequence.) */ ++ TE_INVALID, ++ /* This Transfer-Encoding line ended with the "chunked" encoding. */ ++ TE_ENDS_IN_CHUNKED, ++ /* This Transfer-Encoding line was valid and did not contain "chunked" */ ++ TE_NO_CHUNKED, ++}; ++int evhttp_str_is_chunked_(const char *value, const char *eos); ++enum evhttp_transfer_encoding_header_status ++evhttp_check_transfer_encoding_(const char *value); ++ + enum message_read_status; + + EVENT2_EXPORT_SYMBOL +diff --git a/sntp/libevent/http.c b/sntp/libevent/http.c +index e96ce0b..e6fd70e 100644 +--- a/sntp/libevent/http.c ++++ b/sntp/libevent/http.c +@@ -123,7 +123,6 @@ + #ifndef NI_NUMERICSERV + #define NI_NUMERICSERV 2 + #endif +- + static int + fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, + size_t hostlen, char *serv, size_t servlen, int flags) +@@ -163,6 +162,8 @@ fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, + + #endif + ++static int evhttp_validate_len_and_encoding_(struct evhttp_request *req); ++ + #define REQ_VERSION_BEFORE(req, major_v, minor_v) \ + ((req)->major < (major_v) || \ + ((req)->major == (major_v) && (req)->minor < (minor_v))) +@@ -929,7 +930,7 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) + if (req->ntoread < 0) { + /* Read chunk size */ + ev_int64_t ntoread; +- char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF); ++ char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF_STRICT); + char *endp; + int error; + if (p == NULL) +@@ -1916,6 +1917,32 @@ evhttp_find_header(const struct evkeyvalq *headers, const char *key) + return (NULL); + } + ++/* Like evhttp_find_header, but set *duplicate to 1 if the header appears ++ * more than once, and to 0 otherwise. ++ */ ++static const char * ++evhttp_find_unique_header(const struct evkeyvalq *headers, const char *key, ++ int *duplicate) ++{ ++ const char *result = NULL; ++ struct evkeyval *header; ++ ++ *duplicate = 0; ++ ++ TAILQ_FOREACH(header, headers, next) { ++ if (evutil_ascii_strcasecmp(header->key, key) == 0) { ++ if (result == NULL) { ++ result = header->value; ++ } else { ++ *duplicate = 1; ++ break; ++ } ++ } ++ } ++ ++ return (result); ++} ++ + void + evhttp_clear_headers(struct evkeyvalq *headers) + { +@@ -2173,6 +2200,126 @@ evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer *buffer) + return evhttp_parse_headers_impl_(req, buffer, req->input_headers); + } + ++/* Return true if 'ch' is a single linear WS character (per the HTTP spec). ++ * We reject CR and LF elsewhere. */ ++#define IS_LWS(ch) \ ++ (((ch) == ' ' ) || ((ch) == '\t')) ++ ++/* Returns true when the string beginning at `value` and ending at `eos` ++ * (non-inclusive) is a `transfer-coding` "chunked". Case insensitive. ++ */ ++int ++evhttp_str_is_chunked_(const char *value, const char *eos) ++{ ++ /* the end of the encoding. */ ++ const char *end; ++ ++ if (eos == NULL) { ++ eos = value + strlen(value); ++ } ++ ++ while (value < eos && IS_LWS(*value)) { ++ ++value; ++ } ++ end = value; ++ /* A transfer-coding can end with OWS ; OWS to indicate a ++ * transfer-parameter. (See RFC 9110) ++ */ ++ while (end < eos && !IS_LWS(*end) && *end != ';') { ++ ++end; ++ } ++ ++ return (end - value) == strlen("chunked") ++ && evutil_ascii_strncasecmp(value, "chunked", strlen("chunked")) == 0; ++} ++ ++/* Check a single Transfer-Encoding header value. ++ * ++ * Returns an evhttp_transfer_encoding_header_status value depending ++ * on its contents. ++ */ ++enum evhttp_transfer_encoding_header_status ++evhttp_check_transfer_encoding_(const char *value) ++{ ++ const char *comma; ++ ++ while ((comma = strchr(value, ',')) != NULL) { ++ if (evhttp_str_is_chunked_(value, comma)) { ++ /* If we find that an encoding is chunked ++ * and it is followed by a comma, it is not the final ++ * encoding ++ */ ++ return TE_INVALID; ++ } ++ value = comma + 1; ++ } ++ ++ if (evhttp_str_is_chunked_(value, NULL)) { ++ return TE_ENDS_IN_CHUNKED; ++ } else { ++ return TE_NO_CHUNKED; ++ } ++} ++ ++ ++/* Return 0 if the Transfer-Encoding and Content-Length heeaders appear to be consistent, ++ * and -1 otherwise. ++ * ++ * Sets "req->chunked" if appropriate. ++ * ++ * Used to prevent request smuggling. ++ */ ++static int ++evhttp_validate_len_and_encoding_(struct evhttp_request *req) ++{ ++ struct evkeyvalq *headers = req->input_headers; ++ struct evkeyval *h = NULL; ++ int is_chunked = 0; ++ int dup_cl = 0; ++ ++ if (evhttp_find_header(headers, "Transfer-Encoding") != NULL && ++ evhttp_find_unique_header(headers, "Content-Length", &dup_cl) != NULL) { ++ /* Both TE and CL were present: Not allowed. */ ++ return -1; ++ } ++ if (dup_cl) { ++ /* CL was present twice: Not allowed. ++ * (Technically we can permit this if the values are the same, ++ * but we don't.) */ ++ return -1; ++ } ++ ++ /* Now walk through the Transfer-Encoding headers. */ ++ TAILQ_FOREACH(h, headers, next) { ++ if (evutil_ascii_strcasecmp(h->key, "Transfer-Encoding") == 0) { ++ if (is_chunked) { ++ /* We already encountered a chunked ++ encoding; no further encodings are allowed */ ++ return -1; ++ } ++ ++ switch (evhttp_check_transfer_encoding_(h->value)) ++ { ++ case TE_INVALID: ++ /* We found "chunked" somewhere not at the end. */ ++ return -1; ++ case TE_ENDS_IN_CHUNKED: ++ /* We found chunked at the end. */ ++ is_chunked = 1; ++ break; ++ case TE_NO_CHUNKED: ++ /* "chunked" didn't appear; this is fine. */ ++ break; ++ } ++ } ++ } ++ ++ req->chunked = is_chunked; ++ ++ return 0; ++} ++ ++ + static int + evhttp_get_body_length(struct evhttp_request *req) + { +@@ -2232,8 +2379,6 @@ evhttp_method_may_have_body(enum evhttp_cmd_type type) + static void + evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) + { +- const char *xfer_enc; +- + /* If this is a request without a body, then we are done */ + if (req->kind == EVHTTP_REQUEST && + !evhttp_method_may_have_body(req->type)) { +@@ -2241,9 +2386,8 @@ evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) + return; + } + evcon->state = EVCON_READING_BODY; +- xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding"); +- if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) { +- req->chunked = 1; ++ ++ if (req->chunked) { + req->ntoread = -1; + } else { + if (evhttp_get_body_length(req) == -1) { +@@ -2329,6 +2473,13 @@ evhttp_read_header(struct evhttp_connection *evcon, + return; + } + ++ if (evhttp_validate_len_and_encoding_(req) < 0) { ++ event_debug(("%s: bad combination of headers on "EV_SOCK_FMT"\n", ++ __func__, EV_SOCK_ARG(fd))); ++ evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); ++ return; ++ } ++ + /* Callback can shut down connection with negative return value */ + if (req->header_cb != NULL) { + if ((*req->header_cb)(req, req->cb_arg) < 0) { +diff --git a/sntp/libevent/test/regress_http.c b/sntp/libevent/test/regress_http.c +index 4493907..8447444 100644 +--- a/sntp/libevent/test/regress_http.c ++++ b/sntp/libevent/test/regress_http.c +@@ -3959,6 +3959,43 @@ http_multi_line_header_test(void *arg) + evhttp_free(http); + } + ++static void ++http_is_chunked_test(void *arg) ++{ ++ (void) arg; ++ tt_assert(evhttp_str_is_chunked_("chunked", NULL)); ++ tt_assert(evhttp_str_is_chunked_("chUNKED", NULL)); ++ tt_assert(evhttp_str_is_chunked_(" CHUNKED ", NULL)); ++ tt_assert(evhttp_str_is_chunked_(" chUNKED ; foo=bar", NULL)); ++ tt_assert(evhttp_str_is_chunked_("chUNKED ; foo=bar", NULL)); ++ ++ tt_assert(! evhttp_str_is_chunked_("wombat", NULL)); ++ tt_assert(! evhttp_str_is_chunked_("chunked+", NULL)); ++ tt_assert(! evhttp_str_is_chunked_("wombchunkedat", NULL)); ++ tt_assert(! evhttp_str_is_chunked_("wombat chunked", NULL)); ++ tt_assert(! evhttp_str_is_chunked_("wombat; chunked=foo", NULL)); ++end: ++ ; ++} ++ ++static void ++http_check_transfer_encoding_test(void *arg) ++{ ++#define CH evhttp_check_transfer_encoding_ ++ tt_int_op(CH("hello"), ==, TE_NO_CHUNKED); ++ tt_int_op(CH("hello, world"), ==, TE_NO_CHUNKED); ++ tt_int_op(CH("hello, world, chunked"), ==, TE_ENDS_IN_CHUNKED); ++ tt_int_op(CH("chunked "), ==, TE_ENDS_IN_CHUNKED); ++ tt_int_op(CH(" , chunked "), ==, TE_ENDS_IN_CHUNKED); ++ tt_int_op(CH("chunked , gzip"), ==, TE_INVALID); ++ tt_int_op(CH("foo, chunked , gzip"), ==, TE_INVALID); ++ tt_int_op(CH(" , chunked, "), ==, TE_INVALID); ++end: ++ ; ++#undef CH ++} ++ ++ + static void + http_request_bad(struct evhttp_request *req, void *arg) + { +@@ -4747,6 +4784,8 @@ struct testcase_t http_testcases[] = { + HTTP(highport), + HTTP(dispatcher), + HTTP(multi_line_header), ++ HTTP(is_chunked), ++ HTTP(check_transfer_encoding), + HTTP(negative_content_length), + HTTP(chunk_out), + HTTP(stream_out), +-- +2.43.0 + diff --git a/SPECS/ntp/CVE-2026-63383.patch b/SPECS/ntp/CVE-2026-63383.patch new file mode 100644 index 00000000000..ed0f62362c2 --- /dev/null +++ b/SPECS/ntp/CVE-2026-63383.patch @@ -0,0 +1,42 @@ +From 51fb2062327ee48192fe82c1f17963196dfa5185 Mon Sep 17 00:00:00 2001 +From: Nick Mathewson +Date: Wed, 24 Jun 2026 09:53:23 -0400 +Subject: [PATCH] evrpc: Fix out-of-bounds read in decode_tag_internal + +This bug could allow an attacker to cause an evrpc client or server +to read out of bounds when decoding a tag. + +Fixes GHSA-fj29-64w6-73h6. + +Reported by @Brubbish. + +Tracking: X5. +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libevent/libevent/commit/e1f9e21887c6b104e206a718385ba3ffc75180cb.patch +--- + sntp/libevent/event_tagging.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/sntp/libevent/event_tagging.c b/sntp/libevent/event_tagging.c +index 790dff3..9ee642b 100644 +--- a/sntp/libevent/event_tagging.c ++++ b/sntp/libevent/event_tagging.c +@@ -210,12 +210,13 @@ decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain) + * the encoding of a number is at most one byte more than its + * storage size. however, it may also be much smaller. + */ ++ size_t pullup_len = len < sizeof(number) + 1 ? len : sizeof(number) + 1; + data = evbuffer_pullup( +- evbuf, len < sizeof(number) + 1 ? len : sizeof(number) + 1); ++ evbuf, pullup_len); + if (!data) + return (-1); + +- while (count++ < len) { ++ while (count++ < pullup_len) { + ev_uint8_t lower = *data++; + if (shift >= 28) { + /* Make sure it fits into 32 bits */ +-- +2.45.4 + diff --git a/SPECS/ntp/CVE-2026-63384.patch b/SPECS/ntp/CVE-2026-63384.patch new file mode 100644 index 00000000000..cc785267b6c --- /dev/null +++ b/SPECS/ntp/CVE-2026-63384.patch @@ -0,0 +1,54 @@ +From 6a098eae9f848b346cab7ac4634e143c9af1fee4 Mon Sep 17 00:00:00 2001 +From: Nick Mathewson +Date: Wed, 24 Jun 2026 10:08:22 -0400 +Subject: [PATCH] evrpc: Fix integer overflow in evtag_unmarshal_header. + +On platforms where int is 32 bits, if this function tried to decode +a header declaring a payload longer than INT_MAX bytes long, this +function would return a negative value, which could cause incorrect +behaviors, incorrect allocations, or denial-of-service. + +We solve this (for now) by rejecting any payload length larger +than INT_MAX. + +Fixes GHSA-45c6-qx49-89m8 + +Reported by @Brubbish + +Tracking: X5 +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libevent/libevent/commit/5e3c6ebe342b34c5a9bcf48e9a32ad6708b9c416.patch +--- + sntp/libevent/event_tagging.c | 2 +- + sntp/libevent/include/event2/tag.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/sntp/libevent/event_tagging.c b/sntp/libevent/event_tagging.c +index b021e8c..790dff3 100644 +--- a/sntp/libevent/event_tagging.c ++++ b/sntp/libevent/event_tagging.c +@@ -445,7 +445,7 @@ evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag) + + if (decode_tag_internal(ptag, evbuf, 1 /* dodrain */) == -1) + return (-1); +- if (evtag_decode_int(&len, evbuf) == -1) ++ if (evtag_decode_int(&len, evbuf) == -1 || len > INT_MAX) + return (-1); + + if (evbuffer_get_length(evbuf) < len) +diff --git a/sntp/libevent/include/event2/tag.h b/sntp/libevent/include/event2/tag.h +index 2f73bfc..ac13049 100644 +--- a/sntp/libevent/include/event2/tag.h ++++ b/sntp/libevent/include/event2/tag.h +@@ -64,6 +64,8 @@ void evtag_init(void); + /** + Unmarshals the header and returns the length of the payload + ++ Returns an error if the payload length is above INT_MAX. ++ + @param evbuf the buffer from which to unmarshal data + @param ptag a pointer in which the tag id is being stored + @returns -1 on failure or the number of bytes in the remaining payload. +-- +2.45.4 + diff --git a/SPECS/ntp/CVE-2026-63385.patch b/SPECS/ntp/CVE-2026-63385.patch new file mode 100644 index 00000000000..f8fa48ac853 --- /dev/null +++ b/SPECS/ntp/CVE-2026-63385.patch @@ -0,0 +1,60 @@ +From 9170dd35e64714613e8d13b290587cfc28e258e2 Mon Sep 17 00:00:00 2001 +From: Nick Mathewson +Date: Fri, 26 Jun 2026 09:08:47 -0400 +Subject: [PATCH] http: Reject headers containing CRLF. + +This causes us to reject obfs-fold, which is deprecated in RFC 9112. + +Otherwise, we would have a header injection opportunity for +certain proxy chains. + +Reported by @AsafMeizner + +Part of GHSA-jcwh-pvf2-73p2 + +Tracking: X10. +Upstream Patch reference: https://github.com/libevent/libevent/commit/9170dd35e64714613e8d13b290587cfc28e258e2.patch +--- + sntp/libevent/http.c | 10 ++++------ + sntp/libevent/test/regress_http.c | 3 ++- + 2 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/sntp/libevent/http.c b/sntp/libevent/http.c +index e6fd70e..19ab491 100644 +--- a/sntp/libevent/http.c ++++ b/sntp/libevent/http.c +@@ -1990,13 +1990,11 @@ evhttp_header_is_valid_value(const char *value) + { + const char *p = value; + +- while ((p = strpbrk(p, "\r\n")) != NULL) { +- /* we really expect only one new line */ +- p += strspn(p, "\r\n"); +- /* we expect a space or tab for continuation */ +- if (*p != ' ' && *p != '\t') +- return (0); ++ if (strpbrk(p, "\r\n") != NULL) { ++ /* Reject any header containing CR or LF. */ ++ return (0); + } ++ + return (1); + } + +diff --git a/sntp/libevent/test/regress_http.c b/sntp/libevent/test/regress_http.c +index 8447444..5404ae0 100644 +--- a/sntp/libevent/test/regress_http.c ++++ b/sntp/libevent/test/regress_http.c +@@ -2406,7 +2406,8 @@ http_bad_header_test(void *ptr) + TAILQ_INIT(&headers); + + tt_want(evhttp_add_header(&headers, "One", "Two") == 0); +- tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0); ++ tt_want(evhttp_add_header(&headers, "One", "Two Three") == 0); ++ tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == -1); + tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1); + tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1); + tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1); +-- +2.43.0 + diff --git a/SPECS/ntp/CVE-2026-63387.patch b/SPECS/ntp/CVE-2026-63387.patch new file mode 100644 index 00000000000..03dcf832cd9 --- /dev/null +++ b/SPECS/ntp/CVE-2026-63387.patch @@ -0,0 +1,43 @@ +From 42141e2ab363c9343291d80929df85d8ed0f65d5 Mon Sep 17 00:00:00 2001 +From: Nick Mathewson +Date: Wed, 24 Jun 2026 09:08:43 -0400 +Subject: [PATCH] evdns: Fix out-of-bounds write in dnsname_to_labels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This bug would cause the program to write a single 0 byte off the +end of a stack buffer, if the code ever tried to make a DNS response +exactly 2^16 + 1 bytes long, ending with a DNS name. + +Resolves issue GHSA-58rx-7448-jw47. + +This issue was identified by MichaƂ Majchrowicz and +Marcin Wyczechowski, members of the AFINE Team. + +Tracking: X1 +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libevent/libevent/commit/377b9022c3ac61aa4540b5dc4b70c60bf74c663d.patch +--- + sntp/libevent/evdns.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sntp/libevent/evdns.c b/sntp/libevent/evdns.c +index a5b31a3..8ddff8b 100644 +--- a/sntp/libevent/evdns.c ++++ b/sntp/libevent/evdns.c +@@ -1671,7 +1671,10 @@ dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j, + /* the labels must be terminated by a 0. */ + /* It's possible that the name ended in a . */ + /* in which case the zero is already there */ +- if (!j || buf[j-1]) buf[j++] = 0; ++ if ((size_t)j >= buf_len) ++ return -2; ++ if (!j || buf[j-1]) ++ buf[j++] = 0; + return j; + overflow: + return (-2); +-- +2.45.4 + diff --git a/SPECS/ntp/CVE-2026-63388.patch b/SPECS/ntp/CVE-2026-63388.patch new file mode 100644 index 00000000000..335be48997b --- /dev/null +++ b/SPECS/ntp/CVE-2026-63388.patch @@ -0,0 +1,138 @@ +From 011eb622b69f995c7d7a611e923f406d3747824e Mon Sep 17 00:00:00 2001 +From: Nick Mathewson +Date: Wed, 24 Jun 2026 09:33:02 -0400 +Subject: [PATCH] bufferevent: Fix heap out-of-bounds write via + AF_UNIX+http+NDEBUG + +When running an evhttp server over an AF_UNIX socket, +on a copy of libevent compiled with NDEBUG, +it was possible for an attacker to use a crafted AF_UNIX address to +cause a heap overflow when recording the address. + +This issue could also be triggered by direct calls +to the internal function bufferevent_socket_set_conn_address_ +on a copy of libevent compiled with NDEBUG. + +This bug still affected copies of libevent compiled without NDEBUG: +except that under those conditions, it would cause an assertion +failure with an abort() rather than a heap overflow. + +As a fix: + - We check the length of the provided address unconditionally + (regardless of NDEBUG) + - We handle failures caused by the provided address being too long. + - We allocate enough room to store an AF_UNIX address. + +Resolves GHSA-cvq5-vrvr-j338. + +Reported by @mat-mo. + +Tracking: X3 +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/libevent/libevent/commit/ef38f926e9cd1f082416c6fff13587bc1f431d72.patch +--- + sntp/libevent/bufferevent-internal.h | 11 ++++++----- + sntp/libevent/bufferevent_sock.c | 17 ++++++++++++----- + sntp/libevent/http.c | 4 +++- + 3 files changed, 21 insertions(+), 11 deletions(-) + +diff --git a/sntp/libevent/bufferevent-internal.h b/sntp/libevent/bufferevent-internal.h +index 87ab9ad..dfb6384 100644 +--- a/sntp/libevent/bufferevent-internal.h ++++ b/sntp/libevent/bufferevent-internal.h +@@ -34,6 +34,7 @@ extern "C" { + #include "event2/event_struct.h" + #include "evconfig-private.h" + #include "event2/util.h" ++#include "util-internal.h" + #include "defer-internal.h" + #include "evthread-internal.h" + #include "event2/thread.h" +@@ -224,10 +225,10 @@ struct bufferevent_private { + * So we need to save it, just after we connected to remote server, or + * after resolving (to avoid extra dns requests during retrying, since UDP + * is slow) */ +- union { +- struct sockaddr_in6 in6; +- struct sockaddr_in in; +- } conn_address; ++ /* NOTE: it might be nice to use fewer bytes here, but we need to store ++ * sockaddr_un sometimes in order to make AF_UNIX sockets work as expected ++ * with sntp/libevent/http.c. */ ++ struct sockaddr_storage conn_address; + + struct evdns_getaddrinfo_request *dns_request; + }; +@@ -449,7 +450,7 @@ void + bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev, evutil_socket_t fd); + + EVENT2_EXPORT_SYMBOL +-void ++int + bufferevent_socket_set_conn_address_(struct bufferevent *bev, struct sockaddr *addr, size_t addrlen); + + +diff --git a/sntp/libevent/bufferevent_sock.c b/sntp/libevent/bufferevent_sock.c +index f40a8d9..543fce4 100644 +--- a/sntp/libevent/bufferevent_sock.c ++++ b/sntp/libevent/bufferevent_sock.c +@@ -116,13 +116,17 @@ bufferevent_socket_set_conn_address_fd_(struct bufferevent *bev, + getpeername(fd, addr, &len); + } + +-void ++int + bufferevent_socket_set_conn_address_(struct bufferevent *bev, + struct sockaddr *addr, size_t addrlen) + { + struct bufferevent_private *bev_p = BEV_UPCAST(bev); +- EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address)); +- memcpy(&bev_p->conn_address, addr, addrlen); ++ if (addrlen <= sizeof(bev_p->conn_address)) { ++ memcpy(&bev_p->conn_address, addr, addrlen); ++ return 0; ++ } else { ++ return EVUTIL_EAI_FAIL; ++ } + } + + static void +@@ -472,6 +476,11 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, + bufferevent_decref_and_unlock_(bev); + return; + } ++ if (result == 0) { ++ /* XXX use the other addrinfos? */ ++ result = bufferevent_socket_set_conn_address_( ++ bev, ai->ai_addr, (int)ai->ai_addrlen); ++ } + if (result != 0) { + bev_p->dns_error = result; + bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); +@@ -481,8 +490,6 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, + return; + } + +- /* XXX use the other addrinfos? */ +- bufferevent_socket_set_conn_address_(bev, ai->ai_addr, (int)ai->ai_addrlen); + r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen); + if (r < 0) + bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); +diff --git a/sntp/libevent/http.c b/sntp/libevent/http.c +index 04f089b..516f6f9 100644 +--- a/sntp/libevent/http.c ++++ b/sntp/libevent/http.c +@@ -4273,7 +4273,9 @@ evhttp_get_request_connection( + goto err; + if (bufferevent_disable(evcon->bufev, EV_WRITE)) + goto err; +- bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen); ++ if (bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen)) { ++ goto err; ++ } + + return (evcon); + +-- +2.45.4 + diff --git a/SPECS/ntp/ntp.spec b/SPECS/ntp/ntp.spec index 9c99d30c37c..19b2ba00cf7 100644 --- a/SPECS/ntp/ntp.spec +++ b/SPECS/ntp/ntp.spec @@ -1,7 +1,7 @@ Summary: Network Time Protocol reference implementation Name: ntp Version: 4.2.8p17 -Release: 2%{?dist} +Release: 3%{?dist} License: BSD AND GPLv2+ AND LGPLv2+ AND MIT AND OpenLDAP AND Public Domain Vendor: Microsoft Corporation Distribution: Azure Linux @@ -17,6 +17,14 @@ Source5: ntpdate.sysconfig Source6: ntpdate.service Source7: ntpd.service Source8: LICENSE.PTR +Patch0: CVE-2026-63379.patch +Patch1: CVE-2026-63381.patch +Patch2: CVE-2026-63382.patch +Patch3: CVE-2026-63383.patch +Patch4: CVE-2026-63384.patch +Patch5: CVE-2026-63385.patch +Patch6: CVE-2026-63387.patch +Patch7: CVE-2026-63388.patch BuildRequires: gcc >= 11.2.0 BuildRequires: glibc >= 2.34 @@ -61,7 +69,7 @@ ntpstat is a utility which reports the synchronisation state of the NTP daemon running on the local machine. %prep -%setup -q -a 1 +%autosetup -a 1 -p1 %build @@ -84,8 +92,10 @@ make -C ntpstat-master CFLAGS="$CFLAGS" cp %{SOURCE8} . make DESTDIR=%{buildroot} install -install -v -m755 -d %{buildroot}%{_docdir}/%{name}-%{version} -cp -v -R html/* %{buildroot}%{_docdir}/%{name}-%{version}/ +rm -f \ + %{buildroot}%{_docdir}/%{name}/html/copyright.html \ + %{buildroot}%{_docdir}/%{name}/html/hints/bsdi \ + %{buildroot}%{_docdir}/%{name}/html/hints/freebsd install -vdm 755 %{buildroot}%{_sysconfdir} mkdir -p %{buildroot}%{_sharedstatedir}/ntp/drift @@ -105,7 +115,6 @@ restrict -6 ::1 driftfile %{_sharedstatedir}/ntp/drift/ntp.drift EOF -install -D -m644 COPYRIGHT %{buildroot}%{_datadir}/licenses/%{name}/LICENSE rm -rf %{buildroot}%{_sysconfdir}/rc.d/* %{_fixperms} %{buildroot}/* @@ -150,7 +159,7 @@ fi %files %defattr(-,root,root) -%license COPYRIGHT LICENSE.PTR +%license COPYRIGHT LICENSE.PTR html/copyright.html html/hints/bsdi html/hints/freebsd %dir %{_sharedstatedir}/ntp/drift %attr(0755, ntp, ntp) %{_sharedstatedir}/ntp/drift %attr(0750, root, root) %config(noreplace) %{_sysconfdir}/ntp.conf @@ -169,10 +178,8 @@ fi %{_bindir}/ntptime %{_bindir}/sntp %{_bindir}/tickadj -%{_docdir}/%{name}-%{version}/* -%{_docdir}/ntp/* -%{_docdir}/sntp/* -%{_datadir}/licenses/ntp/LICENSE +%doc %{_docdir}/ntp/* +%doc %{_docdir}/sntp/* %{_mandir}/man1/ntpd.1.gz %{_mandir}/man1/ntpdc.1.gz %{_mandir}/man1/ntp-keygen.1.gz @@ -197,6 +204,9 @@ fi %{_mandir}/man8/ntpstat.8* %changelog +* Tue Aug 25 2026 Azure Linux Security Servicing Account - 4.2.8p17-3 +- Patch for CVE-2026-63388, CVE-2026-63387, CVE-2026-63385, CVE-2026-63384, CVE-2026-63383, CVE-2026-63382, CVE-2026-63381, CVE-2026-63379 + * Tue Mar 17 2026 Sudipta Pandit - 4.2.8p17-2 - Fix ntpdate-wrapper to use /usr/bin/ntpdate