From patchwork Thu Oct 22 22:46:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101702 Received: from mta-65-226.siemens.flowmailer.net (mta-65-226.siemens.flowmailer.net [185.136.65.226]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2227.1792709251511447035 for ; Thu, 22 Oct 2026 15:47:31 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=IUniCBeF; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.65.226, mailfrom: fm-256628-20261022224728fb61af7e9a00020788-exc15d@rts-flowmailer.siemens.com) Received: by mta-65-226.siemens.flowmailer.net with ESMTPSA id 20261022224728fb61af7e9a00020788 for ; Fri, 23 Oct 2026 00:47:28 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc; bh=CyUfY8b/oe5+D51oRejhbMx41yGu5XJZJ+GPV+gvbvM=; b=IUniCBeF3b29iPDBfCyKxl0hayVyXhwq1EkuDYF14DAJ/D1KcdIdOm9YQXx4gIu83ALv9Z Y9lpb0DoBntme02Tz1GfuxfMIQ4S54DfYTZD1X0nBQf3nfc9x8EPlQd1NG2vauJjBKZynGRY VET63yw4pOOlzHISr3iOugVpAljvMmiuRXiAehmSHdzxbbtWYJhSN3zAOiPOPVAvlg3aJoWL Sc1OPfsPTcr+xn1BcAtcu16yTD8vY08Ijua5281pBmhcOCGnx4UJ/Dzk6VyOOknoUTJ6wa+L v4OIiAc+RnA84vG08oVB/t8Cm+P3lijb/avdIrrPaQ9je2Lo404laddA==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 01/15] glibc: patch CVE-2026-5928 Date: Fri, 23 Oct 2026 00:46:54 +0200 Message-ID: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:47:32 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248457 From: Peter Marko Pick patch [1] which is [2] backported to 3.41 (oldest release still receiving security updates) which is mentioned in [3]. [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=8941538b92a574a24e9308e164869239d2b0d845 [2] https://sourceware.org/git/?p=glibc.git;a=commit;h=ef3bfb5f910011f3780cb06aa47e730035f53285 [3] https://security-tracker.debian.org/tracker/CVE-2026-5928 Signed-off-by: Peter Marko --- .../glibc/glibc/0031-CVE-2026-5928.patch | 112 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 113 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0031-CVE-2026-5928.patch diff --git a/meta/recipes-core/glibc/glibc/0031-CVE-2026-5928.patch b/meta/recipes-core/glibc/glibc/0031-CVE-2026-5928.patch new file mode 100644 index 00000000000..60b81e74529 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0031-CVE-2026-5928.patch @@ -0,0 +1,112 @@ +From 8941538b92a574a24e9308e164869239d2b0d845 Mon Sep 17 00:00:00 2001 +From: Rocket Ma +Date: Fri, 1 May 2026 20:39:07 -0700 +Subject: [PATCH] libio: Fix ungetwc operating on byte stream [BZ #33998] + +* libio/wgenops.c: When _IO_wdefault_pbackfail attempts to push back one +character, it accidently compare the wchar to push back with the last +char from byte stream, instead of wide stream. Under specific coding, +attacker may exploit this to leak information. This commit fix bug +33998, or CVE-2026-5928. + +Signed-off-by: Rocket Ma +Reviewed-by: Carlos O'Donell +(cherry picked from commit ef3bfb5f910011f3780cb06aa47e730035f53285) + +CVE: CVE-2026-5928 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=8941538b92a574a24e9308e164869239d2b0d845] +Signed-off-by: Peter Marko +--- + libio/Makefile | 1 + + libio/bug-wgenops-bz33998.c | 54 +++++++++++++++++++++++++++++++++++++ + libio/wgenops.c | 4 +-- + 3 files changed, 57 insertions(+), 2 deletions(-) + create mode 100644 libio/bug-wgenops-bz33998.c + +diff --git a/libio/Makefile b/libio/Makefile +index e143ccdb2c..43ee8db06d 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -83,6 +83,7 @@ tests = \ + bug-ungetwc1 \ + bug-ungetwc2 \ + bug-wfflush \ ++ bug-wgenops-bz33998 \ + bug-wmemstream1 \ + bug-wsetpos \ + test-fmemopen \ +diff --git a/libio/bug-wgenops-bz33998.c b/libio/bug-wgenops-bz33998.c +new file mode 100644 +index 0000000000..cc4067da99 +--- /dev/null ++++ b/libio/bug-wgenops-bz33998.c +@@ -0,0 +1,54 @@ ++/* Regression test for ungetwc operating on byte stream (BZ #33998) ++ Copyright (C) 2026 The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "support/temp_file.h" ++#include "support/xstdio.h" ++#include "support/xunistd.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char *filename; ++ int fd = create_temp_file ("tst-bz33998-", &filename); ++ TEST_VERIFY (fd != -1); ++ xwrite (fd, "A", sizeof ("A")); // write "A\0" by design ++ xclose (fd); ++ ++ FILE *fp = xfopen (filename, "r+"); ++ TEST_COMPARE (getwc (fp), L'A'); ++ /* If the bug is fixed, then ungetwc should not touch byte stream. ++ If the bug is not fixed, ungetwc firstly match last read char, L'A', ++ failed, then the pbackfail branch, matching last read char in byte ++ stream, that is, '\0' (initialized when setup wide stream). */ ++ char *old_read_ptr = fp->_IO_read_ptr; ++ TEST_COMPARE (ungetwc (L'\0', fp), L'\0'); ++ TEST_VERIFY (fp->_IO_read_ptr == old_read_ptr); ++ ++ xfclose (fp); ++ free (filename); ++ ++ return 0; ++} ++ ++#include +diff --git a/libio/wgenops.c b/libio/wgenops.c +index 0a11d1b1de..9e0b2c00ea 100644 +--- a/libio/wgenops.c ++++ b/libio/wgenops.c +@@ -108,8 +108,8 @@ _IO_wdefault_pbackfail (FILE *fp, wint_t c) + { + if (fp->_wide_data->_IO_read_ptr > fp->_wide_data->_IO_read_base + && !_IO_in_backup (fp) +- && (wint_t) fp->_IO_read_ptr[-1] == c) +- --fp->_IO_read_ptr; ++ && (wint_t) fp->_wide_data->_IO_read_ptr[-1] == c) ++ --fp->_wide_data->_IO_read_ptr; + else + { + /* Need to handle a filebuf in write mode (switch to read mode). FIXME!*/ diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index d31c8656414..0a4f7ac3bd6 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -63,6 +63,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0028-CVE-2026-6238-0004.patch \ file://0029-CVE-2026-6238-0005.patch \ file://0030-CVE-2026-6238-0006.patch \ + file://0031-CVE-2026-5928.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:46:55 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101703 Received: from mta-65-228.siemens.flowmailer.net (mta-65-228.siemens.flowmailer.net [185.136.65.228]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2338.1792709259340280506 for ; Thu, 22 Oct 2026 15:47:40 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=b/AJuhIT; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.65.228, mailfrom: fm-256628-20261022224737225e6f53b600020763-97bqdr@rts-flowmailer.siemens.com) Received: by mta-65-228.siemens.flowmailer.net with ESMTPSA id 20261022224737225e6f53b600020763 for ; Fri, 23 Oct 2026 00:47:37 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=ZtkW/W1EUm/BjBLKLV68Dn5CxIY3oILpZA3wWmbUjSo=; b=b/AJuhITieJrpSZRUmOs3rsGhIr5yqxg3MrZhvl9c2eQGH9sZcr/tvmMeHPtIuZjWuEkLc 28hejqbdDpinzo2ziGNs+dqwwJEOCdBFTmogVw7mERO7B80oXHibtIgwYXfLH6l8vUrCM5tT zfHrcqjAN/13bUGm5I2R2b92AIcZZFEz3FsxXLpP+wqY7reHkTnfaLZClKkxPJjq+xUzXauC geej0kjS0W2WBWZMDdNJIFkpRGicbVrGY01g9UCINrcd9vn6Ooj2dYef5uxoIanLx15+aCqp W6T+zK62ENeSsjIf4oqjD9njGv/8EYNwF4Za/8XX6H2Nk+PUrcphpWeg==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 02/15] glibc: patch CVE-2026-5450 Date: Fri, 23 Oct 2026 00:46:55 +0200 Message-ID: <20261022224711.3783258-2-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:47:42 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248458 From: Peter Marko Pick patch [1] which is [2] backported to 3.41 (oldest release still receiving security updates) which is mentioned in [3]. [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=1a74f82eedaf0987eda1f522121e6a48fac502e7 [2] https://sourceware.org/git/?p=glibc.git;a=commit;h=839898777226a3ed88c0859f25ffe712519b4ead [3] https://security-tracker.debian.org/tracker/CVE-2026-5450 Signed-off-by: Peter Marko --- .../glibc/glibc/0032-CVE-2026-5450.patch | 133 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 134 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0032-CVE-2026-5450.patch diff --git a/meta/recipes-core/glibc/glibc/0032-CVE-2026-5450.patch b/meta/recipes-core/glibc/glibc/0032-CVE-2026-5450.patch new file mode 100644 index 00000000000..631b63f4654 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0032-CVE-2026-5450.patch @@ -0,0 +1,133 @@ +From 1a74f82eedaf0987eda1f522121e6a48fac502e7 Mon Sep 17 00:00:00 2001 +From: Rocket Ma +Date: Fri, 17 Apr 2026 23:48:41 -0700 +Subject: [PATCH] stdio-common: Fix buffer overflow in scanf %mc [BZ #34008] + +* stdio-common/vfscanf-internal.c: When enlarging allocated buffer with +format %mc or %mC, glibc allocates one byte less, leading to +user-controlled one byte overflow. This commit fixes BZ #34008, or +CVE-2026-5450. + +Reviewed-by: Carlos O'Donell +Signed-off-by: Rocket Ma +Reviewed-by: H.J. Lu +(cherry picked from commit 839898777226a3ed88c0859f25ffe712519b4ead) + +CVE: CVE-2026-5450 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=1a74f82eedaf0987eda1f522121e6a48fac502e7] +Signed-off-by: Peter Marko +--- + stdio-common/Makefile | 4 +++ + stdio-common/tst-vfscanf-bz34008.c | 48 ++++++++++++++++++++++++++++++ + stdio-common/vfscanf-internal.c | 7 ++--- + 3 files changed, 55 insertions(+), 4 deletions(-) + create mode 100644 stdio-common/tst-vfscanf-bz34008.c + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index ac098dcd8a..72c18e5dc1 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -266,6 +266,7 @@ tests := \ + tst-vfprintf-width-i18n \ + tst-vfprintf-width-prec \ + tst-vfprintf-width-prec-alloc \ ++ tst-vfscanf-bz34008 \ + tst-wc-printf \ + tstdiomisc \ + tstgetln \ +@@ -401,6 +402,9 @@ tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \ + tst-vfprintf-width-prec-ENV = \ + MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++tst-vfscanf-bz34008-ENV = \ ++ MALLOC_CHECK_=3 \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so + tst-printf-bz25691-ENV = \ + MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so +diff --git a/stdio-common/tst-vfscanf-bz34008.c b/stdio-common/tst-vfscanf-bz34008.c +new file mode 100644 +index 0000000000..48371c8a3d +--- /dev/null ++++ b/stdio-common/tst-vfscanf-bz34008.c +@@ -0,0 +1,48 @@ ++/* Regression test for vfscanf %Nmc out-of-bound write (BZ #34008) ++ Copyright (C) 2026 The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "malloc/mcheck.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define WIDTH 0x410 ++#define SCANFSTR "%1040mc" ++static int ++do_test (void) ++{ ++ mcheck_pedantic (NULL); ++ char *input = malloc (WIDTH + 1); ++ TEST_VERIFY (input != NULL); ++ memset (input, 'A', WIDTH); ++ input[WIDTH] = '\0'; ++ ++ char *buf = NULL; ++ TEST_VERIFY (sscanf (input, SCANFSTR, &buf) != -1); ++ TEST_VERIFY (buf != NULL); ++ ++ free (buf); ++ free (input); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c +index 1ba034d961..fabb0ec874 100644 +--- a/stdio-common/vfscanf-internal.c ++++ b/stdio-common/vfscanf-internal.c +@@ -853,8 +853,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, + { + /* Enlarge the buffer. */ + size_t newsize +- = strsize +- + (strsize >= width ? width - 1 : strsize); ++ = strsize + (strsize >= width ? width : strsize); + + str = (char *) realloc (*strptr, newsize); + if (str == NULL) +@@ -925,7 +924,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, + && wstr == (wchar_t *) *strptr + strsize) + { + size_t newsize +- = strsize + (strsize > width ? width - 1 : strsize); ++ = strsize + (strsize >= width ? width : strsize); + /* Enlarge the buffer. */ + wstr = (wchar_t *) realloc (*strptr, + newsize * sizeof (wchar_t)); +@@ -980,7 +979,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, + && wstr == (wchar_t *) *strptr + strsize) + { + size_t newsize +- = strsize + (strsize > width ? width - 1 : strsize); ++ = strsize + (strsize >= width ? width : strsize); + /* Enlarge the buffer. */ + wstr = (wchar_t *) realloc (*strptr, + newsize * sizeof (wchar_t)); diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 0a4f7ac3bd6..e62d941fdde 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -64,6 +64,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0029-CVE-2026-6238-0005.patch \ file://0030-CVE-2026-6238-0006.patch \ file://0031-CVE-2026-5928.patch \ + file://0032-CVE-2026-5450.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:46:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101704 Received: from mta-65-225.siemens.flowmailer.net (mta-65-225.siemens.flowmailer.net [185.136.65.225]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2229.1792709266423383138 for ; Thu, 22 Oct 2026 15:47:46 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=Vf/21nZh; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.65.225, mailfrom: fm-256628-202610222247440a9d00422200020711-iocyjm@rts-flowmailer.siemens.com) Received: by mta-65-225.siemens.flowmailer.net with ESMTPSA id 202610222247440a9d00422200020711 for ; Fri, 23 Oct 2026 00:47:44 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=GwkuNlz1kJKM3qJbZ7njLodKxfS4R302/eddshDdz24=; b=Vf/21nZhL0UF5nGfhdkMqvUxnOQ4l2Zpqs6SKWSnc3lVisowiOiik9c3fdssP8UajNz3/v pMsBgZvXri6d8OdAEBVC4xKGnNUOmXIisa613n6z1kEjN0AyTi3BYgRST7uFH5rjz+oIDhBU vkfCILv+aeh7BRzOdGjDZw7SdmoeR5HURPNt6w6DSLS6AtTAKarTKhJx3LjDtsr64N/Vwc3y o8L2RKCy/6umlec37I2sywg3LOn2NzLTrlTIZhzKNqrl5QfO3KZxgMcNtVsVmJKRoWsJ7U0/ wia94qVgAxE+dxBgrzao9ljqExXJ+wSRIfzfKmbGvTM+9YswUfCbkwjA==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 03/15] glibc: patch CVE-2026-6791 Date: Fri, 23 Oct 2026 00:46:56 +0200 Message-ID: <20261022224711.3783258-3-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:47:52 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248459 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0033-CVE-2026-6791.patch | 364 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 365 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0033-CVE-2026-6791.patch diff --git a/meta/recipes-core/glibc/glibc/0033-CVE-2026-6791.patch b/meta/recipes-core/glibc/glibc/0033-CVE-2026-6791.patch new file mode 100644 index 00000000000..83294df46e8 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0033-CVE-2026-6791.patch @@ -0,0 +1,364 @@ +From 965b580070b8184b0dd390800d9194291a600e67 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Tue, 14 Apr 2026 10:50:37 -0300 +Subject: [PATCH] posix: Fix stack overflow in wordexp tilde expansion (BZ + 34091, CVE-2026-6791) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The parse_tilde function previously used strndupa to allocate memory +for the parsed username on the stack, and since the input is +user-defined, this can lead to a stack overflow. + +This patch fixes the issue by replacing strndupa with scratch_buffer, +by reusing the buffer used in the __getpwnam_r call. + +The new “tst-wordexp-tilde.c” test is a test-container to avoid using +system-defined NSS modules. + +Checked on x86_64-linux-gnu and i686-linux-gnu. + +(cherry picked from commit 07c24f35392b727e6100d33edfdf811a6c68c218) + +CVE: CVE-2026-6791 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=965b580070b8184b0dd390800d9194291a600e67] +Signed-off-by: Peter Marko +--- + posix/Makefile | 1 + + posix/tst-wordexp-tilde.c | 244 ++++++++++++++++++ + posix/tst-wordexp-tilde.root/etc/group | 1 + + .../tst-wordexp-tilde.root/etc/nsswitch.conf | 3 + + posix/tst-wordexp-tilde.root/etc/passwd | 1 + + posix/wordexp.c | 24 +- + 6 files changed, 268 insertions(+), 6 deletions(-) + create mode 100644 posix/tst-wordexp-tilde.c + create mode 100644 posix/tst-wordexp-tilde.root/etc/group + create mode 100644 posix/tst-wordexp-tilde.root/etc/nsswitch.conf + create mode 100644 posix/tst-wordexp-tilde.root/etc/passwd + +diff --git a/posix/Makefile b/posix/Makefile +index 9360bc7ff8..c2c05b3973 100644 +--- a/posix/Makefile ++++ b/posix/Makefile +@@ -354,6 +354,7 @@ tests-internal := \ + tests-container := \ + bug-ga2 \ + tst-vfork3 \ ++ tst-wordexp-tilde \ + # tests-container + + tests-time64 := \ +diff --git a/posix/tst-wordexp-tilde.c b/posix/tst-wordexp-tilde.c +new file mode 100644 +index 0000000000..1661603681 +--- /dev/null ++++ b/posix/tst-wordexp-tilde.c +@@ -0,0 +1,244 @@ ++/* Test wordexp tilde expansion with large usernames (BZ 34091). ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++typedef void (*func_callback_t)(void); ++ ++static void ++subprocess_small_stack (void *closure) ++{ ++ struct rlimit rl; ++ TEST_COMPARE (getrlimit (RLIMIT_STACK, &rl), 0); ++ rl.rlim_cur = 512 * 1024; ++ TEST_COMPARE (setrlimit (RLIMIT_STACK, &rl), 0); ++ ++ func_callback_t func_test = closure; ++ func_test (); ++} ++ ++/* Build a string "~/tail" where is LEN bytes of the ++ character CH. The caller must free the result. */ ++static char * ++make_tilde_input (char ch, size_t len, const char *tail) ++{ ++ /* ~ + len + / + tail + \0 */ ++ size_t taillen = tail != NULL ? strlen (tail) : 0; ++ size_t total = 1 + len + 1 + taillen + 1; ++ char *buf = xmalloc (total); ++ buf[0] = '~'; ++ memset (buf + 1, ch, len); ++ buf[1 + len] = '/'; ++ if (tail != NULL) ++ memcpy (buf + 1 + len + 1, tail, taillen); ++ buf[total - 1] = '\0'; ++ return buf; ++} ++ ++/* Test 1: A very long username must not crash. The username will not match ++ any real user, so wordexp returns ~/rest. */ ++static void ++test_long_username (void) ++{ ++ printf ("info: test_long_username_no_crash\n"); ++ ++ static const char REST[] = "rest"; ++ ++ /* 1 MiB username — well beyond any reasonable stack frame. */ ++ const size_t long_len = 1024 * 1024; ++ char *input = make_tilde_input ('A', long_len, REST); ++ ++ wordexp_t we = { 0 }; ++ int ret = wordexp (input, &we, 0); ++ /* The (non-existent) username is invalid, so wordexp falls back to ++ literal output: ~AAA…/rest. */ ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE (we.we_wordc, 1); ++ ++ /* Verify prefix: '~' followed by long_len 'A's. */ ++ const char *result = we.we_wordv[0]; ++ TEST_COMPARE (result[0], '~'); ++ TEST_COMPARE (strlen (result), ++ 1 /* ~ */ + long_len + sizeof (REST)); ++ for (size_t j = 1; j <= long_len; j++) ++ if (result[j] != 'A') ++ { ++ printf (" mismatch at position %zu: expected 'A', got '%c'\n", ++ j, result[j]); ++ support_record_failure (); ++ break; ++ } ++ /* Verify the tail after the username. */ ++ TEST_COMPARE_STRING (result + 1 + long_len, "/rest"); ++ ++ wordfree (&we); ++ free (input); ++} ++ ++/* Test 2: A username that just exceeds the default scratch_buffer inline ++ size (1024 bytes) exercises the scratch_buffer_set_array_size growth path ++ without being excessively large. */ ++static void ++test_scratch_buffer_growth (void) ++{ ++ printf ("info: test_scratch_buffer_growth\n"); ++ ++ const size_t len = 2048; ++ char *input = make_tilde_input ('x', len, NULL); ++ ++ wordexp_t we = { 0 }; ++ int ret = wordexp (input, &we, 0); ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE (we.we_wordc, 1); ++ ++ /* ~xxx…/ — the trailing slash makes a separate empty component, but ++ wordexp merges it into the single token ~xxx…/. */ ++ const char *result = we.we_wordv[0]; ++ TEST_COMPARE (result[0], '~'); ++ for (size_t j = 1; j <= len; j++) ++ if (result[j] != 'x') ++ { ++ printf (" mismatch at position %zu\n", j); ++ support_record_failure (); ++ break; ++ } ++ TEST_COMPARE (result[1 + len], '/'); ++ ++ wordfree (&we); ++ free (input); ++} ++ ++/* Test 3: ~root still resolves to the correct home directory through the ++ __getpwnam_r path. */ ++static void ++test_known_user (void) ++{ ++ printf ("info: test_known_user\n"); ++ ++ /* Look up root's home directory for comparison. */ ++ struct passwd *pw = getpwnam ("root"); ++ if (pw == NULL || pw->pw_dir == NULL) ++ { ++ printf (" SKIP: cannot look up root\n"); ++ return; ++ } ++ ++ char *expected = xasprintf ("%s/file", pw->pw_dir); ++ ++ wordexp_t we = { 0 }; ++ TEST_COMPARE (wordexp ("~root/file", &we, 0), 0); ++ TEST_COMPARE (we.we_wordc, 1); ++ TEST_COMPARE_STRING (we.we_wordv[0], expected); ++ ++ wordfree (&we); ++ free (expected); ++} ++ ++/* Test 4: Bare tilde expands to $HOME. */ ++static void ++test_bare_tilde (void) ++{ ++ printf ("info: test_bare_tilde\n"); ++ ++ const char *home = getenv ("HOME"); ++ if (home == NULL) ++ { ++ printf (" SKIP: HOME is not set\n"); ++ return; ++ } ++ ++ wordexp_t we = { 0 }; ++ TEST_COMPARE (wordexp ("~", &we, 0), 0); ++ TEST_COMPARE (we.we_wordc, 1); ++ TEST_COMPARE_STRING (we.we_wordv[0], home); ++ ++ wordfree (&we); ++} ++ ++/* Test 5: Short non-existent username falls back to literal ~username output, ++ exercising the invalid-login-name path. */ ++static void ++test_unknown_user (void) ++{ ++ printf ("info: test_unknown_user\n"); ++ ++ /* Pick a username that is extremely unlikely to exist. */ ++ wordexp_t we = { 0 }; ++ TEST_COMPARE (wordexp ("~no_such_user_xyzzy42", &we, 0), 0); ++ TEST_COMPARE (we.we_wordc, 1); ++ TEST_COMPARE_STRING (we.we_wordv[0], "~no_such_user_xyzzy42"); ++ ++ wordfree (&we); ++} ++ ++/* Test 6: Tilde with username and WRDE_APPEND — exercises parse_tilde's ++ interaction with the WRDE_APPEND word list. */ ++static void ++test_tilde_with_append (void) ++{ ++ printf ("info: test_tilde_with_append\n"); ++ ++ const char *home = getenv ("HOME"); ++ if (home == NULL) ++ { ++ printf (" SKIP: HOME is not set\n"); ++ return; ++ } ++ ++ wordexp_t we = { 0 }; ++ TEST_COMPARE (wordexp ("first", &we, 0), 0); ++ ++ TEST_COMPARE (wordexp ("~/path", &we, WRDE_APPEND), 0); ++ TEST_COMPARE (we.we_wordc, 2); ++ TEST_COMPARE_STRING (we.we_wordv[0], "first"); ++ ++ char *expected = xasprintf ("%s/path", home); ++ TEST_COMPARE_STRING (we.we_wordv[1], expected); ++ ++ wordfree (&we); ++ free (expected); ++} ++ ++static int ++do_test (void) ++{ ++ test_known_user (); ++ test_bare_tilde (); ++ test_unknown_user (); ++ test_tilde_with_append (); ++ ++ support_isolate_in_subprocess (subprocess_small_stack, ++ test_long_username); ++ ++ support_isolate_in_subprocess (subprocess_small_stack, ++ test_scratch_buffer_growth); ++ ++ return 0; ++} ++ ++#include +diff --git a/posix/tst-wordexp-tilde.root/etc/group b/posix/tst-wordexp-tilde.root/etc/group +new file mode 100644 +index 0000000000..1dbf9013ee +--- /dev/null ++++ b/posix/tst-wordexp-tilde.root/etc/group +@@ -0,0 +1 @@ ++root:x:0: +diff --git a/posix/tst-wordexp-tilde.root/etc/nsswitch.conf b/posix/tst-wordexp-tilde.root/etc/nsswitch.conf +new file mode 100644 +index 0000000000..098a8d5938 +--- /dev/null ++++ b/posix/tst-wordexp-tilde.root/etc/nsswitch.conf +@@ -0,0 +1,3 @@ ++passwd: files ++group: files ++shadow: files +diff --git a/posix/tst-wordexp-tilde.root/etc/passwd b/posix/tst-wordexp-tilde.root/etc/passwd +new file mode 100644 +index 0000000000..eb85a552ad +--- /dev/null ++++ b/posix/tst-wordexp-tilde.root/etc/passwd +@@ -0,0 +1 @@ ++root:x:0:0:root:/root:/bin/sh +diff --git a/posix/wordexp.c b/posix/wordexp.c +index 9df4bb7424..731d1650e9 100644 +--- a/posix/wordexp.c ++++ b/posix/wordexp.c +@@ -335,17 +335,29 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length, + else + { + /* Look up user name in database to get home directory */ +- char *user = strndupa (&words[1 + *offset], i - (1 + *offset)); +- struct passwd pwd, *tpwd; +- int result; ++ size_t userlen = i - (1 + *offset); ++ /* tmpbuf contains both the user and the __getpwnam_r working area. */ + struct scratch_buffer tmpbuf; + scratch_buffer_init (&tmpbuf); ++ if (!scratch_buffer_set_array_size (&tmpbuf, userlen + 1, 1)) ++ return WRDE_NOSPACE; ++ char *user = tmpbuf.data; ++ memcpy (user, &words[1 + *offset], userlen); ++ user[userlen] = '\0'; + +- while ((result = __getpwnam_r (user, &pwd, tmpbuf.data, tmpbuf.length, ++ struct passwd pwd, *tpwd; ++ int result; ++ while ((result = __getpwnam_r (user, ++ &pwd, ++ tmpbuf.data + userlen + 1, ++ tmpbuf.length - userlen - 1, + &tpwd)) != 0 + && errno == ERANGE) +- if (!scratch_buffer_grow (&tmpbuf)) +- return WRDE_NOSPACE; ++ { ++ if (!scratch_buffer_grow_preserve (&tmpbuf)) ++ return WRDE_NOSPACE; ++ user = tmpbuf.data; ++ } + + if (result == 0 && tpwd != NULL && pwd.pw_dir) + *word = w_addstr (*word, word_length, max_length, pwd.pw_dir); diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index e62d941fdde..26aa6fb275e 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -65,6 +65,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0030-CVE-2026-6238-0006.patch \ file://0031-CVE-2026-5928.patch \ file://0032-CVE-2026-5450.patch \ + file://0033-CVE-2026-6791.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:46:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101705 Received: from mta-65-228.siemens.flowmailer.net (mta-65-228.siemens.flowmailer.net [185.136.65.228]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2341.1792709272809997498 for ; Thu, 22 Oct 2026 15:47:53 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=YI01CBhM; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.65.228, mailfrom: fm-256628-202610222247519a0061002d0002079f-jtospt@rts-flowmailer.siemens.com) Received: by mta-65-228.siemens.flowmailer.net with ESMTPSA id 202610222247519a0061002d0002079f for ; Fri, 23 Oct 2026 00:47:51 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=XhS9K4sELQxi6W/LdZi7rm8L61Fy+SMZ9XdnhazA8VM=; b=YI01CBhMUH2otR+PU5T5mPF0GLtCYLT8MRtlspmmYAe5zEsu1B7coEjxmLJlkV5cIunRxf fJOvQgFf0dton8f22cdkSvrskLcIBfEbKSZL+NrpNjh3AQkjqpZMx4GXmZUHNCosFcN2rG9A rSQe4aegvlFQ7G4C/mKPJVII/OCAQc7nzglMcvex0f3mqfr6LvnDI3M8GS7Y+hLoNPt0ZII/ wZrANSoso0BLpC/x0udSxDKPuVq6WYVKdLI6eyH8YxOb7ooYIlvZQl1Zor0r9rojx1SQ6ImM 6yLG5yTk4Tdc2mESsh7rmauAdZfoVpqJDS07croMaN2/4E1ANn4twk3w==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 04/15] glibc: patch CVE-2026-6368 Date: Fri, 23 Oct 2026 00:46:57 +0200 Message-ID: <20261022224711.3783258-4-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:02 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248460 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0034-CVE-2026-6368.patch | 577 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 578 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0034-CVE-2026-6368.patch diff --git a/meta/recipes-core/glibc/glibc/0034-CVE-2026-6368.patch b/meta/recipes-core/glibc/glibc/0034-CVE-2026-6368.patch new file mode 100644 index 00000000000..8ce9ce682f5 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0034-CVE-2026-6368.patch @@ -0,0 +1,577 @@ +From dfc8ef388ef7856f318ade7dec501f92ce54f9e3 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 13 Apr 2026 16:33:30 -0300 +Subject: [PATCH] posix: Fix wordexp WRDE_APPEND to preserve state on + non-NOSPACE errors (BZ 34090, CVE-2026-6368) + +The previous implementation saved a copy of the wordexp_t struct at +entry and blindly restored it on error via (*pwordexp = old_word). +This is incorrect when WRDE_APPEND is set because w_addword may have +called realloc on we_wordv during partial processing before the error +was detected. If realloc relocated the buffer, the saved we_wordv +pointer is dangling; restoring it causes a use-after-free in the +caller (e.g. via wordfree), and the relocated buffer is leaked. + +Fix this by duplicating the we_wordv pointer array at entry when +WRDE_APPEND is set, so that all subsequent realloc calls inside +w_addword operate on the copy. + +This change also fixes a POSIX conformance issue: if the WRDE_APPEND +flag is specified, pwordexp->we_wordc and pwordexp->we_wordv shall +not be modified. + +Also fix two pre-existing error return paths in the '"' and '\'' cases +that returned directly from w_addword failures instead of going through +do_error, which would leak the saved array (and previously would also +skip the word cleanup). + +Checked on x86_64-linux-gnu and i686-linux-gnu. + +Reviewed-by: DJ Delorie +(cherry picked from commit e2cefe16c37a617df9f11407cb00a272a6098823) + +CVE: CVE-2026-6368 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;dfc8ef388ef7856f318ade7dec501f92ce54f9e3] +Signed-off-by: Peter Marko +--- + posix/Makefile | 1 + + posix/tst-wordexp-append.c | 393 +++++++++++++++++++++++++++++++++++++ + posix/wordexp.c | 69 ++++++- + 3 files changed, 454 insertions(+), 9 deletions(-) + create mode 100644 posix/tst-wordexp-append.c + +diff --git a/posix/Makefile b/posix/Makefile +index c2c05b3973..5358a3f8c1 100644 +--- a/posix/Makefile ++++ b/posix/Makefile +@@ -325,6 +325,7 @@ tests := \ + tst-wait3 \ + tst-wait4 \ + tst-waitid \ ++ tst-wordexp-append \ + tst-wordexp-nocmd \ + tst-wordexp-reuse \ + tstgetopt \ +diff --git a/posix/tst-wordexp-append.c b/posix/tst-wordexp-append.c +new file mode 100644 +index 0000000000..87f388f0a7 +--- /dev/null ++++ b/posix/tst-wordexp-append.c +@@ -0,0 +1,393 @@ ++/* Test for wordexp with WRDE_APPEND flag. ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static unsigned int relocating_reallocs; ++ ++/* w_addword grows we_wordv with realloc, make every call guaranteed to ++ relocate the block. This makes BZ 34090 regression more deterministic. */ ++void * ++realloc (void *ptr, size_t size) ++{ ++ if (ptr == NULL) ++ return malloc (size); ++ if (size == 0) ++ { ++ free (ptr); ++ return NULL; ++ } ++ ++ void *new = malloc (size); ++ if (new == NULL) ++ return NULL; ++ ++ /* Copy only what is valid in the old block to avoid reading past it. */ ++ size_t old = malloc_usable_size (ptr); ++ memcpy (new, ptr, old < size ? old : size); ++ /* Clobber the old block so that a stale we_wordv pointer restored on the ++ error path reads garbage instead of the old contents, which might ++ otherwise survive intact and mask the bug. */ ++ memset (ptr, 0x5a, old); ++ free (ptr); ++ relocating_reallocs++; ++ return new; ++} ++ ++/* Verify that all words in we match the expected NULL-terminated ++ array. */ ++static void ++check_words (const wordexp_t *we, const char *const *expected) ++{ ++ size_t i; ++ for (i = 0; expected[i] != NULL; i++) ++ { ++ TEST_VERIFY (i < we->we_wordc); ++ TEST_COMPARE_STRING (we->we_wordv[we->we_offs + i], expected[i]); ++ } ++ TEST_COMPARE (we->we_wordc, i); ++} ++ ++#define CHECK_WORDS(we, ...) \ ++ do { \ ++ const char *const expected_[] = { __VA_ARGS__, NULL }; \ ++ check_words (we, expected_); \ ++ } while (0) ++ ++/* Test 1: WRDE_APPEND + WRDE_BADCHAR preserves we_wordc. */ ++static void ++test_append_badchar_preserves_count (void) ++{ ++ printf ("info: test_append_badchar_preserves_count\n"); ++ wordexp_t we = { 0 }; ++ ++ TEST_COMPARE (wordexp ("one two three", &we, 0), 0); ++ TEST_COMPARE (we.we_wordc, 3); ++ ++ size_t saved_count = we.we_wordc; ++ ++ /* ')' triggers WRDE_BADCHAR and "extra" would be a new word if the ++ expansion succeeded, exercising the w_addword path before the error ++ is detected. */ ++ TEST_COMPARE (wordexp ("extra )", &we, WRDE_APPEND), WRDE_BADCHAR); ++ TEST_COMPARE (we.we_wordc, saved_count); ++ ++ wordfree (&we); ++} ++ ++/* Test 2: WRDE_APPEND + WRDE_BADCHAR preserves the we_wordv pointer even ++ when internal realloc would move the buffer. */ ++static void ++test_append_badchar_preserves_pointer (void) ++{ ++ printf ("info: test_append_badchar_preserves_pointer\n"); ++ wordexp_t we = { 0 }; ++ ++ /* Use many words so that the initial we_wordv allocation is ++ non-trivial and a later realloc is more likely to move it. */ ++ TEST_COMPARE (wordexp ("a b c d e f g h", &we, 0), 0); ++ TEST_COMPARE (we.we_wordc, 8); ++ ++ char **saved_wordv = we.we_wordv; ++ size_t saved_count = we.we_wordc; ++ unsigned int saved_reallocs = relocating_reallocs; ++ ++ /* The interposed realloc guarantees the internal we_wordv buffer moves ++ during parsing, so the pointer-stability check below is meaningful. */ ++ TEST_COMPARE (wordexp ("append )", &we, WRDE_APPEND), WRDE_BADCHAR); ++ /* Verify that a relocating realloc actually happened during the failed ++ call, otherwise the pointer-stability check is vacuous. */ ++ TEST_VERIFY (relocating_reallocs > saved_reallocs); ++ TEST_COMPARE (we.we_wordc, saved_count); ++ TEST_VERIFY (we.we_wordv == saved_wordv); ++ ++ wordfree (&we); ++} ++ ++/* Test 3: After a failed WRDE_APPEND the original words are still accessible ++ and correct. */ ++static void ++test_append_badchar_words_intact (void) ++{ ++ printf ("info: test_append_badchar_words_intact\n"); ++ wordexp_t we = { 0 }; ++ ++ TEST_COMPARE (wordexp ("alpha beta gamma", &we, 0), 0); ++ CHECK_WORDS (&we, "alpha", "beta", "gamma"); ++ ++ TEST_COMPARE (wordexp ("delta )", &we, WRDE_APPEND), WRDE_BADCHAR); ++ ++ /* Words must still be intact. */ ++ CHECK_WORDS (&we, "alpha", "beta", "gamma"); ++ /* The NULL terminator must still be present. */ ++ TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL); ++ ++ wordfree (&we); ++} ++ ++/* Test 4: Successful WRDE_APPEND still works (regression test). */ ++static void ++test_append_success (void) ++{ ++ printf ("info: test_append_success\n"); ++ wordexp_t we = { 0 }; ++ ++ TEST_COMPARE (wordexp ("hello", &we, 0), 0); ++ TEST_COMPARE (we.we_wordc, 1); ++ ++ char **saved_wordv = we.we_wordv; ++ ++ TEST_COMPARE (wordexp ("world", &we, WRDE_APPEND), 0); ++ TEST_COMPARE (we.we_wordc, 2); ++ /* A successful append works on a fresh copy of the array, so the ++ caller-visible pointer must have changed. */ ++ TEST_VERIFY (we.we_wordv != saved_wordv); ++ CHECK_WORDS (&we, "hello", "world"); ++ ++ wordfree (&we); ++} ++ ++/* Test 5: Successful append after a failed append — the implementation must ++ recover and allow further use of the wordexp_t. */ ++static void ++test_append_success_after_failure (void) ++{ ++ printf ("info: test_append_success_after_failure\n"); ++ wordexp_t we = { 0 }; ++ ++ TEST_COMPARE (wordexp ("first", &we, 0), 0); ++ CHECK_WORDS (&we, "first"); ++ ++ TEST_COMPARE (wordexp ("bad |", &we, WRDE_APPEND), WRDE_BADCHAR); ++ ++ /* State must be exactly as before the failed call. */ ++ CHECK_WORDS (&we, "first"); ++ ++ /* A subsequent successful append must work. */ ++ TEST_COMPARE (wordexp ("second third", &we, WRDE_APPEND), 0); ++ CHECK_WORDS (&we, "first", "second", "third"); ++ ++ wordfree (&we); ++} ++ ++/* Test 6: Multiple consecutive failed appends do not corrupt state. */ ++static void ++test_append_multiple_failures (void) ++{ ++ printf ("info: test_append_multiple_failures\n"); ++ wordexp_t we = { 0 }; ++ ++ TEST_COMPARE (wordexp ("keep this", &we, 0), 0); ++ CHECK_WORDS (&we, "keep", "this"); ++ ++ size_t saved_count = we.we_wordc; ++ char **saved_wordv = we.we_wordv; ++ ++ /* Each of these bad characters must leave the state unchanged. */ ++ TEST_COMPARE (wordexp ("x )", &we, WRDE_APPEND), WRDE_BADCHAR); ++ TEST_COMPARE (wordexp ("x |", &we, WRDE_APPEND), WRDE_BADCHAR); ++ TEST_COMPARE (wordexp ("x ;", &we, WRDE_APPEND), WRDE_BADCHAR); ++ TEST_COMPARE (wordexp ("x &", &we, WRDE_APPEND), WRDE_BADCHAR); ++ TEST_COMPARE (wordexp ("x <", &we, WRDE_APPEND), WRDE_BADCHAR); ++ TEST_COMPARE (wordexp ("x >", &we, WRDE_APPEND), WRDE_BADCHAR); ++ ++ TEST_COMPARE (we.we_wordc, saved_count); ++ TEST_VERIFY (we.we_wordv == saved_wordv); ++ CHECK_WORDS (&we, "keep", "this"); ++ ++ wordfree (&we); ++} ++ ++/* Test 7: WRDE_APPEND with WRDE_SYNTAX error (unterminated quote) also ++ preserves state. */ ++static void ++test_append_syntax_error (void) ++{ ++ printf ("info: test_append_syntax_error\n"); ++ wordexp_t we = { 0 }; ++ ++ TEST_COMPARE (wordexp ("original", &we, 0), 0); ++ CHECK_WORDS (&we, "original"); ++ ++ char **saved_wordv = we.we_wordv; ++ size_t saved_count = we.we_wordc; ++ ++ /* Unterminated double quote triggers WRDE_SYNTAX. */ ++ TEST_COMPARE (wordexp ("\"unterminated", &we, WRDE_APPEND), WRDE_SYNTAX); ++ ++ TEST_COMPARE (we.we_wordc, saved_count); ++ TEST_VERIFY (we.we_wordv == saved_wordv); ++ CHECK_WORDS (&we, "original"); ++ ++ wordfree (&we); ++} ++ ++/* Test 8: Error without WRDE_APPEND still works (regression test for the ++ non-APPEND code path in do_error). */ ++static void ++test_no_append_error (void) ++{ ++ printf ("info: test_no_append_error\n"); ++ wordexp_t we = { 0 }; ++ ++ /* Simple failure without WRDE_APPEND. */ ++ TEST_COMPARE (wordexp ("bad |", &we, 0), WRDE_BADCHAR); ++ ++ /* After failure without WRDE_APPEND the struct should be safe to ++ reuse — start fresh. */ ++ TEST_COMPARE (wordexp ("ok", &we, 0), 0); ++ CHECK_WORDS (&we, "ok"); ++ ++ wordfree (&we); ++} ++ ++/* Test 9: WRDE_BADCHAR on the very first character (no partial words added ++ before the error). */ ++static void ++test_append_badchar_immediate (void) ++{ ++ printf ("info: test_append_badchar_immediate\n"); ++ wordexp_t we = { 0 }; ++ ++ TEST_COMPARE (wordexp ("hello world", &we, 0), 0); ++ CHECK_WORDS (&we, "hello", "world"); ++ ++ char **saved_wordv = we.we_wordv; ++ size_t saved_count = we.we_wordc; ++ ++ /* The bad character is the very first byte — no w_addword call happens ++ before the error. */ ++ TEST_COMPARE (wordexp ("|", &we, WRDE_APPEND), WRDE_BADCHAR); ++ TEST_COMPARE (we.we_wordc, saved_count); ++ TEST_VERIFY (we.we_wordv == saved_wordv); ++ ++ wordfree (&we); ++} ++ ++/* Test 10: WRDE_APPEND into an empty wordexp_t (initial call uses WRDE_APPEND ++ with a zeroed struct — unusual but allowed). */ ++static void ++test_append_into_empty (void) ++{ ++ printf ("info: test_append_into_empty\n"); ++ wordexp_t we = { 0 }; ++ ++ /* First call with WRDE_APPEND on a zeroed struct. The implementation ++ must handle we_wordv == NULL gracefully. */ ++ TEST_COMPARE (wordexp ("solo", &we, WRDE_APPEND), 0); ++ TEST_COMPARE (we.we_wordc, 1); ++ CHECK_WORDS (&we, "solo"); ++ ++ wordfree (&we); ++} ++ ++/* Verify that the leading we_offs slots are all NULL. */ ++static void ++check_offs_null (const wordexp_t *we) ++{ ++ for (size_t i = 0; i < we->we_offs; i++) ++ TEST_VERIFY (we->we_wordv[i] == NULL); ++} ++ ++/* Test 11: successful WRDE_APPEND with WRDE_DOOFFS and a non-zero we_offs. ++ The leading offset slots must stay NULL and words must land at ++ we_wordv[we_offs + i] across both the initial and the appended call. */ ++static void ++test_dooffs_append_success (void) ++{ ++ printf ("info: test_dooffs_append_success\n"); ++ wordexp_t we = { 0 }; ++ we.we_offs = 2; ++ ++ TEST_COMPARE (wordexp ("one two", &we, WRDE_DOOFFS), 0); ++ TEST_COMPARE (we.we_offs, 2); ++ check_offs_null (&we); ++ CHECK_WORDS (&we, "one", "two"); ++ ++ TEST_COMPARE (wordexp ("three", &we, WRDE_APPEND | WRDE_DOOFFS), 0); ++ TEST_COMPARE (we.we_offs, 2); ++ check_offs_null (&we); ++ CHECK_WORDS (&we, "one", "two", "three"); ++ /* The NULL terminator must sit right after the last word. */ ++ TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL); ++ ++ wordfree (&we); ++} ++ ++/* Test 12: failed WRDE_APPEND with WRDE_DOOFFS preserves we_wordc, the ++ we_wordv pointer, the words and the leading NULL offset slots. This ++ exercises the we_offs arithmetic in the array duplication and in the ++ error-path cleanup (we_wordv[we_offs + --we_wordc]). */ ++static void ++test_dooffs_append_error_preserves_state (void) ++{ ++ printf ("info: test_dooffs_append_error_preserves_state\n"); ++ wordexp_t we = { 0 }; ++ we.we_offs = 3; ++ ++ TEST_COMPARE (wordexp ("alpha beta", &we, WRDE_DOOFFS), 0); ++ check_offs_null (&we); ++ CHECK_WORDS (&we, "alpha", "beta"); ++ ++ char **saved_wordv = we.we_wordv; ++ size_t saved_count = we.we_wordc; ++ unsigned int saved_reallocs = relocating_reallocs; ++ ++ /* "gamma" is a partial word added via w_addword (forcing a relocating ++ realloc of we_wordv) before ')' triggers WRDE_BADCHAR. */ ++ TEST_COMPARE (wordexp ("gamma )", &we, WRDE_APPEND | WRDE_DOOFFS), ++ WRDE_BADCHAR); ++ TEST_VERIFY (relocating_reallocs > saved_reallocs); ++ ++ TEST_COMPARE (we.we_offs, 3); ++ TEST_COMPARE (we.we_wordc, saved_count); ++ TEST_VERIFY (we.we_wordv == saved_wordv); ++ check_offs_null (&we); ++ CHECK_WORDS (&we, "alpha", "beta"); ++ TEST_VERIFY (we.we_wordv[we.we_offs + we.we_wordc] == NULL); ++ ++ wordfree (&we); ++} ++ ++static int ++do_test (void) ++{ ++ test_append_badchar_preserves_count (); ++ test_append_badchar_preserves_pointer (); ++ test_append_badchar_words_intact (); ++ test_append_success (); ++ test_append_success_after_failure (); ++ test_append_multiple_failures (); ++ test_append_syntax_error (); ++ test_no_append_error (); ++ test_append_badchar_immediate (); ++ test_append_into_empty (); ++ test_dooffs_append_success (); ++ test_dooffs_append_error_preserves_state (); ++ ++ return 0; ++} ++ ++#include +diff --git a/posix/wordexp.c b/posix/wordexp.c +index 731d1650e9..50b0d7a256 100644 +--- a/posix/wordexp.c ++++ b/posix/wordexp.c +@@ -35,6 +35,7 @@ + #include + #include <_itoa.h> + #include ++#include + + /* + * This is a recursive-descent-style word expansion routine. +@@ -2224,6 +2225,12 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) + char ifs_white[4]; + wordexp_t old_word = *pwordexp; + ++ /* When WRDE_APPEND is set we work on a copy of the we_wordv array so that ++ the caller's original pointer is never invalidated by realloc inside ++ w_addword. The saved_wordv keeps the original; on success we free it, ++ on non-NOSPACE error we free the working copy and restore the original. */ ++ char **saved_wordv = NULL; ++ + if (flags & WRDE_REUSE) + { + /* Minimal implementation of WRDE_REUSE for now */ +@@ -2258,6 +2265,23 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) + pwordexp->we_offs = 0; + } + } ++ else if (pwordexp->we_wordv != NULL) ++ { ++ /* WRDE_APPEND with an existing word list: duplicate the array so that ++ realloc during parsing does not invalidate the caller's pointer. The ++ strings themselves are shared. */ ++ size_t num_p; ++ char **dup; ++ if (INT_ADD_WRAPV (pwordexp->we_offs, pwordexp->we_wordc, &num_p) ++ || INT_ADD_WRAPV (num_p, 1, &num_p)) ++ return WRDE_NOSPACE; ++ dup = __libc_reallocarray (NULL, num_p, sizeof *dup); ++ if (dup == NULL) ++ return WRDE_NOSPACE; ++ memcpy (dup, pwordexp->we_wordv, num_p * sizeof *dup); ++ saved_wordv = pwordexp->we_wordv; ++ pwordexp->we_wordv = dup; ++ } + + /* Find out what the field separators are. + * There are two types: whitespace and non-whitespace. +@@ -2338,7 +2362,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) + error = w_addword (pwordexp, NULL); + + if (error) +- return error; ++ goto do_error; + } + + break; +@@ -2356,7 +2380,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) + error = w_addword (pwordexp, NULL); + + if (error) +- return error; ++ goto do_error; + } + + break; +@@ -2422,10 +2446,18 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags) + + /* There was a word separator at the end */ + if (word == NULL) /* i.e. w_newword */ +- return 0; ++ { ++ free (saved_wordv); ++ return 0; ++ } + +- /* There was no field separator at the end */ +- return w_addword (pwordexp, word); ++ /* There was no field separator at the end. The only possible error ++ from w_addword is WRDE_NOSPACE. */ ++ error = w_addword (pwordexp, word); ++ if (error != 0) ++ goto do_error; ++ free (saved_wordv); ++ return 0; + + do_error: + /* Error: +@@ -2436,11 +2468,30 @@ do_error: + free (word); + + if (error == WRDE_NOSPACE) +- return WRDE_NOSPACE; ++ { ++ /* we_wordc and we_wordv are updated to reflect any words that were ++ successfully expanded. The old array is obsolete. */ ++ free (saved_wordv); ++ return WRDE_NOSPACE; ++ } + +- if ((flags & WRDE_APPEND) == 0) +- wordfree (pwordexp); ++ if (flags & WRDE_APPEND) ++ { ++ /* POSIX 2024 states that for in other error cases, if the WRDE_APPEND ++ flag was specified, we_wordc and we_wordv shall not be modified. ++ ++ Free strings appended during this call, discard the working copy of ++ we_wordv, and restore the caller's original pointer. */ ++ while (pwordexp->we_wordc > old_word.we_wordc) ++ free (pwordexp->we_wordv[pwordexp->we_offs + --pwordexp->we_wordc]); ++ free (pwordexp->we_wordv); ++ pwordexp->we_wordv = saved_wordv; ++ } ++ else ++ { ++ wordfree (pwordexp); ++ *pwordexp = old_word; ++ } + +- *pwordexp = old_word; + return error; + } diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 26aa6fb275e..b7f6278c95a 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -66,6 +66,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0031-CVE-2026-5928.patch \ file://0032-CVE-2026-5450.patch \ file://0033-CVE-2026-6791.patch \ + file://0034-CVE-2026-6368.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:46:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101706 Received: from mta-64-228.siemens.flowmailer.net (mta-64-228.siemens.flowmailer.net [185.136.64.228]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2235.1792709281575017209 for ; Thu, 22 Oct 2026 15:48:01 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=f0ZjL5ho; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.228, mailfrom: fm-256628-20261022224759a49d78894f00020756-qehtzq@rts-flowmailer.siemens.com) Received: by mta-64-228.siemens.flowmailer.net with ESMTPSA id 20261022224759a49d78894f00020756 for ; Fri, 23 Oct 2026 00:47:59 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=TEvpwfCOpJgS4ByKDb2wHA6M5TAcELEk1HZfLpnXSlk=; b=f0ZjL5hoYCTpbB+Y+lghc2JlCqBi6mZhL2nFRsAO4iQoJvbhp9qocntTWL5ckgyrv0Vy2h aNuqXu6ujnoZM//ClJqDt75AekOnl4kAZpShG5rTJHAQ4CxeINvWPfx24CgTPW1Ogb0f6CWu ELGDclNfODHI1YyOIoKWkLJ1GYv8nWr/3b4GFJFN+jsCCM4OSSaveInCx85LT5TT6Dh4gmG7 6r8ZE7aHBXtpB+snenjwV0Zv59Fpy+Y2BNL9VCq9ohU5NBdVJ4xGAFRsnNy0CW8lzKXkqJJT MoIEm1zibF41rQwVWzKCXAMuspw1lMRJu5nEiktBYXqCwyPBqgyJfmgA==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 05/15] glibc: patch CVE-2026-19542 Date: Fri, 23 Oct 2026 00:46:58 +0200 Message-ID: <20261022224711.3783258-5-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:02 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248461 From: Peter Marko Pick patch [1] which is [2] backported to 3.41 (oldest release still receiving security updates) which is mentioned in [3]. [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=9318c2571576017d280a31b7b9ab576c9b696b1a [2] https://sourceware.org/git/?p=glibc.git;a=commit;h=e2789c46e3bfdcd67a82bea9946b315c179e83d3 [3] https://security-tracker.debian.org/tracker/CVE-2026-19542 Signed-off-by: Peter Marko --- .../glibc/glibc/0035-CVE-2026-19542.patch | 99 +++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 100 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0035-CVE-2026-19542.patch diff --git a/meta/recipes-core/glibc/glibc/0035-CVE-2026-19542.patch b/meta/recipes-core/glibc/glibc/0035-CVE-2026-19542.patch new file mode 100644 index 00000000000..5c82606792c --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0035-CVE-2026-19542.patch @@ -0,0 +1,99 @@ +From 9318c2571576017d280a31b7b9ab576c9b696b1a Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 14 Aug 2026 13:41:16 +0200 +Subject: [PATCH] misc: Fix out-of-bounds array write in tdelete (bug 34506) + +Allocate the maximum array sizes directly, instead of resizing +the arrays as needed. This eliminates alloca usage from the +function, and fixes the out-of-bounds accesses. The asserts +guard against the bug coming back if the balancing of the tree +turns out not to work correctly. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit e2789c46e3bfdcd67a82bea9946b315c179e83d3) + +CVE: CVE-2026-19542 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=9318c2571576017d280a31b7b9ab576c9b696b1a] +Signed-off-by: Peter Marko +--- + misc/tsearch.c | 31 +++++++++++-------------------- + 1 file changed, 11 insertions(+), 20 deletions(-) + +diff --git a/misc/tsearch.c b/misc/tsearch.c +index d15260baed..350fe15bf0 100644 +--- a/misc/tsearch.c ++++ b/misc/tsearch.c +@@ -85,6 +85,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -406,12 +407,13 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar) + int cmp; + node *rootp = (node *) vrootp; + node root, unchained; +- /* Stack of nodes so we remember the parents without recursion. It's +- _very_ unlikely that there are paths longer than 40 nodes. The tree +- would need to have around 250.000 nodes. */ +- int stacksize = 40; ++ /* Stack of nodes so we remember the parents without recursion. The ++ stack size is a conservative approximation of the maximum height ++ of a red-black tree, based on size of the address space. ++ Actual numbers are closer to 57 (32 bit) and 117 (63 bit). */ ++ enum { stacksize = 2 * UINTPTR_WIDTH }; + int sp = 0; +- node **nodestack = alloca (sizeof (node *) * stacksize); ++ node *nodestack[stacksize]; + + if (rootp == NULL) + return NULL; +@@ -424,14 +426,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar) + root = DEREFNODEPTR(rootp); + while ((cmp = (*compar) (key, root->key)) != 0) + { +- if (sp == stacksize) +- { +- node **newstack; +- stacksize += 20; +- newstack = alloca (sizeof (node *) * stacksize); +- nodestack = memcpy (newstack, nodestack, sp * sizeof (node *)); +- } +- ++ assert (sp < stacksize); + nodestack[sp++] = rootp; + p = DEREFNODEPTR(rootp); + if (cmp < 0) +@@ -470,13 +465,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar) + node upn; + for (;;) + { +- if (sp == stacksize) +- { +- node **newstack; +- stacksize += 20; +- newstack = alloca (sizeof (node *) * stacksize); +- nodestack = memcpy (newstack, nodestack, sp * sizeof (node *)); +- } ++ assert (sp < stacksize); + nodestack[sp++] = parentp; + parentp = up; + upn = DEREFNODEPTR(up); +@@ -541,6 +530,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar) + SETNODEPTR(pp,q); + /* Make sure pp is right if the case below tries to use + it. */ ++ assert (sp < stacksize); + nodestack[sp++] = pp = LEFTPTR(q); + q = RIGHT(p); + } +@@ -625,6 +615,7 @@ __tdelete (const void *key, void **vrootp, __compar_fn_t compar) + SETLEFT(p,RIGHT(q)); + SETRIGHT(q,p); + SETNODEPTR(pp,q); ++ assert (sp < stacksize); + nodestack[sp++] = pp = RIGHTPTR(q); + q = LEFT(p); + } diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index b7f6278c95a..eb198427d1a 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -67,6 +67,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0032-CVE-2026-5450.patch \ file://0033-CVE-2026-6791.patch \ file://0034-CVE-2026-6368.patch \ + file://0035-CVE-2026-19542.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:46:59 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101707 Received: from mta-65-225.siemens.flowmailer.net (mta-65-225.siemens.flowmailer.net [185.136.65.225]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2237.1792709288180369279 for ; Thu, 22 Oct 2026 15:48:08 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=IrJQE6FT; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.65.225, mailfrom: fm-256628-20261022224806eae5fbfa0200020792-p7nivw@rts-flowmailer.siemens.com) Received: by mta-65-225.siemens.flowmailer.net with ESMTPSA id 20261022224806eae5fbfa0200020792 for ; Fri, 23 Oct 2026 00:48:06 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=qxT6aBe/d5t3SVcEcAPZiesV/u62jlj74zqTF5rCXm8=; b=IrJQE6FTevb/K+wNb1Li1kIfQS0s7TC5VIP9adK5CQ1SQ566ryVCgWyo3u1TsD+flH//yZ P0yQfaMFFRN/FpIt1BhFwlIYIZ5/d1xQhBevmNBMw0yWTQTZaDZo66pFhcq02tKS7xOFFP3q kEC252XJFQQDoabdjC0xfmm/JcqnSiKodVcOTDl7gt/l2cxXvPUTNwSub5n0iwNRbJU2ilZj lP6rvaexlxwhxoDPujiCsdzfIEWZVJ0cBheDhvqY1Q/z0E2fcZJ4uKukOJvAzDNZTkUTKHxQ x22qZMB+44srVsRZSInR70ia/MhZ5GtSBaN8VA7+5WOgWelyZb1Yevcw==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 06/15] glibc: patch CVE-2026-19499 Date: Fri, 23 Oct 2026 00:46:59 +0200 Message-ID: <20261022224711.3783258-6-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:12 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248462 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0036-CVE-2026-19499.patch | 100 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 101 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0036-CVE-2026-19499.patch diff --git a/meta/recipes-core/glibc/glibc/0036-CVE-2026-19499.patch b/meta/recipes-core/glibc/glibc/0036-CVE-2026-19499.patch new file mode 100644 index 00000000000..792c5276d0b --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0036-CVE-2026-19499.patch @@ -0,0 +1,100 @@ +From 5256941bc811248670eda4636dccd0a390d34dec Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 27 Aug 2026 13:34:54 +0200 +Subject: [PATCH] stdlib: Fix right-justification in strfmon (bug 34510, + CVE-2026-19499) + +The memmove call did not take into account that __printf_buffer_pad +updated the buffer pointers. + +Fixes commit e88b9f0e5cc50cab57a299dc7efe1a4eb385161d +("stdio-common: Convert vfprintf and related functions to buffers"), +which went into glibc 2.37. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit b090cf226ff65b913e41536f1f573f500855615c) + +CVE: CVE-2026-19499 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=5256941bc811248670eda4636dccd0a390d34dec] +Signed-off-by: Peter Marko +--- + stdlib/Makefile | 1 + + stdlib/strfmon_l.c | 5 +++-- + stdlib/tst-strfmon-bug34510.c | 33 +++++++++++++++++++++++++++++++++ + 3 files changed, 37 insertions(+), 2 deletions(-) + create mode 100644 stdlib/tst-strfmon-bug34510.c + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index c9c8f702a2..b655f0e5eb 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -324,6 +324,7 @@ tests := \ + tst-stdc_leading_zeros \ + tst-stdc_trailing_ones \ + tst-stdc_trailing_zeros \ ++ tst-strfmon-bug34510 \ + tst-strfmon_l \ + tst-strfrom \ + tst-strfrom-locale \ +diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c +index 5e22aac750..bd849ff470 100644 +--- a/stdlib/strfmon_l.c ++++ b/stdlib/strfmon_l.c +@@ -549,7 +549,8 @@ __vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc, + /* Now test whether the output width is filled. */ + if (buf->write_ptr - startp < width) + { +- size_t pad_width = width - (buf->write_ptr - startp); ++ size_t written_width = buf->write_ptr - startp; ++ size_t pad_width = width - written_width; + __printf_buffer_pad (buf, ' ', pad_width); + if (__printf_buffer_has_failed (buf)) + /* Implies length check. */ +@@ -558,7 +559,7 @@ __vstrfmon_l_buffer (struct __printf_buffer *buf, locale_t loc, + Otherwise move the field contents in place. */ + if (!left) + { +- memmove (startp + pad_width, startp, buf->write_ptr - startp); ++ memmove (startp + pad_width, startp, written_width); + memset (startp, ' ', pad_width); + } + } +diff --git a/stdlib/tst-strfmon-bug34510.c b/stdlib/tst-strfmon-bug34510.c +new file mode 100644 +index 0000000000..b187bde1f4 +--- /dev/null ++++ b/stdlib/tst-strfmon-bug34510.c +@@ -0,0 +1,33 @@ ++/* Test handling of right-padding in strfmon (bug 34510, CVE-2026-19499). ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ struct support_next_to_fault ntf = support_next_to_fault_allocate (100); ++ TEST_COMPARE (strfmon (ntf.buffer, ntf.length, "%100n", 1.23), -1); ++ TEST_COMPARE (errno, E2BIG); ++ return 0; ++} ++ ++#include diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index eb198427d1a..567d53dd6f6 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -68,6 +68,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0033-CVE-2026-6791.patch \ file://0034-CVE-2026-6368.patch \ file://0035-CVE-2026-19542.patch \ + file://0036-CVE-2026-19499.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:00 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101708 Received: from mta-64-226.siemens.flowmailer.net (mta-64-226.siemens.flowmailer.net [185.136.64.226]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2238.1792709296598462393 for ; Thu, 22 Oct 2026 15:48:16 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=WVcCOqKA; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.226, mailfrom: fm-256628-20261022224814dadb34943f000207c3-cmpsvt@rts-flowmailer.siemens.com) Received: by mta-64-226.siemens.flowmailer.net with ESMTPSA id 20261022224814dadb34943f000207c3 for ; Fri, 23 Oct 2026 00:48:14 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=RHa2CUfFnUCvJ0HjlIOhcfalS1r5ZHGd7zHn4w8T0bA=; b=WVcCOqKAgeHH6HMdu2sTUh8vCD6mTbW975O6EyVgbS8lH/QPG1iV1J+hxQ7aCaw/0eDasE wIBbBw81hH/01rLc8dIJoDwSTDDub7/LZ3G6FJGH41ms620qOjgUCdgVP/20W1j2oVtoW0IR wAwKE4g/h0TwK/CJ7/tNIkgcEBS7UTyuWJxqb/v7TJ3ni4tR55p8dM/Mu0CvVKuU7z023c7o uFzqfAFRIp/r3+sy9DRWOPqPGvyzgnyG/IWRJk4v+OSX65ANQpN8uvab55CB6zKSZGp6bXKl 6zAX2ma6EezWloeCuLPvoVZ142hG8OiohYebbb3Fyh7vzmtJYlDXSOSA==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 07/15] glibc: patch CVE-2026-77117 Date: Fri, 23 Oct 2026 00:47:00 +0200 Message-ID: <20261022224711.3783258-7-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:22 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248463 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0037-CVE-2026-77117.patch | 32 +++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 33 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0037-CVE-2026-77117.patch diff --git a/meta/recipes-core/glibc/glibc/0037-CVE-2026-77117.patch b/meta/recipes-core/glibc/glibc/0037-CVE-2026-77117.patch new file mode 100644 index 00000000000..fa42a548c34 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0037-CVE-2026-77117.patch @@ -0,0 +1,32 @@ +From e43e46f94398b3de446fec11da1e7633ea5202ec Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 28 Aug 2026 10:26:07 +0200 +Subject: [PATCH] iconvdata: SHIFT_JISX0213 decoding lacks pending character + reset (CVE-2026-77117) + +This fixes bug 34556. + +Reviewed-by: Carlos O'Donell +(cherry picked from commit 68d94bbe50b7577d48998107d632ef3a0df050e3) + +CVE: CVE-2026-77117 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=e43e46f94398b3de446fec11da1e7633ea5202ec] +Signed-off-by: Peter Marko +--- + iconvdata/shift_jisx0213.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/iconvdata/shift_jisx0213.c b/iconvdata/shift_jisx0213.c +index 364298dcff..834fa81322 100644 +--- a/iconvdata/shift_jisx0213.c ++++ b/iconvdata/shift_jisx0213.c +@@ -226,6 +226,9 @@ + STANDARD_FROM_LOOP_ERR_HANDLER (1); \ + } \ + } \ ++ else \ ++ /* There was a pending character. Clear it. */ \ ++ *statep = 0; \ + \ + put32 (outptr, ch); \ + outptr += 4; \ diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 567d53dd6f6..3090b9cd277 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -69,6 +69,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0034-CVE-2026-6368.patch \ file://0035-CVE-2026-19542.patch \ file://0036-CVE-2026-19499.patch \ + file://0037-CVE-2026-77117.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101709 Received: from mta-65-226.siemens.flowmailer.net (mta-65-226.siemens.flowmailer.net [185.136.65.226]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2349.1792709303605860554 for ; Thu, 22 Oct 2026 15:48:23 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=ZPs46wrk; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.65.226, mailfrom: fm-256628-202610222248212c979b346100020743-by_7zv@rts-flowmailer.siemens.com) Received: by mta-65-226.siemens.flowmailer.net with ESMTPSA id 202610222248212c979b346100020743 for ; Fri, 23 Oct 2026 00:48:21 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=aB0XogAD+erY0sdkc82its+1MPVyrResMwY1eCsTurg=; b=ZPs46wrkDk/hB7YGDSlT36wa+FZndY04HFu9EZsKHgTtaj7l0dt2ZeVZ947yUSVe+52M+G CkgxorW5ZDsPELNcYJT3tN9gsjL2zk7IBwWb+kxTcYDwBvUaPnDIqF8w+5BiLcbFx0men7k1 MwHg/wzxcGlHbgCB+agrtpEVnj+4pBSh/WeH3voAKOc2DrgJ/xLvjgB3BAIkzgBOgkk9uB9w jvl+IY863HAqZWMbaVRueFFwvCdfnr2oQnE1yOQlQnVICua29qHNA91ScQSi6oqdkEVHUd+a NMnGs+Dc8H2JGeqaV0PNgj3pghhb3vJxhSJz/lBPhwu09QJuGpcU5ZaA==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 08/15] glibc: patch CVE-2026-80489 Date: Fri, 23 Oct 2026 00:47:01 +0200 Message-ID: <20261022224711.3783258-8-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:32 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248464 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0038-CVE-2026-80489.patch | 32 +++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 33 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0038-CVE-2026-80489.patch diff --git a/meta/recipes-core/glibc/glibc/0038-CVE-2026-80489.patch b/meta/recipes-core/glibc/glibc/0038-CVE-2026-80489.patch new file mode 100644 index 00000000000..3ca1c959bb2 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0038-CVE-2026-80489.patch @@ -0,0 +1,32 @@ +From ec116a0fbedcc860631e525e70b409cf295f27da Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 28 Aug 2026 10:26:07 +0200 +Subject: [PATCH] iconvdata: EUC_JISX0213 decoding lacks pending character + reset (CVE-2026-80489) + +This fixes bug 34568. + +Reviewed-by: Carlos O'Donell +(cherry picked from commit 4dafa087ff5fe7df45bd37dc727e988da6b8c935) + +CVE: CVE-2026-80489 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=ec116a0fbedcc860631e525e70b409cf295f27da] +Signed-off-by: Peter Marko +--- + iconvdata/euc-jisx0213.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/iconvdata/euc-jisx0213.c b/iconvdata/euc-jisx0213.c +index 9c3f28da2d..f0305c113a 100644 +--- a/iconvdata/euc-jisx0213.c ++++ b/iconvdata/euc-jisx0213.c +@@ -224,6 +224,9 @@ + STANDARD_FROM_LOOP_ERR_HANDLER (1); \ + } \ + } \ ++ else \ ++ /* There was a pending character. Clear it. */ \ ++ *statep = 0; \ + \ + put32 (outptr, ch); \ + outptr += 4; \ diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 3090b9cd277..bd0b4f06190 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -70,6 +70,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0035-CVE-2026-19542.patch \ file://0036-CVE-2026-19499.patch \ file://0037-CVE-2026-77117.patch \ + file://0038-CVE-2026-80489.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101710 Received: from mta-64-227.siemens.flowmailer.net (mta-64-227.siemens.flowmailer.net [185.136.64.227]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2244.1792709308167137794 for ; Thu, 22 Oct 2026 15:48:28 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=SEoiFRnz; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.227, mailfrom: fm-256628-2026102222482636347efa4500020712-zhun8x@rts-flowmailer.siemens.com) Received: by mta-64-227.siemens.flowmailer.net with ESMTPSA id 2026102222482636347efa4500020712 for ; Fri, 23 Oct 2026 00:48:26 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=qG3YgKQDNqUuLSSCNHrVVqn4HOPYEguwsHSMIk3sFwU=; b=SEoiFRnzNa+qGzNown1omUmI6aoSq+UChs6gDi5WxAPMF3XVw7j3BMQoBf6nrJrGgmzYNw 1I2rgxXdCpTg10BIBQQ2vAZWy94mf2spIUapDGop6JgkOgicMnvbKv8baG7IK5YuEJCirqjA HO6jYxny1RU+HWXEeKO2lKBFUB3wKtHWi7HK0bVOAJJea7+Ns/m+NPHgg6PapvXNtxsCV+Kl aPOdAyLkbFJdHGeTGbQBMrCoKMNAUf/OOth0kIVPEReIMsby5TL0YXqaKfwzBFAU1YLWFcsA vWBarco/amAu4KS829f5qqhntIRhROpMZMDgiz56cRNNa4I9ASnQFybQ==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 09/15] glibc: add tests for CVE-2026-77117 and CVE-2026-80489. Date: Fri, 23 Oct 2026 00:47:02 +0200 Message-ID: <20261022224711.3783258-9-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:32 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248465 From: Peter Marko Pick commit referencing bug IDs from patches for these CVEs from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../0039-CVE-2026-77117-CVE-2026-80489.patch | 172 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 173 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0039-CVE-2026-77117-CVE-2026-80489.patch diff --git a/meta/recipes-core/glibc/glibc/0039-CVE-2026-77117-CVE-2026-80489.patch b/meta/recipes-core/glibc/glibc/0039-CVE-2026-77117-CVE-2026-80489.patch new file mode 100644 index 00000000000..7e9141bd9f7 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0039-CVE-2026-77117-CVE-2026-80489.patch @@ -0,0 +1,172 @@ +From 3d141c23899d90559741b5fe74db97ccf0ef5c29 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 28 Aug 2026 10:26:07 +0200 +Subject: [PATCH] iconvdata: Test case for bug 34556, bug 34568 + +Assisted-by: LLM +Reviewed-by: Carlos O'Donell +(cherry picked from commit 35efcffa97553df071bc37ab31fd7dc2c634e7da) + +CVE: CVE-2026-77117 +CVE: CVE-2026-80489 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=3d141c23899d90559741b5fe74db97ccf0ef5c29] +Signed-off-by: Peter Marko +--- + iconvdata/Makefile | 5 +- + iconvdata/tst-jisx0213-progress.c | 124 ++++++++++++++++++++++++++++++ + 2 files changed, 128 insertions(+), 1 deletion(-) + create mode 100644 iconvdata/tst-jisx0213-progress.c + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index cc689f63e9..36f48749d2 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -76,7 +76,8 @@ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ + bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ + bug-iconv13 bug-iconv14 bug-iconv15 \ +- tst-iconv-iso-2022-cn-ext tst-bug33980 ++ tst-iconv-iso-2022-cn-ext tst-bug33980 \ ++ tst-jisx0213-progress + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +@@ -335,6 +336,8 @@ $(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)tst-bug33980.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) ++$(objpfx)tst-jisx0213-progress.out: \ ++ $(addprefix $(objpfx), $(gconv-modules)) $(addprefix $(objpfx),$(modules.so)) + + $(objpfx)iconv-test.out: run-iconv-test.sh \ + $(addprefix $(objpfx), $(gconv-modules)) \ +diff --git a/iconvdata/tst-jisx0213-progress.c b/iconvdata/tst-jisx0213-progress.c +new file mode 100644 +index 0000000000..7b2073be1f +--- /dev/null ++++ b/iconvdata/tst-jisx0213-progress.c +@@ -0,0 +1,124 @@ ++/* Test JISX0213 combining character conversion progress (bug 34556, bug 34568). ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Certain JISX0213 byte sequences map to a combining sequence, for ++ example U+304B (HIRAGANA LETTER KA) followed by U+309A (COMBINING ++ SEMI-VOICED SOUND MARK). When converting to internal encoding ++ (actually UTF-32) with a small output buffer, the first code point ++ is emitted and the second is queued in the converter state. This ++ test verifies that the queued code point is consumed exactly once ++ on retry, so that the conversion makes progress and terminates. */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static void ++test_one (const char *charset, const char *input, size_t outbufsize) ++{ ++ printf ("info: %s: testing output buffer size %zu\n", charset, outbufsize); ++ ++ /* Expected UTF-32 output. */ ++ static const wchar_t expected[] = { 0x304b, 0x309a, 'A' }; ++ ++ /* Use WCHAR_T encoding to avoid the BOM. */ ++ iconv_t cd = iconv_open ("WCHAR_T", charset); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ char result[64]; ++ size_t result_len = 0; ++ ++ char *inptr = (char *) input; ++ size_t inleft = strlen (input); ++ ++ char outbuf[64]; ++ ++ int iterations = 0; ++ while (inleft > 0) ++ { ++ char *outptr = outbuf; ++ size_t outleft = outbufsize; ++ size_t inleft_before = inleft; ++ ++ size_t ret = iconv (cd, &inptr, &inleft, &outptr, &outleft); ++ size_t produced = outptr - outbuf; ++ ++ TEST_VERIFY_EXIT (result_len + produced <= sizeof (result)); ++ memcpy (result + result_len, outbuf, produced); ++ result_len += produced; ++ ++ if (ret == (size_t) -1 && errno == E2BIG) ++ { ++ if (produced == 0 && inleft == inleft_before) ++ { ++ /* Output buffer too small for a single code point. */ ++ TEST_VERIFY_EXIT (outbufsize < 4); ++ break; ++ } ++ /* Bound iterations to detect non-progress bugs. */ ++ if (++iterations < 10) ++ continue; ++ else ++ { ++ FAIL ("%s: no progress", charset); ++ goto out; ++ } ++ } ++ if (ret == (size_t) -1) ++ FAIL_EXIT1 ("outbufsize %zu: iconv: %m", outbufsize); ++ break; ++ } ++ ++ /* Flush pending converter state. */ ++ { ++ char *outptr = outbuf; ++ size_t outleft = outbufsize; ++ size_t ret = iconv (cd, NULL, NULL, &outptr, &outleft); ++ TEST_VERIFY (ret == 0); ++ size_t produced = outptr - outbuf; ++ memcpy (result + result_len, outbuf, produced); ++ result_len += produced; ++ } ++ ++ if (outbufsize >= 4) ++ { ++ TEST_COMPARE (inleft, 0); ++ TEST_COMPARE_BLOB (result, result_len, ++ expected, sizeof (expected)); ++ } ++ ++ out: ++ TEST_VERIFY_EXIT (iconv_close (cd) == 0); ++} ++ ++static int ++do_test (void) ++{ ++ for (size_t outbufsize = 1; outbufsize <= 16; outbufsize++) ++ { ++ test_one ("EUC-JISX0213", "\244\367A", outbufsize); ++ test_one ("SHIFT_JISX0213", "\202\365A", outbufsize); ++ } ++ return 0; ++} ++ ++#include diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index bd0b4f06190..144ce36ccc2 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -71,6 +71,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0036-CVE-2026-19499.patch \ file://0037-CVE-2026-77117.patch \ file://0038-CVE-2026-80489.patch \ + file://0039-CVE-2026-77117-CVE-2026-80489.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:51:20 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101716 Received: from mta-65-225.siemens.flowmailer.net (mta-65-225.siemens.flowmailer.net [185.136.65.225]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2291.1792709495400860782 for ; Thu, 22 Oct 2026 15:51:36 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=XcfJg8/i; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.65.225, mailfrom: fm-256628-20261022225133e69f1a28ff00020783-4_xs9o@rts-flowmailer.siemens.com) Received: by mta-65-225.siemens.flowmailer.net with ESMTPSA id 20261022225133e69f1a28ff00020783 for ; Fri, 23 Oct 2026 00:51:33 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc; bh=coLMsMS9yRXoeetTEErHT4rpRKtFJw+OqA5EjCrfy3w=; b=XcfJg8/iD2VRa9vhbQHhaGa6xs1Uh0po+/faEc2i9nEwjmZON7nfOxuKF8FFbUDbpE8LjM Gtg/qSrbDVe5w5ADPSgNp+YglVH3vbveLPeuBdVQ/ZoygcupVvEehIlPlR2qhy5wmWqZGIDl FBcVdJbukbuCwBQkBi106NjiyljtMNQ8MtleJmen4pUXo/tuz4Bifo6SWdAYk0k9bI5AGuHG AgaS1Z/toS1c8g7p9vElJ6JxZmWw/K8wFcQwa7HTbUa/fKtiQXYmEcIj7v9E7Ayq6yW8v1o1 ZbWIWJ56jcWW1TQDchyA67HCeIv4RTdQt2OJFmgY4dLgXtmVPQSgs+iA==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 10/15] glibc: patch CVE-2026-18374 Date: Fri, 23 Oct 2026 00:51:20 +0200 Message-ID: <20261022225120.3784827-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:51:42 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248471 From: Peter Marko Pick patches referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0040-CVE-2026-18374-01.patch | 53 +++++++++ .../glibc/glibc/0041-CVE-2026-18374-02.patch | 103 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 2 + 3 files changed, 158 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0040-CVE-2026-18374-01.patch create mode 100644 meta/recipes-core/glibc/glibc/0041-CVE-2026-18374-02.patch diff --git a/meta/recipes-core/glibc/glibc/0040-CVE-2026-18374-01.patch b/meta/recipes-core/glibc/glibc/0040-CVE-2026-18374-01.patch new file mode 100644 index 00000000000..a5a71473ab2 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0040-CVE-2026-18374-01.patch @@ -0,0 +1,53 @@ +From f806c45178dbca3be08a25cc5dd6d5542ce84a59 Mon Sep 17 00:00:00 2001 +From: Dongkyun Son +Date: Fri, 4 Sep 2026 21:28:41 +0900 +Subject: [PATCH] libio: Fix CVE-2026-18374 heap buffer overflow in ccs= + handling + +When fopen() is called with a ,ccs= parameter whose value becomes empty +after strip(), the code must reject it with EINVAL instead of attempting +to use it. The original upstr() fallback could read past the ',' delimiter +and cause a heap buffer overflow. + +The fix checks if the charset specification is empty after strip() and +returns EINVAL immediately, preventing the overflow and following the +approach described in BZ #34574. + +CVE-2026-18374 - CVSS 4.9 (AV:L/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L) + +Reported-by: AISLE in partnership with Red Hat +Signed-off-by: Dongkyun Son +Reviewed-by: Florian Weimer +(cherry picked from commit 9765a538ebf8661a6e5578e01e35a3dd30db7eb4) + +CVE: CVE-2026-18374 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=f806c45178dbca3be08a25cc5dd6d5542ce84a59] +Signed-off-by: Peter Marko +--- + libio/fileops.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/libio/fileops.c b/libio/fileops.c +index 775999deb3..18efe8e0c0 100644 +--- a/libio/fileops.c ++++ b/libio/fileops.c +@@ -305,12 +305,14 @@ _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode, + *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0'; + strip (ccs, ccs); + +- if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0' +- ? upstr (ccs, cs + 5) : ccs) != 0) ++ /* After stripping, ccs[2] == '\0' means the charset name is empty. ++ This is not a valid charset and would cause problems downstream. ++ Reject it with EINVAL (BZ #34574, CVE-2026-18374). */ ++ if (ccs[2] == '\0' || __wcsmbs_named_conv (&fcts, ccs) != 0) + { +- /* Something went wrong, we cannot load the conversion modules. +- This means we cannot proceed since the user explicitly asked +- for these. */ ++ /* Either the charset name is empty after strip(), or conversion ++ modules cannot be loaded. This means we cannot proceed since ++ the user explicitly asked for character conversion. */ + (void) _IO_file_close_it (fp); + free (ccs); + __set_errno (EINVAL); diff --git a/meta/recipes-core/glibc/glibc/0041-CVE-2026-18374-02.patch b/meta/recipes-core/glibc/glibc/0041-CVE-2026-18374-02.patch new file mode 100644 index 00000000000..d653d545f51 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0041-CVE-2026-18374-02.patch @@ -0,0 +1,103 @@ +From 5dd252cf1d113644b3679f5a158e9ef20217865e Mon Sep 17 00:00:00 2001 +From: Shamil Abdulaev +Date: Thu, 3 Sep 2026 20:19:42 +0300 +Subject: [PATCH] libio: Add test for fopen with an empty ", ccs=" value [BZ + #34574] + +This goes on top of the fix for CVE-2026-18374. The test runs the +reproducer from the bug report, plus "w,ccs=" and "w,ccs=,", and +expects NULL with errno set to EINVAL. + +Signed-off-by: Shamil Abdulaev +Reviewed-by: Florian Weimer +(cherry picked from commit cca93e5d88d3d4ed073c03100467696f652269e7) + +CVE: CVE-2026-18374 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=5dd252cf1d113644b3679f5a158e9ef20217865e] +Signed-off-by: Peter Marko +--- + libio/Makefile | 1 + + libio/tst-fopen-ccs-empty.c | 62 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 63 insertions(+) + create mode 100644 libio/tst-fopen-ccs-empty.c + +diff --git a/libio/Makefile b/libio/Makefile +index 43ee8db06d..5b9929c3de 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -99,6 +99,7 @@ tests = \ + tst-fgetc-after-eof \ + tst-fgetwc \ + tst-fgetws \ ++ tst-fopen-ccs-empty \ + tst-fopenloc2 \ + tst-fputws \ + tst-freopen \ +diff --git a/libio/tst-fopen-ccs-empty.c b/libio/tst-fopen-ccs-empty.c +new file mode 100644 +index 0000000000..64723965e1 +--- /dev/null ++++ b/libio/tst-fopen-ccs-empty.c +@@ -0,0 +1,62 @@ ++/* Test fopen with an empty ",ccs=" value in the mode string (bug 34574). ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++check_fopen_fails (const char *path, const char *mode) ++{ ++ errno = 0; ++ FILE *fp = fopen (path, mode); ++ TEST_VERIFY (fp == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ if (fp != NULL) ++ fclose (fp); ++} ++ ++static int ++do_test (void) ++{ ++ char *path; ++ xclose (create_temp_file ("tst-fopen-ccs-empty", &path)); ++ ++ /* The value is blank and the mode string continues well past it. */ ++ enum { size = 1024 * 1024 }; ++ char *mode = xmalloc (size); ++ memset (mode, 'X', size); ++ mode[size - 1] = '\0'; ++ static const char prefix[] = "w,ccs= ,"; ++ memcpy (mode, prefix, sizeof (prefix) - 1); ++ check_fopen_fails (path, mode); ++ free (mode); ++ ++ check_fopen_fails (path, "w,ccs="); ++ check_fopen_fails (path, "w,ccs=,"); ++ ++ free (path); ++ return 0; ++} ++ ++#include diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 144ce36ccc2..3e95792b359 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -72,6 +72,8 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0037-CVE-2026-77117.patch \ file://0038-CVE-2026-80489.patch \ file://0039-CVE-2026-77117-CVE-2026-80489.patch \ + file://0040-CVE-2026-18374-01.patch \ + file://0041-CVE-2026-18374-02.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101711 Received: from mta-64-228.siemens.flowmailer.net (mta-64-228.siemens.flowmailer.net [185.136.64.228]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2246.1792709321364008109 for ; Thu, 22 Oct 2026 15:48:41 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=NpyQY9w5; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.228, mailfrom: fm-256628-20261022224839e68114feb80002078d-wrodky@rts-flowmailer.siemens.com) Received: by mta-64-228.siemens.flowmailer.net with ESMTPSA id 20261022224839e68114feb80002078d for ; Fri, 23 Oct 2026 00:48:39 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=Zj94oDb/Xbp77YFOSyH1Mg27M8Qp6BCFSDLzqJonbKA=; b=NpyQY9w5e59C07w66a0cFfk30nROACtbGnt68uJoK2cYynCTu9rzuBTuGmXCivMnh717Go xywB7b2cjDORLKrzP06pglzGoBkWGgpLhojTzMfaQtQKouvGl777wNpOlgGbjOWJqmtbaCiw Y7CZGOT2x1SQ8sdCxIxrCf8jl4488TWfCdNy/J6+SCXtaBnz12RJravbz9AhD1ECN251+/Kz X+scnXGFWkB65dkjd/4M3Pzq/0IzDNE2hqAF+fOiFtJEmu+naABLbm2OGC8P6/9L0VWJM99j mb3FtsoiILR3iCzolmOcCnJrCiGrC2DxbiLPoxOw/DqLcu1mTRhF0WQg==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 11/15] glibc: patch CVE-2026-8674 Date: Fri, 23 Oct 2026 00:47:04 +0200 Message-ID: <20261022224711.3783258-11-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:42 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248466 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0042-CVE-2026-8674.patch | 118 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 119 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0042-CVE-2026-8674.patch diff --git a/meta/recipes-core/glibc/glibc/0042-CVE-2026-8674.patch b/meta/recipes-core/glibc/glibc/0042-CVE-2026-8674.patch new file mode 100644 index 00000000000..bbdeafd5f38 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0042-CVE-2026-8674.patch @@ -0,0 +1,118 @@ +From c97fdd483232a831829aaff458a212307f1bf4bc Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 14 Sep 2026 17:08:03 -0300 +Subject: [PATCH] resolv: Fix assertion failure on search list truncation [BZ + 31026, CVE-2026-8674] + +update_from_conf copies the search list into the 256-byte +resp->defdname and truncates it when an entry does not fit, then +asserts that resolv_conf_matches accepts the result. + +The truncation check there compared the accumulated size against +sizeof (resp->dnsrch) (the pointer array) instead of resp->defdname, +and the empty-list case did not account for a first entry that does +not fit at all. A long search domain in resolv.conf or LOCALDOMAIN +thus aborts any process using the resolver. + +Check whether the entry fits in the remaining defdname space, matching +alloc_buffer_copy_string, and also accept an empty resp->dnsrch when +the first entry is too long. Add tests covering both cases through +the search and domain directives. + +Checked on x86_64-linux-gnu and i686-linux-gnu. +Reviewed-by: Florian Weimer + +(cherry picked from commit 506ea57086bfb9ce3daff1c14246a1cb532aba0a) +(cherry picked from commit c0c8a45dee30c8089822d859575a3ad4324b15ff) + +CVE: CVE-2026-8674 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=c97fdd483232a831829aaff458a212307f1bf4bc] +Signed-off-by: Peter Marko +--- + resolv/resolv_conf.c | 19 +++++++++------ + resolv/tst-resolv-res_init-skeleton.c | 35 +++++++++++++++++++++++++++ + 2 files changed, 47 insertions(+), 7 deletions(-) + +diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c +index dcf92ee90e..0418267044 100644 +--- a/resolv/resolv_conf.c ++++ b/resolv/resolv_conf.c +@@ -281,8 +281,12 @@ resolv_conf_matches (const struct __res_state *resp, + { + if (resp->dnsrch[0] == NULL) + { +- /* Empty search list. No default domain name. */ +- return conf->search_list_size == 0 && resp->defdname[0] == '\0'; ++ /* Empty search list, or the first entry does not fit in ++ resp->defdname. No default domain name. */ ++ return resp->defdname[0] == '\0' ++ && (conf->search_list_size == 0 ++ || (strlen (conf->search_list[0]) + 1 ++ > sizeof (resp->defdname))); + } + + if (resp->dnsrch[0] != resp->defdname) +@@ -309,11 +313,12 @@ resolv_conf_matches (const struct __res_state *resp, + } + else + { +- /* resp->dnsrch is truncated if the number of elements +- exceeds MAXDNSRCH, or if the combined storage space for +- the search list exceeds what can be stored in +- resp->defdname. */ +- if (i == MAXDNSRCH || search_list_size > sizeof (resp->dnsrch)) ++ /* resp->dnsrch is truncated if the number of elements exceeds ++ MAXDNSRCH, or if conf->search_list[i] does not fit in the ++ remaining space of resp->defdname. */ ++ if (i == MAXDNSRCH ++ || (search_list_size + strlen (conf->search_list[i]) + 1 ++ > sizeof (resp->defdname))) + break; + /* Otherwise, a mismatch indicates a match failure. */ + return false; +diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +index 3ccbe71db9..4e9c57f3cb 100644 +--- a/resolv/tst-resolv-res_init-skeleton.c ++++ b/resolv/tst-resolv-res_init-skeleton.c +@@ -713,6 +713,41 @@ struct test_case test_cases[] = + "nameserver 192.0.2.1\n" + "; nameserver[0]: [192.0.2.1]:53\n" + }, ++/* Search list entries which do not fit in the legacy 256-byte ++ resp->defdname buffer (bug 31026). LONG244 is 244 characters long, ++ so it does not fit after "example.com\0" (12 bytes). LONG256 is 256 ++ characters long, so it does not fit even as the first entry. */ ++#define LBL63 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ++#define LONG244 LBL63 "." LBL63 "." LBL63 "." \ ++ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" ++#define LONG256 LBL63 "." LBL63 "." LBL63 "." LBL63 "a" ++ {.name = "search list truncated at long entry after short entry", ++ .conf = "nameserver 192.0.2.1\n" ++ "search example.com " LONG244 "\n", ++ .expected = "search example.com\n" ++ "; search[0]: example.com\n" ++ "; search[1]: " LONG244 "\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, ++ {.name = "search list truncated at long first entry", ++ .conf = "nameserver 192.0.2.1\n" ++ "search " LONG256 " example.com\n", ++ .expected = "; search[0]: " LONG256 "\n" ++ "; search[1]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, ++ {.name = "long first entry from the domain directive", ++ .conf = "nameserver 192.0.2.1\n" ++ "domain " LONG256 "\n", ++ .expected = "; search[0]: " LONG256 "\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, ++#undef LONG256 ++#undef LONG244 ++#undef LBL63 + {.name = "trust-ad flag", + .conf = "options trust-ad\n" + "nameserver 192.0.2.1\n", diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 3e95792b359..3b27328c21a 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -74,6 +74,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0039-CVE-2026-77117-CVE-2026-80489.patch \ file://0040-CVE-2026-18374-01.patch \ file://0041-CVE-2026-18374-02.patch \ + file://0042-CVE-2026-8674.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101712 Received: from mta-64-228.siemens.flowmailer.net (mta-64-228.siemens.flowmailer.net [185.136.64.228]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2358.1792709326386017388 for ; Thu, 22 Oct 2026 15:48:47 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=YZoDScqs; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.228, mailfrom: fm-256628-20261022224844b4e3f8cd9e0002075f-xf4uj0@rts-flowmailer.siemens.com) Received: by mta-64-228.siemens.flowmailer.net with ESMTPSA id 20261022224844b4e3f8cd9e0002075f for ; Fri, 23 Oct 2026 00:48:44 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=9S8yatxTxwD6pnJO+JQ4aQd75mzvAcLg94B2qScZ22Y=; b=YZoDScqsQ3BGSV1/QL5zsJIpXujre1JQfMx0BoffHKjZR86Ctda62RHLLgIyPbgROKWda0 TWhPAzmf3FJWK1OYo2xewRwf0xL/c+rmuTEKKeboUAJcSac1N6q1i0+7BLgySSeq4N/9qkYb zcM60Mc03tuTmzqkFAlvREpoHdIVzXpBnb9VRijBdY2h4SelIVHjOB8GzCVqs8pwB3yEoY7f kgpheKit90jB/4DfIV9z8+lC+7St5wcYnoYOpZfvnjM8fVy1ZJ23X/KK9E63Rn1gArgVSz1f 3xZcTNsI4MPSSwyDh6Gud7Wfs+iMRndy736w+6Va8wdMx/0K71JN077w==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 12/15] glibc: patch CVE-2026-86805 and CVE-2026-95818 Date: Fri, 23 Oct 2026 00:47:05 +0200 Message-ID: <20261022224711.3783258-12-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:48:52 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248467 From: Peter Marko Pick patch [1] which is [2] backported to 3.41 (oldest release still receiving security updates) which is mentioned in [3] and [4]. Additionally pick 3 patches for test harness to support new tests. [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=71648e80042658f23965924616fb7db9c2fccff9 [2] https://sourceware.org/git/?p=glibc.git;a=commit;h=ed0c137b97eb940b4b64981e84ed806d3276edd9 [3] https://security-tracker.debian.org/tracker/CVE-2026-86805 [3] https://security-tracker.debian.org/tracker/CVE-2026-95818 Signed-off-by: Peter Marko --- ...043-CVE-2026-86805-CVE-2026-95818-01.patch | 244 +++++ ...044-CVE-2026-86805-CVE-2026-95818-02.patch | 298 ++++++ ...045-CVE-2026-86805-CVE-2026-95818-03.patch | 115 +++ ...046-CVE-2026-86805-CVE-2026-95818-04.patch | 862 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 4 + 5 files changed, 1523 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0043-CVE-2026-86805-CVE-2026-95818-01.patch create mode 100644 meta/recipes-core/glibc/glibc/0044-CVE-2026-86805-CVE-2026-95818-02.patch create mode 100644 meta/recipes-core/glibc/glibc/0045-CVE-2026-86805-CVE-2026-95818-03.patch create mode 100644 meta/recipes-core/glibc/glibc/0046-CVE-2026-86805-CVE-2026-95818-04.patch diff --git a/meta/recipes-core/glibc/glibc/0043-CVE-2026-86805-CVE-2026-95818-01.patch b/meta/recipes-core/glibc/glibc/0043-CVE-2026-86805-CVE-2026-95818-01.patch new file mode 100644 index 00000000000..42294f02838 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0043-CVE-2026-86805-CVE-2026-95818-01.patch @@ -0,0 +1,244 @@ +From 71648e80042658f23965924616fb7db9c2fccff9 Mon Sep 17 00:00:00 2001 +From: Joe Simmons-Talbott +Date: Thu, 29 Feb 2024 19:55:58 +0000 +Subject: [PATCH] rtld: Add glibc.rtld.enable_secure tunable. + +Add a tunable for setting __libc_enable_secure to 1. Do not set +__libc_enable_secure to 0 if the tunable is set to 0. Ignore all +tunables if glib.rtld.enable_secure is set. One use-case for this +addition is to enable testing code paths that depend on +__libc_enable_secure being set without the need to use setxid binaries. + +Reviewed-by: Siddhesh Poyarekar + +CVE: CVE-2026-86805 +CVE: CVE-2026-95818 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=71648e80042658f23965924616fb7db9c2fccff9] +Signed-off-by: Peter Marko +--- + NEWS | 5 ++ + elf/Makefile | 2 + + elf/dl-tunables.c | 10 +++ + elf/dl-tunables.list | 6 ++ + elf/tst-rtld-list-tunables.exp | 1 + + elf/tst-tunables-enable_secure.c | 126 +++++++++++++++++++++++++++++++ + 6 files changed, 150 insertions(+) + create mode 100644 elf/tst-tunables-enable_secure.c + +diff --git a/NEWS b/NEWS +index 2d8eaffc58..19f4e93ea3 100644 +--- a/NEWS ++++ b/NEWS +@@ -177,6 +177,11 @@ Major new features: + exp, expf, exp10, exp10f, exp2, exp2f, expm1, expm1f, log, logf, + log10, log10f, log1p, log1pf, log2, log2f, sin, sinf, tan, tanf. + ++* A new tunable, glibc.rtld.enable_secure, used to run a program ++ as if it were a setuid process. This is currently a testing tool to allow ++ more extensive verification tests for AT_SECURE programs and not meant to ++ be a security feature. ++ + Deprecated and removed features, and other changes affecting compatibility: + + * The ldconfig program now skips file names containing ';' or ending in +diff --git a/elf/Makefile b/elf/Makefile +index f0439ef634..520a270f0f 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -288,6 +288,7 @@ tests-static-internal := \ + tst-tls1-static \ + tst-tls1-static-non-pie \ + tst-tunables \ ++ tst-tunables-enable_secure \ + # tests-static-internal + + CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o +@@ -2741,6 +2742,7 @@ $(objpfx)tst-glibc-hwcaps-mask.out: \ + $(objpfx)tst-glibc-hwcaps-cache.out: $(objpfx)tst-glibc-hwcaps + + tst-tunables-ARGS = -- $(host-test-program-cmd) ++tst-tunables-enable_secure-ARGS = -- $(host-test-program-cmd) + + $(objpfx)list-tunables.out: tst-rtld-list-tunables.sh $(objpfx)ld.so + $(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \ +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 03e1a68675..d3ccd2ecd4 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -225,6 +225,16 @@ parse_tunables_string (const char *valstring, struct tunable_toset_t *tunables) + tunables[ntunables++] = + (struct tunable_toset_t) { cur, value, p - value }; + ++ /* Ignore tunables if enable_secure is set */ ++ if (tunable_is_name ("glibc.rtld.enable_secure", name)) ++ { ++ tunable_num_t val = (tunable_num_t) _dl_strtoul (value, NULL); ++ if (val == 1) ++ { ++ __libc_enable_secure = 1; ++ return 0; ++ } ++ } + break; + } + } +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index 1b40407814..1186272c81 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -136,6 +136,12 @@ glibc { + minval: 0 + default: 512 + } ++ enable_secure { ++ type: INT_32 ++ minval: 0 ++ maxval: 1 ++ default: 0 ++ } + } + + mem { +diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp +index 2233ea9c7c..db0e1c86e9 100644 +--- a/elf/tst-rtld-list-tunables.exp ++++ b/elf/tst-rtld-list-tunables.exp +@@ -12,5 +12,6 @@ glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.top_pad: 0x20000 (min: 0x0, max: 0x[f]+) + glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+) + glibc.rtld.dynamic_sort: 2 (min: 1, max: 2) ++glibc.rtld.enable_secure: 0 (min: 0, max: 1) + glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10) + glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+) +diff --git a/elf/tst-tunables-enable_secure.c b/elf/tst-tunables-enable_secure.c +new file mode 100644 +index 0000000000..e31e1f7faa +--- /dev/null ++++ b/elf/tst-tunables-enable_secure.c +@@ -0,0 +1,126 @@ ++/* Check GLIBC_TUNABLES parsing for enable_secure. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++static const struct test_t ++{ ++ const char *env; ++ int32_t expected_malloc_check; ++ int32_t expected_enable_secure; ++} tests[] = ++{ ++ /* Expected tunable format. */ ++ /* Tunables should be ignored if enable_secure is set. */ ++ { ++ "glibc.malloc.check=2:glibc.rtld.enable_secure=1", ++ 0, ++ 1, ++ }, ++ /* Tunables should be ignored if enable_secure is set. */ ++ { ++ "glibc.rtld.enable_secure=1:glibc.malloc.check=2", ++ 0, ++ 1, ++ }, ++ /* Tunables should be set if enable_secure is unset. */ ++ { ++ "glibc.rtld.enable_secure=0:glibc.malloc.check=2", ++ 2, ++ 0, ++ }, ++}; ++ ++static int ++handle_restart (int i) ++{ ++ if (tests[i].expected_enable_secure == 1) ++ { ++ TEST_COMPARE (1, __libc_enable_secure); ++ } ++ else ++ { ++ TEST_COMPARE (tests[i].expected_malloc_check, ++ TUNABLE_GET_FULL (glibc, malloc, check, int32_t, NULL)); ++ TEST_COMPARE (tests[i].expected_enable_secure, ++ TUNABLE_GET_FULL (glibc, rtld, enable_secure, int32_t, ++ NULL)); ++ } ++ return 0; ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One or four parameters left if called initially: ++ + path to ld.so optional ++ + "--library-path" optional ++ + the library path optional ++ + the application name ++ + the test to check */ ++ ++ TEST_VERIFY_EXIT (argc == 2 || argc == 5); ++ ++ if (restart) ++ return handle_restart (atoi (argv[1])); ++ ++ char nteststr[INT_BUFSIZE_BOUND (int)]; ++ ++ char *spargv[10]; ++ { ++ int i = 0; ++ for (; i < argc - 1; i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i++] = nteststr; ++ spargv[i] = NULL; ++ } ++ ++ for (int i = 0; i < array_length (tests); i++) ++ { ++ snprintf (nteststr, sizeof nteststr, "%d", i); ++ ++ printf ("[%d] Spawned test for %s\n", i, tests[i].env); ++ setenv ("GLIBC_TUNABLES", tests[i].env, 1); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-tunables-enable_secure", ++ 0, sc_allow_stderr); ++ support_capture_subprocess_free (&result); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include diff --git a/meta/recipes-core/glibc/glibc/0044-CVE-2026-86805-CVE-2026-95818-02.patch b/meta/recipes-core/glibc/glibc/0044-CVE-2026-86805-CVE-2026-95818-02.patch new file mode 100644 index 00000000000..bcb1e08a30f --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0044-CVE-2026-86805-CVE-2026-95818-02.patch @@ -0,0 +1,298 @@ +From 1e1ad714ee9a663eda0e2bffad1d9f258b00a4e9 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 6 May 2024 13:18:47 -0300 +Subject: [PATCH] support: Add envp argument to support_capture_subprogram + +So tests can specify a list of environment variables. +Reviewed-by: Siddhesh Poyarekar + +CVE: CVE-2026-86805 +CVE: CVE-2026-95818 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=1e1ad714ee9a663eda0e2bffad1d9f258b00a4e9] +Signed-off-by: Peter Marko +--- + elf/tst-audit18.c | 2 +- + elf/tst-audit19b.c | 2 +- + elf/tst-audit22.c | 2 +- + elf/tst-audit23.c | 2 +- + elf/tst-audit25a.c | 4 ++-- + elf/tst-audit25b.c | 4 ++-- + elf/tst-glibc-hwcaps-2-cache.c | 2 +- + elf/tst-rtld-run-static.c | 4 ++-- + elf/tst-tunables-enable_secure.c | 2 +- + elf/tst-tunables.c | 2 +- + support/capture_subprocess.h | 9 +++++---- + support/subprocess.h | 7 ++++--- + support/support_capture_subprocess.c | 5 +++-- + support/support_subprocess.c | 5 +++-- + support/tst-support_capture_subprocess.c | 2 +- + sysdeps/x86/tst-hwcap-tunables.c | 2 +- + 16 files changed, 30 insertions(+), 26 deletions(-) + +diff --git a/elf/tst-audit18.c b/elf/tst-audit18.c +index 841251dd70..cec93e269c 100644 +--- a/elf/tst-audit18.c ++++ b/elf/tst-audit18.c +@@ -79,7 +79,7 @@ do_test (int argc, char *argv[]) + + setenv ("LD_AUDIT", "tst-auditmod18.so", 0); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit18", 0, sc_allow_stderr); + + struct +diff --git a/elf/tst-audit19b.c b/elf/tst-audit19b.c +index 70bfe4eadf..88d99a416b 100644 +--- a/elf/tst-audit19b.c ++++ b/elf/tst-audit19b.c +@@ -69,7 +69,7 @@ do_test (int argc, char *argv[]) + + setenv ("LD_AUDIT", "tst-auditmod18b.so", 0); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit18b", 0, sc_allow_stderr); + + bool find_symbind = false; +diff --git a/elf/tst-audit22.c b/elf/tst-audit22.c +index 4e97be3be0..6aa18af948 100644 +--- a/elf/tst-audit22.c ++++ b/elf/tst-audit22.c +@@ -83,7 +83,7 @@ do_test (int argc, char *argv[]) + + setenv ("LD_AUDIT", "tst-auditmod22.so", 0); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr); + + /* The respawned process should always print the vDSO address (otherwise it +diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c +index 32e7c8b2a3..d2640fe8b2 100644 +--- a/elf/tst-audit23.c ++++ b/elf/tst-audit23.c +@@ -87,7 +87,7 @@ do_one_test (int argc, char *argv[], bool pass_dlclose_flag) + + setenv ("LD_AUDIT", "tst-auditmod23.so", 0); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr); + + { +diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c +index b209ee820f..cdd4f2ce2b 100644 +--- a/elf/tst-audit25a.c ++++ b/elf/tst-audit25a.c +@@ -77,7 +77,7 @@ do_test (int argc, char *argv[]) + + { + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit25a", 0, + sc_allow_stderr); + +@@ -102,7 +102,7 @@ do_test (int argc, char *argv[]) + { + setenv ("LD_BIND_NOW", "1", 0); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit25a", 0, + sc_allow_stderr); + +diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c +index 9b8665d517..939f4d6188 100644 +--- a/elf/tst-audit25b.c ++++ b/elf/tst-audit25b.c +@@ -76,7 +76,7 @@ do_test (int argc, char *argv[]) + + { + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit25a", 0, + sc_allow_stderr); + +@@ -102,7 +102,7 @@ do_test (int argc, char *argv[]) + { + setenv ("LD_BIND_NOW", "1", 0); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-audit25a", 0, + sc_allow_stderr); + +diff --git a/elf/tst-glibc-hwcaps-2-cache.c b/elf/tst-glibc-hwcaps-2-cache.c +index 81ab44ff78..af91476cca 100644 +--- a/elf/tst-glibc-hwcaps-2-cache.c ++++ b/elf/tst-glibc-hwcaps-2-cache.c +@@ -32,7 +32,7 @@ main (int argc, char **argv) + /* Run ldconfig to populate the cache. */ + char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir); + struct support_capture_subprocess result = +- support_capture_subprogram (command, &((char *) { NULL })); ++ support_capture_subprogram (command, &((char *) { NULL }), NULL); + support_capture_subprocess_check (&result, "ldconfig", 0, sc_allow_none); + free (command); + +diff --git a/elf/tst-rtld-run-static.c b/elf/tst-rtld-run-static.c +index b2650e85ff..f05c00eb7b 100644 +--- a/elf/tst-rtld-run-static.c ++++ b/elf/tst-rtld-run-static.c +@@ -30,7 +30,7 @@ do_test (void) + { + char *argv[] = { (char *) "ld.so", ldconfig_path, (char *) "--help", NULL }; + struct support_capture_subprocess cap +- = support_capture_subprogram (support_objdir_elf_ldso, argv); ++ = support_capture_subprogram (support_objdir_elf_ldso, argv, NULL); + support_capture_subprocess_check (&cap, "no --argv0", 0, sc_allow_stdout); + puts ("info: output without --argv0:"); + puts (cap.out.buffer); +@@ -46,7 +46,7 @@ do_test (void) + ldconfig_path, (char *) "--help", NULL + }; + struct support_capture_subprocess cap +- = support_capture_subprogram (support_objdir_elf_ldso, argv); ++ = support_capture_subprogram (support_objdir_elf_ldso, argv, NULL); + support_capture_subprocess_check (&cap, "with --argv0", 0, sc_allow_stdout); + puts ("info: output with --argv0:"); + puts (cap.out.buffer); +diff --git a/elf/tst-tunables-enable_secure.c b/elf/tst-tunables-enable_secure.c +index e31e1f7faa..f5db1c84e9 100644 +--- a/elf/tst-tunables-enable_secure.c ++++ b/elf/tst-tunables-enable_secure.c +@@ -113,7 +113,7 @@ do_test (int argc, char *argv[]) + printf ("[%d] Spawned test for %s\n", i, tests[i].env); + setenv ("GLIBC_TUNABLES", tests[i].env, 1); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-tunables-enable_secure", + 0, sc_allow_stderr); + support_capture_subprocess_free (&result); +diff --git a/elf/tst-tunables.c b/elf/tst-tunables.c +index dff34ed748..4884dd09f0 100644 +--- a/elf/tst-tunables.c ++++ b/elf/tst-tunables.c +@@ -396,7 +396,7 @@ do_test (int argc, char *argv[]) + tests[i].value); + setenv (tests[i].name, tests[i].value, 1); + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-tunables", 0, + sc_allow_stderr); + support_capture_subprocess_free (&result); +diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h +index 1ecbdfe4fc..93b7245d2a 100644 +--- a/support/capture_subprocess.h ++++ b/support/capture_subprocess.h +@@ -35,11 +35,12 @@ struct support_capture_subprocess + struct support_capture_subprocess support_capture_subprocess + (void (*callback) (void *), void *closure); + +-/* Issue FILE with ARGV arguments by using posix_spawn and capture standard +- output, standard error, and the exit status. The out.buffer and err.buffer +- are handle as support_capture_subprocess. */ ++/* Issue FILE with ARGV arguments and ENVP environments by using posix_spawn ++ and capture standard output, standard error, and the exit status. If ++ ENVP is NULL the current environment variable is used. The out.buffer and ++ err.buffer are handle by support_capture_subprocess. */ + struct support_capture_subprocess support_capture_subprogram +- (const char *file, char *const argv[]); ++ (const char *file, char *const argv[], char *const envp[]); + + /* Copy the running program into a setgid binary and run it with + CHILD_ID argument. If the program exits with a non-zero status, +diff --git a/support/subprocess.h b/support/subprocess.h +index 8fbb895353..8274a2b22b 100644 +--- a/support/subprocess.h ++++ b/support/subprocess.h +@@ -33,10 +33,11 @@ struct support_subprocess + struct support_subprocess support_subprocess + (void (*callback) (void *), void *closure); + +-/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a +- pipe redirected to STDOUT, and a pipe redirected to STDERR. */ ++/* Issue FILE with ARGV arguments and ENVP environments by using posix_spawn ++ and return is PID, a pipe redirected to STDOUT, and a pipe redirected to ++ STDERR. If ENVP is NULL the current environment variable is used. */ + struct support_subprocess support_subprogram +- (const char *file, char *const argv[]); ++ (const char *file, char *const argv[], char *const envp[]); + + /* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it + to complete. Return program exit status. */ +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +index ffced8a89f..53847194cb 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -98,13 +98,14 @@ support_capture_subprocess (void (*callback) (void *), void *closure) + } + + struct support_capture_subprocess +-support_capture_subprogram (const char *file, char *const argv[]) ++support_capture_subprogram (const char *file, char *const argv[], ++ char *const envp[]) + { + struct support_capture_subprocess result; + xopen_memstream (&result.out); + xopen_memstream (&result.err); + +- struct support_subprocess proc = support_subprogram (file, argv); ++ struct support_subprocess proc = support_subprogram (file, argv, envp); + + support_capture_poll (&result, &proc); + return result; +diff --git a/support/support_subprocess.c b/support/support_subprocess.c +index a2fef394d4..b692a7f8b1 100644 +--- a/support/support_subprocess.c ++++ b/support/support_subprocess.c +@@ -69,7 +69,7 @@ support_subprocess (void (*callback) (void *), void *closure) + } + + struct support_subprocess +-support_subprogram (const char *file, char *const argv[]) ++support_subprogram (const char *file, char *const argv[], char *const envp[]) + { + struct support_subprocess result = support_subprocess_init (); + +@@ -84,7 +84,8 @@ support_subprogram (const char *file, char *const argv[]) + xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]); + xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]); + +- result.pid = xposix_spawn (file, &fa, NULL, argv, environ); ++ result.pid = xposix_spawn (file, &fa, NULL, argv, ++ envp == NULL ? environ : envp); + + xclose (result.stdout_pipe[1]); + xclose (result.stderr_pipe[1]); +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +index 8145548982..756fb75d19 100644 +--- a/support/tst-support_capture_subprocess.c ++++ b/support/tst-support_capture_subprocess.c +@@ -238,7 +238,7 @@ do_subprogram (const struct test *test) + args[argc] = NULL; + TEST_VERIFY (argc < argv_size); + +- return support_capture_subprogram (args[0], args); ++ return support_capture_subprogram (args[0], args, NULL); + } + + enum test_type +diff --git a/sysdeps/x86/tst-hwcap-tunables.c b/sysdeps/x86/tst-hwcap-tunables.c +index f6a65b88de..8589a9fd66 100644 +--- a/sysdeps/x86/tst-hwcap-tunables.c ++++ b/sysdeps/x86/tst-hwcap-tunables.c +@@ -133,7 +133,7 @@ do_test (int argc, char *argv[]) + setenv ("GLIBC_TUNABLES", tunable, 1); + + struct support_capture_subprocess result +- = support_capture_subprogram (spargv[0], spargv); ++ = support_capture_subprogram (spargv[0], spargv, NULL); + support_capture_subprocess_check (&result, "tst-tunables", 0, + sc_allow_stderr); + support_capture_subprocess_free (&result); diff --git a/meta/recipes-core/glibc/glibc/0045-CVE-2026-86805-CVE-2026-95818-03.patch b/meta/recipes-core/glibc/glibc/0045-CVE-2026-86805-CVE-2026-95818-03.patch new file mode 100644 index 00000000000..bb39978881d --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0045-CVE-2026-86805-CVE-2026-95818-03.patch @@ -0,0 +1,115 @@ +From eeb687bb4b371d67abcd3c4c84d5990d8bc78b71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20B=C3=A9rat?= +Date: Fri, 29 Nov 2024 14:48:43 +0100 +Subject: [PATCH] support: Add support_next_to_fault_before support function + +Refactor the support_next_to_fault and add the +support_next_to_fault_before method returns a buffer with a protected +page before it, to be able to test buffer underflow accesses. + +Reviewed-by: Tulio Magno Quites Machado Filho +(cherry picked from commit fa53723cdb6f0338558e57a2a0a6459c00a1bc5f) + +CVE: CVE-2026-86805 +CVE: CVE-2026-95818 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=eeb687bb4b371d67abcd3c4c84d5990d8bc78b71] +Signed-off-by: Peter Marko +--- + support/next_to_fault.c | 44 +++++++++++++++++++++++++++++++---------- + support/next_to_fault.h | 5 +++++ + 2 files changed, 39 insertions(+), 10 deletions(-) + +diff --git a/support/next_to_fault.c b/support/next_to_fault.c +index eb2457d12d..b60d5a5744 100644 +--- a/support/next_to_fault.c ++++ b/support/next_to_fault.c +@@ -1,4 +1,4 @@ +-/* Memory allocation next to an unmapped page. ++/* Memory allocation either before or after an unmapped page. + Copyright (C) 2017-2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -16,34 +16,58 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include + #include + #include + +-struct support_next_to_fault +-support_next_to_fault_allocate (size_t size) ++static struct support_next_to_fault ++support_next_to_fault_allocate_any (size_t size, bool fault_after_alloc) + { + long page_size = sysconf (_SC_PAGE_SIZE); ++ long protect_offset = 0; ++ long buffer_offset = page_size; ++ + TEST_VERIFY_EXIT (page_size > 0); + struct support_next_to_fault result; + result.region_size = roundup (size, page_size) + page_size; + if (size + page_size <= size || result.region_size <= size) +- FAIL_EXIT1 ("support_next_to_fault_allocate (%zu): overflow", size); ++ FAIL_EXIT1 ("%s (%zu): overflow", __func__, size); + result.region_start + = xmmap (NULL, result.region_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1); +- /* Unmap the page after the allocation. */ +- xmprotect (result.region_start + (result.region_size - page_size), +- page_size, PROT_NONE); +- /* Align the allocation within the region so that it ends just +- before the PROT_NONE page. */ +- result.buffer = result.region_start + result.region_size - page_size - size; ++ ++ if (fault_after_alloc) ++ { ++ protect_offset = result.region_size - page_size; ++ buffer_offset = protect_offset - size; ++ } ++ ++ /* Unmap the page before or after the allocation. */ ++ xmprotect (result.region_start + protect_offset, page_size, PROT_NONE); ++ /* Align the allocation within the region so that it starts after or ends ++ just before the PROT_NONE page. */ ++ result.buffer = result.region_start + buffer_offset; + result.length = size; + return result; + } + ++/* Unmapped a page after the buffer */ ++struct support_next_to_fault ++support_next_to_fault_allocate (size_t size) ++{ ++ return support_next_to_fault_allocate_any (size, true); ++} ++ ++/* Unmapped a page before the buffer */ ++struct support_next_to_fault ++support_next_to_fault_allocate_before (size_t size) ++{ ++ return support_next_to_fault_allocate_any (size, false); ++} ++ + void + support_next_to_fault_free (struct support_next_to_fault *ntf) + { +diff --git a/support/next_to_fault.h b/support/next_to_fault.h +index 7112cc4c65..cec4b97332 100644 +--- a/support/next_to_fault.h ++++ b/support/next_to_fault.h +@@ -41,6 +41,11 @@ struct support_next_to_fault + fault). */ + struct support_next_to_fault support_next_to_fault_allocate (size_t size); + ++/* Allocate a buffer of SIZE bytes just *after* a page which is mapped ++ with PROT_NONE (so that under-running the buffer will cause a ++ fault). */ ++struct support_next_to_fault support_next_to_fault_allocate_before (size_t size); ++ + /* Deallocate the memory region allocated by + next_to_fault_allocate. */ + void support_next_to_fault_free (struct support_next_to_fault *); diff --git a/meta/recipes-core/glibc/glibc/0046-CVE-2026-86805-CVE-2026-95818-04.patch b/meta/recipes-core/glibc/glibc/0046-CVE-2026-86805-CVE-2026-95818-04.patch new file mode 100644 index 00000000000..f6c92a7a3a8 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0046-CVE-2026-86805-CVE-2026-95818-04.patch @@ -0,0 +1,862 @@ +From 629565b0c91dc326ac622b05982f21a374cd03c4 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 17 Aug 2026 15:15:32 -0300 +Subject: [PATCH] elf: Open the normalized $ORIGIN rpath in AT_SECURE programs + (BZ 34360) + +For AT_SECURE programs the loader honors $ORIGIN in DT_RPATH only when the +expansion is rooted in a trusted directory, but it validated the lexically +normalized path while opening the raw expansion. As "a/b/../c" only names +"a/c" when "b" is not a symlink, an attacker who controls a component of +$ORIGIN -- e.g. by hard-linking the setuid binary into an attacker-owned +directory -- can make the opened path escape the trusted directory even +though the check passed, loading an attacker-controlled object. + +Normalize the expansion in place and open that, so the path that is opened +is exactly the path that was validated. _dl_normalize_path rewrites the +string in place without ever advancing its write cursor past its read +cursor or appending, so it stays within the original storage. + +Add elf/tst-origin-secure as a regression test. + +Reviewed-by: Florian Weimer +(cherry picked from commit ed0c137b97eb940b4b64981e84ed806d3276edd9) + +CVE: CVE-2026-86805 +CVE: CVE-2026-95818 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=629565b0c91dc326ac622b05982f21a374cd03c4] +Signed-off-by: Peter Marko +--- + elf/Makefile | 18 ++ + elf/dl-load.c | 74 +++------ + elf/dl-path-normalize.h | 118 +++++++++++++ + elf/libtst-origin-secure-mod.c | 25 +++ + elf/tst-dl-path-normalize.c | 142 ++++++++++++++++ + elf/tst-origin-secure-evilmod.c | 28 ++++ + elf/tst-origin-secure-victim.c | 43 +++++ + elf/tst-origin-secure.c | 203 +++++++++++++++++++++++ + elf/tst-origin-secure.h | 41 +++++ + elf/tst-origin-secure.root/postclean.req | 0 + 10 files changed, 643 insertions(+), 49 deletions(-) + create mode 100644 elf/dl-path-normalize.h + create mode 100644 elf/libtst-origin-secure-mod.c + create mode 100644 elf/tst-dl-path-normalize.c + create mode 100644 elf/tst-origin-secure-evilmod.c + create mode 100644 elf/tst-origin-secure-victim.c + create mode 100644 elf/tst-origin-secure.c + create mode 100644 elf/tst-origin-secure.h + create mode 100644 elf/tst-origin-secure.root/postclean.req + +diff --git a/elf/Makefile b/elf/Makefile +index d8a0c0c4ae..8a5aa0123a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -520,6 +520,7 @@ tests-internal += \ + tst-audit19a \ + tst-create_format1 \ + tst-dl-hwcaps_split \ ++ tst-dl-path-normalize \ + tst-dl_find_object \ + tst-dl_find_object-threads \ + tst-dlmopen2 \ +@@ -543,12 +544,14 @@ endif + tests-container += \ + tst-dlopen-self-container \ + tst-dlopen-tlsmodid-container \ ++ tst-origin-secure \ + tst-pldd \ + tst-preload-pthread-libc \ + tst-rootdir \ + # tests-container + + test-srcs = \ ++ tst-origin-secure-victim \ + tst-pathopt \ + tst-sprof-basic \ + # tests-srcs +@@ -722,6 +725,7 @@ modules-names += \ + libtracemod3-1 \ + libtracemod4-1 \ + libtracemod5-1 \ ++ libtst-origin-secure-mod \ + ltglobmod1 \ + ltglobmod2 \ + neededobj1 \ +@@ -907,6 +911,7 @@ modules-names += \ + tst-nodeps2-mod \ + tst-non-directory-mod \ + tst-null-argv-lib \ ++ tst-origin-secure-evilmod \ + tst-p_alignmod-base \ + tst-p_alignmod3 \ + tst-recursive-tlsmallocmod \ +@@ -3217,3 +3222,16 @@ $(objpfx)tst-dlopen-constructor-null: \ + $(objpfx)tst-dlopen-constructor-null-mod2.so + $(objpfx)tst-dlopen-constructor-null-mod2.so: \ + $(objpfx)tst-dlopen-constructor-null-mod1.so ++ ++LDFLAGS-libtst-origin-secure-mod.so += -Wl,-soname,libtst-origin-secure-mod.so ++LDFLAGS-tst-origin-secure-evilmod.so += -Wl,-soname,libtst-origin-secure-mod.so ++$(objpfx)tst-origin-secure-victim: $(objpfx)libtst-origin-secure-mod.so ++# The number of "../" here must match the layout invariants described in ++# tst-origin-secure.c. ++LDFLAGS-tst-origin-secure-victim += \ ++ -Wl,--no-as-needed \ ++ -Wl,-rpath,\$$ORIGIN/sub/../../../../..$(slibdir)/tst-origin-secure \ ++ -Wl,--disable-new-dtags ++$(objpfx)tst-origin-secure.out: $(objpfx)tst-origin-secure-victim \ ++ $(objpfx)libtst-origin-secure-mod.so \ ++ $(objpfx)tst-origin-secure-evilmod.so +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 7b21f1dffa..0d141a61c1 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + /* Type for the buffer we put the ELF header and hopefully the program + header. This buffer does not really have to be too large. In most +@@ -124,54 +125,24 @@ static const size_t system_dirs_len[] = + }; + #define nsystem_dirs_len array_length (system_dirs_len) + ++/* Return true if the normalized path NPATH of length NLEN is rooted in one of ++ the trusted system directories. The system_dirs entries carry a trailing ++ '/'; NPATH matches an entry when it shares the entry's leading component ++ sequence and then either ends or continues with '/'. For instance, ++ "/lib64" and "/lib64/x" match "/lib64/" but "/lib64x" does not. */ + static bool +-is_trusted_path_normalize (const char *path, size_t len) ++path_is_trusted (const char *npath, size_t nlen) + { +- if (len == 0) +- return false; +- +- char *npath = (char *) alloca (len + 2); +- char *wnp = npath; +- while (*path != '\0') +- { +- if (path[0] == '/') +- { +- if (path[1] == '.') +- { +- if (path[2] == '.' && (path[3] == '/' || path[3] == '\0')) +- { +- while (wnp > npath && *--wnp != '/') +- ; +- path += 3; +- continue; +- } +- else if (path[2] == '/' || path[2] == '\0') +- { +- path += 2; +- continue; +- } +- } +- +- if (wnp > npath && wnp[-1] == '/') +- { +- ++path; +- continue; +- } +- } +- +- *wnp++ = *path++; +- } +- +- if (wnp == npath || wnp[-1] != '/') +- *wnp++ = '/'; +- + const char *trun = system_dirs; + + for (size_t idx = 0; idx < nsystem_dirs_len; ++idx) + { +- if (wnp - npath >= system_dirs_len[idx] +- && memcmp (trun, npath, system_dirs_len[idx]) == 0) +- /* Found it. */ ++ /* Compare against the entry without its trailing '/'. */ ++ size_t dirlen = system_dirs_len[idx] - 1; ++ ++ if (nlen >= dirlen ++ && memcmp (trun, npath, dirlen) == 0 ++ && (npath[dirlen] == '/' || npath[dirlen] == '\0')) + return true; + + trun += system_dirs_len[idx] + 1; +@@ -361,16 +332,21 @@ _dl_dst_substitute (struct link_map *l, const char *input, char *result) + checked for trust, the authors of the binaries themselves are + trusted to have designed this correctly. Only $ORIGIN is tested in + this way because it may be manipulated in some ways with hard +- links. */ +- if (__glibc_unlikely (check_for_trusted) +- && !is_trusted_path_normalize (result, wp - result)) +- { +- *result = '\0'; +- return result; +- } ++ links. ++ ++ _dl_normalize_path replaces the expansion with its normalized form ++ in place, so that the path that is opened is exactly the path that ++ was validated. */ + + *wp = '\0'; + ++ if (__glibc_unlikely (check_for_trusted)) ++ { ++ size_t nlen = _dl_normalize_path (result); ++ if (!path_is_trusted (result, nlen)) ++ *result = '\0'; ++ } ++ + return result; + } + +diff --git a/elf/dl-path-normalize.h b/elf/dl-path-normalize.h +new file mode 100644 +index 0000000000..ca4b14698c +--- /dev/null ++++ b/elf/dl-path-normalize.h +@@ -0,0 +1,118 @@ ++/* In-place lexical path normalization for the dynamic loader. ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _DL_PATH_NORMALIZE_H ++#define _DL_PATH_NORMALIZE_H ++ ++#include ++#include ++ ++/* Lexically normalize the null-terminated PATH in place and return the ++ length of the result (excluding the terminating NUL byte): ++ ++ - Runs of '/' are collapsed to a single '/'. ++ ++ - "." components are removed. ++ ++ - A ".." component removes the preceding component if there is one and it ++ is not itself a preserved "..". In an absolute path a surplus ".." at ++ the root is dropped ("/../a" normalizes to "/a"), in a relative path ++ leading ".." components are preserved ("../a" stays "../a", "a/../../b" ++ normalizes to "../b"). ++ ++ - The result has no trailing '/' except for the root path "/" itself ++ ("/a/" normalizes to "/a"). ++ ++ - The result is empty if and only if every component cancels or is removed ++ ("", ".", "a/.." all normalize to ""). ++ ++ The PATH is written in place, and the internal write cursor never runs ++ ahead of the read cursor. Only bytes within the strlen (PATH) + 1 storage ++ are accessed. */ ++static inline size_t ++_dl_normalize_path (char *path) ++{ ++ /* The root '/' of an absolute path is not removed. */ ++ char *pstart = path + (path[0] == '/'); ++ const char *rnp = pstart; ++ char *wnp = pstart; ++ /* End of the prefix a ".." may not remove. Either the root '/', or, for ++ relative paths, the original start of the string extended by any ++ preserved leading ".." components. */ ++ char *limit = pstart; ++ ++ while (*rnp != '\0') ++ { ++ /* Collapse consecutive separators. */ ++ if (*rnp == '/') ++ { ++ ++rnp; ++ continue; ++ } ++ ++ /* [RNP, REND) is the next input component. */ ++ const char *rend = rnp; ++ while (*rend != '\0' && *rend != '/') ++ ++rend; ++ size_t clen = rend - rnp; ++ ++ /* Drop '.' component. */ ++ if (clen == 1 && rnp[0] == '.') ++ ; ++ else if (clen == 2 && rnp[0] == '.' && rnp[1] == '.') ++ { ++ if (wnp > limit) ++ { ++ /* Remove the last component along with the '/' separating it ++ from its predecessor (the root '/' of an absolute path is ++ retained). */ ++ while (wnp > limit && wnp[-1] != '/') ++ --wnp; ++ if (wnp > pstart) ++ --wnp; ++ } ++ else if (pstart == path) ++ { ++ /* No component is left and the original path is relative: ++ keep the unresolvable ".." (it becomes part of the ++ preserved prefix). */ ++ if (wnp > pstart) ++ *wnp++ = '/'; ++ *wnp++ = '.'; ++ *wnp++ = '.'; ++ limit = wnp; ++ } ++ /* Otherwise the path is absolute and the surplus ".." at the ++ root is dropped ("/../a" normalizes to "/a"). */ ++ } ++ else ++ { ++ if (wnp > pstart) ++ *wnp++ = '/'; ++ memmove (wnp, rnp, clen); ++ wnp += clen; ++ } ++ ++ rnp = rend; ++ } ++ ++ *wnp = '\0'; ++ return wnp - path; ++} ++ ++#endif /* _DL_PATH_NORMALIZE_H */ +diff --git a/elf/libtst-origin-secure-mod.c b/elf/libtst-origin-secure-mod.c +new file mode 100644 +index 0000000000..8d7f372094 +--- /dev/null ++++ b/elf/libtst-origin-secure-mod.c +@@ -0,0 +1,25 @@ ++/* Module for tst-origin-secure (the "good" copy). ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "tst-origin-secure.h" ++ ++int ++origin_secure_id (void) ++{ ++ return ORIGIN_SECURE_ID_TRUSTED; ++} +diff --git a/elf/tst-dl-path-normalize.c b/elf/tst-dl-path-normalize.c +new file mode 100644 +index 0000000000..f6d45d654f +--- /dev/null ++++ b/elf/tst-dl-path-normalize.c +@@ -0,0 +1,142 @@ ++/* Unit tests for dl-path-normalize.h. ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++check_one_guarded (const char *input, const char *expected, bool before) ++{ ++ size_t size = strlen (input) + 1; ++ struct support_next_to_fault ntf ++ = before ? support_next_to_fault_allocate_before (size) ++ : support_next_to_fault_allocate (size); ++ memcpy (ntf.buffer, input, size); ++ ++ size_t len = _dl_normalize_path (ntf.buffer); ++ ++ TEST_COMPARE (len, strlen (ntf.buffer)); ++ TEST_COMPARE_STRING (ntf.buffer, expected); ++ ++ support_next_to_fault_free (&ntf); ++} ++ ++static void ++check_one (const char *input, const char *expected) ++{ ++ /* Check that _dl_normalize_path does not access the string outside the ++ input argument. It checks for both over-runs and under-runs (the ++ latter for the case of '..' expansions). */ ++ check_one_guarded (input, expected, false); ++ check_one_guarded (input, expected, true); ++} ++ ++static int ++do_test (void) ++{ ++ /* Absolute paths. */ ++ check_one ("/", "/"); ++ check_one ("//", "/"); ++ check_one ("///", "/"); ++ check_one ("////", "/"); ++ check_one ("/a", "/a"); ++ check_one ("/a/", "/a"); ++ check_one ("/a//", "/a"); ++ check_one ("//a//b//", "/a/b"); ++ check_one ("/.", "/"); ++ check_one ("/./", "/"); ++ check_one ("/./a", "/a"); ++ check_one ("/a/./b", "/a/b"); ++ check_one ("/a/.", "/a"); ++ check_one ("/..", "/"); ++ check_one ("/../", "/"); ++ check_one ("/../a", "/a"); ++ check_one ("/a/..", "/"); ++ check_one ("/a/../", "/"); ++ check_one ("/a/../..", "/"); ++ check_one ("/a/../b", "/b"); ++ check_one ("/a/../../b", "/b"); ++ check_one ("/a/b/../../c", "/c"); ++ check_one ("/a/b/../c", "/a/c"); ++ check_one ("/a/b/c/../..", "/a"); ++ check_one ("/usr/lib/../lib64", "/usr/lib64"); ++ check_one ("/usr/lib/../lib64/", "/usr/lib64"); ++ check_one ("/usr/lib/..//lib64/", "/usr/lib64"); ++ check_one ("/usr/lib/../../lib64/", "/lib64"); ++ ++ /* "." and ".." are special only as complete components. */ ++ check_one ("/a..", "/a.."); ++ check_one ("/..a", "/..a"); ++ check_one ("/a/...", "/a/..."); ++ check_one ("/.../a", "/.../a"); ++ check_one ("/a./b", "/a./b"); ++ check_one (".a", ".a"); ++ check_one ("a.", "a."); ++ check_one ("..a", "..a"); ++ check_one ("...", "..."); ++ ++ /* Relative paths. */ ++ check_one ("", ""); ++ check_one (".", ""); ++ check_one ("./", ""); ++ check_one ("..", ".."); ++ check_one ("../", ".."); ++ check_one ("a", "a"); ++ check_one ("a/", "a"); ++ check_one ("a//b", "a/b"); ++ check_one ("a..", "a.."); ++ check_one ("./a", "a"); ++ check_one ("./.", ""); ++ check_one ("./..", ".."); ++ ++ check_one ("a/..", ""); ++ check_one ("a/../", ""); ++ check_one ("ab/..", ""); ++ check_one (".a/..", ""); ++ check_one ("a./..", ""); ++ check_one (".../..", ""); ++ check_one ("a/./..", ""); ++ check_one ("a/b/..", "a"); ++ check_one ("abc/def/..", "abc"); ++ ++ /* Appending a component to an emptied relative output must not produce a ++ leading '/' (the path must stay relative). */ ++ check_one ("a/../b", "b"); ++ check_one ("a/.././b", "b"); ++ check_one ("a/../lib64/b", "lib64/b"); ++ ++ /* Leading ".." components of a relative path are preserved and stack ++ instead of cancelling each other; ordinary components may follow and be ++ removed again afterwards. */ ++ check_one ("../a", "../a"); ++ check_one ("../..", "../.."); ++ check_one ("../../..", "../../.."); ++ check_one ("../../a", "../../a"); ++ check_one ("../a/..", ".."); ++ check_one ("../../a/..", "../.."); ++ check_one ("a/../../b", "../b"); ++ check_one ("a/b/../../..", ".."); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-origin-secure-evilmod.c b/elf/tst-origin-secure-evilmod.c +new file mode 100644 +index 0000000000..0913e32e21 +--- /dev/null ++++ b/elf/tst-origin-secure-evilmod.c +@@ -0,0 +1,28 @@ ++/* Module for tst-origin-secure (the attacker-controlled copy). ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "tst-origin-secure.h" ++ ++/* If the victim reports this copy, the loader opened the un-normalized rpath ++ and resolved it through the attacker's symlink -- i.e. the trusted-path ++ check was bypassed (bug 34360). */ ++int ++origin_secure_id (void) ++{ ++ return ORIGIN_SECURE_ID_ATTACKER; ++} +diff --git a/elf/tst-origin-secure-victim.c b/elf/tst-origin-secure-victim.c +new file mode 100644 +index 0000000000..601265aaa4 +--- /dev/null ++++ b/elf/tst-origin-secure-victim.c +@@ -0,0 +1,43 @@ ++/* Victim program for tst-origin-secure. ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "tst-origin-secure.h" ++ ++extern int __libc_enable_secure; ++ ++/* Report both which module was loaded and whether the loader ran in secure ++ mode, so the driver can tell a genuine trusted-path bypass apart from a run ++ that simply was not secure. ++ ++ The exit status is the combination of the ORIGIN_SECURE_STATUS_* bits: ++ ++ _NONE trusted copy, not secure ++ _ATTACKER attacker copy, not secure (the control run) ++ _SECURE trusted copy, secure (a fixed loader) ++ _SECURE | _ATTACKER attacker copy, secure (the bug: the raw ++ rpath was opened) */ ++int ++main (void) ++{ ++ int status = ORIGIN_SECURE_STATUS_NONE; ++ if (origin_secure_id () == ORIGIN_SECURE_ID_ATTACKER) ++ status |= ORIGIN_SECURE_STATUS_ATTACKER; ++ if (__libc_enable_secure != 0) ++ status |= ORIGIN_SECURE_STATUS_SECURE; ++ return status; ++} +diff --git a/elf/tst-origin-secure.c b/elf/tst-origin-secure.c +new file mode 100644 +index 0000000000..f304823b49 +--- /dev/null ++++ b/elf/tst-origin-secure.c +@@ -0,0 +1,203 @@ ++/* Test that AT_SECURE $ORIGIN rpath entries are looked up using the ++ normalized (trusted) path, not the raw expansion (bug 34360). ++ ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++ ++/* For a SUID/SGID program the loader only honors $ORIGIN in DT_RPATH when ++ the normalized expansion is rooted in a trusted directory. If the loader ++ opens the un-normalized string (that contains "../"), it might disagree ++ as soon as a path component is a symbolic link. ++ ++ This test builds the executable with the rpath: ++ ++ $ORIGIN/sub/../../../../..SLIBDIR/tst-origin-secure ++ ++ and runs it as BASE/a/b/victim, so $ORIGIN is BASE/a/b. Lexically the ++ five "../" pop $ORIGIN/sub back to "/" (BASE is /tmp/tst-origin-secure, ++ so $ORIGIN/sub is the five components tmp, tst-origin-secure, a, b, sub), ++ and the entry normalizes to the trusted SLIBDIR/tst-origin-secure. But ++ "sub" is a symlink pointing six levels deep under BASE, so opening the raw ++ string makes the kernel resolve the "../" through the symlink and land in ++ BASE/x1 SLIBDIR/tst-origin-secure instead. ++ ++ The "../" count in the rpath (see the Makefile) is therefore ++ depth(BASE) + 2 (for the "a/b" of $ORIGIN) + 1 (for "sub"); it is ++ independent of SLIBDIR, which is appended whole on both the raw and the ++ normalized side. ++ ++ A trusted copy of the module (ORIGIN_SECURE_ID_TRUSTED) is installed in ++ SLIBDIR/tst-origin-secure; an attacker copy (ORIGIN_SECURE_ID_ATTACKER) is ++ placed at the symlink-diverted location. The trusted subdirectory is ++ rooted under SLIBDIR (so it passes the trusted-path check) but is not ++ itself a default loader search directory. ++ ++ The victim reports, in its exit status, both which module it loaded and ++ whether it ran in secure mode. ++ ++ Secure mode is forced with glibc.rtld.enable_secure=1 so that no real ++ SUID/SGID binary is required. */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include "tst-origin-secure.h" ++ ++#define BASE "/tmp/tst-origin-secure" ++#define SONAME "libtst-origin-secure-mod.so" ++/* Subdirectory of the trusted SLIBDIR that the rpath normalizes to. It is ++ trusted (rooted under SLIBDIR) but not a default search directory. */ ++#define SUBDIR "tst-origin-secure" ++ ++static int ++run_victim (char *const *envp) ++{ ++ const char *victim = BASE "/a/b/victim"; ++ char *const argv[] = { (char *) victim, NULL }; ++ ++ struct support_capture_subprocess res ++ = support_capture_subprogram (victim, argv, envp); ++ /* The victim itself prints nothing; forward any loader diagnostics to ++ the test log. */ ++ if (res.err.length > 0) ++ printf ("info: victim stderr: %s\n", res.err.buffer); ++ int status = res.status; ++ support_capture_subprocess_free (&res); ++ return WIFEXITED (status) ? WEXITSTATUS (status) : -1; ++} ++ ++/* With SLIBDIR "/lib64" the container layout is: ++ ++ /lib64/tst-origin-secure/libtst-origin-secure-mod.so trusted copy (id 1) ++ BASE/a/b/victim the executable ++ BASE/a/b/sub -> BASE/x1/x2/x3/x4/x5/x6 six levels deep ++ BASE/x1/lib64/tst-origin-secure/libtst-origin-secure-mod.so ++ attacker copy (id 2) ++ BASE/x1/x2/x3/x4/x5/x6/ the symlink target ++ ++ The victim's rpath is $ORIGIN/sub + five "../" + /lib64/tst-origin-secure. */ ++static void ++do_prepare (int argc, char **argv) ++{ ++ const char *slibdir = support_slibdir_prefix; ++ const char *objelf = support_objdir_root; ++ ++ char *good_src = xasprintf ("%s/elf/libtst-origin-secure-mod.so", objelf); ++ char *evil_src = xasprintf ("%s/elf/tst-origin-secure-evilmod.so", objelf); ++ char *victim_src = xasprintf ("%s/elf/tst-origin-secure-victim", objelf); ++ ++ xmkdirp (BASE "/a/b", 0755); ++ xmkdirp (BASE "/x1/x2/x3/x4/x5/x6", 0755); ++ ++ /* Where the trusted copy lives (reached only via the normalized rpath, ++ SLIBDIR/SUBDIR) ... */ ++ char *good_dir = xasprintf ("%s/%s", slibdir, SUBDIR); ++ char *good_dst = xasprintf ("%s/%s", good_dir, SONAME); ++ xmkdirp (good_dir, 0755); ++ /* ... and where the raw, symlink-diverted lookup lands. */ ++ char *evil_dir = xasprintf ("%s/x1%s/%s", BASE, slibdir, SUBDIR); ++ char *evil_dst = xasprintf ("%s/%s", evil_dir, SONAME); ++ xmkdirp (evil_dir, 0755); ++ ++ /* support_copy_file preserves the source mode, so the victim stays ++ executable and the modules readable; no chmod is needed. */ ++ support_copy_file (good_src, good_dst); ++ support_copy_file (evil_src, evil_dst); ++ support_copy_file (victim_src, BASE "/a/b/victim"); ++ ++ unlink (BASE "/a/b/sub"); ++ xsymlink (BASE "/x1/x2/x3/x4/x5/x6", BASE "/a/b/sub"); ++ ++ free (good_src); ++ free (evil_src); ++ free (victim_src); ++ free (good_dir); ++ free (good_dst); ++ free (evil_dir); ++ free (evil_dst); ++} ++#define PREPARE do_prepare ++ ++static int ++do_test (void) ++{ ++ /* Control run: in normal mode $ORIGIN is honored without the trusted check, ++ so the raw rpath resolves through "sub" and the attacker copy is ++ loaded. */ ++ { ++ char *const env[] = { NULL }; ++ int rc = run_victim (env); ++ if (rc != ORIGIN_SECURE_STATUS_ATTACKER) ++ FAIL_EXIT1 ("control run returned status %d, expected %d (attacker " ++ "copy, not secure): the $ORIGIN layout does not reproduce " ++ "the divergence between the raw and the normalized rpath", ++ rc, ORIGIN_SECURE_STATUS_ATTACKER); ++ } ++ ++ /* Secure run: force AT_SECURE. A fixed loader normalizes the rpath to the ++ trusted SLIBDIR/SUBDIR and loads the trusted copy; a loader with the bug ++ opens the raw path, resolves "sub", and loads the attacker copy. */ ++ { ++ char *const env[] = { (char *) "GLIBC_TUNABLES=glibc.rtld.enable_secure=1", ++ NULL }; ++ int rc = run_victim (env); ++ switch (rc) ++ { ++ /* Secure, trusted copy loaded via the normalized rpath: fixed. */ ++ case ORIGIN_SECURE_STATUS_SECURE: ++ break; ++ ++ /* Secure, attacker copy loaded: the raw rpath was opened. */ ++ case ORIGIN_SECURE_STATUS_SECURE | ORIGIN_SECURE_STATUS_ATTACKER: ++ FAIL_EXIT1 ("secure-mode loader resolved the un-normalized rpath " ++ "through the attacker symlink (bug 34360)"); ++ ++ /* Not secure, attacker copy: exactly what the control run produced, so ++ the tunable did not engage and this run says nothing about the ++ trusted-path handling. */ ++ case ORIGIN_SECURE_STATUS_ATTACKER: ++ FAIL_UNSUPPORTED ("glibc.rtld.enable_secure=1 did not enable " ++ "secure mode (victim status %d)", rc); ++ ++ /* Not secure, yet the trusted copy was loaded, which is reachable only ++ through the normalized rpath, and only a secure loader normalizes it. ++ Fail rather than report UNSUPPORTED. */ ++ case ORIGIN_SECURE_STATUS_NONE: ++ FAIL_EXIT1 ("secure run loaded the trusted copy but the victim " ++ "reports not being secure: __libc_enable_secure is no " ++ "longer a valid proxy for secure mode"); ++ ++ /* Neither copy loaded: since the trusted copy is reachable only through ++ the normalized rpath, this means the rpath entry was not honored at ++ all. */ ++ default: ++ FAIL_EXIT1 ("secure run did not load the module via the normalized " ++ "rpath (victim status %d)", rc); ++ } ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-origin-secure.h b/elf/tst-origin-secure.h +new file mode 100644 +index 0000000000..2e2b944607 +--- /dev/null ++++ b/elf/tst-origin-secure.h +@@ -0,0 +1,41 @@ ++/* Definitions shared by the tst-origin-secure test, its victim and modules. ++ Copyright (C) 2026 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _TST_ORIGIN_SECURE_H ++#define _TST_ORIGIN_SECURE_H 1 ++ ++enum ++ { ++ ORIGIN_SECURE_ID_TRUSTED = 1, /* The copy installed in the trusted ++ SLIBDIR. */ ++ ORIGIN_SECURE_ID_ATTACKER = 2, /* The copy reachable only by resolving the ++ "sub" symlink. */ ++ }; ++ ++extern int origin_secure_id (void); ++ ++enum ++ { ++ ORIGIN_SECURE_STATUS_NONE = 0, ++ ORIGIN_SECURE_STATUS_ATTACKER = 1 << 0, /* The victim loaded attacker ++ rather than the trusted. */ ++ ORIGIN_SECURE_STATUS_SECURE = 1 << 1, /* The loader ran the victim in ++ secure mode. */ ++ }; ++ ++#endif +diff --git a/elf/tst-origin-secure.root/postclean.req b/elf/tst-origin-secure.root/postclean.req +new file mode 100644 +index 0000000000..e69de29bb2 diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 3b27328c21a..d8867bcff9a 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -75,6 +75,10 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0040-CVE-2026-18374-01.patch \ file://0041-CVE-2026-18374-02.patch \ file://0042-CVE-2026-8674.patch \ + file://0043-CVE-2026-86805-CVE-2026-95818-01.patch \ + file://0044-CVE-2026-86805-CVE-2026-95818-02.patch \ + file://0045-CVE-2026-86805-CVE-2026-95818-03.patch \ + file://0046-CVE-2026-86805-CVE-2026-95818-04.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101713 Received: from mta-64-227.siemens.flowmailer.net (mta-64-227.siemens.flowmailer.net [185.136.64.227]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2249.1792709333561021653 for ; Thu, 22 Oct 2026 15:48:53 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=VWq5IB2K; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.227, mailfrom: fm-256628-20261022224851bcf25f8e8300020732-rvaa3p@rts-flowmailer.siemens.com) Received: by mta-64-227.siemens.flowmailer.net with ESMTPSA id 20261022224851bcf25f8e8300020732 for ; Fri, 23 Oct 2026 00:48:52 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=yCLGE6IoO8plch1L5S+thnqZ3vR8A9IATlQ8JMfirK4=; b=VWq5IB2KJS+jtofQ/PM4IymUl9XoKHiigZest/bCCbVKDGTdskTf3imguG9TDm76iu4o2X FG+oxd2mqGW0YOrxLpLlA8uAJB20nCYmKYAASy6zr+RKHwkQsTowGT8VpPGx/8Yhsy3MUJLr 9cWuvEzYd3QwiP8XebsxhHVe6GYjLryVlmgvJcS44LBsPySLZT2O503P3ZA4aXuen9dgJ/bv Fhnx/RPAw2N0h2DjDTt9Ogib9MATf8p8l21605WskMc35FWPGoVF7aVSFCg8i7mB91IkFPgu xzIbpWXF8ZWTDKeJA6Qo3tavTpQVfdbpy0JorAOy0nVEvIz/afBds5hQ==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 13/15] glibc: patch CVE-2026-89092 Date: Fri, 23 Oct 2026 00:47:06 +0200 Message-ID: <20261022224711.3783258-13-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:49:02 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248468 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0047-CVE-2026-89092.patch | 245 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 246 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0047-CVE-2026-89092.patch diff --git a/meta/recipes-core/glibc/glibc/0047-CVE-2026-89092.patch b/meta/recipes-core/glibc/glibc/0047-CVE-2026-89092.patch new file mode 100644 index 00000000000..8df9dc904e4 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0047-CVE-2026-89092.patch @@ -0,0 +1,245 @@ +From fa3ea0362354af7370abb5fe8c6f31a32a73af8e Mon Sep 17 00:00:00 2001 +From: DJ Delorie +Date: Mon, 28 Sep 2026 14:27:16 +0200 +Subject: [PATCH] CVE-2026-89092: nscd: replace alloca with malloc in aicache, + hstcache + +This changes the alloca fallback to a malloc fallback +in the addrinfo and host cache code. + +This fixes bug 34624. + +Co-authored-by: Florian Weimer +Reviewed-by: Adhemerval Zanella +(cherry picked from commit cbf59b836645b6ac69ad8c47a560598bc4942ecc) + +CVE: CVE-2026-89092 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=fa3ea0362354af7370abb5fe8c6f31a32a73af8e] +Signed-off-by: Peter Marko +--- + nscd/aicache.c | 27 ++++++++++++++++++--------- + nscd/hstcache.c | 47 ++++++++++++++++++++++++++++++++++------------- + 2 files changed, 52 insertions(+), 22 deletions(-) + +diff --git a/nscd/aicache.c b/nscd/aicache.c +index 6f47236627..1ac86b86d8 100644 +--- a/nscd/aicache.c ++++ b/nscd/aicache.c +@@ -93,7 +93,9 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + int32_t ttl = INT32_MAX; + ssize_t total = 0; + char *key_copy = NULL; +- bool alloca_used = false; ++ /* If not NULL, dataset is a temporary dataset not inserted into the ++ database, and needs to be free'd. */ ++ void *dataset_alloc = NULL; + time_t timeout = MAX_TIMEOUT_VALUE; + + while (!no_more) +@@ -164,10 +166,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + /* We cannot permanently add the result in the moment. But + we can provide the result as is. Store the data in some + temporary memory. */ +- dataset = (struct dataset *) alloca (total + req->key_len); ++ dataset = (struct dataset *) malloc (total + req->key_len); ++ if (dataset == NULL) ++ goto out; + + /* We cannot add this record to the permanent database. */ +- alloca_used = true; ++ dataset_alloc = dataset; + } + + /* Fill in the address and address families. */ +@@ -336,10 +340,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + /* We cannot permanently add the result in the moment. But + we can provide the result as is. Store the data in some + temporary memory. */ +- dataset = (struct dataset *) alloca (total + req->key_len); ++ dataset = (struct dataset *) malloc (total + req->key_len); ++ if (dataset == NULL) ++ goto out; + + /* We cannot add this record to the permanent database. */ +- alloca_used = true; ++ dataset_alloc = dataset; + } + + /* Fill in the address and address families. */ +@@ -391,8 +397,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + resp)) == 0) + { + /* The data has not changed. We will just bump the +- timeout value. Note that the new record has been +- allocated on the stack and need not be freed. */ ++ timeout value. */ + dh->timeout = dataset->head.timeout; + dh->ttl = dataset->head.ttl; + ++dh->nreloads; +@@ -410,7 +415,9 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + key_copy = (char *) newp + (key_copy - (char *) dataset); + + dataset = memcpy (newp, dataset, total + req->key_len); +- alloca_used = false; ++ ++ free (dataset_alloc); ++ dataset_alloc = NULL; + } + + /* Mark the old record as obsolete. */ +@@ -488,7 +495,7 @@ next_nip: + out: + __resolv_context_put (ctx); + +- if (dataset != NULL && !alloca_used) ++ if (dataset != NULL && dataset_alloc == NULL) + { + /* If necessary, we also propagate the data to disk. */ + if (db->persistent) +@@ -514,6 +521,8 @@ next_nip: + scratch_buffer_free (&tmpbuf4); + scratch_buffer_free (&canonbuf); + ++ free (dataset_alloc); ++ + return timeout; + } + +diff --git a/nscd/hstcache.c b/nscd/hstcache.c +index 7b3a8ab1ea..11af5cb34a 100644 +--- a/nscd/hstcache.c ++++ b/nscd/hstcache.c +@@ -15,7 +15,6 @@ + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +-#include + #include + #include + #include +@@ -187,7 +186,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + /* Determine the I/O structure. */ + size_t h_name_len = strlen (hst->h_name) + 1; + size_t h_aliases_cnt; +- uint32_t *h_aliases_len; ++ uint32_t *h_aliases_len = NULL; + size_t h_addr_list_cnt; + char *addresses; + char *aliases; +@@ -201,7 +200,13 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt) + ++h_aliases_cnt; + /* Determine the length of all aliases. */ +- h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t)); ++ if (h_aliases_cnt > 0) ++ { ++ h_aliases_len = (uint32_t *) reallocarray (NULL, h_aliases_cnt, ++ sizeof (uint32_t)); ++ if (h_aliases_len == NULL) ++ return MAX_TIMEOUT_VALUE; ++ } + total = 0; + for (cnt = 0; cnt < h_aliases_cnt; ++cnt) + { +@@ -215,8 +220,11 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + ++h_addr_list_cnt; + + if (h_addr_list_cnt == 0) +- /* Invalid entry. */ +- return MAX_TIMEOUT_VALUE; ++ { ++ /* Invalid entry. */ ++ free (h_aliases_len); ++ return MAX_TIMEOUT_VALUE; ++ } + + total += (sizeof (struct dataset) + + h_name_len +@@ -227,8 +235,10 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + change. Allocate memory on the cache since it is likely + discarded anyway. If it turns out to be necessary to have a + new record we can still allocate real memory. */ +- bool alloca_used = false; + dataset = NULL; ++ /* If not NULL, dataset is a temporary dataset not inserted into ++ the database, and needs to be free'd. */ ++ void *dataset_alloc = NULL; + + /* If the record contains more than one IP address (used for + load balancing etc) don't cache the entry. This is something +@@ -244,10 +254,15 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + /* We cannot permanently add the result in the moment. But + we can provide the result as is. Store the data in some + temporary memory. */ +- dataset = (struct dataset *) alloca (total + req->key_len); ++ dataset = (struct dataset *) malloc (total + req->key_len); ++ if (dataset == NULL) ++ { ++ free (h_aliases_len); ++ return MAX_TIMEOUT_VALUE; ++ } + + /* We cannot add this record to the permanent database. */ +- alloca_used = true; ++ dataset_alloc = dataset; + } + + timeout = datahead_init_pos (&dataset->head, total + req->key_len, +@@ -270,7 +285,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + cp = dataset->strdata; + + cp = mempcpy (cp, hst->h_name, h_name_len); +- cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t)); ++ if (h_aliases_cnt > 0) ++ cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t)); + + /* The normal addresses first. */ + addresses = cp; +@@ -282,6 +298,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + for (cnt = 0; cnt < h_aliases_cnt; ++cnt) + cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]); + ++ free (h_aliases_len); ++ + assert (cp + == dataset->strdata + total - offsetof (struct dataset, + strdata)); +@@ -307,8 +325,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + dh->allocsize - offsetof (struct dataset, resp)) == 0) + { + /* The data has not changed. We will just bump the +- timeout value. Note that the new record has been +- allocated on the stack and need not be freed. */ ++ timeout value. */ + assert (h_addr_list_cnt == 1); + dh->ttl = dataset->head.ttl; + dh->timeout = dataset->head.timeout; +@@ -334,7 +351,9 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + key_copy = (char *) newp + (key_copy - (char *) dataset); + + dataset = memcpy (newp, dataset, total + req->key_len); +- alloca_used = false; ++ ++ free (dataset_alloc); ++ dataset_alloc = NULL; + } + } + +@@ -362,7 +381,7 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + the current cache handling cannot handle and it is more than + questionable whether it is worthwhile complicating the cache + handling just for handling such a special case. */ +- if (! alloca_used) ++ if (dataset_alloc == NULL) + { + /* If necessary, we also propagate the data to disk. */ + if (db->persistent) +@@ -393,6 +412,8 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req, + + pthread_rwlock_unlock (&db->lock); + } ++ free (dataset_alloc); ++ dataset_alloc = NULL; + } + + if (__builtin_expect (!all_written, 0) && debug_level > 0) diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index d8867bcff9a..66250fbdb2a 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -79,6 +79,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0044-CVE-2026-86805-CVE-2026-95818-02.patch \ file://0045-CVE-2026-86805-CVE-2026-95818-03.patch \ file://0046-CVE-2026-86805-CVE-2026-95818-04.patch \ + file://0047-CVE-2026-89092.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101714 Received: from mta-64-227.siemens.flowmailer.net (mta-64-227.siemens.flowmailer.net [185.136.64.227]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.2251.1792709341248369225 for ; Thu, 22 Oct 2026 15:49:01 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=qJiJL2Hl; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.227, mailfrom: fm-256628-20261022224859d114baa41d0002075a-docqtj@rts-flowmailer.siemens.com) Received: by mta-64-227.siemens.flowmailer.net with ESMTPSA id 20261022224859d114baa41d0002075a for ; Fri, 23 Oct 2026 00:48:59 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=KpSKysK7KxeygRV7lXfTZFocbALq7bK+04Mt/kJkb6w=; b=qJiJL2Hl+iD9Lt4Gr4A7j+WjeeZ3pXq8DfxaKJqiHQ44sh9SNnDQWSaifuZdMrepMpFowG +nGmEhbNkCjz2zco+q4A8QRNNWEf4F1zI4WUxTHtKoXuMWA49matVhs4JXDrHnoNErLmvxJI CbutXZ/pjE9NTqRu0RPM2J0n18PXGIKf4qTwwbQ6Df5HgSq1i/rB/3g0En517f5cGHJnefRl 56HW6U4xQjv2ccSiPOZRNgcvPoRg3v1FOPp7T1UdQWatGsD1b8wig1VeqJmj4SKiDbY5WkV7 Ks6ufDeT2KyMBTAiFAFHJ5yNzBNT0uxAgTXEF2y0WK8WfmefbAFquxYg==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 14/15] glibc: patch CVE-2026-97399 Date: Fri, 23 Oct 2026 00:47:07 +0200 Message-ID: <20261022224711.3783258-14-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:49:02 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248469 From: Peter Marko Pick patch referencing this CVE from 3.41 branch (oldest release still receiving security updates). Signed-off-by: Peter Marko --- .../glibc/glibc/0048-CVE-2026-97399.patch | 128 ++++++++++++++++++ meta/recipes-core/glibc/glibc_2.39.bb | 1 + 2 files changed, 129 insertions(+) create mode 100644 meta/recipes-core/glibc/glibc/0048-CVE-2026-97399.patch diff --git a/meta/recipes-core/glibc/glibc/0048-CVE-2026-97399.patch b/meta/recipes-core/glibc/glibc/0048-CVE-2026-97399.patch new file mode 100644 index 00000000000..c5aec0802c9 --- /dev/null +++ b/meta/recipes-core/glibc/glibc/0048-CVE-2026-97399.patch @@ -0,0 +1,128 @@ +From f247c0a2fb5b3e48a771d2d23efc9a45c64e957d Mon Sep 17 00:00:00 2001 +From: Sachin Monga +Date: Thu, 1 Oct 2026 00:51:23 +0530 +Subject: [PATCH] powerpc: Fix one byte overread in strncasecmp (bug 34683, + CVE-2026-97399) + +The Power8 strncasecmp (strcasecmp.S with USE_AS_STRNCASECMP) touches +s1[n]/s2[n] in three places when the first n bytes compare equal and +contain no NUL: L(loop) preloads the next byte before its bdnz; +L(loop1) increments then loads before its bdnz; and L(bytebybyte) loads +s1[0]/s2[0] before checking r5. A caller that maps exactly n readable bytes +can get SIGSEGV if byte n falls on an unmapped page. + +The L(bytebybyte) site was identified by Florian Weimer; the +original AISLE report covered only the two loops. + +Fix all three sites: guard L(bytebybyte) with a r5 == 0 check, split the +bdnz/load pairs in L(loop) and L(loop1) so the load only runs when the +count is still positive, and preload rCHAR1/rCHAR2 in L(lessthan4) after +confirming r5 != 0. strcasecmp is unaffected; its generated code is +unchanged. + +Add string/test-strncasecmp-nonarray.c, built on the test-Xncmp-nonarray.c +skeleton: maps a PROT_NONE page past both buffers and sweeps all start +offsets and lengths. Runs as an xtest. + +Reported-by: AISLE in partnership with Red Hat +Suggested-by: Florian Weimer +(cherry picked from commit e622f82ea8797704ac8f761f88ed3e429e97fedd) + +CVE: CVE-2026-97399 +Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=f247c0a2fb5b3e48a771d2d23efc9a45c64e957d] +Signed-off-by: Peter Marko +--- + string/Makefile | 4 +-- + string/test-strncasecmp-nonarray.c | 4 +++ + sysdeps/powerpc/powerpc64/power8/strcasecmp.S | 25 +++++++++++++++---- + 3 files changed, 26 insertions(+), 7 deletions(-) + create mode 100644 string/test-strncasecmp-nonarray.c + +diff --git a/string/Makefile b/string/Makefile +index c83b195e2e..d7437cd915 100644 +--- a/string/Makefile ++++ b/string/Makefile +@@ -238,8 +238,8 @@ endif + # This test allocates a lot of memory and can run for a long time. + xtests += tst-strcoll-overflow + +-# This test runs for a long time. +-xtests += test-strncmp-nonarray ++# These tests run for a long time. ++xtests += test-strncasecmp-nonarray test-strncmp-nonarray + + # This test needs libdl. + ifeq (yes,$(build-shared)) +diff --git a/string/test-strncasecmp-nonarray.c b/string/test-strncasecmp-nonarray.c +new file mode 100644 +index 0000000000..d68e58d5ec +--- /dev/null ++++ b/string/test-strncasecmp-nonarray.c +@@ -0,0 +1,4 @@ ++#define TEST_IDENTIFIER strncasecmp ++#define TEST_NAME "strncasecmp" ++typedef char CHAR; ++#include "test-Xncmp-nonarray.c" +diff --git a/sysdeps/powerpc/powerpc64/power8/strcasecmp.S b/sysdeps/powerpc/powerpc64/power8/strcasecmp.S +index 7ce53407b8..838b8bf75f 100644 +--- a/sysdeps/powerpc/powerpc64/power8/strcasecmp.S ++++ b/sysdeps/powerpc/powerpc64/power8/strcasecmp.S +@@ -355,6 +355,14 @@ L(bytebybyte): + offset and string descriptors are only updated in the end + of loop unrolling. */ + ld rLOC, LOCALE_CTYPE_TOLOWER(rLOC) ++#ifdef USE_AS_STRNCASECMP ++ /* This entry point can be reached from the vector loop with ++ r5 == 0 (the last vector chunk ended exactly at the `n' ++ boundary). Do not read s1[0]/s2[0] in that case: those ++ bytes are s1[n]/s2[n], one past the caller's bound. */ ++ cmpdi cr7, r5, 0 ++ beq cr7, L(retnull) ++#endif + lbz rCHAR1, 0(rSTR1) /* Load char from s1 */ + lbz rCHAR2, 0(rSTR2) /* Load char from s2 */ + #ifdef USE_AS_STRNCASECMP +@@ -405,19 +413,23 @@ L(loop): + cmpw cr1, rLWR1, rLWR2 + crorc 4*cr1+eq,eq,4*cr1+eq + beq cr1, L(done) ++#ifdef USE_AS_STRNCASECMP ++ /* Test the remaining count before touching the next byte. */ ++ bdnz L(loop_load) ++ b L(lessthan4) ++L(loop_load): ++#endif + lbz rCHAR1, 0(rSTR1) /* Load char from s1 */ + lbz rCHAR2, 0(rSTR2) /* Load char from s2 */ +-#ifdef USE_AS_STRNCASECMP +- bdnz L(loop) +-#else + b L(loop) +-#endif + #ifdef USE_AS_STRNCASECMP + L(lessthan4): + clrldi r5, r5, 62 + cmpdi cr7, r5, 0 + beq cr7, L(retnull) + mtctr r5 ++ lbz rCHAR1, 0(rSTR1) ++ lbz rCHAR2, 0(rSTR2) + L(loop1): + cmpdi rCHAR1, 0 + sldi rADDR1, rCHAR1, 2 +@@ -427,11 +439,14 @@ L(loop1): + cmpw cr1, rLWR1, rLWR2 + crorc 4*cr1+eq,eq,4*cr1+eq + beq cr1, L(done) ++ bdnz L(loop1_load) ++ b L(retnull) ++L(loop1_load): + addi rSTR1, rSTR1, 1 + addi rSTR2, rSTR2, 1 + lbz rCHAR1, 0(rSTR1) + lbz rCHAR2, 0(rSTR2) +- bdnz L(loop1) ++ b L(loop1) + #endif + L(done): + subf r0, rLWR2, rLWR1 diff --git a/meta/recipes-core/glibc/glibc_2.39.bb b/meta/recipes-core/glibc/glibc_2.39.bb index 66250fbdb2a..3e377f66875 100644 --- a/meta/recipes-core/glibc/glibc_2.39.bb +++ b/meta/recipes-core/glibc/glibc_2.39.bb @@ -80,6 +80,7 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \ file://0045-CVE-2026-86805-CVE-2026-95818-03.patch \ file://0046-CVE-2026-86805-CVE-2026-95818-04.patch \ file://0047-CVE-2026-89092.patch \ + file://0048-CVE-2026-97399.patch \ " S = "${WORKDIR}/git" B = "${WORKDIR}/build-${TARGET_SYS}" From patchwork Thu Oct 22 22:47:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marko, Peter" X-Patchwork-Id: 101715 Received: from mta-64-227.siemens.flowmailer.net (mta-64-227.siemens.flowmailer.net [185.136.64.227]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.2362.1792709343926508290 for ; Thu, 22 Oct 2026 15:49:04 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=peter.marko@siemens.com header.s=fm2 header.b=RX5cx5jn; spf=pass (domain: rts-flowmailer.siemens.com, ip: 185.136.64.227, mailfrom: fm-256628-2026102222490295e88cb23d000207fb-rpc1wk@rts-flowmailer.siemens.com) Received: by mta-64-227.siemens.flowmailer.net with ESMTPSA id 2026102222490295e88cb23d000207fb for ; Fri, 23 Oct 2026 00:49:02 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=peter.marko@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=XAw7Gv3GbpODWFXSo+hl/13YFBSx2+RpjTpCQxjfMbI=; b=RX5cx5jnZIsdI0dbipzkkNepufOqkz+FWoEN3X9VZCPC63XnwAImYW8vfs8xOJdaePlUDp 8Dz9Xo5gq1Yc4faH/H+JgiOtZOwQ3qs4Fh8CFbP9MeALsYKObA5AWBh3oC/adjMdjWKhrsUh X6BCk1esu+w+24tXK2VmtdSKYsGu3avivp/LpehkeXmqpQIazqmH52jNPvWbpvZ/QD9dosBn 7c1Tbwo9v4AvazD/VwoRXoVmTEIdYstLQ5RgU31JHRuxyb7z2QJ6tVXHwP+mXZCG98UlQ/on Y9DauPIPpo3M9HuZcqOtZBQBiffyzMHJlUDF9euSnWrEWqhNY5gNXesQ==; From: Peter Marko To: openembedded-core@lists.openembedded.org Cc: Peter Marko Subject: [scarthgap][PATCH 15/15] glibc: stable 2.39 branch updates to b7a0de2c8f Date: Fri, 23 Oct 2026 00:47:08 +0200 Message-ID: <20261022224711.3783258-15-peter.marko@siemens.com> In-Reply-To: <20261022224711.3783258-1-peter.marko@siemens.com> References: <20261022224711.3783258-1-peter.marko@siemens.com> MIME-Version: 1.0 X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-256628:519-21489:flowmailer List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Thu, 22 Oct 2026 22:49:12 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/248470 From: Peter Marko Update SRCREV to pull the latest fixes from the upstream release/2.44/master branch. This branch does not seem to receive security fixes anymore, but still got two new commits during last months. Commits between the old SRCREV (be1e627cd7) and the new SRCREV (b7a0de2c8f): b7a0de2c8f powerpc: Fix off-by-one in AT_HWCAP4 loop in _dl_procinfo d9eaad3515 rtld: cache cpuid results on the stack for intel Testing Results: (note that the comparison is done against yocto-20.0.21, so includes testing of last 14 CVE patches) +--------------+--------+--------+------+ | Result | Before | After | Diff | +--------------+--------+--------+------+ | PASS | 4933 | 4941 | +8 | | FAIL | 221 | 223 | +2 | | XFAIL | 16 | 16 | 0 | | XPASS | 4 | 4 | 0 | | UNSUPPORTED | 227 | 227 | 0 | +--------------+--------+--------+------+ Changes in testcases: Before After Source (no change in already existing tests, flaky test filtered by 3 runs) elf/tst-dl-path-normalize --- PASS CVE-2026-86805/CVE-2026-95818 elf/tst-tunables-enable_secure --- PASS CVE-2026-86805/CVE-2026-95818 test harness iconvdata/tst-jisx0213-progress --- PASS CVE-2026-77117/CVE-2026-80489 libio/bug-wgenops-bz33998.test-result --- PASS CVE-2026-5928 libio/tst-fopen-ccs-empty --- PASS CVE-2026-18374 posix/tst-wordexp-append --- PASS CVE-2026-6368 stdio-common/tst-vfscanf-bz34008 --- PASS CVE-2026-5450 stdlib/tst-strfmon-bug34510 --- PASS CVE-2026-19499 elf/tst-origin-secure --- FAIL CVE-2026-86805/CVE-2026-95818 posix/tst-wordexp-tilde --- FAIL CVE-2026-6791 The two new tests which do not pass when running glibc-testsuite will pass under following conditions: * FAIL -> UNSUPPORTED: removing patch 0022 fixes these tests this fixes 41 FAIL -> 6 PASS + 35 UNSUPPORTED and can be sent as separate patch if requested see OE-Core rev: 5eb80f3c562f6e395562c52df67fab60ae0ff32b * UNSUPPORTED -> PASS: running natively qemu-user doesn't support the call test-container makes to create its isolated environment (unshare(CLONE_NEWUSER)) running natively is possible when target arch equals to host arch Signed-off-by: Peter Marko --- meta/recipes-core/glibc/glibc-version.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta/recipes-core/glibc/glibc-version.inc b/meta/recipes-core/glibc/glibc-version.inc index 5d57dafed0a..1f4f372c13b 100644 --- a/meta/recipes-core/glibc/glibc-version.inc +++ b/meta/recipes-core/glibc/glibc-version.inc @@ -1,6 +1,6 @@ SRCBRANCH ?= "release/2.39/master" PV = "2.39+git" -SRCREV_glibc ?= "be1e627cd72db31161a3b4ce1c8114674f0895eb" +SRCREV_glibc ?= "b7a0de2c8f68722cfdfc735b8358a3a6559ec0eb" SRCREV_localedef ?= "cba02c503d7c853a38ccfb83c57e343ca5ecd7e5" GLIBC_GIT_URI ?= "git://sourceware.org/git/glibc.git;protocol=https"