From 30b957336e3bf75d8055ee1287fce88c0990d48d Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Tue, 1 Sep 2026 13:14:30 -0400 Subject: [PATCH] import CS git wget-1.19.5-16.el8_10 --- SOURCES/wget-1.19.5-CVE-2026-58469.patch | 103 +++++++ SOURCES/wget-1.19.5-CVE-2026-58471.patch | 65 +++++ SOURCES/wget-1.19.5-CVE-2026-58472.patch | 264 ++++++++++++++++++ ...get-1.19.5-async-safe-signal-handler.patch | 110 ++++++++ SPECS/wget.spec | 32 ++- 5 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 SOURCES/wget-1.19.5-CVE-2026-58469.patch create mode 100644 SOURCES/wget-1.19.5-CVE-2026-58471.patch create mode 100644 SOURCES/wget-1.19.5-CVE-2026-58472.patch create mode 100644 SOURCES/wget-1.19.5-async-safe-signal-handler.patch diff --git a/SOURCES/wget-1.19.5-CVE-2026-58469.patch b/SOURCES/wget-1.19.5-CVE-2026-58469.patch new file mode 100644 index 0000000..18f32e6 --- /dev/null +++ b/SOURCES/wget-1.19.5-CVE-2026-58469.patch @@ -0,0 +1,103 @@ +From b2f6dfe67d78c82071842e3d7ea3447b3ff24e8f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tim=20R=C3=BChsen?= +Date: Mon, 29 Jun 2026 18:32:02 +0200 +Subject: [PATCH 1/3] * src/metalink.c (clean_metalink_string): Fix buffer + underflow + +Reported-by: TristanInSec@gmail.com +--- + src/metalink.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/src/metalink.c b/src/metalink.c +index 47c8acc..58a9fd5 100644 +--- a/src/metalink.c ++++ b/src/metalink.c +@@ -1043,7 +1043,6 @@ void + clean_metalink_string (char **str) + { + int c; +- size_t len; + char *new, *beg, *end; + + if (!str || !*str) +@@ -1051,7 +1050,7 @@ clean_metalink_string (char **str) + + beg = *str; + +- while ((c = *beg) && (c == '\n' || c == '\r' || c == '\t' || c == ' ')) ++ while (isspace(*beg)) + beg++; + + end = beg; +@@ -1064,12 +1063,10 @@ clean_metalink_string (char **str) + /* If we are at the end of the string, search the first legit + character going backward. */ + if (*end == '\0') +- while ((c = *(end - 1)) && (c == '\n' || c == '\r' || c == '\t' || c == ' ')) ++ while (end > beg && !isspace(*(end - 1))) + end--; + +- len = end - beg; +- +- new = xmemdup0 (beg, len); ++ new = xmemdup0 (beg, end - beg); + xfree (*str); + *str = new; + } + +From 989ba32056757509631d6588e47a59a9a06f8a36 Mon Sep 17 00:00:00 2001 +From: ChenYanpan +Date: Wed, 8 Jul 2026 12:09:55 +0800 +Subject: [PATCH 2/3] * src/metalink.c (clean_metalink_string): Fix inverted + trailing-space check + +37a40fcb added an `end > beg' bound guard to prevent a buffer +underflow, but accidentally flipped the condition from `isspace' to +`!isspace'. The loop therefore walked back over non-space characters +instead of trailing whitespace, collapsing any string without a +trailing newline to "". Every Metalink/HTTP resource URL was wiped, +so wget could not follow any mirror and +testenv/Test-metalink-http.py failed ("Expected file test.meta not +found"). Restore the `isspace' condition. + +Copyright-paperwork-exempt: Yes +--- + src/metalink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/metalink.c b/src/metalink.c +index 58a9fd5..084c262 100644 +--- a/src/metalink.c ++++ b/src/metalink.c +@@ -1063,7 +1063,7 @@ clean_metalink_string (char **str) + /* If we are at the end of the string, search the first legit + character going backward. */ + if (*end == '\0') +- while (end > beg && !isspace(*(end - 1))) ++ while (end > beg && isspace(*(end - 1))) + end--; + + new = xmemdup0 (beg, end - beg); + +From 26af7a227b1af4219ba66898afbedec62c26bcd8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tim=20R=C3=BChsen?= +Date: Thu, 9 Jul 2026 14:50:40 +0200 +Subject: [PATCH 3/3] * src/metalink.c: Include ctype.h + +--- + src/metalink.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/metalink.c b/src/metalink.c +index 084c262..96bfd46 100644 +--- a/src/metalink.c ++++ b/src/metalink.c +@@ -46,6 +46,7 @@ as that of the covered work. */ + #include "c-strcase.h" + #include + #include /* For unlink. */ ++#include + #include + #ifdef HAVE_GPGME + #include diff --git a/SOURCES/wget-1.19.5-CVE-2026-58471.patch b/SOURCES/wget-1.19.5-CVE-2026-58471.patch new file mode 100644 index 0000000..419307f --- /dev/null +++ b/SOURCES/wget-1.19.5-CVE-2026-58471.patch @@ -0,0 +1,65 @@ +From 3514c0f2ad4e3d8a2e9ad0893accdb7a21cae729 Mon Sep 17 00:00:00 2001 +From: Arkadi Vainbrand +Date: Tue, 13 Jan 2026 12:22:04 +0200 +Subject: [PATCH] Fix buffer size handling in filename conversion + +* src/url.c (convert_fname): Fix buffer overflow. + +Copyright-paperwork-exempt: Yes +Signed-off-by: Arkadi Vainbrand +--- + src/url.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/src/url.c b/src/url.c +index ebe0536..848b88f 100644 +--- a/src/url.c ++++ b/src/url.c +@@ -1583,7 +1583,7 @@ convert_fname (char *fname) + const char *from_encoding = opt.encoding_remote; + const char *to_encoding = opt.locale; + iconv_t cd; +- size_t len, done, inlen, outlen; ++ size_t len, inlen, outlen; + char *s; + const char *orig_fname; + +@@ -1605,7 +1605,6 @@ convert_fname (char *fname) + inlen = strlen (fname); + len = outlen = inlen * 2; + converted_fname = s = xmalloc (outlen + 1); +- done = 0; + + for (;;) + { +@@ -1613,7 +1612,7 @@ convert_fname (char *fname) + if (iconv (cd, (ICONV_CONST char **) &fname, &inlen, &s, &outlen) == 0 + && iconv (cd, NULL, NULL, &s, &outlen) == 0) + { +- *(converted_fname + len - outlen - done) = '\0'; ++ *s = '\0'; + iconv_close (cd); + DEBUGP (("Converted file name '%s' (%s) -> '%s' (%s)\n", + orig_fname, from_encoding, converted_fname, to_encoding)); +@@ -1636,10 +1635,17 @@ convert_fname (char *fname) + } + else if (errno == E2BIG) /* Output buffer full */ + { +- done = len; +- len = outlen = done + inlen * 2; +- converted_fname = xrealloc (converted_fname, outlen + 1); +- s = converted_fname + done; ++ size_t used = s - converted_fname; ++ size_t newlen = used + inlen * 2 + 1; ++ ++ /* Ensure we actually grow the buffer */ ++ if (newlen <= len) ++ newlen = len * 2; ++ ++ converted_fname = xrealloc (converted_fname, newlen + 1); ++ len = newlen; ++ s = converted_fname + used; ++ outlen = len - used; + } + else /* Weird, we got an unspecified error */ + { diff --git a/SOURCES/wget-1.19.5-CVE-2026-58472.patch b/SOURCES/wget-1.19.5-CVE-2026-58472.patch new file mode 100644 index 0000000..2b3586a --- /dev/null +++ b/SOURCES/wget-1.19.5-CVE-2026-58472.patch @@ -0,0 +1,264 @@ +From 2133f09782cefec5f174218d8d984744277fa891 Mon Sep 17 00:00:00 2001 +From: RHEL Packaging Agent +Date: Wed, 15 Jul 2026 10:38:03 +0000 +Subject: [PATCH] Fix CVE-2026-58472: integer+buffer overflow in + html_quote_string() + +Backport of upstream commits dd692d9 and f76978a, adapted to use +INT_ADD_WRAPV (available in wget 1.19.5 gnulib) instead of INT_ADD_OK +(not available in this gnulib version). + +* src/convert.c (html_quote_string): Fix integer+buffer overflow using + overflow-safe integer arithmetic via INT_ADD_WRAPV. + Fix string size calculation regression (+1 per special character). + Add unit tests for construct_relative, match_except_index, + find_fragment, and html_quote_string. +* tests/unit-tests.c: Register new test functions. +* tests/unit-tests.h: Declare new test functions. +--- + src/convert.c | 171 +++++++++++++++++++++++++++++++++++++++++++-- + tests/unit-tests.c | 4 ++ + tests/unit-tests.h | 4 ++ + 3 files changed, 172 insertions(+), 7 deletions(-) + +diff --git a/src/convert.c b/src/convert.c +index e6ca8fbb..1284d991 100644 +--- a/src/convert.c ++++ b/src/convert.c +@@ -36,6 +36,7 @@ as that of the covered work. */ + #include + #include + #include ++#include + #include "convert.h" + #include "url.h" + #include "recur.h" +@@ -47,6 +48,9 @@ as that of the covered work. */ + #include "css-url.h" + #include "iri.h" + #include "xstrndup.h" ++#ifdef TESTING ++#include "../tests/unit-tests.h" ++#endif + + static struct hash_table *dl_file_url_map; + struct hash_table *dl_url_file_map; +@@ -1131,21 +1135,37 @@ html_quote_string (const char *s) + { + const char *b = s; + char *p, *res; +- int i; ++ size_t i; ++ int ok; + + /* Pass through the string, and count the new size. */ +- for (i = 0; *s; s++, i++) ++ for (i = 0; *s; s++) + { + if (*s == '&') +- i += 4; /* `amp;' */ ++ ok = !INT_ADD_WRAPV (i, 4 + 1, &i); /* `amp;' */ + else if (*s == '<' || *s == '>') +- i += 3; /* `lt;' and `gt;' */ ++ ok = !INT_ADD_WRAPV (i, 3 + 1, &i); /* `lt;' and `gt;' */ + else if (*s == '\"') +- i += 5; /* `quot;' */ ++ ok = !INT_ADD_WRAPV (i, 5 + 1, &i); /* `quot;' */ + else if (*s == ' ') +- i += 4; /* #32; */ ++ ok = !INT_ADD_WRAPV (i, 4 + 1, &i); /* #32; */ ++ else ++ ok = !INT_ADD_WRAPV (i, 1, &i); ++ ++ if (!ok) ++ { ++ DEBUGP (("Overflow detected in html_quote_string().\n")); ++ abort(); ++ } ++ } ++ ++ if (INT_ADD_WRAPV (i, 1, &i)) ++ { ++ DEBUGP (("Overflow detected in html_quote_string().\n")); ++ abort(); + } +- res = xmalloc (i + 1); ++ ++ res = xmalloc (i); + s = b; + for (p = res; *s; s++) + { +@@ -1187,6 +1207,143 @@ html_quote_string (const char *s) + return res; + } + ++#ifdef TESTING ++ ++const char * ++test_construct_relative (void) ++{ ++ static const struct { ++ const char *basefile; ++ const char *linkfile; ++ const char *expected; ++ } test_array[] = { ++ { "foo", "bar", "bar" }, ++ { "A/foo", "A/bar", "bar" }, ++ { "A/foo", "A/B/bar", "B/bar" }, ++ { "A/X/foo", "A/Y/bar", "../Y/bar" }, ++ { "X/", "Y/bar", "../Y/bar" }, ++ { "/foo", "/bar", "bar" }, ++ { "/a/b/c", "/a/b/d", "d" }, ++ { "/a/b/c", "/a/b/c/d", "c/d" }, ++ { "/a/b/c", "/a/b/c/d/e", "c/d/e" }, ++ { "/a/b/c", "/x/y/z", "../../x/y/z" }, ++ { "a/b", "c/d", "../c/d" }, ++ { "./foo", "./bar", "bar" }, ++ }; ++ ++ for (unsigned i = 0; i < countof (test_array); ++i) ++ { ++ char *result = construct_relative (test_array[i].basefile, ++ test_array[i].linkfile); ++ mu_assert ("test_construct_relative: wrong result", ++ strcmp (result, test_array[i].expected) == 0); ++ xfree (result); ++ } ++ ++ return NULL; ++} ++ ++const char * ++test_match_except_index (void) ++{ ++ static const struct { ++ const char *s1; ++ const char *s2; ++ bool expected; ++ } test_array[] = { ++ { "foo/index.html", "foo/", true }, ++ { "foo/", "foo/index.html", true }, ++ { "foo", "foo/index.html", true }, ++ { "foo", "foo/", true }, ++ { "foo", "foo", true }, ++ { "/foo/index.html", "/foo/", true }, ++ { "/foo/", "/foo/index.html", true }, ++ { "/foo", "/foo/index.html", true }, ++ { "/foo", "/foo/", true }, ++ { "foo/bar", "foo/qux", false }, ++ { "foo/bar", "bar/foo", false }, ++ }; ++ ++ for (unsigned i = 0; i < countof (test_array); ++i) ++ { ++ bool result = match_except_index (test_array[i].s1, test_array[i].s2); ++ mu_assert ("test_match_except_index: wrong result", ++ result == test_array[i].expected); ++ } ++ ++ return NULL; ++} ++ ++const char * ++test_find_fragment (void) ++{ ++ static const struct { ++ const char *input; ++ int size; ++ bool has_fragment; ++ const char *fragment; ++ } test_array[] = { ++ { "http://example.com#section", 26, true, "#section" }, ++ { "http://example.com", 18, false, NULL }, ++ { "http://example.com?a=1#frag", 24, true, "#frag" }, ++ { "http://example.com?a=1%26#frag", 28, true, "#frag" }, ++ { "http://example.com?a=1&b=2#frag", 30, true, "#frag" }, ++ { "a#b", 3, true, "#b" }, ++ { "a", 1, false, NULL }, ++ }; ++ const char *bp, *ep; ++ ++ for (unsigned i = 0; i < countof (test_array); ++i) ++ { ++ bool result = find_fragment (test_array[i].input, ++ test_array[i].size, &bp, &ep); ++ mu_assert ("test_find_fragment: wrong result", ++ result == test_array[i].has_fragment); ++ if (test_array[i].has_fragment) ++ { ++ mu_assert ("test_find_fragment: wrong fragment", bp != NULL); ++ mu_assert ("test_find_fragment: fragment mismatch", ++ strncmp (bp, test_array[i].fragment, ++ strlen (test_array[i].fragment)) == 0 && ++ ep == test_array[i].input + test_array[i].size); ++ } ++ } ++ ++ return NULL; ++} ++ ++const char * ++test_html_quote_string (void) ++{ ++ static const struct { ++ const char *input; ++ const char *expected; ++ } test_array[] = { ++ { "hello", "hello" }, ++ { "a&b", "a&b" }, ++ { "", "<tag>" }, ++ { "\"quote\"", ""quote"" }, ++ { "space here", "space here" }, ++ { "&<>\" ", "&<>" " }, ++ { "no special", "no special" }, ++ { "&&&&", "&&&&" }, ++ { "<<>>", "<<>>" }, ++ { "" , "" }, ++ }; ++ ++ for (unsigned i = 0; i < countof (test_array); ++i) ++ { ++ char *result = html_quote_string (test_array[i].input); ++ mu_assert ("test_html_quote_string: wrong result", ++ strcmp (result, test_array[i].expected) == 0); ++ xfree (result); ++ } ++ ++ return NULL; ++} ++ ++#endif /* TESTING */ ++ + /* + * vim: et ts=2 sw=2 + */ +diff --git a/tests/unit-tests.c b/tests/unit-tests.c +index 0db434be..f3149343 100644 +--- a/tests/unit-tests.c ++++ b/tests/unit-tests.c +@@ -64,6 +64,10 @@ all_tests(void) + mu_run_test (test_hsts_url_rewrite_congruent); + mu_run_test (test_hsts_read_database); + #endif ++ mu_run_test (test_construct_relative); ++ mu_run_test (test_match_except_index); ++ mu_run_test (test_find_fragment); ++ mu_run_test (test_html_quote_string); + + return NULL; + } +diff --git a/tests/unit-tests.h b/tests/unit-tests.h +index 74552120..002a785f 100644 +--- a/tests/unit-tests.h ++++ b/tests/unit-tests.h +@@ -60,6 +60,10 @@ const char *test_hsts_new_entry(void); + const char *test_hsts_url_rewrite_superdomain(void); + const char *test_hsts_url_rewrite_congruent(void); + const char *test_hsts_read_database(void); ++const char *test_construct_relative(void); ++const char *test_match_except_index(void); ++const char *test_find_fragment(void); ++const char *test_html_quote_string(void); + + #endif /* TEST_H */ + diff --git a/SOURCES/wget-1.19.5-async-safe-signal-handler.patch b/SOURCES/wget-1.19.5-async-safe-signal-handler.patch new file mode 100644 index 0000000..86c8fa7 --- /dev/null +++ b/SOURCES/wget-1.19.5-async-safe-signal-handler.patch @@ -0,0 +1,110 @@ +From e1f2559efad5e2733ded804f9f1ba8acd8c4de61 Mon Sep 17 00:00:00 2001 +From: Michal Ruprich +Date: Tue, 14 Jul 2026 16:35:42 +0200 +Subject: [PATCH] Moving async signal unsafe functions out of signal handler + +There is a very rare race condition in function redirect_output_signal(). +If SIGHUP is received while wget is in malloc() function and a new +logfile is opened with fopen, another malloc() is called. malloc() is +not an async signal safe function and should not be called from within a +signal handler. + +* src/main.c (redirect_output_signal): do not call redirect_output(), +add an atomic flag. +* src/log.c (check_redirect_output): move redirect_output() here since this +is not in a signal handler + +Copyright-paperwork-exempt: Yes +--- + src/log.c | 26 ++++++++++++++++++++++++++ + src/main.c | 21 ++++++++------------- + 2 files changed, 34 insertions(+), 13 deletions(-) + +diff --git a/src/log.c b/src/log.c +index fe8c3982..17511327 100644 +--- a/src/log.c ++++ b/src/log.c +@@ -37,11 +37,16 @@ as that of the covered work. */ + #include + #include + #include ++#include + + #include "utils.h" + #include "exits.h" + #include "log.h" + ++#if defined(SIGHUP) || defined(SIGUSR1) ++extern volatile sig_atomic_t redirect_output_sig; ++#endif ++ + /* 2005-10-25 SMS. + VMS log files are often VFC record format, not stream, so fputs() can + produce multiple records, even when there's no newline terminator in +@@ -973,6 +978,27 @@ static void + check_redirect_output (void) + { + #ifndef WINDOWS ++#if defined(SIGHUP) || defined(SIGUSR1) ++ { ++ int sig = redirect_output_sig; ++ if (sig) ++ { ++ redirect_output_sig = 0; ++ const char *signal_name = "WTF?!"; ++#ifdef SIGHUP ++ if (sig == SIGHUP) ++ signal_name = "SIGHUP"; ++#endif ++#ifdef SIGUSR1 ++ if (sig == SIGUSR1) ++ signal_name = "SIGUSR1"; ++#endif ++ redirect_output (true, signal_name); ++ return; ++ } ++ } ++#endif /* defined(SIGHUP) || defined(SIGUSR1) */ ++ + /* If it was redirected already to log file by SIGHUP, SIGUSR1 or -o parameter, + * it was permanent. + * If there was no SIGHUP or SIGUSR1 and shell is interactive +diff --git a/src/main.c b/src/main.c +index a10a17f3..3926f501 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -123,23 +123,18 @@ int numurls = 0; + #if defined(SIGHUP) || defined(SIGUSR1) + /* Hangup signal handler. When wget receives SIGHUP or SIGUSR1, it + will proceed operation as usual, trying to write into a log file. +- If that is impossible, the output will be turned off. */ ++ If that is impossible, the output will be turned off. ++ ++ Only async-signal-safe operations are performed here. The actual ++ redirect (which needs malloc/fopen) is deferred to ++ check_redirect_output(), called from the logging functions. */ ++ ++volatile sig_atomic_t redirect_output_sig = 0; + + static void + redirect_output_signal (int sig) + { +- const char *signal_name = "WTF?!"; +- +-#ifdef SIGHUP +- if (sig == SIGHUP) +- signal_name = "SIGHUP"; +-#endif +-#ifdef SIGUSR1 +- if (sig == SIGUSR1) +- signal_name = "SIGUSR1"; +-#endif +- +- redirect_output (true,signal_name); ++ redirect_output_sig = sig; + progress_schedule_redirect (); + signal (sig, redirect_output_signal); + } +-- +GitLab + diff --git a/SPECS/wget.spec b/SPECS/wget.spec index fa6a22d..136ed9f 100644 --- a/SPECS/wget.spec +++ b/SPECS/wget.spec @@ -1,7 +1,7 @@ Summary: A utility for retrieving files using the HTTP or FTP protocols Name: wget Version: 1.19.5 -Release: 12%{?dist} +Release: 16%{?dist} License: GPLv3+ Group: Applications/Internet Url: http://www.gnu.org/software/wget/ @@ -24,6 +24,17 @@ Patch10: wget-1.19.5-no_proxy-tests.patch Patch11: wget-1.19.5-ca-cert-too-verbose.patch Patch12: wget-1.19.5-no-log-when-quiet.patch Patch13: wget-1.19.5-CVE-2024-38428.patch +# https://gitlab.com/gnuwget/wget/-/commit/dd692d9cea5335b181d877ae917fe6e75587a812 +# https://gitlab.com/gnuwget/wget/-/commit/f76978a51ba9365e7ecaed96c1cfb73197a38ca2 +Patch14: wget-1.19.5-CVE-2026-58472.patch +# https://gitlab.com/gnuwget/wget/-/commit/3514c0f2ad4e3d8a2e9ad0893accdb7a21cae729 +Patch15: wget-1.19.5-CVE-2026-58471.patch +# https://gitlab.com/gnuwget/wget/-/commit/37a40fcb450153f69537c7cbc2a7a4fb0b6f7826 +# https://gitlab.com/gnuwget/wget/-/commit/7b1cdecc49bc77bde220fc575c8a00386c3f3bcf +# https://gitlab.com/gnuwget/wget/-/commit/82d945ff5dc9942b78b2bf736aac298c24fe00a1 +Patch16: wget-1.19.5-CVE-2026-58469.patch +# https://gitlab.com/gnuwget/wget/-/merge_requests/72 +Patch17: wget-1.19.5-async-safe-signal-handler.patch Provides: webclient Provides: bundled(gnulib) @@ -62,6 +73,10 @@ grep "PACKAGE_STRING='wget .* (Red Hat modified)'" configure || exit 1 %patch11 -p1 -b .too_verbose %patch12 -p1 -b .no-log-quiet %patch13 -p1 -b .CVE-2024-38428 +%patch14 -p1 -b .CVE-2026-58472 +%patch15 -p1 -b .CVE-2026-58471 +%patch16 -p1 -b .CVE-2026-58469 +%patch17 -p1 -b .async-signal-handler %build %configure \ @@ -108,6 +123,21 @@ rm -rf $RPM_BUILD_ROOT %{_infodir}/* %changelog +* Tue Aug 04 2026 Michal Ruprich - 1.19.5-16 +- Resolves: RHEL-145875 - async unsafe code in signal handler context + +* Tue Jul 21 2026 RHEL Packaging Agent - 1.19.5-15 +- Fix CVE-2026-58469: buffer underflow in clean_metalink_string() +- Resolves: RHEL-212496 + +* Wed Jul 15 2026 RHEL Packaging Agent - 1.19.5-14 +- Fix CVE-2026-58471: buffer overflow in convert_fname() +- Resolves: RHEL-194519 + +* Wed Jul 15 2026 RHEL Packaging Agent - 1.19.5-13 +- Fix CVE-2026-58472: integer and buffer overflow in html_quote_string() +- Resolves: RHEL-210627 + * Wed Jul 10 2024 Michal Ruprich - 1.19.5-12 - Resolves: RHEL-43559 - Misinterpretation of input may lead to improper behavior