* [OE-core][scarthgap 01/21] libpng: Fix CVE-2026-33416
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 02/21] busybox: Fix CVE-2026-29004 Jeremy Rosen
` (19 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: Zahir Hussain <mail2szahir@gmail.com>
Backport fixes for CVE-2026-33416
Backport patches from security debian tracker [1] also mentioned at NVD Report [2]
[1] https://security-tracker.debian.org/tracker/CVE-2026-33416
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-33416
Add below patches to fix the CVE:
CVE-2026-33416-01.patch
CVE-2026-33416-02.patch
CVE-2026-33416-03.patch
CVE-2026-33416-04.patch
Signed-off-by: Sourav Kumar Pramanik <souravkumar.pramanik@bmwtechworks.in>
Signed-off-by: Zahir Hussain <zahir.basha@kpit.com>
Signed-off-by: Jérémy Rosen <jeremy.rosen@smile.fr>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
.../libpng/files/CVE-2026-33416-01.patch | 143 +++++++++++++++
.../libpng/files/CVE-2026-33416-02.patch | 53 ++++++
.../libpng/files/CVE-2026-33416-03.patch | 163 ++++++++++++++++++
.../libpng/files/CVE-2026-33416-04.patch | 53 ++++++
.../libpng/libpng_1.6.42.bb | 4 +
5 files changed, 416 insertions(+)
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2026-33416-01.patch
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2026-33416-02.patch
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2026-33416-03.patch
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2026-33416-04.patch
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2026-33416-01.patch b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-01.patch
new file mode 100644
index 0000000000..a60a8d6b5b
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-01.patch
@@ -0,0 +1,143 @@
+From 23019269764e35ed8458e517f1897bd3c54820eb Mon Sep 17 00:00:00 2001
+From: Oblivionsage <cookieandcream560@gmail.com>
+Date: Sun, 15 Mar 2026 10:35:29 +0100
+Subject: [PATCH] fix: Resolve use-after-free on `png_ptr->trans_alpha`
+
+The function `png_set_tRNS` sets `png_ptr->trans_alpha` to point at
+`info_ptr->trans_alpha` directly, so both structs share the same heap
+buffer. If the application calls `png_free_data(PNG_FREE_TRNS)`, or if
+`png_set_tRNS` is called a second time, the buffer is freed through
+`info_ptr` while `png_ptr` still holds a dangling reference. Any
+subsequent row read that hits the function `png_do_expand_palette` will
+dereference freed memory.
+
+The fix gives `png_struct` its own allocation instead of aliasing the
+`info_ptr` pointer. This was already flagged with a TODO in
+`png_handle_tRNS` ("horrible side effect ... Fix this.") but it was
+never addressed.
+
+Verified with AddressSanitizer. All 34 existing tests pass without
+regressions.
+
+CVE: CVE-2026-33416
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/23019269764e35ed8458e517f1897bd3c54820eb]
+Comment: Refreshed hunk to match latest scarthgap
+
+Reviewed-by: Cosmin Truta <ctruta@gmail.com>
+Signed-off-by: Cosmin Truta <ctruta@gmail.com>
+Signed-off-by: Sourav Kumar Pramanik <Souravkumar.Pramanik@bmwtechworks.in>
+Signed-off-by: Zahir Hussain <zahir.basha@kpit.com>
+---
+ pngread.c | 11 +++++------
+ pngrutil.c | 4 ----
+ pngset.c | 31 +++++++++++++++++++------------
+ pngwrite.c | 6 ++++++
+ 4 files changed, 30 insertions(+), 22 deletions(-)
+
+diff --git a/pngread.c b/pngread.c
+index 01b731d8eb..0086edf6cf 100644
+--- a/pngread.c
++++ b/pngread.c
+@@ -968,12 +968,11 @@ png_read_destroy(png_structrp png_ptr)
+
+ #if defined(PNG_tRNS_SUPPORTED) || \
+ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+- if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)
+- {
+- png_free(png_ptr, png_ptr->trans_alpha);
+- png_ptr->trans_alpha = NULL;
+- }
+- png_ptr->free_me &= ~PNG_FREE_TRNS;
++ /* png_ptr->trans_alpha is always independently allocated (not aliased
++ * with info_ptr->trans_alpha), so free it unconditionally.
++ */
++ png_free(png_ptr, png_ptr->trans_alpha);
++ png_ptr->trans_alpha = NULL;
+ #endif
+
+ inflateEnd(&png_ptr->zstream);
+diff --git a/pngrutil.c b/pngrutil.c
+index 366379b991..a19507bf1b 100644
+--- a/pngrutil.c
++++ b/pngrutil.c
+@@ -1905,10 +1905,6 @@ png_handle_tRNS(png_structrp png_ptr, pn
+ return;
+ }
+
+- /* TODO: this is a horrible side effect in the palette case because the
+- * png_struct ends up with a pointer to the tRNS buffer owned by the
+- * png_info. Fix this.
+- */
+ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
+ &(png_ptr->trans_color));
+ }
+diff --git a/pngset.c b/pngset.c
+index 4b78b8960c..47883684e4 100644
+--- a/pngset.c
++++ b/pngset.c
+@@ -990,28 +990,36 @@ png_set_tRNS(png_structrp png_ptr, png_i
+
+ if (trans_alpha != NULL)
+ {
+- /* It may not actually be necessary to set png_ptr->trans_alpha here;
+- * we do it for backward compatibility with the way the png_handle_tRNS
+- * function used to do the allocation.
+- *
+- * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
+- * relies on png_set_tRNS storing the information in png_struct
+- * (otherwise it won't be there for the code in pngrtran.c).
+- */
+-
+ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
+
+ if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+ {
+- /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
++ /* Allocate info_ptr's copy of the transparency data. */
+ info_ptr->trans_alpha = png_voidcast(png_bytep,
+ png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+ memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+-
+ info_ptr->free_me |= PNG_FREE_TRNS;
+ info_ptr->valid |= PNG_INFO_tRNS;
++
++
++ /* Allocate an independent copy for png_struct, so that the
++ * lifetime of png_ptr->trans_alpha is decoupled from the
++ * lifetime of info_ptr->trans_alpha. Previously these two
++ * pointers were aliased, which caused a use-after-free if
++ * png_free_data freed info_ptr->trans_alpha while
++ * png_ptr->trans_alpha was still in use by the row transform
++ * functions (e.g. png_do_expand_palette).
++ */
++ png_free(png_ptr, png_ptr->trans_alpha);
++ png_ptr->trans_alpha = png_voidcast(png_bytep,
++ png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
++ memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
++ }
++ else
++ {
++ png_free(png_ptr, png_ptr->trans_alpha);
++ png_ptr->trans_alpha = NULL;
+ }
+- png_ptr->trans_alpha = info_ptr->trans_alpha;
+ }
+
+ if (trans_color != NULL)
+diff --git a/pngwrite.c b/pngwrite.c
+index 5fc77d91f7..84af1e73fb 100644
+--- a/pngwrite.c
++++ b/pngwrite.c
+@@ -977,6 +977,12 @@ png_write_destroy(png_structrp png_ptr)
+ png_ptr->chunk_list = NULL;
+ #endif
+
++#if defined(PNG_tRNS_SUPPORTED)
++ /* Free the independent copy of trans_alpha owned by png_struct. */
++ png_free(png_ptr, png_ptr->trans_alpha);
++ png_ptr->trans_alpha = NULL;
++#endif
++
+ /* The error handling and memory handling information is left intact at this
+ * point: the jmp_buf may still have to be freed. See png_destroy_png_struct
+ * for how this happens.
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2026-33416-02.patch b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-02.patch
new file mode 100644
index 0000000000..e746293bf2
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-02.patch
@@ -0,0 +1,53 @@
+From a3a21443ed12bfa1ef46fa0d4fb2b74a0fa34a25 Mon Sep 17 00:00:00 2001
+From: Oblivionsage <cookieandcream560@gmail.com>
+Date: Tue, 17 Mar 2026 08:55:18 +0100
+Subject: [PATCH] fix: Initialize tail bytes in `trans_alpha` buffers
+
+Although the arrays `info_ptr->trans_alpha` and `png_ptr->trans_alpha`
+are allocated 256 bytes, only `num_trans` bytes are copied.
+The remaining entries were left uninitialized. Set them to 0xff (fully
+opaque) before copying, which matches the conventional treatment of
+entries beyond `num_trans`.
+
+This is a follow-up to the previous use-after-free fix.
+
+CVE: CVE-2026-33416
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/a3a21443ed12bfa1ef46fa0d4fb2b74a0fa34a25]
+Comment: Refreshed hunk to match latest scarthgap
+
+Reported-by: Cosmin Truta <ctruta@gmail.com>
+Reviewed-by: Cosmin Truta <ctruta@gmail.com>
+Signed-off-by: Cosmin Truta <ctruta@gmail.com>
+Signed-off-by: Sourav Kumar Pramanik <Souravkumar.Pramanik@bmwtechworks.in>
+Signed-off-by: Zahir Hussain <zahir.basha@kpit.com>
+---
+ pngset.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/pngset.c b/pngset.c
+index 47883684e4..dccc6498d7 100644
+--- a/pngset.c
++++ b/pngset.c
+@@ -994,9 +994,13 @@ png_set_tRNS(png_structrp png_ptr, png_i
+
+ if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+ {
+- /* Allocate info_ptr's copy of the transparency data. */
++ /* Allocate info_ptr's copy of the transparency data.
++ * Initialize all entries to fully opaque (0xff), then overwrite
++ * the first num_trans entries with the actual values.
++ */
+ info_ptr->trans_alpha = png_voidcast(png_bytep,
+ png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
++ memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
+ memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+ info_ptr->free_me |= PNG_FREE_TRNS;
+ info_ptr->valid |= PNG_INFO_tRNS;
+@@ -1013,6 +1017,7 @@ png_set_tRNS(png_structrp png_ptr, png_i
+ png_free(png_ptr, png_ptr->trans_alpha);
+ png_ptr->trans_alpha = png_voidcast(png_bytep,
+ png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
++ memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
+ memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+ }
+ else
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2026-33416-03.patch b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-03.patch
new file mode 100644
index 0000000000..21ce35dcd1
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-03.patch
@@ -0,0 +1,163 @@
+From 7ea9eea884a2328cc7fdcb3c0c00246a50d90667 Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Fri, 20 Mar 2026 17:37:22 +0200
+Subject: [PATCH] fix: Resolve use-after-free on `png_ptr->palette`
+
+Give `png_struct` its own independently-allocated copy of the palette
+buffer, decoupling it from `info_struct`'s palette. Allocate both
+copies with `png_calloc` to zero-fill, because the ARM NEON palette
+riffle reads all 256 entries unconditionally.
+
+In function `png_set_PLTE`, `png_ptr->palette` was aliased directly to
+`info_ptr->palette`: a single heap buffer shared across two structs
+with independent lifetimes. If the buffer was freed through `info_ptr`
+(via `png_free_data(PNG_FREE_PLTE)` or a second call to `png_set_PLTE`),
+`png_ptr->palette` became a dangling pointer. Subsequent row reads,
+performed in `png_do_expand_palette` and in other transform functions,
+dereferenced (and in the bit-shift path, wrote to) freed memory.
+
+Also fix `png_set_quantize` to allocate an owned copy of the caller's
+palette rather than aliasing the user pointer, so that the unconditional
+free in `png_read_destroy` does not free unmanaged memory.
+
+CVE: CVE-2026-33416
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/7ea9eea884a2328cc7fdcb3c0c00246a50d90667]
+Comment: Refreshed hunk to match latest scarthgap
+
+Signed-off-by: Sourav Kumar Pramanik <Souravkumar.Pramanik@bmwtechworks.in>
+Signed-off-by: Zahir Hussain <zahir.basha@kpit.com>
+---
+ pngread.c | 11 +++++------
+ pngrtran.c | 8 +++++++-
+ pngrutil.c | 13 -------------
+ pngset.c | 28 +++++++++++++++++++---------
+ pngwrite.c | 4 ++++
+ 5 files changed, 35 insertions(+), 29 deletions(-)
+
+diff --git a/pngread.c b/pngread.c
+index 0086edf6cf..e1d38d578a 100644
+--- a/pngread.c
++++ b/pngread.c
+@@ -959,12 +959,11 @@ png_read_destroy(png_structrp png_ptr)
+ png_ptr->quantize_index = NULL;
+ #endif
+
+- if ((png_ptr->free_me & PNG_FREE_PLTE) != 0)
+- {
+- png_zfree(png_ptr, png_ptr->palette);
+- png_ptr->palette = NULL;
+- }
+- png_ptr->free_me &= ~PNG_FREE_PLTE;
++ /* png_ptr->palette is always independently allocated (not aliased
++ * with info_ptr->palette), so free it unconditionally.
++ */
++ png_free(png_ptr, png_ptr->palette);
++ png_ptr->palette = NULL;
+
+ #if defined(PNG_tRNS_SUPPORTED) || \
+ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+diff --git a/pngrtran.c b/pngrtran.c
+index bfb7d423b7..fd736ab672 100644
+--- a/pngrtran.c
++++ b/pngrtran.c
+@@ -750,7 +750,13 @@ png_set_quantize(png_structrp png_ptr, p
+ }
+ if (png_ptr->palette == NULL)
+ {
+- png_ptr->palette = palette;
++ /* Allocate an owned copy rather than aliasing the caller's pointer,
++ * so that png_read_destroy can free png_ptr->palette unconditionally.
++ */
++ png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
++ PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
++ memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
++ (sizeof (png_color)));
+ }
+ png_ptr->num_palette = (png_uint_16)num_palette;
+
+diff --git a/pngrutil.c b/pngrutil.c
+index a19507bf1b..3a35fe9de2 100644
+--- a/pngrutil.c
++++ b/pngrutil.c
+@@ -1047,14 +1047,6 @@ png_handle_PLTE(png_structrp png_ptr, pn
+ }
+ #endif
+
+- /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its
+- * own copy of the palette. This has the side effect that when png_start_row
+- * is called (this happens after any call to png_read_update_info) the
+- * info_ptr palette gets changed. This is extremely unexpected and
+- * confusing.
+- *
+- * Fix this by not sharing the palette in this way.
+- */
+ png_set_PLTE(png_ptr, info_ptr, palette, num);
+
+ /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before
+diff --git a/pngset.c b/pngset.c
+index dccc6498d7..b9ccb7fb15 100644
+--- a/pngset.c
++++ b/pngset.c
+@@ -595,28 +595,38 @@ png_set_PLTE(png_structrp png_ptr, png_i
+ png_error(png_ptr, "Invalid palette");
+ }
+
+- /* It may not actually be necessary to set png_ptr->palette here;
+- * we do it for backward compatibility with the way the png_handle_tRNS
+- * function used to do the allocation.
+- *
+- * 1.6.0: the above statement appears to be incorrect; something has to set
+- * the palette inside png_struct on read.
+- */
+ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
+
+ /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
+ * of num_palette entries, in case of an invalid PNG file or incorrect
+ * call to png_set_PLTE() with too-large sample values.
++ *
++ * Allocate independent buffers for info_ptr and png_ptr so that the
++ * lifetime of png_ptr->palette is decoupled from the lifetime of
++ * info_ptr->palette. Previously, these two pointers were aliased,
++ * which caused a use-after-free vulnerability if png_free_data freed
++ * info_ptr->palette while png_ptr->palette was still in use by the
++ * row transform functions (e.g. png_do_expand_palette).
++ *
++ * Both buffers are allocated with png_calloc to zero-fill, because
++ * the ARM NEON palette riffle reads all 256 entries unconditionally,
++ * regardless of num_palette.
+ */
++ png_free(png_ptr, png_ptr->palette);
+ png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+ PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
++ info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
++ PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
++ png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
+
+ if (num_palette > 0)
++ {
++ memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
++ (sizeof (png_color)));
+ memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
+ (sizeof (png_color)));
++ }
+
+- info_ptr->palette = png_ptr->palette;
+- info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
+ info_ptr->free_me |= PNG_FREE_PLTE;
+ info_ptr->valid |= PNG_INFO_PLTE;
+ }
+diff --git a/pngwrite.c b/pngwrite.c
+index 84af1e73fb..348763e940 100644
+--- a/pngwrite.c
++++ b/pngwrite.c
+@@ -982,6 +982,10 @@ png_write_destroy(png_structrp png_ptr)
+ png_free(png_ptr, png_ptr->trans_alpha);
+ png_ptr->trans_alpha = NULL;
+ #endif
++
++ /* Free the independent copy of the palette owned by png_struct. */
++ png_free(png_ptr, png_ptr->palette);
++ png_ptr->palette = NULL;
+
+ /* The error handling and memory handling information is left intact at this
+ * point: the jmp_buf may still have to be freed. See png_destroy_png_struct
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2026-33416-04.patch b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-04.patch
new file mode 100644
index 0000000000..ff7db53c81
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2026-33416-04.patch
@@ -0,0 +1,53 @@
+From c1b0318b393c90679e6fa5bc1d329fd5d5012ec1 Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Fri, 20 Mar 2026 21:25:12 +0200
+Subject: [PATCH] fix: Sync `info_ptr->palette` after in-place transforms
+
+Copy `png_ptr->palette` into `info_ptr->palette` upon entering
+the function that runs immediately after the in-place transforms.
+
+The palette decoupling in the previous commit gave `png_struct`
+and `png_info` independently-allocated palette buffers, fixing a
+use-after-free vulnerability. However, `png_init_read_transformations`
+modifies `png_ptr->palette` in place (e.g. for gamma correction or
+background compositing), and the old aliasing made those modifications
+visible through `png_get_PLTE`. With independent buffers,
+`info_ptr->palette` retained the original values, causing our tests to
+fail on indexed-colour background compositing.
+
+CVE: CVE-2026-33416
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/c1b0318b393c90679e6fa5bc1d329fd5d5012ec1]
+Comment: Refreshed hunk to match latest scarthgap
+
+Signed-off-by: Sourav Kumar Pramanik <Souravkumar.Pramanik@bmwtechworks.in>
+Signed-off-by: Zahir Hussain <zahir.basha@kpit.com>
+---
+ pngrtran.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/pngrtran.c b/pngrtran.c
+index fd736ab672..978dac5888 100644
+--- a/pngrtran.c
++++ b/pngrtran.c
+@@ -1984,6 +1984,21 @@ png_read_transform_info(png_structrp png
+ {
+ png_debug(1, "in png_read_transform_info");
+
++ if (png_ptr->transformations != 0)
++ {
++ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
++ info_ptr->palette != NULL && png_ptr->palette != NULL)
++ {
++ /* Sync info_ptr->palette with png_ptr->palette.
++ * The function png_init_read_transformations may have modified
++ * png_ptr->palette in place (e.g. for gamma correction or for
++ * background compositing).
++ */
++ memcpy(info_ptr->palette, png_ptr->palette,
++ PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)));
++ }
++ }
++
+ #ifdef PNG_READ_EXPAND_SUPPORTED
+ if ((png_ptr->transformations & PNG_EXPAND) != 0)
+ {
diff --git a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
index 923ed79896..e4cc63686e 100644
--- a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
+++ b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
@@ -25,6 +25,10 @@ SRC_URI = "${SOURCEFORGE_MIRROR}/project/${BPN}/${BPN}${LIBV}/${PV}/${BP}.tar.xz
file://CVE-2026-22801.patch \
file://CVE-2026-25646.patch \
file://CVE-2026-33636.patch \
+ file://CVE-2026-33416-01.patch \
+ file://CVE-2026-33416-02.patch \
+ file://CVE-2026-33416-03.patch \
+ file://CVE-2026-33416-04.patch \
"
SRC_URI[sha256sum] = "c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450"
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 02/21] busybox: Fix CVE-2026-29004
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 01/21] libpng: Fix CVE-2026-33416 Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 03/21] nfs-utils: fix CVE-2025-12801 Jeremy Rosen
` (18 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Hugo SIMELIERE (Schneider Electric)" <hsimeliere.opensource@witekio.com>
Pick patches from [1] and [2] as mentioned in Debian report in [3].
[1] https://git.busybox.net/busybox/commit/archival?id=42202bfb1e6ac51fa995beda8be4d7b654aeee2a
[2] https://git.busybox.net/busybox/commit/archival?id=d368f3f7836d1c2484c8f839316e5c93e76d4409
[3] https://security-tracker.debian.org/tracker/CVE-2026-29004
Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
Reviewed-by: Bruno VERNAY <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
.../busybox/busybox/CVE-2026-29004-01.patch | 41 +++++++++++++++++
.../busybox/busybox/CVE-2026-29004-02.patch | 46 +++++++++++++++++++
meta/recipes-core/busybox/busybox_1.36.1.bb | 2 +
3 files changed, 89 insertions(+)
create mode 100644 meta/recipes-core/busybox/busybox/CVE-2026-29004-01.patch
create mode 100644 meta/recipes-core/busybox/busybox/CVE-2026-29004-02.patch
diff --git a/meta/recipes-core/busybox/busybox/CVE-2026-29004-01.patch b/meta/recipes-core/busybox/busybox/CVE-2026-29004-01.patch
new file mode 100644
index 0000000000..0423a76730
--- /dev/null
+++ b/meta/recipes-core/busybox/busybox/CVE-2026-29004-01.patch
@@ -0,0 +1,41 @@
+From e49fb0f6ad0a0f924ec2cfe6838d04c4f1f4c3ba Mon Sep 17 00:00:00 2001
+From: Denys Vlasenko <vda.linux@googlemail.com>
+Date: Thu, 12 Mar 2026 07:25:38 +0100
+Subject: [PATCH 1/2] udhcpc6: fix buffer overflow
+
+CVE: CVE-2026-29004
+Upstream-Status: Backport [https://git.busybox.net/busybox/commit/archival?id=42202bfb1e6ac51fa995beda8be4d7b654aeee2a]
+
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+(cherry picked from commit 42202bfb1e6ac51fa995beda8be4d7b654aeee2a)
+Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
+---
+ networking/udhcp/d6_dhcpc.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
+index cdd06188e..62cc0f466 100644
+--- a/networking/udhcp/d6_dhcpc.c
++++ b/networking/udhcp/d6_dhcpc.c
+@@ -351,15 +351,15 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end)
+ addrs = option[3] >> 4;
+
+ /* Setup environment variable */
+- *new_env() = dlist = xmalloc(4 + addrs * 40 - 1);
++ *new_env() = dlist = xmalloc(4 + addrs * 40 + 1);
+ dlist = stpcpy(dlist, "dns=");
+ option_offset = 0;
+
+- while (addrs--) {
++ while (addrs-- != 0) {
+ sprint_nip6(dlist, option + 4 + option_offset);
+ dlist += 39;
+ option_offset += 16;
+- if (addrs)
++ if (addrs != 0)
+ *dlist++ = ' ';
+ }
+
+--
+2.43.0
+
diff --git a/meta/recipes-core/busybox/busybox/CVE-2026-29004-02.patch b/meta/recipes-core/busybox/busybox/CVE-2026-29004-02.patch
new file mode 100644
index 0000000000..ac8c031cc6
--- /dev/null
+++ b/meta/recipes-core/busybox/busybox/CVE-2026-29004-02.patch
@@ -0,0 +1,46 @@
+From 4d8d5b7c4426e62375235cf4903b6cb53bb193d3 Mon Sep 17 00:00:00 2001
+From: Denys Vlasenko <vda.linux@googlemail.com>
+Date: Thu, 12 Mar 2026 13:23:48 +0100
+Subject: [PATCH 2/2] udhcpc6: check the size of D6_OPT_IAPREFIX option
+
+function old new delta
+option_to_env 694 711 +17
+
+CVE: CVE-2026-29004
+Upstream-Status: Backport [https://git.busybox.net/busybox/commit/archival?id=d368f3f7836d1c2484c8f839316e5c93e76d4409]
+
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+(cherry picked from commit d368f3f7836d1c2484c8f839316e5c93e76d4409)
+Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
+---
+ networking/udhcp/d6_dhcpc.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
+index 62cc0f466..64a41c9d8 100644
+--- a/networking/udhcp/d6_dhcpc.c
++++ b/networking/udhcp/d6_dhcpc.c
+@@ -287,8 +287,8 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end)
+ * | valid-lifetime |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+- /* Make sure payload contains an address */
+- if (option[3] < 24)
++ /* Make sure payload exists */
++ if (option[3] < (16 + 4 + 4))
+ break;
+
+ sprint_nip6(ipv6str, option + 4);
+@@ -332,6 +332,9 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end)
+ * | |
+ * +-+-+-+-+-+-+-+-+
+ */
++ /* Make sure payload exists */
++ if (option[3] < (4 + 4 + 1 + 16))
++ break;
+ move_from_unaligned32(v32, option + 4 + 4);
+ v32 = ntohl(v32);
+ *new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);
+--
+2.43.0
+
diff --git a/meta/recipes-core/busybox/busybox_1.36.1.bb b/meta/recipes-core/busybox/busybox_1.36.1.bb
index 228bfdadd3..7929d396c8 100644
--- a/meta/recipes-core/busybox/busybox_1.36.1.bb
+++ b/meta/recipes-core/busybox/busybox_1.36.1.bb
@@ -64,6 +64,8 @@ SRC_URI = "https://busybox.net/downloads/busybox-${PV}.tar.bz2;name=tarball \
file://CVE-2025-60876.patch \
file://CVE-2026-26157-CVE-2026-26158-01.patch \
file://CVE-2026-26157-CVE-2026-26158-02.patch \
+ file://CVE-2026-29004-01.patch \
+ file://CVE-2026-29004-02.patch \
"
SRC_URI:append:libc-musl = " file://musl.cfg "
# TODO http://lists.busybox.net/pipermail/busybox/2023-January/090078.html
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 03/21] nfs-utils: fix CVE-2025-12801
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 01/21] libpng: Fix CVE-2026-33416 Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 02/21] busybox: Fix CVE-2026-29004 Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-15 7:59 ` Paul Barker
2026-06-12 14:25 ` [OE-core][scarthgap 04/21] xz: Fix CVE-2026-34743 Jeremy Rosen
` (17 subsequent siblings)
20 siblings, 1 reply; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: Sudhir Dumbhare <sudumbha@cisco.com>
- This patch applies the upstream fix [5] as referenced in [7].
- To successfully apply the fixed commit, apply the dependent commits [2] to [4]
which are included in v2.8.6, as referenced in [7].
- Additionally, include dependent commit [1] from v2.8.3, as referenced in [8]
under the [2.5.4-38.2] description, along with compilation fix commit [6]
from v2.7.1
- Reference:
[1] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=cd90f2925790
[2] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=7e8b36522f58
[3] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=42f01e6a78fe
[4] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=51738ae56d92
[5] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=f36bd900a899
[6] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=a2c95e4f557a
[7] https://security-tracker.debian.org/tracker/CVE-2025-12801
[8] https://linux.oracle.com/errata/ELSA-2026-3940.html
Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
.../nfs-utils/CVE-2025-12801-build-fix.patch | 44 ++
.../CVE-2025-12801-dependent_p1.patch | 71 +++
.../CVE-2025-12801-dependent_p2.patch | 81 +++
.../CVE-2025-12801-dependent_p3.patch | 185 +++++++
.../CVE-2025-12801-dependent_p4.patch | 468 ++++++++++++++++++
.../nfs-utils/nfs-utils/CVE-2025-12801.patch | 254 ++++++++++
.../nfs-utils/nfs-utils_2.6.4.bb | 6 +
7 files changed, 1109 insertions(+)
create mode 100644 meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-build-fix.patch
create mode 100644 meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p1.patch
create mode 100644 meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p2.patch
create mode 100644 meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p3.patch
create mode 100644 meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p4.patch
create mode 100644 meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801.patch
diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-build-fix.patch b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-build-fix.patch
new file mode 100644
index 0000000000..d7aaca2242
--- /dev/null
+++ b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-build-fix.patch
@@ -0,0 +1,44 @@
+From 30e0f57fff545b0bb3071fa071c7b12c2923bac8 Mon Sep 17 00:00:00 2001
+From: Steve Dickson <steved@redhat.com>
+Date: Mon, 22 Jan 2024 13:23:57 -0500
+Subject: [PATCH] reexport.c: Some Distros need the following include to
+ avoid the following error
+
+reexport.c: In function ‘connect_fsid_service’:
+reexport.c:41:28: error: implicit declaration of function ‘offsetof’ [-Werror=implicit-function-declaration]
+ 41 | addr_len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path);
+ | ^~~~~~~~
+reexport.c:19:1: note: ‘offsetof’ is defined in header ‘<stddef.h>’; did you forget to ‘#include <stddef.h>’?
+ 18 | #include "xlog.h"
+ +++ |+#include <stddef.h>
+ 19 |
+reexport.c:41:37: error: expected expression before ‘struct’
+ 41 | addr_len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path);
+ | ^~~~~~
+cc1: some warnings being treated as errors
+
+CVE: CVE-2025-12801
+Upstream-Status: Backport [https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=a2c95e4f557a71b482bb62bad6d93ddde51e5dc6]
+
+Signed-off-by: Steve Dickson <steved@redhat.com>
+(cherry picked from commit a2c95e4f557a71b482bb62bad6d93ddde51e5dc6)
+Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
+---
+ support/reexport/reexport.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/support/reexport/reexport.c b/support/reexport/reexport.c
+index 78516586..16dde0fb 100644
+--- a/support/reexport/reexport.c
++++ b/support/reexport/reexport.c
+@@ -8,6 +8,7 @@
+ #include <sys/types.h>
+ #include <sys/vfs.h>
+ #include <errno.h>
++#include <stddef.h>
+
+ #include "nfsd_path.h"
+ #include "conffile.h"
+--
+2.44.4
+
diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p1.patch b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p1.patch
new file mode 100644
index 0000000000..223249a9d6
--- /dev/null
+++ b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p1.patch
@@ -0,0 +1,71 @@
+From 647c9cb3ac3cbdf9ffd9e29f7d5dd04da84afdbc Mon Sep 17 00:00:00 2001
+From: Christopher Bii <christopherbii@hyub.org>
+Date: Wed, 15 Jan 2025 12:10:48 -0500
+Subject: [PATCH] NFS export symlink vulnerability fix
+
+Replaced dangerous use of realpath within support/nfs/export.c with
+nfsd_realpath variant that is executed within the chrooted thread
+rather than main thread.
+
+Implemented nfsd_path.h methods to work securely within chrooted
+thread using nfsd_run_task() help
+
+CVE: CVE-2025-12801
+Upstream-Status: Backport [https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=cd90f29257904f36509ea5a04a86f42398fbe94a]
+
+Backport Changes:
+- In support/misc/nfsd_path.c file, only nfsd_run_task() and the
+ struct nfsd_task_t have been included to resolve a compilation
+ issue. All other non-essential changes were excluded.
+- The non-required file support/export/cache.c and support/nfs/exports.c
+ has been excluded.
+
+Signed-off-by: Christopher Bii <christopherbii@hyub.org>
+Signed-off-by: Steve Dickson <steved@redhat.com>
+(cherry picked from commit cd90f29257904f36509ea5a04a86f42398fbe94a)
+Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
+---
+ support/include/nfsd_path.h | 1 +
+ support/misc/nfsd_path.c | 14 +++++++++++++-
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h
+index aa1e1dd0..4f5fc44e 100644
+--- a/support/include/nfsd_path.h
++++ b/support/include/nfsd_path.h
+@@ -8,6 +8,7 @@
+
+ struct file_handle;
+ struct statfs;
++struct nfsd_task_t;
+
+ void nfsd_path_init(void);
+
+diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
+index c3dea4f0..fa908f7c 100644
+--- a/support/misc/nfsd_path.c
++++ b/support/misc/nfsd_path.c
+@@ -19,7 +19,19 @@
+ #include "nfsd_path.h"
+ #include "workqueue.h"
+
+-static struct xthread_workqueue *nfsd_wq;
++static struct xthread_workqueue *nfsd_wq = NULL;
++
++struct nfsd_task_t {
++ int ret;
++ void* data;
++};
++/* Function used to offload tasks that must be ran within the correct
++ * chroot environment.
++ */
++static void
++nfsd_run_task(void (*func)(void*), void* data){
++ nfsd_wq ? xthread_work_run_sync(nfsd_wq, func, data) : func(data);
++};
+
+ static int
+ nfsd_path_isslash(const char *path)
+--
+2.35.6
+
diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p2.patch b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p2.patch
new file mode 100644
index 0000000000..f088eadb4b
--- /dev/null
+++ b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p2.patch
@@ -0,0 +1,81 @@
+From a6ddd0e9594884cf61816478e8c561f1b3aac709 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+Date: Mon, 10 Nov 2025 11:26:03 -0500
+Subject: [PATCH] mountd: Minor refactor of get_rootfh()
+
+Perform the mountpoint checks before checking the user path.
+
+CVE: CVE-2025-12801
+Upstream-Status: Backport [https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=7e8b36522f58657359c6842119fc516c6dd1baa4]
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Steve Dickson <steved@redhat.com>
+(cherry picked from commit 7e8b36522f58657359c6842119fc516c6dd1baa4)
+Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
+---
+ utils/mountd/mountd.c | 34 +++++++++++++++++-----------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
+index dbd5546d..39afd4aa 100644
+--- a/utils/mountd/mountd.c
++++ b/utils/mountd/mountd.c
+@@ -412,6 +412,23 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ *error = MNT3ERR_ACCES;
+ return NULL;
+ }
++ if (nfsd_path_stat(exp->m_export.e_path, &estb) < 0) {
++ xlog(L_WARNING, "can't stat export point %s: %s",
++ p, strerror(errno));
++ *error = MNT3ERR_NOENT;
++ return NULL;
++ }
++ if (exp->m_export.e_mountpoint &&
++ !check_is_mountpoint(exp->m_export.e_mountpoint[0]?
++ exp->m_export.e_mountpoint:
++ exp->m_export.e_path,
++ nfsd_path_lstat)) {
++ xlog(L_WARNING, "request to export an unmounted filesystem: %s",
++ p);
++ *error = MNT3ERR_NOENT;
++ return NULL;
++ }
++
+ if (nfsd_path_stat(p, &stb) < 0) {
+ xlog(L_WARNING, "can't stat exported dir %s: %s",
+ p, strerror(errno));
+@@ -426,12 +443,6 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ *error = MNT3ERR_NOTDIR;
+ return NULL;
+ }
+- if (nfsd_path_stat(exp->m_export.e_path, &estb) < 0) {
+- xlog(L_WARNING, "can't stat export point %s: %s",
+- p, strerror(errno));
+- *error = MNT3ERR_NOENT;
+- return NULL;
+- }
+ if (estb.st_dev != stb.st_dev
+ && !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) {
+ xlog(L_WARNING, "request to export directory %s below nearest filesystem %s",
+@@ -439,17 +450,6 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ *error = MNT3ERR_ACCES;
+ return NULL;
+ }
+- if (exp->m_export.e_mountpoint &&
+- !check_is_mountpoint(exp->m_export.e_mountpoint[0]?
+- exp->m_export.e_mountpoint:
+- exp->m_export.e_path,
+- nfsd_path_lstat)) {
+- xlog(L_WARNING, "request to export an unmounted filesystem: %s",
+- p);
+- *error = MNT3ERR_NOENT;
+- return NULL;
+- }
+-
+ /* This will be a static private nfs_export with just one
+ * address. We feed it to kernel then extract the filehandle,
+ */
+--
+2.44.4
+
diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p3.patch b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p3.patch
new file mode 100644
index 0000000000..59b28b557a
--- /dev/null
+++ b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p3.patch
@@ -0,0 +1,185 @@
+From 0c2561328ce5e09636663ac2312b5f1f52fc0111 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+Date: Mon, 10 Nov 2025 11:28:39 -0500
+Subject: [PATCH] mountd: Separate lookup of the exported directory and the
+ mount path
+
+When the caller asks to mount a path that does not terminate with an
+exported directory, we want to split up the lookups so that we can
+look up the exported directory using the mountd privileged credential,
+and the remaining subdirectory lookups using the RPC caller's
+credential.
+
+CVE: CVE-2025-12801
+Upstream-Status: Backport [https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=42f01e6a78fed98f12437ac8b28cfb12b6bad056]
+
+Backport Changes:
+- In support/misc/nfsd_path.c, the closing brace of struct
+ nfsd_read_data was adjusted from line 320 to 282.
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Steve Dickson <steved@redhat.com>
+(cherry picked from commit 42f01e6a78fed98f12437ac8b28cfb12b6bad056)
+Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
+---
+ support/include/nfsd_path.h | 1 +
+ support/misc/nfsd_path.c | 31 ++++++++++++++++++
+ utils/mountd/mountd.c | 63 +++++++++++++++++++++++++++++++------
+ 3 files changed, 86 insertions(+), 9 deletions(-)
+
+diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h
+index 4f5fc44e..be2dc38d 100644
+--- a/support/include/nfsd_path.h
++++ b/support/include/nfsd_path.h
+@@ -18,6 +18,7 @@ char * nfsd_path_prepend_dir(const char *dir, const char *pathname);
+
+ int nfsd_path_stat(const char *pathname, struct stat *statbuf);
+ int nfsd_path_lstat(const char *pathname, struct stat *statbuf);
++int nfsd_openat(int dirfd, const char *path, int flags);
+
+ int nfsd_path_statfs(const char *pathname,
+ struct statfs *statbuf);
+diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
+index fa908f7c..1c5aa3f3 100644
+--- a/support/misc/nfsd_path.c
++++ b/support/misc/nfsd_path.c
+@@ -280,6 +280,37 @@ struct nfsd_read_data {
+ int err;
+ };
+
++struct nfsd_openat_t {
++ const char *path;
++ int dirfd;
++ int flags;
++ int res_fd;
++ int res_error;
++};
++
++static void nfsd_openatfunc(void *data)
++{
++ struct nfsd_openat_t *d = data;
++
++ d->res_fd = openat(d->dirfd, d->path, d->flags);
++ if (d->res_fd == -1)
++ d->res_error = errno;
++}
++
++int nfsd_openat(int dirfd, const char *path, int flags)
++{
++ struct nfsd_openat_t open_buf = {
++ .path = path,
++ .dirfd = dirfd,
++ .flags = flags,
++ };
++
++ nfsd_run_task(nfsd_openatfunc, &open_buf);
++ if (open_buf.res_fd == -1)
++ errno = open_buf.res_error;
++ return open_buf.res_fd;
++}
++
+ static void
+ nfsd_readfunc(void *data)
+ {
+diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
+index 39afd4aa..f43ebef5 100644
+--- a/utils/mountd/mountd.c
++++ b/utils/mountd/mountd.c
+@@ -392,7 +392,10 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ struct nfs_fh_len *fh;
+ char rpath[MAXPATHLEN+1];
+ char *p = *path;
++ char *subpath;
+ char buf[INET6_ADDRSTRLEN];
++ size_t epathlen;
++ int dirfd;
+
+ if (*p == '\0')
+ p = "/";
+@@ -412,12 +415,21 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ *error = MNT3ERR_ACCES;
+ return NULL;
+ }
+- if (nfsd_path_stat(exp->m_export.e_path, &estb) < 0) {
+- xlog(L_WARNING, "can't stat export point %s: %s",
++
++ dirfd = nfsd_openat(AT_FDCWD, exp->m_export.e_path, O_PATH);
++ if (dirfd == -1) {
++ xlog(L_WARNING, "can't open export point %s: %s",
+ p, strerror(errno));
+ *error = MNT3ERR_NOENT;
+ return NULL;
+ }
++ if (fstat(dirfd, &estb) == -1) {
++ xlog(L_WARNING, "can't stat export point %s: %s",
++ p, strerror(errno));
++ *error = MNT3ERR_ACCES;
++ close(dirfd);
++ return NULL;
++ }
+ if (exp->m_export.e_mountpoint &&
+ !check_is_mountpoint(exp->m_export.e_mountpoint[0]?
+ exp->m_export.e_mountpoint:
+@@ -426,18 +438,51 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ xlog(L_WARNING, "request to export an unmounted filesystem: %s",
+ p);
+ *error = MNT3ERR_NOENT;
++ close(dirfd);
+ return NULL;
+ }
+
+- if (nfsd_path_stat(p, &stb) < 0) {
+- xlog(L_WARNING, "can't stat exported dir %s: %s",
+- p, strerror(errno));
+- if (errno == ENOENT)
+- *error = MNT3ERR_NOENT;
+- else
+- *error = MNT3ERR_ACCES;
++ epathlen = strlen(exp->m_export.e_path);
++ if (epathlen > strlen(p)) {
++ xlog(L_WARNING, "raced with change of exported path: %s", p);
++ *error = MNT3ERR_NOENT;
++ close(dirfd);
+ return NULL;
+ }
++ subpath = &p[epathlen];
++ while (*subpath == '/')
++ subpath++;
++ if (*subpath != '\0') {
++ int fd;
++
++ /* Just perform a lookup of the path */
++ fd = nfsd_openat(dirfd, subpath, O_PATH);
++ close(dirfd);
++ if (fd == -1) {
++ xlog(L_WARNING, "can't open exported dir %s: %s", p,
++ strerror(errno));
++ if (errno == ENOENT)
++ *error = MNT3ERR_NOENT;
++ else
++ *error = MNT3ERR_ACCES;
++ return NULL;
++ }
++ if (fstat(fd, &stb) == -1) {
++ xlog(L_WARNING, "can't open exported dir %s: %s", p,
++ strerror(errno));
++ if (errno == ENOENT)
++ *error = MNT3ERR_NOENT;
++ else
++ *error = MNT3ERR_ACCES;
++ close(fd);
++ return NULL;
++ }
++ close(fd);
++ } else {
++ close(dirfd);
++ stb = estb;
++ }
++
+ if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
+ xlog(L_WARNING, "%s is not a directory or regular file", p);
+ *error = MNT3ERR_NOTDIR;
+--
+2.44.4
+
diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p4.patch b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p4.patch
new file mode 100644
index 0000000000..4ef529e737
--- /dev/null
+++ b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p4.patch
@@ -0,0 +1,468 @@
+From 7eef498b6bd01adc45415b03ddf321c84f82aa45 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+Date: Mon, 10 Nov 2025 12:18:38 -0500
+Subject: [PATCH] support: Add a mini-library to extract and apply RPC
+ credentials
+
+Add server functionality to extract the credentials from the client RPC
+call, and apply them. This is needed in order to perform access checking
+on the requested path in the mountd daemon.
+
+CVE: CVE-2025-12801
+Upstream-Status: Backport [https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=51738ae56d922d4961e60dad73ad1c2d97d8d99b]
+
+Backport Changes:
+- In support/misc/Makefile.am, the non-essential file.c was omitted
+ as it does not exist in the current nfs-utils version.
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Steve Dickson <steved@redhat.com>
+(cherry picked from commit 51738ae56d922d4961e60dad73ad1c2d97d8d99b)
+Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
+---
+ aclocal/libtirpc.m4 | 11 +++
+ support/include/Makefile.am | 1 +
+ support/include/nfs_ucred.h | 44 ++++++++++
+ support/misc/Makefile.am | 2 +-
+ support/misc/ucred.c | 162 ++++++++++++++++++++++++++++++++++++
+ support/nfs/Makefile.am | 2 +-
+ support/nfs/ucred.c | 147 ++++++++++++++++++++++++++++++++
+ 7 files changed, 367 insertions(+), 2 deletions(-)
+ create mode 100644 support/include/nfs_ucred.h
+ create mode 100644 support/misc/ucred.c
+ create mode 100644 support/nfs/ucred.c
+
+diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4
+index bddae022..84e18f7e 100644
+--- a/aclocal/libtirpc.m4
++++ b/aclocal/libtirpc.m4
+@@ -26,6 +26,17 @@ AC_DEFUN([AC_LIBTIRPC], [
+ [Define to 1 if your tirpc library provides libtirpc_set_debug])],,
+ [${LIBS}])])
+
++ AS_IF([test -n "${LIBTIRPC}"],
++ [AC_CHECK_LIB([tirpc], [rpc_gss_getcred],
++ [AC_DEFINE([HAVE_TIRPC_GSS_GETCRED], [1],
++ [Define to 1 if your tirpc library provides rpc_gss_getcred])],,
++ [${LIBS}])])
++
++ AS_IF([test -n "${LIBTIRPC}"],
++ [AC_CHECK_LIB([tirpc], [authdes_getucred],
++ [AC_DEFINE([HAVE_TIRPC_AUTHDES_GETUCRED], [1],
++ [Define to 1 if your tirpc library provides authdes_getucred])],,
++ [${LIBS}])])
+ AC_SUBST([AM_CPPFLAGS])
+ AC_SUBST(LIBTIRPC)
+
+diff --git a/support/include/Makefile.am b/support/include/Makefile.am
+index 1373891a..631a84f8 100644
+--- a/support/include/Makefile.am
++++ b/support/include/Makefile.am
+@@ -10,6 +10,7 @@ noinst_HEADERS = \
+ misc.h \
+ nfs_mntent.h \
+ nfs_paths.h \
++ nfs_ucred.h \
+ nfsd_path.h \
+ nfslib.h \
+ nfsrpc.h \
+diff --git a/support/include/nfs_ucred.h b/support/include/nfs_ucred.h
+new file mode 100644
+index 00000000..d58b61e4
+--- /dev/null
++++ b/support/include/nfs_ucred.h
+@@ -0,0 +1,44 @@
++#ifndef _NFS_UCRED_H
++#define _NFS_UCRED_H
++
++#include <sys/types.h>
++
++struct nfs_ucred {
++ uid_t uid;
++ gid_t gid;
++ int ngroups;
++ gid_t *groups;
++};
++
++struct svc_req;
++struct exportent;
++
++int nfs_ucred_get(struct nfs_ucred **credp, struct svc_req *rqst,
++ const struct exportent *ep);
++
++void nfs_ucred_squash_groups(struct nfs_ucred *cred,
++ const struct exportent *ep);
++int nfs_ucred_reload_groups(struct nfs_ucred *cred, const struct exportent *ep);
++int nfs_ucred_swap_effective(const struct nfs_ucred *cred,
++ struct nfs_ucred **savedp);
++
++static inline void nfs_ucred_free(struct nfs_ucred *cred)
++{
++ free(cred->groups);
++ free(cred);
++}
++
++static inline void nfs_ucred_init_groups(struct nfs_ucred *cred, gid_t *groups,
++ int ngroups)
++{
++ cred->groups = groups;
++ cred->ngroups = ngroups;
++}
++
++static inline void nfs_ucred_free_groups(struct nfs_ucred *cred)
++{
++ free(cred->groups);
++ nfs_ucred_init_groups(cred, NULL, 0);
++}
++
++#endif /* _NFS_UCRED_H */
+diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am
+index 8b0e9db9..ea970064 100644
+--- a/support/misc/Makefile.am
++++ b/support/misc/Makefile.am
+@@ -2,6 +2,6 @@
+
+ noinst_LIBRARIES = libmisc.a
+ libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c misc.c \
+- nfsd_path.c workqueue.c xstat.c
++ nfsd_path.c ucred.c workqueue.c xstat.c
+
+ MAINTAINERCLEANFILES = Makefile.in
+diff --git a/support/misc/ucred.c b/support/misc/ucred.c
+new file mode 100644
+index 00000000..92d97912
+--- /dev/null
++++ b/support/misc/ucred.c
+@@ -0,0 +1,162 @@
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <alloca.h>
++#include <errno.h>
++#include <pwd.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <grp.h>
++
++#include "exportfs.h"
++#include "nfs_ucred.h"
++
++#include "xlog.h"
++
++void nfs_ucred_squash_groups(struct nfs_ucred *cred, const struct exportent *ep)
++{
++ int i;
++
++ if (!(ep->e_flags & NFSEXP_ROOTSQUASH))
++ return;
++ if (cred->gid == 0)
++ cred->gid = ep->e_anongid;
++ for (i = 0; i < cred->ngroups; i++) {
++ if (cred->groups[i] == 0)
++ cred->groups[i] = ep->e_anongid;
++ }
++}
++
++static int nfs_ucred_init_effective(struct nfs_ucred *cred)
++{
++ int ngroups = getgroups(0, NULL);
++
++ if (ngroups > 0) {
++ size_t sz = ngroups * sizeof(gid_t);
++ gid_t *groups = malloc(sz);
++ if (groups == NULL)
++ return ENOMEM;
++ if (getgroups(ngroups, groups) == -1) {
++ free(groups);
++ return errno;
++ }
++ nfs_ucred_init_groups(cred, groups, ngroups);
++ } else
++ nfs_ucred_init_groups(cred, NULL, 0);
++ cred->uid = geteuid();
++ cred->gid = getegid();
++ return 0;
++}
++
++static size_t nfs_ucred_getpw_r_size_max(void)
++{
++ long buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
++
++ if (buflen == -1)
++ return 16384;
++ return buflen;
++}
++
++int nfs_ucred_reload_groups(struct nfs_ucred *cred, const struct exportent *ep)
++{
++ struct passwd pwd, *pw;
++ uid_t uid = cred->uid;
++ gid_t gid = cred->gid;
++ size_t buflen;
++ char *buf;
++ int ngroups = 0;
++ int ret;
++
++ if (ep->e_flags & (NFSEXP_ALLSQUASH | NFSEXP_ROOTSQUASH) &&
++ (int)uid == ep->e_anonuid)
++ return 0;
++ buflen = nfs_ucred_getpw_r_size_max();
++ buf = alloca(buflen);
++ ret = getpwuid_r(uid, &pwd, buf, buflen, &pw);
++ if (ret != 0)
++ return ret;
++ if (!pw)
++ return ENOENT;
++ if (getgrouplist(pw->pw_name, gid, NULL, &ngroups) == -1 &&
++ ngroups > 0) {
++ gid_t *groups = malloc(ngroups * sizeof(groups[0]));
++ if (groups == NULL)
++ return ENOMEM;
++ if (getgrouplist(pw->pw_name, gid, groups, &ngroups) == -1) {
++ free(groups);
++ return ENOMEM;
++ }
++ free(cred->groups);
++ nfs_ucred_init_groups(cred, groups, ngroups);
++ nfs_ucred_squash_groups(cred, ep);
++ } else
++ nfs_ucred_free_groups(cred);
++ return 0;
++}
++
++static int nfs_ucred_set_effective(const struct nfs_ucred *cred,
++ const struct nfs_ucred *saved)
++{
++ uid_t suid = saved ? saved->uid : geteuid();
++ gid_t sgid = saved ? saved->gid : getegid();
++ int ret;
++
++ /* Start with a privileged effective user */
++ if (setresuid(-1, 0, -1) < 0) {
++ xlog(L_WARNING, "can't change privileged user %u-%u. %s",
++ geteuid(), getegid(), strerror(errno));
++ return errno;
++ }
++
++ if (setgroups(cred->ngroups, cred->groups) == -1) {
++ xlog(L_WARNING, "can't change groups for user %u-%u. %s",
++ geteuid(), getegid(), strerror(errno));
++ return errno;
++ }
++ if (setresgid(-1, cred->gid, sgid) == -1) {
++ xlog(L_WARNING, "can't change gid for user %u-%u. %s",
++ geteuid(), getegid(), strerror(errno));
++ ret = errno;
++ goto restore_groups;
++ }
++ if (setresuid(-1, cred->uid, suid) == -1) {
++ xlog(L_WARNING, "can't change uid for user %u-%u. %s",
++ geteuid(), getegid(), strerror(errno));
++ ret = errno;
++ goto restore_gid;
++ }
++ return 0;
++restore_gid:
++ if (setresgid(-1, sgid, -1) < 0) {
++ xlog(L_WARNING, "can't restore privileged user %u-%u. %s",
++ geteuid(), getegid(), strerror(errno));
++ }
++restore_groups:
++ if (saved)
++ setgroups(saved->ngroups, saved->groups);
++ else
++ setgroups(0, NULL);
++ return ret;
++}
++
++int nfs_ucred_swap_effective(const struct nfs_ucred *cred,
++ struct nfs_ucred **savedp)
++{
++ struct nfs_ucred *saved = malloc(sizeof(*saved));
++ int ret;
++
++ if (saved == NULL)
++ return ENOMEM;
++ ret = nfs_ucred_init_effective(saved);
++ if (ret != 0) {
++ free(saved);
++ return ret;
++ }
++ ret = nfs_ucred_set_effective(cred, saved);
++ if (savedp == NULL || ret != 0)
++ nfs_ucred_free(saved);
++ else
++ *savedp = saved;
++ return ret;
++}
+diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am
+index 2e1577cc..f6921265 100644
+--- a/support/nfs/Makefile.am
++++ b/support/nfs/Makefile.am
+@@ -7,7 +7,7 @@ libnfs_la_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \
+ xcommon.c wildmat.c mydaemon.c \
+ rpc_socket.c getport.c \
+ svc_socket.c cacheio.c closeall.c nfs_mntent.c \
+- svc_create.c atomicio.c strlcat.c strlcpy.c
++ svc_create.c atomicio.c strlcat.c strlcpy.c ucred.c
+ libnfs_la_LIBADD = libnfsconf.la
+ libnfs_la_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) -I$(top_srcdir)/support/reexport
+
+diff --git a/support/nfs/ucred.c b/support/nfs/ucred.c
+new file mode 100644
+index 00000000..6ea8efdf
+--- /dev/null
++++ b/support/nfs/ucred.c
+@@ -0,0 +1,147 @@
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <errno.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <rpc/rpc.h>
++
++#include "exportfs.h"
++#include "nfs_ucred.h"
++
++#ifdef HAVE_TIRPC_GSS_GETCRED
++#include <rpc/rpcsec_gss.h>
++#endif /* HAVE_TIRPC_GSS_GETCRED */
++#ifdef HAVE_TIRPC_AUTHDES_GETUCRED
++#include <rpc/auth_des.h>
++#endif /* HAVE_TIRPC_AUTHDES_GETUCRED */
++
++static int nfs_ucred_copy_cred(struct nfs_ucred *cred, uid_t uid, gid_t gid,
++ const gid_t *groups, int ngroups)
++{
++ if (ngroups > 0) {
++ size_t sz = ngroups * sizeof(groups[0]);
++ cred->groups = malloc(sz);
++ if (cred->groups == NULL)
++ return ENOMEM;
++ cred->ngroups = ngroups;
++ memcpy(cred->groups, groups, sz);
++ } else
++ nfs_ucred_init_groups(cred, NULL, 0);
++ cred->uid = uid;
++ cred->gid = gid;
++ return 0;
++}
++
++static int nfs_ucred_init_cred_squashed(struct nfs_ucred *cred,
++ const struct exportent *ep)
++{
++ cred->uid = ep->e_anonuid;
++ cred->gid = ep->e_anongid;
++ nfs_ucred_init_groups(cred, NULL, 0);
++ return 0;
++}
++
++static int nfs_ucred_init_cred(struct nfs_ucred *cred, uid_t uid, gid_t gid,
++ const gid_t *groups, int ngroups,
++ const struct exportent *ep)
++{
++ if (ep->e_flags & NFSEXP_ALLSQUASH) {
++ nfs_ucred_init_cred_squashed(cred, ep);
++ } else if (ep->e_flags & NFSEXP_ROOTSQUASH && uid == 0) {
++ nfs_ucred_init_cred_squashed(cred, ep);
++ if (gid != 0)
++ cred->gid = gid;
++ } else {
++ int ret = nfs_ucred_copy_cred(cred, uid, gid, groups, ngroups);
++ if (ret != 0)
++ return ret;
++ nfs_ucred_squash_groups(cred, ep);
++ }
++ return 0;
++}
++
++static int nfs_ucred_init_null(struct nfs_ucred *cred,
++ const struct exportent *ep)
++{
++ return nfs_ucred_init_cred_squashed(cred, ep);
++}
++
++static int nfs_ucred_init_unix(struct nfs_ucred *cred, struct svc_req *rqst,
++ const struct exportent *ep)
++{
++ struct authunix_parms *aup;
++
++ aup = (struct authunix_parms *)rqst->rq_clntcred;
++ return nfs_ucred_init_cred(cred, aup->aup_uid, aup->aup_gid,
++ aup->aup_gids, aup->aup_len, ep);
++}
++
++#ifdef HAVE_TIRPC_GSS_GETCRED
++static int nfs_ucred_init_gss(struct nfs_ucred *cred, struct svc_req *rqst,
++ const struct exportent *ep)
++{
++ rpc_gss_ucred_t *gss_ucred = NULL;
++
++ if (!rpc_gss_getcred(rqst, NULL, &gss_ucred, NULL) || gss_ucred == NULL)
++ return EINVAL;
++ return nfs_ucred_init_cred(cred, gss_ucred->uid, gss_ucred->gid,
++ gss_ucred->gidlist, gss_ucred->gidlen, ep);
++}
++#endif /* HAVE_TIRPC_GSS_GETCRED */
++
++#ifdef HAVE_TIRPC_AUTHDES_GETUCRED
++int authdes_getucred(struct authdes_cred *adc, uid_t *uid, gid_t *gid,
++ int *grouplen, gid_t *groups);
++
++static int nfs_ucred_init_des(struct nfs_ucred *cred, struct svc_req *rqst,
++ const struct exportent *ep)
++{
++ struct authdes_cred *des_cred;
++ uid_t uid;
++ gid_t gid;
++ int grouplen;
++ gid_t groups[NGROUPS];
++
++ des_cred = (struct authdes_cred *)rqst->rq_clntcred;
++ if (!authdes_getucred(des_cred, &uid, &gid, &grouplen, &groups[0]))
++ return EINVAL;
++ return nfs_ucred_init_cred(cred, uid, gid, groups, grouplen, ep);
++}
++#endif /* HAVE_TIRPC_AUTHDES_GETUCRED */
++
++int nfs_ucred_get(struct nfs_ucred **credp, struct svc_req *rqst,
++ const struct exportent *ep)
++{
++ struct nfs_ucred *cred = malloc(sizeof(*cred));
++ int ret;
++
++ *credp = NULL;
++ if (cred == NULL)
++ return ENOMEM;
++ switch (rqst->rq_cred.oa_flavor) {
++ case AUTH_UNIX:
++ ret = nfs_ucred_init_unix(cred, rqst, ep);
++ break;
++#ifdef HAVE_TIRPC_GSS_GETCRED
++ case RPCSEC_GSS:
++ ret = nfs_ucred_init_gss(cred, rqst, ep);
++ break;
++#endif /* HAVE_TIRPC_GSS_GETCRED */
++#ifdef HAVE_TIRPC_AUTHDES_GETUCRED
++ case AUTH_DES:
++ ret = nfs_ucred_init_des(cred, rqst, ep);
++ break;
++#endif /* HAVE_TIRPC_AUTHDES_GETUCRED */
++ default:
++ ret = nfs_ucred_init_null(cred, ep);
++ break;
++ }
++ if (ret == 0) {
++ *credp = cred;
++ return 0;
++ }
++ free(cred);
++ return ret;
++}
+--
+2.44.4
+
diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801.patch b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801.patch
new file mode 100644
index 0000000000..3381d6e645
--- /dev/null
+++ b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801.patch
@@ -0,0 +1,254 @@
+From e22a15eb39c88367c35bfd4e057bccbddc6519d4 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+Date: Thu, 5 Mar 2026 10:41:02 -0500
+Subject: [PATCH] Fix access checks when mounting subdirectories in NFSv3
+
+If a NFSv3 client asks to mount a subdirectory of one of the exported
+directories, then apply the RPC credential together with any root
+or all squash rules that would apply to the client in question.
+
+CVE: CVE-2025-12801
+Upstream-Status: Backport [https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=f36bd900a899088ca1925de079bd58d6205a1f3c]
+
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Scott Mayhew <smayhew@redhat.com>
+Signed-off-by: Steve Dickson <steved@redhat.com>
+(cherry picked from commit f36bd900a899088ca1925de079bd58d6205a1f3c)
+Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
+---
+ nfs.conf | 1 +
+ support/include/nfsd_path.h | 9 ++++++++-
+ support/misc/nfsd_path.c | 32 ++++++++++++++++++++++++++++++--
+ utils/mountd/mountd.c | 28 ++++++++++++++++++++++++++--
+ utils/mountd/mountd.man | 26 ++++++++++++++++++++++++++
+ 5 files changed, 91 insertions(+), 5 deletions(-)
+
+diff --git a/nfs.conf b/nfs.conf
+index 323f072b..e08cd9a9 100644
+--- a/nfs.conf
++++ b/nfs.conf
+@@ -45,6 +45,7 @@
+ # ttl=1800
+ [mountd]
+ # debug="all|auth|call|general|parse"
++# apply-root-cred=n
+ # manage-gids=n
+ # descriptors=0
+ # port=0
+diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h
+index be2dc38d..834925ec 100644
+--- a/support/include/nfsd_path.h
++++ b/support/include/nfsd_path.h
+@@ -9,6 +9,7 @@
+ struct file_handle;
+ struct statfs;
+ struct nfsd_task_t;
++struct nfs_ucred;
+
+ void nfsd_path_init(void);
+
+@@ -18,7 +19,8 @@ char * nfsd_path_prepend_dir(const char *dir, const char *pathname);
+
+ int nfsd_path_stat(const char *pathname, struct stat *statbuf);
+ int nfsd_path_lstat(const char *pathname, struct stat *statbuf);
+-int nfsd_openat(int dirfd, const char *path, int flags);
++int nfsd_cred_openat(const struct nfs_ucred *cred, int dirfd,
++ const char *path, int flags);
+
+ int nfsd_path_statfs(const char *pathname,
+ struct statfs *statbuf);
+@@ -31,4 +33,9 @@ ssize_t nfsd_path_write(int fd, const char *buf, size_t len);
+ int nfsd_name_to_handle_at(int fd, const char *path,
+ struct file_handle *fh,
+ int *mount_id, int flags);
++
++static inline int nfsd_openat(int dirfd, const char *path, int flags)
++{
++ return nfsd_cred_openat(NULL, dirfd, path, flags);
++}
+ #endif
+diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
+index 1c5aa3f3..a2083989 100644
+--- a/support/misc/nfsd_path.c
++++ b/support/misc/nfsd_path.c
+@@ -17,6 +17,7 @@
+ #include "xstat.h"
+ #include "nfslib.h"
+ #include "nfsd_path.h"
++#include "nfs_ucred.h"
+ #include "workqueue.h"
+
+ static struct xthread_workqueue *nfsd_wq = NULL;
+@@ -281,6 +282,7 @@ struct nfsd_read_data {
+ };
+
+ struct nfsd_openat_t {
++ const struct nfs_ucred *cred;
+ const char *path;
+ int dirfd;
+ int flags;
+@@ -297,15 +299,41 @@ static void nfsd_openatfunc(void *data)
+ d->res_error = errno;
+ }
+
+-int nfsd_openat(int dirfd, const char *path, int flags)
++static void nfsd_cred_openatfunc(void *data)
++{
++ struct nfsd_openat_t *d = data;
++ struct nfs_ucred *saved = NULL;
++ int ret;
++
++ ret = nfs_ucred_swap_effective(d->cred, &saved);
++ if (ret != 0) {
++ d->res_fd = -1;
++ d->res_error = ret;
++ return;
++ }
++
++ nfsd_openatfunc(data);
++
++ if (saved != NULL) {
++ nfs_ucred_swap_effective(saved, NULL);
++ nfs_ucred_free(saved);
++ }
++}
++
++int nfsd_cred_openat(const struct nfs_ucred *cred, int dirfd, const char *path,
++ int flags)
+ {
+ struct nfsd_openat_t open_buf = {
++ .cred = cred,
+ .path = path,
+ .dirfd = dirfd,
+ .flags = flags,
+ };
+
+- nfsd_run_task(nfsd_openatfunc, &open_buf);
++ if (cred)
++ nfsd_run_task(nfsd_cred_openatfunc, &open_buf);
++ else
++ nfsd_run_task(nfsd_openatfunc, &open_buf);
+ if (open_buf.res_fd == -1)
+ errno = open_buf.res_error;
+ return open_buf.res_fd;
+diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
+index f43ebef5..6e6777cd 100644
+--- a/utils/mountd/mountd.c
++++ b/utils/mountd/mountd.c
+@@ -31,6 +31,7 @@
+ #include "nfsd_path.h"
+ #include "nfslib.h"
+ #include "export.h"
++#include "nfs_ucred.h"
+
+ extern void my_svc_run(void);
+
+@@ -40,6 +41,7 @@ static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, nfs_export **,
+
+ int reverse_resolve = 0;
+ int manage_gids;
++int apply_root_cred;
+ int use_ipaddr = -1;
+
+ /* PRC: a high-availability callout program can be specified with -H
+@@ -74,9 +76,10 @@ static struct option longopts[] =
+ { "log-auth", 0, 0, 'l'},
+ { "cache-use-ipaddr", 0, 0, 'i'},
+ { "ttl", 1, 0, 'T'},
++ { "apply-root-cred", 0, 0, 'c' },
+ { NULL, 0, 0, 0 }
+ };
+-static char shortopts[] = "o:nFd:p:P:hH:N:V:vurs:t:gliT:";
++static char shortopts[] = "o:nFd:p:P:hH:N:V:vurs:t:gliT:c";
+
+ #define NFSVERSBIT(vers) (0x1 << (vers - 1))
+ #define NFSVERSBIT_ALL (NFSVERSBIT(2) | NFSVERSBIT(3) | NFSVERSBIT(4))
+@@ -453,11 +456,27 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ while (*subpath == '/')
+ subpath++;
+ if (*subpath != '\0') {
++ struct nfs_ucred *cred = NULL;
+ int fd;
+
++ /* Load the user cred */
++ if (!apply_root_cred) {
++ nfs_ucred_get(&cred, rqstp, &exp->m_export);
++ if (cred == NULL) {
++ xlog(L_WARNING, "can't retrieve credential");
++ *error = MNT3ERR_ACCES;
++ close(dirfd);
++ return NULL;
++ }
++ if (manage_gids)
++ nfs_ucred_reload_groups(cred, &exp->m_export);
++ }
++
+ /* Just perform a lookup of the path */
+- fd = nfsd_openat(dirfd, subpath, O_PATH);
++ fd = nfsd_cred_openat(cred, dirfd, subpath, O_PATH);
+ close(dirfd);
++ if (cred)
++ nfs_ucred_free(cred);
+ if (fd == -1) {
+ xlog(L_WARNING, "can't open exported dir %s: %s", p,
+ strerror(errno));
+@@ -681,6 +700,8 @@ read_mountd_conf(char **argv)
+ ttl = conf_get_num("mountd", "ttl", default_ttl);
+ if (ttl > 0)
+ default_ttl = ttl;
++ apply_root_cred = conf_get_bool("mountd", "apply-root-cred",
++ apply_root_cred);
+ }
+
+ int
+@@ -794,6 +815,9 @@ main(int argc, char **argv)
+ }
+ default_ttl = ttl;
+ break;
++ case 'c':
++ apply_root_cred = 1;
++ break;
+ case 0:
+ break;
+ case '?':
+diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
+index a206a3e2..f4f1fc23 100644
+--- a/utils/mountd/mountd.man
++++ b/utils/mountd/mountd.man
+@@ -242,6 +242,32 @@ can support both NFS version 2 and the newer version 3.
+ Print the version of
+ .B rpc.mountd
+ and exit.
++.TP
++.B \-c " or " \-\-apply-root-cred
++When mountd is asked to allow a NFSv3 mount to a subdirectory of the
++exported directory, then it will check if the user asking to mount has
++lookup rights to the directories below that exported directory. When
++performing the check, mountd will apply any root squash or all squash
++rules that were specified for that client.
++
++Performing lookup checks as the user requires that the mountd daemon
++be run as root or that it be given CAP_SETUID and CAP_SETGID privileges
++so that it can change its own effective user and effective group settings.
++When troubleshooting, please also note that LSM frameworks such as SELinux
++can sometimes prevent the daemon from changing the effective user/groups
++despite the capability settings.
++
++In earlier versions of mountd, the same checks were performed using the
++mountd daemon's root privileges, meaning that it could authorise access
++to directories that are not normally accessible to the user requesting
++to mount them. This option enables that legacy behaviour.
++
++.BR Note:
++If there is a need to provide access to specific subdirectories that
++are not normally accessible to a client, it is always possible to add
++export entries that explicitly grant such access. That ability does
++not depend on this option being enabled.
++
+ .TP
+ .B \-g " or " \-\-manage-gids
+ Accept requests from the kernel to map user id numbers into lists of
+--
+2.44.4
+
diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils_2.6.4.bb b/meta/recipes-connectivity/nfs-utils/nfs-utils_2.6.4.bb
index 2f2644f9a8..91c74fe5ef 100644
--- a/meta/recipes-connectivity/nfs-utils/nfs-utils_2.6.4.bb
+++ b/meta/recipes-connectivity/nfs-utils/nfs-utils_2.6.4.bb
@@ -33,6 +33,12 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/nfs-utils/${PV}/nfs-utils-${PV}.tar.x
file://0001-locktest-Makefile.am-Do-not-use-build-flags.patch \
file://0001-tools-locktest-Use-intmax_t-to-print-off_t.patch \
file://0001-reexport.h-Include-unistd.h-to-compile-with-musl.patch \
+ file://CVE-2025-12801-dependent_p1.patch \
+ file://CVE-2025-12801-dependent_p2.patch \
+ file://CVE-2025-12801-dependent_p3.patch \
+ file://CVE-2025-12801-dependent_p4.patch \
+ file://CVE-2025-12801.patch \
+ file://CVE-2025-12801-build-fix.patch \
"
SRC_URI[sha256sum] = "01b3b0fb9c7d0bbabf5114c736542030748c788ec2fd9734744201e9b0a1119d"
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [OE-core][scarthgap 03/21] nfs-utils: fix CVE-2025-12801
2026-06-12 14:25 ` [OE-core][scarthgap 03/21] nfs-utils: fix CVE-2025-12801 Jeremy Rosen
@ 2026-06-15 7:59 ` Paul Barker
2026-06-16 7:43 ` [scarthgap " Sudhir Dumbhare
0 siblings, 1 reply; 24+ messages in thread
From: Paul Barker @ 2026-06-15 7:59 UTC (permalink / raw)
To: jeremy.rosen, openembedded-core; +Cc: Sudhir Dumbhare, Yoann Congal
[-- Attachment #1: Type: text/plain, Size: 4773 bytes --]
On Fri, 2026-06-12 at 16:25 +0200, Jérémy Rosen via
lists.openembedded.org wrote:
> From: Sudhir Dumbhare <sudumbha@cisco.com>
+Cc Sudhir
>
> - This patch applies the upstream fix [5] as referenced in [7].
> - To successfully apply the fixed commit, apply the dependent commits [2] to [4]
> which are included in v2.8.6, as referenced in [7].
> - Additionally, include dependent commit [1] from v2.8.3, as referenced in [8]
> under the [2.5.4-38.2] description, along with compilation fix commit [6]
> from v2.7.1
> - Reference:
> [1] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=cd90f2925790
> [2] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=7e8b36522f58
> [3] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=42f01e6a78fe
> [4] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=51738ae56d92
> [5] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=f36bd900a899
> [6] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=a2c95e4f557a
> [7] https://security-tracker.debian.org/tracker/CVE-2025-12801
> [8] https://linux.oracle.com/errata/ELSA-2026-3940.html
>
> Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
> Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
[snip]
> diff --git a/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p1.patch b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p1.patch
> new file mode 100644
> index 0000000000..223249a9d6
> --- /dev/null
> +++ b/meta/recipes-connectivity/nfs-utils/nfs-utils/CVE-2025-12801-dependent_p1.patch
> @@ -0,0 +1,71 @@
> +From 647c9cb3ac3cbdf9ffd9e29f7d5dd04da84afdbc Mon Sep 17 00:00:00 2001
> +From: Christopher Bii <christopherbii@hyub.org>
> +Date: Wed, 15 Jan 2025 12:10:48 -0500
> +Subject: [PATCH] NFS export symlink vulnerability fix
> +
> +Replaced dangerous use of realpath within support/nfs/export.c with
> +nfsd_realpath variant that is executed within the chrooted thread
> +rather than main thread.
> +
> +Implemented nfsd_path.h methods to work securely within chrooted
> +thread using nfsd_run_task() help
> +
> +CVE: CVE-2025-12801
> +Upstream-Status: Backport [https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=cd90f29257904f36509ea5a04a86f42398fbe94a]
> +
> +Backport Changes:
> +- In support/misc/nfsd_path.c file, only nfsd_run_task() and the
> + struct nfsd_task_t have been included to resolve a compilation
> + issue. All other non-essential changes were excluded.
> +- The non-required file support/export/cache.c and support/nfs/exports.c
> + has been excluded.
> +
> +Signed-off-by: Christopher Bii <christopherbii@hyub.org>
> +Signed-off-by: Steve Dickson <steved@redhat.com>
> +(cherry picked from commit cd90f29257904f36509ea5a04a86f42398fbe94a)
> +Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
> +---
> + support/include/nfsd_path.h | 1 +
> + support/misc/nfsd_path.c | 14 +++++++++++++-
> + 2 files changed, 14 insertions(+), 1 deletion(-)
> +
> +diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h
> +index aa1e1dd0..4f5fc44e 100644
> +--- a/support/include/nfsd_path.h
> ++++ b/support/include/nfsd_path.h
> +@@ -8,6 +8,7 @@
> +
> + struct file_handle;
> + struct statfs;
> ++struct nfsd_task_t;
> +
> + void nfsd_path_init(void);
> +
> +diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
> +index c3dea4f0..fa908f7c 100644
> +--- a/support/misc/nfsd_path.c
> ++++ b/support/misc/nfsd_path.c
> +@@ -19,7 +19,19 @@
> + #include "nfsd_path.h"
> + #include "workqueue.h"
> +
> +-static struct xthread_workqueue *nfsd_wq;
> ++static struct xthread_workqueue *nfsd_wq = NULL;
> ++
> ++struct nfsd_task_t {
> ++ int ret;
> ++ void* data;
> ++};
> ++/* Function used to offload tasks that must be ran within the correct
> ++ * chroot environment.
> ++ */
> ++static void
> ++nfsd_run_task(void (*func)(void*), void* data){
> ++ nfsd_wq ? xthread_work_run_sync(nfsd_wq, func, data) : func(data);
> ++};
> +
> + static int
> + nfsd_path_isslash(const char *path)
> +--
> +2.35.6
> +
Reading the commit message, and looking at the diff in the original
commit [1], I think we should apply the complete patch here. And it
seems that's what RedHat have done when backporting this fix for RHEL
9 [2].
Sudhir, what's the reason for trimming the patch down?
[1]: https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=cd90f29257904f36509ea5a04a86f42398fbe94a
[2]: https://gitlab.com/redhat/centos-stream/rpms/nfs-utils/-/commit/6f332316f7aa605d67f6b60db0be68f63bf28f9c
Best regards,
--
Paul Barker
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [scarthgap 03/21] nfs-utils: fix CVE-2025-12801
2026-06-15 7:59 ` Paul Barker
@ 2026-06-16 7:43 ` Sudhir Dumbhare
0 siblings, 0 replies; 24+ messages in thread
From: Sudhir Dumbhare @ 2026-06-16 7:43 UTC (permalink / raw)
To: openembedded-core
[-- Attachment #1: Type: text/plain, Size: 1400 bytes --]
Hi Paul,
Thank you for pointing this out and for referencing both the original upstream commit and the RHEL backport.
When applying the upstream change, including prerequisites [1][2][3] and the fix [4], as noted in [6],
we observed the following compilation failure on scarthgap with nfs-utils v2.6.4:
nfsd_path.c:322:17: error: implicit declaration of function 'nfsd_run_task'
Because of this, we backported only the required changes from [5], specifically nfsd_run_task() and
struct nfsd_task_t, to support the fix. Non-essential parts were trimmed to keep the patch minimal
and build-safe for scarthgap.
Please let us know if you would prefer us to align with the full backport, similar to the RHEL approach.
References:
[1] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=7e8b36522f58657359c6842119fc516c6dd1baa4
[2] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=42f01e6a78fed98f12437ac8b28cfb12b6bad056
[3] https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=51738ae56d922d4961e60dad73ad1c2d97d8d99b
[4] Fixed by: https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=f36bd900a899088ca1925de079bd58d6205a1f3c
[5] Dependent patch: https://git.linux-nfs.org/?p=steved/nfs-utils.git;a=commit;h=cd90f29257904f36509ea5a04a86f42398fbe94a
[6] https://security-tracker.debian.org/tracker/CVE-2025-12801
Thanks and regards,
Sudhir
[-- Attachment #2: Type: text/html, Size: 1499 bytes --]
^ permalink raw reply [flat|nested] 24+ messages in thread
* [OE-core][scarthgap 04/21] xz: Fix CVE-2026-34743
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (2 preceding siblings ...)
2026-06-12 14:25 ` [OE-core][scarthgap 03/21] nfs-utils: fix CVE-2025-12801 Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 05/21] util-linux: Fix CVE-2026-27456 Jeremy Rosen
` (16 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Hugo SIMELIERE (Schneider Electric)" <hsimeliere.opensource@witekio.com>
Pick patch from [1] as 5.4.x upstream backport of [2] mentioned in Debian report in [3].
[1] https://github.com/tukaani-project/xz/commit/8538443d08591693a8c61f3a03656650f39c7c32
[2] https://github.com/tukaani-project/xz/commit/c8c22869e780ff57c96b46939c3d79ff99395f87
[3] https://security-tracker.debian.org/tracker/CVE-2026-34743
Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
Reviewed-by: Bruno VERNAY <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
.../xz/xz/CVE-2026-34743.patch | 68 +++++++++++++++++++
meta/recipes-extended/xz/xz_5.4.7.bb | 1 +
2 files changed, 69 insertions(+)
create mode 100644 meta/recipes-extended/xz/xz/CVE-2026-34743.patch
diff --git a/meta/recipes-extended/xz/xz/CVE-2026-34743.patch b/meta/recipes-extended/xz/xz/CVE-2026-34743.patch
new file mode 100644
index 0000000000..f890851cb2
--- /dev/null
+++ b/meta/recipes-extended/xz/xz/CVE-2026-34743.patch
@@ -0,0 +1,68 @@
+From ae7abca7c721c73bb4aadf41a82a720a842a4364 Mon Sep 17 00:00:00 2001
+From: Lasse Collin <lasse.collin@tukaani.org>
+Date: Sun, 29 Mar 2026 19:11:21 +0300
+Subject: [PATCH] liblzma: Fix a buffer overflow in lzma_index_append()
+
+If lzma_index_decoder() was used to decode an Index that contained no
+Records, the resulting lzma_index had an invalid internal "prealloc"
+value. If lzma_index_append() was called on this lzma_index, too
+little memory would be allocated and a buffer overflow would occur.
+
+While this combination of the API functions is meant to work, in the
+real-world apps this call sequence is rare or might not exist at all.
+
+This bug is older than xz 5.0.0, so all stable releases are affected.
+
+CVE: CVE-2026-34743
+Upstream-Status: Backport [https://github.com/tukaani-project/xz/commit/8538443d08591693a8c61f3a03656650f39c7c32]
+
+Reported-by: GitHub user christos-spearbit
+(cherry picked from commit c8c22869e780ff57c96b46939c3d79ff99395f87)
+(cherry picked from commit 8538443d08591693a8c61f3a03656650f39c7c32)
+Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
+---
+ src/liblzma/common/index.c | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/src/liblzma/common/index.c b/src/liblzma/common/index.c
+index 8a35f439..dae7cab5 100644
+--- a/src/liblzma/common/index.c
++++ b/src/liblzma/common/index.c
+@@ -434,6 +434,26 @@ lzma_index_prealloc(lzma_index *i, lzma_vli records)
+ if (records > PREALLOC_MAX)
+ records = PREALLOC_MAX;
+
++ // If index_decoder.c calls us with records == 0, it's decoding
++ // an Index that has no Records. In that case the decoder won't call
++ // lzma_index_append() at all, and i->prealloc isn't used during
++ // the Index decoding either.
++ //
++ // Normally the first lzma_index_append() call from the Index decoder
++ // would reset i->prealloc to INDEX_GROUP_SIZE. With no Records,
++ // lzma_index_append() isn't called and the resetting of prealloc
++ // won't occur either. Thus, if records == 0, use the default value
++ // INDEX_GROUP_SIZE instead.
++ //
++ // NOTE: lzma_index_append() assumes i->prealloc > 0. liblzma <= 5.8.2
++ // didn't have this check and could set i->prealloc = 0, which would
++ // result in a buffer overflow if the application called
++ // lzma_index_append() after decoding an empty Index. Appending
++ // Records after decoding an Index is a rare thing to do, but
++ // it is supposed to work.
++ if (records == 0)
++ records = INDEX_GROUP_SIZE;
++
+ i->prealloc = (size_t)(records);
+ return;
+ }
+@@ -686,6 +706,7 @@ lzma_index_append(lzma_index *i, const lzma_allocator *allocator,
+ ++g->last;
+ } else {
+ // We need to allocate a new group.
++ assert(i->prealloc > 0);
+ g = lzma_alloc(sizeof(index_group)
+ + i->prealloc * sizeof(index_record),
+ allocator);
+--
+2.43.0
+
diff --git a/meta/recipes-extended/xz/xz_5.4.7.bb b/meta/recipes-extended/xz/xz_5.4.7.bb
index 30a4c8e88c..72759edea0 100644
--- a/meta/recipes-extended/xz/xz_5.4.7.bb
+++ b/meta/recipes-extended/xz/xz_5.4.7.bb
@@ -30,6 +30,7 @@ SRC_URI = "https://github.com/tukaani-project/xz/releases/download/v${PV}/xz-${P
file://CVE-2025-31115-02.patch \
file://CVE-2025-31115-03.patch \
file://CVE-2025-31115-04.patch \
+ file://CVE-2026-34743.patch \
"
SRC_URI[sha256sum] = "8db6664c48ca07908b92baedcfe7f3ba23f49ef2476864518ab5db6723836e71"
UPSTREAM_CHECK_REGEX = "releases/tag/v(?P<pver>\d+(\.\d+)+)"
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 05/21] util-linux: Fix CVE-2026-27456
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (3 preceding siblings ...)
2026-06-12 14:25 ` [OE-core][scarthgap 04/21] xz: Fix CVE-2026-34743 Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 06/21] devtool: prevent 'devtool modify -n' from corrupting kernel Git repos Jeremy Rosen
` (15 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Hugo SIMELIERE (Schneider Electric)" <hsimeliere.opensource@witekio.com>
Pick patch from [1] as 2.39.x upstream backport of [2] mentioned in Debian report in [3].
[1] https://github.com/util-linux/util-linux/commit/79164668a412b71fcb1495c7d299cc5e9741fa30
[2] https://github.com/util-linux/util-linux/commit/0ba0f14caa812349424df0da00ac2d97fee9d972
[3] https://security-tracker.debian.org/tracker/CVE-2026-27456
Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
Reviewed-by: Bruno VERNAY <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-core/util-linux/util-linux.inc | 1 +
.../util-linux/CVE-2026-27456.patch | 115 ++++++++++++++++++
2 files changed, 116 insertions(+)
create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2026-27456.patch
diff --git a/meta/recipes-core/util-linux/util-linux.inc b/meta/recipes-core/util-linux/util-linux.inc
index 4797682c5d..8380419634 100644
--- a/meta/recipes-core/util-linux/util-linux.inc
+++ b/meta/recipes-core/util-linux/util-linux.inc
@@ -46,6 +46,7 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin
file://sys-utils-hwclock-rtc-fix-pointer-usage.patch \
file://CVE-2025-14104-01.patch \
file://CVE-2025-14104-02.patch \
+ file://CVE-2026-27456.patch \
"
SRC_URI[sha256sum] = "7b6605e48d1a49f43cc4b4cfc59f313d0dd5402fa40b96810bd572e167dfed0f"
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2026-27456.patch b/meta/recipes-core/util-linux/util-linux/CVE-2026-27456.patch
new file mode 100644
index 0000000000..4a5fef26d3
--- /dev/null
+++ b/meta/recipes-core/util-linux/util-linux/CVE-2026-27456.patch
@@ -0,0 +1,115 @@
+From af0b619f8eb15f738c69e33e0bb3a794e9cccf17 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 19 Feb 2026 13:59:46 +0100
+Subject: [PATCH] loopdev: add LOOPDEV_FL_NOFOLLOW to prevent symlink attacks
+
+Add a new LOOPDEV_FL_NOFOLLOW flag for loop device context that
+prevents symlink following in both path canonicalization and file open.
+
+When set:
+- loopcxt_set_backing_file() uses strdup() instead of
+ ul_canonicalize_path() (which calls realpath() and follows symlinks)
+- loopcxt_setup_device() adds O_NOFOLLOW to open() flags
+
+The flag is set for non-root (restricted) mount operations in
+libmount's loop device hook. This prevents a TOCTOU race condition
+where an attacker could replace the backing file (specified in
+/etc/fstab) with a symlink to an arbitrary root-owned file between
+path resolution and open().
+
+Vulnerable Code Flow:
+
+ mount /mnt/point (non-root, SUID)
+ mount.c: sanitize_paths() on user args (mountpoint only)
+ mnt_context_mount()
+ mnt_context_prepare_mount()
+ mnt_context_apply_fstab() <-- source path from fstab
+ hooks run at MNT_STAGE_PREP_SOURCE
+ hook_loopdev.c: setup_loopdev()
+ backing_file = fstab source path ("/home/user/disk.img")
+ loopcxt_set_backing_file() <-- calls realpath() as ROOT
+ ul_canonicalize_path() <-- follows symlinks!
+ loopcxt_setup_device()
+ open(lc->filename, O_RDWR|O_CLOEXEC) <-- no O_NOFOLLOW
+
+Two vulnerabilities in the path:
+
+1) loopcxt_set_backing_file() calls ul_canonicalize_path() which uses
+ realpath() -- this follows symlinks as euid=0. If the attacker swaps
+ the file to a symlink before this call, lc->filename becomes the
+ resolved target path (e.g., /root/secret.img).
+
+2) loopcxt_setup_device() opens lc->filename without O_NOFOLLOW. Even
+ if canonicalization happened correctly, the file can be swapped to a
+ symlink between canonicalize and open.
+
+CVE: CVE-2026-27456
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/79164668a412b71fcb1495c7d299cc5e9741fa30]
+
+Addresses: https://github.com/util-linux/util-linux/security/advisories/GHSA-qq4x-vfq4-9h9g
+Signed-off-by: Karel Zak <kzak@redhat.com>
+(cherry picked from commit 5e390467b26a3cf3fecc04e1a0d482dff3162fc4)
+(cherry picked from commit 79164668a412b71fcb1495c7d299cc5e9741fa30)
+Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
+---
+ include/loopdev.h | 3 ++-
+ lib/loopdev.c | 7 ++++++-
+ libmount/src/hook_loopdev.c | 3 ++-
+ 3 files changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/include/loopdev.h b/include/loopdev.h
+index 903adc491..d03e9b65e 100644
+--- a/include/loopdev.h
++++ b/include/loopdev.h
+@@ -139,7 +139,8 @@ enum {
+ LOOPDEV_FL_NOIOCTL = (1 << 6),
+ LOOPDEV_FL_DEVSUBDIR = (1 << 7),
+ LOOPDEV_FL_CONTROL = (1 << 8), /* system with /dev/loop-control */
+- LOOPDEV_FL_SIZELIMIT = (1 << 9)
++ LOOPDEV_FL_SIZELIMIT = (1 << 9),
++ LOOPDEV_FL_NOFOLLOW = (1 << 10) /* O_NOFOLLOW, don't follow symlinks */
+ };
+
+ /*
+diff --git a/lib/loopdev.c b/lib/loopdev.c
+index dd9ead3ee..4da251812 100644
+--- a/lib/loopdev.c
++++ b/lib/loopdev.c
+@@ -1193,7 +1193,10 @@ int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename)
+ if (!lc)
+ return -EINVAL;
+
+- lc->filename = canonicalize_path(filename);
++ if (lc->flags & LOOPDEV_FL_NOFOLLOW)
++ lc->filename = strdup(filename);
++ else
++ lc->filename = canonicalize_path(filename);
+ if (!lc->filename)
+ return -errno;
+
+@@ -1332,6 +1335,8 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
+
+ if (lc->config.info.lo_flags & LO_FLAGS_DIRECT_IO)
+ flags |= O_DIRECT;
++ if (lc->flags & LOOPDEV_FL_NOFOLLOW)
++ flags |= O_NOFOLLOW;
+
+ if ((file_fd = open(lc->filename, mode | flags)) < 0) {
+ if (mode != O_RDONLY && (errno == EROFS || errno == EACCES))
+diff --git a/libmount/src/hook_loopdev.c b/libmount/src/hook_loopdev.c
+index 8c8f7f218..ce39a7a70 100644
+--- a/libmount/src/hook_loopdev.c
++++ b/libmount/src/hook_loopdev.c
+@@ -276,7 +276,8 @@ static int setup_loopdev(struct libmnt_context *cxt,
+ }
+
+ DBG(LOOP, ul_debugobj(cxt, "not found; create a new loop device"));
+- rc = loopcxt_init(&lc, 0);
++ rc = loopcxt_init(&lc,
++ mnt_context_is_restricted(cxt) ? LOOPDEV_FL_NOFOLLOW : 0);
+ if (rc)
+ goto done_no_deinit;
+ if (mnt_opt_has_value(loopopt)) {
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 06/21] devtool: prevent 'devtool modify -n' from corrupting kernel Git repos
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (4 preceding siblings ...)
2026-06-12 14:25 ` [OE-core][scarthgap 05/21] util-linux: Fix CVE-2026-27456 Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 07/21] go: patch CVE-2026-27142 Jeremy Rosen
` (14 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: Enrico Jörns <ejo@pengutronix.de>
Running 'devtool modify -n' on a kernel recipe that inherits
'kernel-yocto' can unintentionally corrupt an existing Git repo or
worktree.
The work-shared optimization introduced in 3c3a9bae ("devtool/standard.py:
Update devtool modify to copy source from work-shared if its already
downloaded") is not skipped when '--no-extract' ('args.no_extract') is set.
As a result, for kernel builds where STAGING_KERNEL_DIR was already
populated when running 'devtool modify -n', the existing source tree is
overwritten (via oe.path.copyhardlinktree()) with the contents of
STAGING_KERNEL_DIR.
Fix by adding 'and not args.no_extract' to the kernel-yocto guard
condition.
(cherry picked from commit d383ea37e4987ecabe011226f1a8e658a52ede12)
Signed-off-by: Enrico Jörns <ejo@pengutronix.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
scripts/lib/devtool/standard.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py
index 908869cc4f..e1e519ce5b 100644
--- a/scripts/lib/devtool/standard.py
+++ b/scripts/lib/devtool/standard.py
@@ -841,7 +841,8 @@ def modify(args, config, basepath, workspace):
commits = {}
check_commits = False
- if bb.data.inherits_class('kernel-yocto', rd):
+ if bb.data.inherits_class('kernel-yocto', rd) and not args.no_extract:
+
# Current set kernel version
kernelVersion = rd.getVar('LINUX_VERSION')
srcdir = rd.getVar('STAGING_KERNEL_DIR')
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 07/21] go: patch CVE-2026-27142
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (5 preceding siblings ...)
2026-06-12 14:25 ` [OE-core][scarthgap 06/21] devtool: prevent 'devtool modify -n' from corrupting kernel Git repos Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 08/21] go: patch CVE-2026-32280 Jeremy Rosen
` (13 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/752081
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-27142.patch | 386 ++++++++++++++++++
2 files changed, 387 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-27142.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 3fa421e223..8efa82f862 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -41,6 +41,7 @@ SRC_URI += "\
file://CVE-2025-68121_p1.patch \
file://CVE-2025-68121_p2.patch \
file://CVE-2025-68121_p3.patch \
+ file://CVE-2026-27142.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-27142.patch b/meta/recipes-devtools/go/go/CVE-2026-27142.patch
new file mode 100644
index 0000000000..e735abaf4b
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-27142.patch
@@ -0,0 +1,386 @@
+From 1ac19df75e9c25951c04008a52b23a1cd95e81cc Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Fri, 9 Jan 2026 11:12:01 -0800
+Subject: [PATCH] html/template: properly escape URLs in meta content
+ attributes
+
+The meta tag can include a content attribute that contains URLs, which
+we currently don't escape if they are inserted via a template action.
+This can plausibly lead to XSS vulnerabilities if untrusted data is
+inserted there, the http-equiv attribute is set to "refresh", and the
+content attribute contains an action like `url={{.}}`.
+
+Track whether we are inside of a meta element, if we are inside of a
+content attribute, _and_ if the content attribute contains "url=". If
+all of those are true, then we will apply the same URL escaping that we
+use elsewhere.
+
+Also add a new GODEBUG, htmlmetacontenturlescape, to allow disabling this
+escaping for cases where this behavior is considered safe. The behavior
+can be disabled by setting htmlmetacontenturlescape=0.
+
+Updates #77954
+Fixes #77972
+Fixes CVE-2026-27142
+
+Change-Id: I9bbca263be9894688e6ef1e9a8f8d2f4304f5873
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3360
+Reviewed-by: Neal Patel <nealpatel@google.com>
+Reviewed-by: Nicholas Husin <husin@google.com>
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3643
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/752081
+Auto-Submit: Gopher Robot <gobot@golang.org>
+Reviewed-by: Cherry Mui <cherryyz@google.com>
+TryBot-Bypass: Gopher Robot <gobot@golang.org>
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+
+CVE: CVE-2026-27142
+Upstream-Status: Backport [https://github.com/golang/go/commit/994692847a2cd3efd319f0cb61a07c0012c8a4ff]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ doc/godebug.md | 5 +++
+ src/html/template/attr_string.go | 5 +--
+ src/html/template/context.go | 8 +++++
+ src/html/template/element_string.go | 5 +--
+ src/html/template/escape.go | 14 +++++++++
+ src/html/template/escape_test.go | 34 +++++++++++++++++++++
+ src/html/template/state_string.go | 8 +++--
+ src/html/template/transition.go | 47 +++++++++++++++++++++++++----
+ src/internal/godebugs/table.go | 1 +
+ src/runtime/metrics/doc.go | 5 +++
+ 10 files changed, 119 insertions(+), 13 deletions(-)
+
+diff --git a/doc/godebug.md b/doc/godebug.md
+index 635597e..07b63cb 100644
+--- a/doc/godebug.md
++++ b/doc/godebug.md
+@@ -126,6 +126,11 @@ for example,
+ see the [runtime documentation](/pkg/runtime#hdr-Environment_Variables)
+ and the [go command documentation](/cmd/go#hdr-Build_and_test_caching).
+
++Go 1.26.1 added a new `htmlmetacontenturlescape` setting that controls whether
++html/template will escape URLs in the `url=` portion of the content attribute of
++HTML meta tags. The default `htmlmetacontentescape=1` will cause URLs to be
++escaped. Setting `htmlmetacontentescape=0` disables this behavior.
++
+ Go 1.26 added a new `urlmaxqueryparams` setting that controls the maximum number
+ of query parameters that net/url will accept when parsing a URL-encoded query string.
+ If the number of parameters exceeds the number set in `urlmaxqueryparams`,
+diff --git a/src/html/template/attr_string.go b/src/html/template/attr_string.go
+index 51c3f26..7159fa9 100644
+--- a/src/html/template/attr_string.go
++++ b/src/html/template/attr_string.go
+@@ -14,11 +14,12 @@ func _() {
+ _ = x[attrStyle-3]
+ _ = x[attrURL-4]
+ _ = x[attrSrcset-5]
++ _ = x[attrMetaContent-6]
+ }
+
+-const _attr_name = "attrNoneattrScriptattrScriptTypeattrStyleattrURLattrSrcset"
++const _attr_name = "attrNoneattrScriptattrScriptTypeattrStyleattrURLattrSrcsetattrMetaContent"
+
+-var _attr_index = [...]uint8{0, 8, 18, 32, 41, 48, 58}
++var _attr_index = [...]uint8{0, 8, 18, 32, 41, 48, 58, 73}
+
+ func (i attr) String() string {
+ if i >= attr(len(_attr_index)-1) {
+diff --git a/src/html/template/context.go b/src/html/template/context.go
+index b78f0f7..8b3af2f 100644
+--- a/src/html/template/context.go
++++ b/src/html/template/context.go
+@@ -156,6 +156,10 @@ const (
+ // stateError is an infectious error state outside any valid
+ // HTML/CSS/JS construct.
+ stateError
++ // stateMetaContent occurs inside a HTML meta element content attribute.
++ stateMetaContent
++ // stateMetaContentURL occurs inside a "url=" tag in a HTML meta element content attribute.
++ stateMetaContentURL
+ // stateDead marks unreachable code after a {{break}} or {{continue}}.
+ stateDead
+ )
+@@ -267,6 +271,8 @@ const (
+ elementTextarea
+ // elementTitle corresponds to the RCDATA <title> element.
+ elementTitle
++ // elementMeta corresponds to the HTML <meta> element.
++ elementMeta
+ )
+
+ //go:generate stringer -type attr
+@@ -288,4 +294,6 @@ const (
+ attrURL
+ // attrSrcset corresponds to a srcset attribute.
+ attrSrcset
++ // attrMetaContent corresponds to the content attribute in meta HTML element.
++ attrMetaContent
+ )
+diff --git a/src/html/template/element_string.go b/src/html/template/element_string.go
+index db28665..bdf9da7 100644
+--- a/src/html/template/element_string.go
++++ b/src/html/template/element_string.go
+@@ -13,11 +13,12 @@ func _() {
+ _ = x[elementStyle-2]
+ _ = x[elementTextarea-3]
+ _ = x[elementTitle-4]
++ _ = x[elementMeta-5]
+ }
+
+-const _element_name = "elementNoneelementScriptelementStyleelementTextareaelementTitle"
++const _element_name = "elementNoneelementScriptelementStyleelementTextareaelementTitleelementMeta"
+
+-var _element_index = [...]uint8{0, 11, 24, 36, 51, 63}
++var _element_index = [...]uint8{0, 11, 24, 36, 51, 63, 74}
+
+ func (i element) String() string {
+ if i >= element(len(_element_index)-1) {
+diff --git a/src/html/template/escape.go b/src/html/template/escape.go
+index 1eace16..b368cab 100644
+--- a/src/html/template/escape.go
++++ b/src/html/template/escape.go
+@@ -165,6 +165,8 @@ func (e *escaper) escape(c context, n parse.Node) context {
+
+ var debugAllowActionJSTmpl = godebug.New("jstmpllitinterp")
+
++var htmlmetacontenturlescape = godebug.New("htmlmetacontenturlescape")
++
+ // escapeAction escapes an action template node.
+ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
+ if len(n.Pipe.Decl) != 0 {
+@@ -222,6 +224,18 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
+ default:
+ panic(c.urlPart.String())
+ }
++ case stateMetaContent:
++ // Handled below in delim check.
++ case stateMetaContentURL:
++ if htmlmetacontenturlescape.Value() != "0" {
++ s = append(s, "_html_template_urlfilter")
++ } else {
++ // We don't have a great place to increment this, since it's hard to
++ // know if we actually escape any urls in _html_template_urlfilter,
++ // since it has no information about what context it is being
++ // executed in etc. This is probably the best we can do.
++ htmlmetacontenturlescape.IncNonDefault()
++ }
+ case stateJS:
+ s = append(s, "_html_template_jsvalescaper")
+ // A slash after a value starts a div operator.
+diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
+index 497ead8..1970db1 100644
+--- a/src/html/template/escape_test.go
++++ b/src/html/template/escape_test.go
+@@ -734,6 +734,16 @@ func TestEscape(t *testing.T) {
+ "<script>var a = `${ var a = \"{{\"a \\\" d\"}}\" }`</script>",
+ "<script>var a = `${ var a = \"a \\u0022 d\" }`</script>",
+ },
++ {
++ "meta content attribute url",
++ `<meta http-equiv="refresh" content="asd; url={{"javascript:alert(1)"}}; asd; url={{"vbscript:alert(1)"}}; asd">`,
++ `<meta http-equiv="refresh" content="asd; url=#ZgotmplZ; asd; url=#ZgotmplZ; asd">`,
++ },
++ {
++ "meta content string",
++ `<meta http-equiv="refresh" content="{{"asd: 123"}}">`,
++ `<meta http-equiv="refresh" content="asd: 123">`,
++ },
+ }
+
+ for _, test := range tests {
+@@ -1016,6 +1026,14 @@ func TestErrors(t *testing.T) {
+ "<script>var tmpl = `asd ${return \"{\"}`;</script>",
+ ``,
+ },
++ {
++ `{{if eq "" ""}}<meta>{{end}}`,
++ ``,
++ },
++ {
++ `{{if eq "" ""}}<meta content="url={{"asd"}}">{{end}}`,
++ ``,
++ },
+
+ // Error cases.
+ {
+@@ -2194,3 +2212,19 @@ func TestAliasedParseTreeDoesNotOverescape(t *testing.T) {
+ t.Fatalf(`Template "foo" and "bar" rendered %q and %q respectively, expected equal values`, got1, got2)
+ }
+ }
++
++func TestMetaContentEscapeGODEBUG(t *testing.T) {
++ savedGODEBUG := os.Getenv("GODEBUG")
++ os.Setenv("GODEBUG", savedGODEBUG+",htmlmetacontenturlescape=0")
++ defer func() { os.Setenv("GODEBUG", savedGODEBUG) }()
++
++ tmpl := Must(New("").Parse(`<meta http-equiv="refresh" content="asd; url={{"javascript:alert(1)"}}; asd; url={{"vbscript:alert(1)"}}; asd">`))
++ var b strings.Builder
++ if err := tmpl.Execute(&b, nil); err != nil {
++ t.Fatalf("unexpected error: %s", err)
++ }
++ want := `<meta http-equiv="refresh" content="asd; url=javascript:alert(1); asd; url=vbscript:alert(1); asd">`
++ if got := b.String(); got != want {
++ t.Fatalf("got %q, want %q", got, want)
++ }
++}
+diff --git a/src/html/template/state_string.go b/src/html/template/state_string.go
+index eed1e8b..f5a70b2 100644
+--- a/src/html/template/state_string.go
++++ b/src/html/template/state_string.go
+@@ -36,12 +36,14 @@ func _() {
+ _ = x[stateCSSBlockCmt-25]
+ _ = x[stateCSSLineCmt-26]
+ _ = x[stateError-27]
+- _ = x[stateDead-28]
++ _ = x[stateMetaContent-28]
++ _ = x[stateMetaContentURL-29]
++ _ = x[stateDead-30]
+ }
+
+-const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSTmplLitstateJSRegexpstateJSBlockCmtstateJSLineCmtstateJSHTMLOpenCmtstateJSHTMLCloseCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead"
++const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSTmplLitstateJSRegexpstateJSBlockCmtstateJSLineCmtstateJSHTMLOpenCmtstateJSHTMLCloseCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateMetaContentstateMetaContentURLstateDead"
+
+-var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 156, 169, 184, 198, 216, 235, 243, 256, 269, 282, 295, 306, 322, 337, 347, 356}
++var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 156, 169, 184, 198, 216, 235, 243, 256, 269, 282, 295, 306, 322, 337, 347, 363, 382, 391}
+
+ func (i state) String() string {
+ if i >= state(len(_state_index)-1) {
+diff --git a/src/html/template/transition.go b/src/html/template/transition.go
+index d5a05f6..5aa3c35 100644
+--- a/src/html/template/transition.go
++++ b/src/html/template/transition.go
+@@ -23,6 +23,8 @@ var transitionFunc = [...]func(context, []byte) (context, int){
+ stateRCDATA: tSpecialTagEnd,
+ stateAttr: tAttr,
+ stateURL: tURL,
++ stateMetaContent: tMetaContent,
++ stateMetaContentURL: tMetaContentURL,
+ stateSrcset: tURL,
+ stateJS: tJS,
+ stateJSDqStr: tJSDelimited,
+@@ -83,6 +85,7 @@ var elementContentType = [...]state{
+ elementStyle: stateCSS,
+ elementTextarea: stateRCDATA,
+ elementTitle: stateRCDATA,
++ elementMeta: stateText,
+ }
+
+ // tTag is the context transition function for the tag state.
+@@ -93,6 +96,11 @@ func tTag(c context, s []byte) (context, int) {
+ return c, len(s)
+ }
+ if s[i] == '>' {
++ // Treat <meta> specially, because it doesn't have an end tag, and we
++ // want to transition into the correct state/element for it.
++ if c.element == elementMeta {
++ return context{state: stateText, element: elementNone}, i + 1
++ }
+ return context{
+ state: elementContentType[c.element],
+ element: c.element,
+@@ -113,6 +121,8 @@ func tTag(c context, s []byte) (context, int) {
+ attrName := strings.ToLower(string(s[i:j]))
+ if c.element == elementScript && attrName == "type" {
+ attr = attrScriptType
++ } else if c.element == elementMeta && attrName == "content" {
++ attr = attrMetaContent
+ } else {
+ switch attrType(attrName) {
+ case contentTypeURL:
+@@ -162,12 +172,13 @@ func tAfterName(c context, s []byte) (context, int) {
+ }
+
+ var attrStartStates = [...]state{
+- attrNone: stateAttr,
+- attrScript: stateJS,
+- attrScriptType: stateAttr,
+- attrStyle: stateCSS,
+- attrURL: stateURL,
+- attrSrcset: stateSrcset,
++ attrNone: stateAttr,
++ attrScript: stateJS,
++ attrScriptType: stateAttr,
++ attrStyle: stateCSS,
++ attrURL: stateURL,
++ attrSrcset: stateSrcset,
++ attrMetaContent: stateMetaContent,
+ }
+
+ // tBeforeValue is the context transition function for stateBeforeValue.
+@@ -203,6 +214,7 @@ var specialTagEndMarkers = [...][]byte{
+ elementStyle: []byte("style"),
+ elementTextarea: []byte("textarea"),
+ elementTitle: []byte("title"),
++ elementMeta: []byte(""),
+ }
+
+ var (
+@@ -612,6 +624,28 @@ func tError(c context, s []byte) (context, int) {
+ return c, len(s)
+ }
+
++// tMetaContent is the context transition function for the meta content attribute state.
++func tMetaContent(c context, s []byte) (context, int) {
++ for i := 0; i < len(s); i++ {
++ if i+3 <= len(s)-1 && bytes.Equal(bytes.ToLower(s[i:i+4]), []byte("url=")) {
++ c.state = stateMetaContentURL
++ return c, i + 4
++ }
++ }
++ return c, len(s)
++}
++
++// tMetaContentURL is the context transition function for the "url=" part of a meta content attribute state.
++func tMetaContentURL(c context, s []byte) (context, int) {
++ for i := 0; i < len(s); i++ {
++ if s[i] == ';' {
++ c.state = stateMetaContent
++ return c, i + 1
++ }
++ }
++ return c, len(s)
++}
++
+ // eatAttrName returns the largest j such that s[i:j] is an attribute name.
+ // It returns an error if s[i:] does not look like it begins with an
+ // attribute name, such as encountering a quote mark without a preceding
+@@ -638,6 +672,7 @@ var elementNameMap = map[string]element{
+ "style": elementStyle,
+ "textarea": elementTextarea,
+ "title": elementTitle,
++ "meta": elementMeta,
+ }
+
+ // asciiAlpha reports whether c is an ASCII letter.
+diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go
+index 7178df6..90311eb 100644
+--- a/src/internal/godebugs/table.go
++++ b/src/internal/godebugs/table.go
+@@ -31,6 +31,7 @@ var All = []Info{
+ {Name: "gocachetest", Package: "cmd/go"},
+ {Name: "gocacheverify", Package: "cmd/go"},
+ {Name: "gotypesalias", Package: "go/types"},
++ {Name: "htmlmetacontenturlescape", Package: "html/template"},
+ {Name: "http2client", Package: "net/http"},
+ {Name: "http2debug", Package: "net/http", Opaque: true},
+ {Name: "http2server", Package: "net/http"},
+diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go
+index 335f787..f68e386 100644
+--- a/src/runtime/metrics/doc.go
++++ b/src/runtime/metrics/doc.go
+@@ -255,6 +255,11 @@ Below is the full list of supported metrics, ordered lexicographically.
+ The number of non-default behaviors executed by the go/types
+ package due to a non-default GODEBUG=gotypesalias=... setting.
+
++ /godebug/non-default-behavior/htmlmetacontenturlescape:events
++ The number of non-default behaviors executed by
++ the html/template package due to a non-default
++ GODEBUG=htmlmetacontenturlescape=... setting.
++
+ /godebug/non-default-behavior/http2client:events
+ The number of non-default behaviors executed by the net/http
+ package due to a non-default GODEBUG=http2client=... setting.
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 08/21] go: patch CVE-2026-32280
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (6 preceding siblings ...)
2026-06-12 14:25 ` [OE-core][scarthgap 07/21] go: patch CVE-2026-27142 Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:25 ` [OE-core][scarthgap 09/21] go: patch CVE-2026-32283 Jeremy Rosen
` (12 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/758320
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-32280.patch | 289 ++++++++++++++++++
2 files changed, 290 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-32280.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 8efa82f862..0d4dff6c21 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -42,6 +42,7 @@ SRC_URI += "\
file://CVE-2025-68121_p2.patch \
file://CVE-2025-68121_p3.patch \
file://CVE-2026-27142.patch \
+ file://CVE-2026-32280.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-32280.patch b/meta/recipes-devtools/go/go/CVE-2026-32280.patch
new file mode 100644
index 0000000000..9a6f7950ae
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-32280.patch
@@ -0,0 +1,289 @@
+From 1d71a2882078ea5057e68a7d2fedc83a5227c764 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Thu, 5 Mar 2026 14:28:44 -0800
+Subject: [PATCH] crypto/x509: fix signature checking limit
+
+We added the "is this cert already in the chain" check (alreadyInChain)
+to considerCandidates before the signature limit. considerCandidates
+bails out when we exceed the signature check, but buildChains keeps
+calling considerCandidates until it exhausts all potential parents. In
+the case where a large number of certificates look to have signed each
+other (e.g. all have subject==issuerSubject and the same key),
+alreadyInChain is not particularly cheap, meaning even though we hit our
+"this is too much work" limit, we still do a lot of work.
+
+Move alreadyInChain after the signature limit, and also return a
+sentinel error, and check it in buildChains so we can break out of the
+loop early if we aren't actually going to do any more work.
+
+Thanks to Jakub Ciolek for reporting this issue.
+
+Fixes #78282
+Fixes CVE-2026-32280
+
+Change-Id: Ie6f05c6ba3b0a40c21f64f7c4f846e74fae3b10e
+Reviewed-on: https://go-review.googlesource.com/c/go/+/758320
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-by: Neal Patel <nealpatel@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Jakub Ciolek <jakub@ciolek.dev>
+
+CVE: CVE-2026-32280
+Upstream-Status: Backport [https://github.com/golang/go/commit/26d8a902002a2b41bc4c302044110f2eae8d597f]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/crypto/x509/verify.go | 31 ++++---
+ src/crypto/x509/verify_test.go | 150 ++++++++++++++++-----------------
+ 2 files changed, 96 insertions(+), 85 deletions(-)
+
+diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
+index 0ae8aef..1de06bc 100644
+--- a/src/crypto/x509/verify.go
++++ b/src/crypto/x509/verify.go
+@@ -939,6 +939,8 @@ func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
+ // for failed checks due to different intermediates having the same Subject.
+ const maxChainSignatureChecks = 100
+
++var errSignatureLimit = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
++
+ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ var (
+ hintErr error
+@@ -946,16 +948,16 @@ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, o
+ )
+
+ considerCandidate := func(certType int, candidate potentialParent) {
+- if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) {
+- return
+- }
+-
+ if sigChecks == nil {
+ sigChecks = new(int)
+ }
+ *sigChecks++
+ if *sigChecks > maxChainSignatureChecks {
+- err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
++ err = errSignatureLimit
++ return
++ }
++
++ if candidate.cert.PublicKey == nil || alreadyInChain(candidate.cert, currentChain) {
+ return
+ }
+
+@@ -996,11 +998,20 @@ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, o
+ }
+ }
+
+- for _, root := range opts.Roots.findPotentialParents(c) {
+- considerCandidate(rootCertificate, root)
+- }
+- for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
+- considerCandidate(intermediateCertificate, intermediate)
++candidateLoop:
++ for _, parents := range []struct {
++ certType int
++ potentials []potentialParent
++ }{
++ {rootCertificate, opts.Roots.findPotentialParents(c)},
++ {intermediateCertificate, opts.Intermediates.findPotentialParents(c)},
++ } {
++ for _, parent := range parents.potentials {
++ considerCandidate(parents.certType, parent)
++ if err == errSignatureLimit {
++ break candidateLoop
++ }
++ }
+ }
+
+ if len(chains) > 0 {
+diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
+index 223c250..f3711ac 100644
+--- a/src/crypto/x509/verify_test.go
++++ b/src/crypto/x509/verify_test.go
+@@ -1765,10 +1765,13 @@ func TestValidHostname(t *testing.T) {
+ }
+ }
+
+-func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
+- priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+- if err != nil {
+- return nil, nil, err
++func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey, priv crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
++ if priv == nil {
++ var err error
++ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
++ if err != nil {
++ return nil, nil, err
++ }
+ }
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+@@ -1779,6 +1782,7 @@ func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.Pr
+ Subject: pkix.Name{CommonName: cn},
+ NotBefore: time.Now().Add(-1 * time.Hour),
+ NotAfter: time.Now().Add(24 * time.Hour),
++ DNSNames: []string{rand.Text()},
+
+ KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature | KeyUsageCertSign,
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
+@@ -1790,7 +1794,7 @@ func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.Pr
+ issuerKey = priv
+ }
+
+- derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.Public(), issuerKey)
++ derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.(crypto.Signer).Public(), issuerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+@@ -1802,81 +1806,77 @@ func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.Pr
+ return cert, priv, nil
+ }
+
+-func TestPathologicalChain(t *testing.T) {
+- if testing.Short() {
+- t.Skip("skipping generation of a long chain of certificates in short mode")
+- }
+-
+- // Build a chain where all intermediates share the same subject, to hit the
+- // path building worst behavior.
+- roots, intermediates := NewCertPool(), NewCertPool()
+-
+- parent, parentKey, err := generateCert("Root CA", true, nil, nil)
+- if err != nil {
+- t.Fatal(err)
+- }
+- roots.AddCert(parent)
+-
+- for i := 1; i < 100; i++ {
+- parent, parentKey, err = generateCert("Intermediate CA", true, parent, parentKey)
+- if err != nil {
+- t.Fatal(err)
+- }
+- intermediates.AddCert(parent)
+- }
+-
+- leaf, _, err := generateCert("Leaf", false, parent, parentKey)
+- if err != nil {
+- t.Fatal(err)
+- }
+-
+- start := time.Now()
+- _, err = leaf.Verify(VerifyOptions{
+- Roots: roots,
+- Intermediates: intermediates,
+- })
+- t.Logf("verification took %v", time.Since(start))
+-
+- if err == nil || !strings.Contains(err.Error(), "signature check attempts limit") {
+- t.Errorf("expected verification to fail with a signature checks limit error; got %v", err)
+- }
+-}
+-
+-func TestLongChain(t *testing.T) {
++func TestPathologicalChains(t *testing.T) {
+ if testing.Short() {
+- t.Skip("skipping generation of a long chain of certificates in short mode")
+- }
+-
+- roots, intermediates := NewCertPool(), NewCertPool()
+-
+- parent, parentKey, err := generateCert("Root CA", true, nil, nil)
+- if err != nil {
+- t.Fatal(err)
+- }
+- roots.AddCert(parent)
++ t.Skip("skipping generation of a long chains of certificates in short mode")
++ }
++
++ // Test four pathological cases, where the intermediates in the chain have
++ // the same/different subjects and the same/different keys. This covers a
++ // number of cases where the chain building algorithm might be inefficient,
++ // such as when there are many intermediates with the same subject but
++ // different keys, many intermediates with the same key but different
++ // subjects, many intermediates with the same subject and key, or many
++ // intermediates with different subjects and keys.
++ //
++ // The worst case for our algorithm is when all of the intermediates share
++ // both subject and key, in which case all of the intermediates appear to
++ // have signed each other, causing us to see a large number of potential
++ // parents for each intermediate.
++ //
++ // All of these cases, Certificate.Verify should return errSignatureLimit.
++ //
++ // In all cases, don't have a root in the pool, so a valid chain cannot actually be built.
++
++ for _, test := range []struct {
++ sameSubject bool
++ sameKey bool
++ }{
++ {sameSubject: false, sameKey: false},
++ {sameSubject: true, sameKey: false},
++ {sameSubject: false, sameKey: true},
++ {sameSubject: true, sameKey: true},
++ } {
++ t.Run(fmt.Sprintf("sameSubject=%t,sameKey=%t", test.sameSubject, test.sameKey), func(t *testing.T) {
++ intermediates := NewCertPool()
++
++ var intermediateKey crypto.PrivateKey
++ if test.sameKey {
++ var err error
++ intermediateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
++ if err != nil {
++ t.Fatal(err)
++ }
++ }
+
+- for i := 1; i < 15; i++ {
+- name := fmt.Sprintf("Intermediate CA #%d", i)
+- parent, parentKey, err = generateCert(name, true, parent, parentKey)
+- if err != nil {
+- t.Fatal(err)
+- }
+- intermediates.AddCert(parent)
+- }
++ var leafSigner crypto.PrivateKey
++ var intermediate *Certificate
++ for i := range 100 {
++ cn := "Intermediate CA"
++ if !test.sameSubject {
++ cn += fmt.Sprintf(" #%d", i)
++ }
++ var err error
++ intermediate, leafSigner, err = generateCert(cn, true, intermediate, leafSigner, intermediateKey)
++ if err != nil {
++ t.Fatal(err)
++ }
++ intermediates.AddCert(intermediate)
++ }
+
+- leaf, _, err := generateCert("Leaf", false, parent, parentKey)
+- if err != nil {
+- t.Fatal(err)
+- }
++ leaf, _, err := generateCert("Leaf", false, intermediate, leafSigner, nil)
++ if err != nil {
++ t.Fatal(err)
++ }
+
+- start := time.Now()
+- if _, err := leaf.Verify(VerifyOptions{
+- Roots: roots,
+- Intermediates: intermediates,
+- }); err != nil {
+- t.Error(err)
++ start := time.Now()
++ _, err = leaf.Verify(VerifyOptions{
++ Roots: NewCertPool(),
++ Intermediates: intermediates,
++ })
++ t.Logf("verification took %v", time.Since(start))
++ })
+ }
+- t.Logf("verification took %v", time.Since(start))
+ }
+
+ func TestSystemRootsError(t *testing.T) {
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 09/21] go: patch CVE-2026-32283
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (7 preceding siblings ...)
2026-06-12 14:25 ` [OE-core][scarthgap 08/21] go: patch CVE-2026-32280 Jeremy Rosen
@ 2026-06-12 14:25 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 10/21] go: patch CVE-2026-32289 Jeremy Rosen
` (11 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:25 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/763767
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-32283.patch | 177 ++++++++++++++++++
2 files changed, 178 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-32283.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 0d4dff6c21..99c2945a8c 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -43,6 +43,7 @@ SRC_URI += "\
file://CVE-2025-68121_p3.patch \
file://CVE-2026-27142.patch \
file://CVE-2026-32280.patch \
+ file://CVE-2026-32283.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-32283.patch b/meta/recipes-devtools/go/go/CVE-2026-32283.patch
new file mode 100644
index 0000000000..87bcc5816f
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-32283.patch
@@ -0,0 +1,177 @@
+From f560f55d3f804dcc3002dfe963b37bfa3a67202c Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Mon, 23 Mar 2026 11:54:41 -0700
+Subject: [PATCH] crypto/tls: prevent deadlock when client sends multiple key
+ update messages
+
+When we made setReadTrafficSecret send an alert when there are pending
+handshake messages, we introduced a deadlock when the client sends
+multiple key update messages that request a response, as handleKeyUpdate
+will lock the mutex, and defer the unlocking until the end of the
+function, but setReadTrafficSecret called sendAlert in the failure case,
+which also tries to lock the mutex.
+
+Add an argument to setReadTrafficSecret which lets the caller indicate
+if the mutex is already locked, and if so, call sendAlertLocked instead
+of sendAlert.
+
+Thanks to Jakub Ciolek for reporting this issue.
+
+Fixes #78334
+Fixes CVE-2026-32283
+
+Change-Id: Id8e56974233c910e0d66ba96eafbd2ea57832610
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3881
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-by: Nicholas Husin <husin@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/763767
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Auto-Submit: David Chase <drchase@google.com>
+Reviewed-by: Russ Cox <rsc@golang.org>
+Reviewed-by: Jakub Ciolek <jakub@ciolek.dev>
+
+CVE: CVE-2026-32283
+Upstream-Status: Backport [https://github.com/golang/go/commit/1ea7966042731bae941511fb2b261b9536ad268f]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/crypto/tls/conn.go | 10 +++--
+ src/crypto/tls/handshake_client_tls13.go | 4 +-
+ src/crypto/tls/handshake_server_tls13.go | 4 +-
+ src/crypto/tls/handshake_test.go | 48 ++++++++++++++++++++++++
+ 4 files changed, 59 insertions(+), 7 deletions(-)
+
+diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
+index 08609ce..770d456 100644
+--- a/src/crypto/tls/conn.go
++++ b/src/crypto/tls/conn.go
+@@ -1345,7 +1345,7 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
+ }
+
+ newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
+- if err := c.setReadTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret); err != nil {
++ if err := c.setReadTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret, keyUpdate.updateRequested); err != nil {
+ return err
+ }
+
+@@ -1675,12 +1675,16 @@ func (c *Conn) VerifyHostname(host string) error {
+ // setReadTrafficSecret sets the read traffic secret for the given encryption level. If
+ // being called at the same time as setWriteTrafficSecret, the caller must ensure the call
+ // to setWriteTrafficSecret happens first so any alerts are sent at the write level.
+-func (c *Conn) setReadTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) error {
++func (c *Conn) setReadTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte, locked bool) error {
+ // Ensure that there are no buffered handshake messages before changing the
+ // read keys, since that can cause messages to be parsed that were encrypted
+ // using old keys which are no longer appropriate.
+ if c.hand.Len() != 0 {
+- c.sendAlert(alertUnexpectedMessage)
++ if locked {
++ c.sendAlertLocked(alertUnexpectedMessage)
++ } else {
++ c.sendAlert(alertUnexpectedMessage)
++ }
+ return errors.New("tls: handshake buffer not empty before setting read traffic secret")
+ }
+ c.in.setTrafficSecret(suite, level, secret)
+diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go
+index 68ff92b..2d58b21 100644
+--- a/src/crypto/tls/handshake_client_tls13.go
++++ b/src/crypto/tls/handshake_client_tls13.go
+@@ -396,7 +396,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
+ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
+ serverSecret := hs.suite.deriveSecret(handshakeSecret,
+ serverHandshakeTrafficLabel, hs.transcript)
+- if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret); err != nil {
++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret, false); err != nil {
+ return err
+ }
+
+@@ -607,7 +607,7 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error {
+ clientApplicationTrafficLabel, hs.transcript)
+ serverSecret := hs.suite.deriveSecret(hs.masterSecret,
+ serverApplicationTrafficLabel, hs.transcript)
+- if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret); err != nil {
++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret, false); err != nil {
+ return err
+ }
+
+diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go
+index 1ecee3a..f73b536 100644
+--- a/src/crypto/tls/handshake_server_tls13.go
++++ b/src/crypto/tls/handshake_server_tls13.go
+@@ -636,7 +636,7 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
+ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+ clientSecret := hs.suite.deriveSecret(hs.handshakeSecret,
+ clientHandshakeTrafficLabel, hs.transcript)
+- if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret); err != nil {
++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret, false); err != nil {
+ return err
+ }
+
+@@ -1005,7 +1005,7 @@ func (hs *serverHandshakeStateTLS13) readClientFinished() error {
+ return errors.New("tls: invalid client finished hash")
+ }
+
+- if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret); err != nil {
++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret, false); err != nil {
+ return err
+ }
+
+diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go
+index 4991a0e..a95d751 100644
+--- a/src/crypto/tls/handshake_test.go
++++ b/src/crypto/tls/handshake_test.go
+@@ -673,3 +673,51 @@ func concatHandshakeMessages(msgs ...handshakeMessage) ([]byte, error) {
+ outBuf = append(outBuf, marshalled...)
+ return outBuf, nil
+ }
++
++func TestMultipleKeyUpdate(t *testing.T) {
++ for _, requestUpdate := range []bool{true, false} {
++ t.Run(fmt.Sprintf("requestUpdate=%t", requestUpdate), func(t *testing.T) {
++
++ c, s := localPipe(t)
++ cfg := testConfig.Clone()
++ cfg.MinVersion = VersionTLS13
++ cfg.MaxVersion = VersionTLS13
++ client := Client(c, testConfig)
++ server := Server(s, testConfig)
++
++ clientHandshakeDone := make(chan struct{})
++ go func() {
++ if err := client.Handshake(); err != nil {
++ }
++ close(clientHandshakeDone)
++ io.Copy(io.Discard, server)
++ }()
++
++ if err := server.Handshake(); err != nil {
++ t.Fatalf("server handshake failed: %v\n", err)
++ }
++ <-clientHandshakeDone
++
++ c.SetReadDeadline(time.Now().Add(1 * time.Second))
++ s.SetReadDeadline(time.Now().Add(1 * time.Second))
++
++ kuMsg, err := (&keyUpdateMsg{updateRequested: requestUpdate}).marshal()
++ if err != nil {
++ t.Fatalf("failed to marshal key update message: %v", err)
++ }
++
++ client.out.Lock()
++ if _, err := client.writeRecordLocked(recordTypeHandshake, append(kuMsg, kuMsg...)); err != nil {
++ t.Fatalf("failed to write key update messages: %v", err)
++ }
++ client.out.Unlock()
++
++ _, err = io.Copy(io.Discard, client)
++ if err == nil {
++ t.Fatal("expected multiple key update messages to cause an error, got nil")
++ } else if !strings.HasSuffix(err.Error(), "tls: unexpected message") {
++ t.Fatalf("unexpected error: %v", err)
++ }
++ })
++ }
++}
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 10/21] go: patch CVE-2026-32289
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (8 preceding siblings ...)
2026-06-12 14:25 ` [OE-core][scarthgap 09/21] go: patch CVE-2026-32283 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 11/21] go: patch CVE-2026-33811 Jeremy Rosen
` (10 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/763762
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-32289.patch | 217 ++++++++++++++++++
2 files changed, 218 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-32289.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 99c2945a8c..288cd5c95f 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -44,6 +44,7 @@ SRC_URI += "\
file://CVE-2026-27142.patch \
file://CVE-2026-32280.patch \
file://CVE-2026-32283.patch \
+ file://CVE-2026-32289.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-32289.patch b/meta/recipes-devtools/go/go/CVE-2026-32289.patch
new file mode 100644
index 0000000000..28ff0c00e0
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-32289.patch
@@ -0,0 +1,217 @@
+From 5291c6d3e6d0bc0a764a9a6bd6b3de1be64b8264 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Mon, 23 Mar 2026 13:34:23 -0700
+Subject: [PATCH] html/template: properly track JS template literal brace depth
+ across contexts
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Properly track JS template literal brace depth across branches/ranges,
+and prevent accidental re-use of escape analysis by including the
+brace depth in the stringification/mangling for contexts.
+
+Fixes #78331
+Fixes CVE-2026-32289
+
+Change-Id: I9f3f47c29e042220b18e4d3299db7a3fae4207fa
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3882
+Reviewed-by: Neal Patel <nealpatel@google.com>
+Reviewed-by: Nicholas Husin <husin@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/763762
+Reviewed-by: Russ Cox <rsc@golang.org>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Auto-Submit: David Chase <drchase@google.com>
+Reviewed-by: Fan Mỹ Tâm Club <letrivien97@gmail.com>
+
+CVE: CVE-2026-32289
+Upstream-Status: Backport [https://github.com/golang/go/commit/199c4d1c3c9d509a51f777c81cb17d4b17728097]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/html/template/context.go | 14 +++++++++++-
+ src/html/template/escape.go | 4 ++--
+ src/html/template/escape_test.go | 38 +++++++++++++++++++++-----------
+ 3 files changed, 40 insertions(+), 16 deletions(-)
+
+diff --git a/src/html/template/context.go b/src/html/template/context.go
+index 8b3af2feab..132ae2d28d 100644
+--- a/src/html/template/context.go
++++ b/src/html/template/context.go
+@@ -6,6 +6,7 @@ package template
+
+ import (
+ "fmt"
++ "slices"
+ "text/template/parse"
+ )
+
+@@ -37,7 +38,7 @@ func (c context) String() string {
+ if c.err != nil {
+ err = c.err
+ }
+- return fmt.Sprintf("{%v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.attr, c.element, err)
++ return fmt.Sprintf("{%v %v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.jsBraceDepth, c.attr, c.element, err)
+ }
+
+ // eq reports whether two contexts are equal.
+@@ -46,6 +47,7 @@ func (c context) eq(d context) bool {
+ c.delim == d.delim &&
+ c.urlPart == d.urlPart &&
+ c.jsCtx == d.jsCtx &&
++ slices.Equal(c.jsBraceDepth, d.jsBraceDepth) &&
+ c.attr == d.attr &&
+ c.element == d.element &&
+ c.err == d.err
+@@ -68,6 +70,9 @@ func (c context) mangle(templateName string) string {
+ if c.jsCtx != jsCtxRegexp {
+ s += "_" + c.jsCtx.String()
+ }
++ if c.jsBraceDepth != nil {
++ s += fmt.Sprintf("_jsBraceDepth(%v)", c.jsBraceDepth)
++ }
+ if c.attr != attrNone {
+ s += "_" + c.attr.String()
+ }
+@@ -77,6 +82,13 @@ func (c context) mangle(templateName string) string {
+ return s
+ }
+
++// clone returns a copy of c with the same field values.
++func (c context) clone() context {
++ clone := c
++ clone.jsBraceDepth = slices.Clone(c.jsBraceDepth)
++ return clone
++}
++
+ // state describes a high-level HTML parser state.
+ //
+ // It bounds the top of the element stack, and by extension the HTML insertion
+diff --git a/src/html/template/escape.go b/src/html/template/escape.go
+index b368cab38c..c031ed27b9 100644
+--- a/src/html/template/escape.go
++++ b/src/html/template/escape.go
+@@ -522,7 +522,7 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string)
+ if nodeName == "range" {
+ e.rangeContext = &rangeContext{outer: e.rangeContext}
+ }
+- c0 := e.escapeList(c, n.List)
++ c0 := e.escapeList(c.clone(), n.List)
+ if nodeName == "range" {
+ if c0.state != stateError {
+ c0 = joinRange(c0, e.rangeContext)
+@@ -553,7 +553,7 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string)
+ return c0
+ }
+ }
+- c1 := e.escapeList(c, n.ElseList)
++ c1 := e.escapeList(c.clone(), n.ElseList)
+ return join(c0, c1, n, nodeName)
+ }
+
+diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
+index 1970db1695..435c83378f 100644
+--- a/src/html/template/escape_test.go
++++ b/src/html/template/escape_test.go
+@@ -1181,6 +1181,18 @@ func TestErrors(t *testing.T) {
+ // html is allowed since it is the last command in the pipeline, but urlquery is not.
+ `predefined escaper "urlquery" disallowed in template`,
+ },
++ {
++ "<script>var a = `{{if .X}}`{{end}}",
++ `{{if}} branches end in different contexts`,
++ },
++ {
++ "<script>var a = `{{if .X}}a{{else}}`{{end}}",
++ `{{if}} branches end in different contexts`,
++ },
++ {
++ "<script>var a = `{{if .X}}a{{else}}b{{end}}`</script>",
++ ``,
++ },
+ }
+ for _, test := range tests {
+ buf := new(bytes.Buffer)
+@@ -1752,7 +1764,7 @@ func TestEscapeText(t *testing.T) {
+ },
+ {
+ "<script>var a = `${",
+- context{state: stateJS, element: elementScript},
++ context{state: stateJS, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var a = `${}",
+@@ -1760,27 +1772,27 @@ func TestEscapeText(t *testing.T) {
+ },
+ {
+ "<script>var a = `${`",
+- context{state: stateJSTmplLit, element: elementScript},
++ context{state: stateJSTmplLit, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var a = `${var a = \"",
+- context{state: stateJSDqStr, element: elementScript},
++ context{state: stateJSDqStr, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var a = `${var a = \"`",
+- context{state: stateJSDqStr, element: elementScript},
++ context{state: stateJSDqStr, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var a = `${var a = \"}",
+- context{state: stateJSDqStr, element: elementScript},
++ context{state: stateJSDqStr, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var a = `${``",
+- context{state: stateJS, element: elementScript},
++ context{state: stateJS, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var a = `${`}",
+- context{state: stateJSTmplLit, element: elementScript},
++ context{state: stateJSTmplLit, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>`${ {} } asd`</script><script>`${ {} }",
+@@ -1788,7 +1800,7 @@ func TestEscapeText(t *testing.T) {
+ },
+ {
+ "<script>var foo = `${ (_ => { return \"x\" })() + \"${",
+- context{state: stateJSDqStr, element: elementScript},
++ context{state: stateJSDqStr, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var a = `${ {</script><script>var b = `${ x }",
+@@ -1816,23 +1828,23 @@ func TestEscapeText(t *testing.T) {
+ },
+ {
+ "<script>`${ { `` }",
+- context{state: stateJS, element: elementScript},
++ context{state: stateJS, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>`${ { }`",
+- context{state: stateJSTmplLit, element: elementScript},
++ context{state: stateJSTmplLit, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ {
+ "<script>var foo = `${ foo({ a: { c: `${",
+- context{state: stateJS, element: elementScript},
++ context{state: stateJS, element: elementScript, jsBraceDepth: []int{2, 0}},
+ },
+ {
+ "<script>var foo = `${ foo({ a: { c: `${ {{.}} }` }, b: ",
+- context{state: stateJS, element: elementScript},
++ context{state: stateJS, element: elementScript, jsBraceDepth: []int{1}},
+ },
+ {
+ "<script>`${ `}",
+- context{state: stateJSTmplLit, element: elementScript},
++ context{state: stateJSTmplLit, element: elementScript, jsBraceDepth: []int{0}},
+ },
+ }
+
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 11/21] go: patch CVE-2026-33811
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (9 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 10/21] go: patch CVE-2026-32289 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 12/21] go: patch CVE-2026-39817 Jeremy Rosen
` (9 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/767860
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-33811.patch | 46 +++++++++++++++++++
2 files changed, 47 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-33811.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 288cd5c95f..9a7695e754 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -45,6 +45,7 @@ SRC_URI += "\
file://CVE-2026-32280.patch \
file://CVE-2026-32283.patch \
file://CVE-2026-32289.patch \
+ file://CVE-2026-33811.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-33811.patch b/meta/recipes-devtools/go/go/CVE-2026-33811.patch
new file mode 100644
index 0000000000..216b33ed8b
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-33811.patch
@@ -0,0 +1,46 @@
+From 9082277a0a78af39190c1f23b622f02b89e46196 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 26 Mar 2026 12:17:06 -0700
+Subject: [PATCH] net: avoid double-free of cgo pointer when handling large DNS
+ response
+
+No test, unfortunately: I've had no luck triggering this without
+the ability to override the local recursive resolver.
+
+Thanks to hamayanhamayan for reporting this issue.
+
+Fixes CVE-2026-33811
+Fixes #78803
+
+Change-Id: I9e51410337316c20e4b9fd5b86657f436a6a6964
+Reviewed-on: https://go-review.googlesource.com/c/go/+/767860
+Reviewed-by: Nicholas Husin <nsh@golang.org>
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Nicholas Husin <husin@google.com>
+
+CVE: CVE-2026-33811
+Upstream-Status: Backport [https://github.com/golang/go/commit/ab2c7eb1c43011dda118282c1e757d8c27cd7d4f]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/net/cgo_unix.go | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
+index 7ed5daad73..bd694859ab 100644
+--- a/src/net/cgo_unix.go
++++ b/src/net/cgo_unix.go
+@@ -343,7 +343,10 @@ func cgoResSearch(hostname string, rtype, class int) ([]dnsmessage.Resource, err
+ // useful in the response, even though there *is* a response.
+ bufSize := maxDNSPacketSize
+ buf := (*_C_uchar)(_C_malloc(uintptr(bufSize)))
+- defer _C_free(unsafe.Pointer(buf))
++ defer func() {
++ // Free in a closure which captures buf to pick up a reallocated buffer from below.
++ _C_free(unsafe.Pointer(buf))
++ }()
+
+ s, err := syscall.BytePtrFromString(hostname)
+ if err != nil {
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 12/21] go: patch CVE-2026-39817
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (10 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 11/21] go: patch CVE-2026-33811 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 13/21] go: patch CVE-2026-39819 Jeremy Rosen
` (8 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1] mentionned in [2]
[1] https://go.dev/cl/767520
[2] https://security-tracker.debian.org/tracker/CVE-2026-39817
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-39817.patch | 105 ++++++++++++++++++
2 files changed, 106 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-39817.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 9a7695e754..f06b974e04 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -46,6 +46,7 @@ SRC_URI += "\
file://CVE-2026-32283.patch \
file://CVE-2026-32289.patch \
file://CVE-2026-33811.patch \
+ file://CVE-2026-39817.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-39817.patch b/meta/recipes-devtools/go/go/CVE-2026-39817.patch
new file mode 100644
index 0000000000..103fbedb7a
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-39817.patch
@@ -0,0 +1,105 @@
+From 7d35508ad684c808ec11fb6ef3ab27f9258a9418 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Wed, 15 Apr 2026 16:27:23 -0400
+Subject: [PATCH] cmd/pack: refuse to extract files with directory components
+
+Do not write to /etc/passwd when running "go tool pack x evil.a"
+on an archive containing a file named /etc/passwd.
+
+Fixes #78778
+
+Change-Id: I4cf69b81af62321ffbb41ace679672a86a6a6964
+Reviewed-on: https://go-review.googlesource.com/c/go/+/767520
+Reviewed-by: Nicholas Husin <nsh@golang.org>
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Nicholas Husin <husin@google.com>
+
+CVE: CVE-2026-39817
+Upstream-Status: Backport [https://github.com/golang/go/commit/7409ada33f99c0d74db2b0389c51a15de116e48d]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/cmd/pack/pack.go | 5 +++++
+ src/cmd/pack/pack_test.go | 44 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
+index 412ea36d60..2fe0258f01 100644
+--- a/src/cmd/pack/pack.go
++++ b/src/cmd/pack/pack.go
+@@ -135,6 +135,11 @@ func openArchive(name string, mode int, files []string) *Archive {
+ if err != nil {
+ log.Fatal(err)
+ }
++ for _, f := range a.Entries {
++ if !filepath.IsLocal(f.Name) || filepath.Base(f.Name) != f.Name {
++ log.Fatalf("%q: invalid name", f.Name)
++ }
++ }
+ return &Archive{
+ a: a,
+ files: files,
+diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
+index c3a63424dd..c4a8c78cbf 100644
+--- a/src/cmd/pack/pack_test.go
++++ b/src/cmd/pack/pack_test.go
+@@ -6,6 +6,7 @@ package main
+
+ import (
+ "bufio"
++ "bytes"
+ "cmd/internal/archive"
+ "fmt"
+ "internal/testenv"
+@@ -409,6 +410,49 @@ func TestRWithNonexistentFile(t *testing.T) {
+ run(packPath(t), "r", "p.a", "p.o") // should succeed
+ }
+
++func TestOutputPathSanitization(t *testing.T) {
++ dir := t.TempDir()
++
++ // Create pack.a containing a file named "longpathname".
++ // Note that "go tool pack" requires that all files be at least 8 bytes long.
++ const validPathName = "longpathname"
++ if err := os.WriteFile(dir+"/"+validPathName, make([]byte, 8), 0o666); err != nil {
++ t.Fatal(err)
++ }
++ doRun(t, dir, packPath(t), "grc", "pack.a", validPathName)
++
++ // Create evil.a from pack.a, replacing "longpathname" with "out/pathname".
++ b, err := os.ReadFile(dir + "/pack.a")
++ if err != nil {
++ t.Fatal(err)
++ }
++ idx := bytes.Index(b, []byte(validPathName))
++ if idx < 0 {
++ t.Fatalf("%v not found in pack.a", validPathName)
++ }
++ copy(b[idx:], "out/")
++ os.WriteFile(dir+"/evil.a", b, 0o666)
++
++ // Extract evil.a. It should fail and not extract a file to /out.
++ os.Mkdir(dir+"/out", 0o777)
++
++ cmd := testenv.Command(t, packPath(t), "x", "evil.a")
++ cmd.Dir = dir
++ _, err = cmd.CombinedOutput()
++ if err == nil {
++ t.Errorf("pack x evil.a: unexpected success")
++ }
++
++ ents, err := os.ReadDir(dir + "/out")
++ if err != nil {
++ t.Error(err)
++ }
++ for _, e := range ents {
++ t.Errorf("unexpected file in /out: %q", e.Name())
++ }
++
++}
++
+ // doRun runs a program in a directory and returns the output.
+ func doRun(t *testing.T, dir string, args ...string) string {
+ cmd := testenv.Command(t, args[0], args[1:]...)
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 13/21] go: patch CVE-2026-39819
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (11 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 12/21] go: patch CVE-2026-39817 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 14/21] go: patch CVE-2026-39820 Jeremy Rosen
` (7 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/763882
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-39819.patch | 48 +++++++++++++++++++
2 files changed, 49 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-39819.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index f06b974e04..dba826011b 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -47,6 +47,7 @@ SRC_URI += "\
file://CVE-2026-32289.patch \
file://CVE-2026-33811.patch \
file://CVE-2026-39817.patch \
+ file://CVE-2026-39819.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-39819.patch b/meta/recipes-devtools/go/go/CVE-2026-39819.patch
new file mode 100644
index 0000000000..cb767e1320
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-39819.patch
@@ -0,0 +1,48 @@
+From db6ceacb046779c763f87060d8a1ba5c936309c9 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Wed, 8 Apr 2026 09:55:54 -0700
+Subject: [PATCH] cmd/go: use MkdirTemp to create temp directory for "go bug"
+
+Don't use a predictable, potentially attacker-controlled filename in /tmp.
+
+Fixes #78584
+Fixes CVE-2026-39819
+
+Change-Id: I72116aa6dd8fa50f65b6dc0292a15a8c6a6a6964
+Reviewed-on: https://go-review.googlesource.com/c/go/+/763882
+Reviewed-by: Nicholas Husin <husin@google.com>
+Reviewed-by: Nicholas Husin <nsh@golang.org>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+
+CVE: CVE-2026-39819
+Upstream-Status: Backport [https://github.com/golang/go/commit/5d6aa23e5b6151d25955a512532383c28c745e18]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/cmd/go/internal/bug/bug.go | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/cmd/go/internal/bug/bug.go b/src/cmd/go/internal/bug/bug.go
+index ed1813605e..9bf97dd511 100644
+--- a/src/cmd/go/internal/bug/bug.go
++++ b/src/cmd/go/internal/bug/bug.go
+@@ -182,14 +182,14 @@ func firstLine(buf []byte) []byte {
+ // printGlibcVersion prints information about the glibc version.
+ // It ignores failures.
+ func printGlibcVersion(w io.Writer) {
+- tempdir := os.TempDir()
+- if tempdir == "" {
++ tempdir, err := os.MkdirTemp("", "")
++ if err != nil {
+ return
+ }
+ src := []byte(`int main() {}`)
+ srcfile := filepath.Join(tempdir, "go-bug.c")
+ outfile := filepath.Join(tempdir, "go-bug")
+- err := os.WriteFile(srcfile, src, 0644)
++ err = os.WriteFile(srcfile, src, 0644)
+ if err != nil {
+ return
+ }
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 14/21] go: patch CVE-2026-39820
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (12 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 13/21] go: patch CVE-2026-39819 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 15/21] go: patch CVE-2026-39825 Jeremy Rosen
` (6 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1] mentionned in [2]
[1] https://go.dev/cl/759940
[2] https://security-tracker.debian.org/tracker/CVE-2026-39820
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-39820.patch | 112 ++++++++++++++++++
2 files changed, 113 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-39820.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index dba826011b..002d443059 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -48,6 +48,7 @@ SRC_URI += "\
file://CVE-2026-33811.patch \
file://CVE-2026-39817.patch \
file://CVE-2026-39819.patch \
+ file://CVE-2026-39820.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-39820.patch b/meta/recipes-devtools/go/go/CVE-2026-39820.patch
new file mode 100644
index 0000000000..c5f84282a9
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-39820.patch
@@ -0,0 +1,112 @@
+From e459f8fe1061679f866c599210466db386348f08 Mon Sep 17 00:00:00 2001
+From: mohammadmseet-hue <mohammadmseet@gmail.com>
+Date: Sat, 4 Apr 2026 05:17:25 +0000
+Subject: [PATCH] net/mail: fix quadratic complexity in consumeComment
+
+consumeComment builds the comment string by repeated string
+concatenation inside a loop. Each concatenation copies the
+entire string built so far, making the function O(n^2) in the
+depth of nested comments.
+
+Replace the concatenation with a strings.Builder, which
+amortizes allocation by doubling its internal buffer. This
+reduces consumeComment from O(n^2) to O(n).
+
+This is the same bug class as the consumeDomainLiteral fix
+in CVE-2025-61725.
+
+Benchmark results (benchstat, 8 runs):
+
+ name old time/op new time/op delta
+ ConsumeComment/depth10 2.481us 1.838us -25.92%
+ ConsumeComment/depth100 86.58us 6.498us -92.50%
+ ConsumeComment/depth1000 7.963ms 52.82us -99.34%
+ ConsumeComment/depth10000 897.8ms 521.3us -99.94%
+
+The quadratic cost becomes visible at depth 100 and dominant
+by depth 1000. At depth 10000, the fix is roughly 1700x
+faster.
+
+Change-Id: I3c927f02646fcab7bab167cb82fd46d3327d6d34
+GitHub-Last-Rev: 7742dad716ee371766543f88e82bd163bd9d7ac2
+GitHub-Pull-Request: golang/go#78393
+Reviewed-on: https://go-review.googlesource.com/c/go/+/759940
+Reviewed-by: Sean Liao <sean@liao.dev>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Auto-Submit: Sean Liao <sean@liao.dev>
+Reviewed-by: David Chase <drchase@google.com>
+Reviewed-by: Junyang Shao <shaojunyang@google.com>
+
+CVE: CVE-2026-39820
+Upstream-Status: Backport [https://github.com/golang/go/commit/0d0799f055dcc9b3b41df74bee3fbe398ae2f0e7]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/net/mail/message.go | 6 +++---
+ src/net/mail/message_test.go | 19 +++++++++++++++++++
+ 2 files changed, 22 insertions(+), 3 deletions(-)
+
+diff --git a/src/net/mail/message.go b/src/net/mail/message.go
+index fc2a9e46f8..37d7ff5df1 100644
+--- a/src/net/mail/message.go
++++ b/src/net/mail/message.go
+@@ -780,7 +780,7 @@ func (p *addrParser) consumeComment() (string, bool) {
+ // '(' already consumed.
+ depth := 1
+
+- var comment string
++ var comment strings.Builder
+ for {
+ if p.empty() || depth == 0 {
+ break
+@@ -794,12 +794,12 @@ func (p *addrParser) consumeComment() (string, bool) {
+ depth--
+ }
+ if depth > 0 {
+- comment += p.s[:1]
++ comment.WriteByte(p.s[0])
+ }
+ p.s = p.s[1:]
+ }
+
+- return comment, depth == 0
++ return comment.String(), depth == 0
+ }
+
+ func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) {
+diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
+index 1f2f62afbf..1b165317f9 100644
+--- a/src/net/mail/message_test.go
++++ b/src/net/mail/message_test.go
+@@ -6,6 +6,7 @@ package mail
+
+ import (
+ "bytes"
++ "fmt"
+ "io"
+ "mime"
+ "reflect"
+@@ -1217,3 +1218,21 @@ func TestEmptyAddress(t *testing.T) {
+ t.Errorf(`ParseAddressList("") = %v, %v, want nil, error`, list, err)
+ }
+ }
++
++func BenchmarkConsumeComment(b *testing.B) {
++ for _, n := range []int{10, 100, 1000, 10000} {
++ b.Run(fmt.Sprintf("depth-%d", n), func(b *testing.B) {
++ // Build a deeply nested comment: (((...a...)))
++ open := strings.Repeat("(", n)
++ close := strings.Repeat(")", n)
++ // consumeComment expects the leading '(' already consumed,
++ // so we start with one fewer opening paren and the parser
++ // will handle nesting from there.
++ input := open[:n-1] + "a" + close
++ for b.Loop() {
++ p := addrParser{s: input}
++ p.consumeComment()
++ }
++ })
++ }
++}
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 15/21] go: patch CVE-2026-39825
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (13 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 14/21] go: patch CVE-2026-39820 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 16/21] go: patch CVE-2026-39826 Jeremy Rosen
` (5 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/770541
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-39825.patch | 104 ++++++++++++++++++
2 files changed, 105 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-39825.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 002d443059..952c0e4638 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -49,6 +49,7 @@ SRC_URI += "\
file://CVE-2026-39817.patch \
file://CVE-2026-39819.patch \
file://CVE-2026-39820.patch \
+ file://CVE-2026-39825.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-39825.patch b/meta/recipes-devtools/go/go/CVE-2026-39825.patch
new file mode 100644
index 0000000000..6082f5fc37
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-39825.patch
@@ -0,0 +1,104 @@
+From 96b1a3f872971fc38d9f2c0ed4a3d1f3ceeb517f Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Fri, 24 Apr 2026 14:10:47 -0700
+Subject: [PATCH] net/http/httputil: reencode queries with many parameters in
+ proxy
+
+When ReverseProxy forwards a request containing more than
+urlmaxqueryparams (GODEBUG) query parameters, reencode the
+outbound query parameters.
+
+Avoids potential smuggling of query parameters, where the
+sender sends many query parameters, the user's Rewrite hook
+fails to observe those parameters due to the limit being
+exceeded, and the request is forwarded with the full set
+of parameters.
+
+Fixes #78948
+Fixes CVE-2026-39825
+
+Change-Id: I691be7899c4b6208bf61f6b78dacfdf56a6a6964
+Reviewed-on: https://go-review.googlesource.com/c/go/+/770541
+Reviewed-by: Nicholas Husin <nsh@golang.org>
+Reviewed-by: Nicholas Husin <husin@google.com>
+Auto-Submit: Damien Neil <dneil@google.com>
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+
+CVE: CVE-2026-39825
+Upstream-Status: Backport [https://github.com/golang/go/commit/6795bb331782b33691f772d30c810b4c3a317aeb]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/net/http/httputil/reverseproxy.go | 14 ++++++++++++++
+ src/net/http/httputil/reverseproxy_test.go | 6 ++++++
+ src/net/url/url.go | 1 +
+ 3 files changed, 21 insertions(+)
+
+diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
+index 5c70f0d27b..37b0eab6b0 100644
+--- a/src/net/http/httputil/reverseproxy.go
++++ b/src/net/http/httputil/reverseproxy.go
+@@ -10,6 +10,7 @@ import (
+ "context"
+ "errors"
+ "fmt"
++ "internal/godebug"
+ "io"
+ "log"
+ "mime"
+@@ -797,11 +798,24 @@ func (c switchProtocolCopier) copyToBackend(errc chan<- error) {
+ errc <- err
+ }
+
++var urlmaxqueryparams = godebug.New("urlmaxqueryparams")
++
++// Keep this in sync with net/url.
++const defaultMaxParams = 10000
++
+ func cleanQueryParams(s string) string {
+ reencode := func(s string) string {
+ v, _ := url.ParseQuery(s)
+ return v.Encode()
+ }
++ if urlmaxqueryparams.Value() != "" {
++ // Always reencode when a non-default urlmaxqueryparams is set.
++ return reencode(s)
++ }
++ if numParams := strings.Count(s, "&") + 1; numParams > defaultMaxParams {
++ // Too many query parameters.
++ return reencode(s)
++ }
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case ';':
+diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
+index dd3330b615..deb1ab9ce2 100644
+--- a/src/net/http/httputil/reverseproxy_test.go
++++ b/src/net/http/httputil/reverseproxy_test.go
+@@ -1845,6 +1845,12 @@ func testReverseProxyQueryParameterSmuggling(t *testing.T, wantCleanQuery bool,
+ }, {
+ rawQuery: "a=1&a=%zz&b=3",
+ cleanQuery: "a=1&b=3",
++ }, {
++ rawQuery: "a=%zz",
++ cleanQuery: "",
++ }, {
++ rawQuery: strings.Repeat("a=1&", 10000) + "a=1",
++ cleanQuery: "",
+ }} {
+ res, err := frontend.Client().Get(frontend.URL + "?" + test.rawQuery)
+ if err != nil {
+diff --git a/src/net/url/url.go b/src/net/url/url.go
+index 5219e3c130..41f3bef1ee 100644
+--- a/src/net/url/url.go
++++ b/src/net/url/url.go
+@@ -961,6 +961,7 @@ func ParseQuery(query string) (Values, error) {
+
+ var urlmaxqueryparams = godebug.New("urlmaxqueryparams")
+
++// Keep this in sync with net/http/httputil.
+ const defaultMaxParams = 10000
+
+ func urlParamsWithinMax(params int) bool {
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 16/21] go: patch CVE-2026-39826
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (14 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 15/21] go: patch CVE-2026-39825 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 17/21] go: patch CVE-2026-42499 Jeremy Rosen
` (4 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/771180
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-39826.patch | 65 +++++++++++++++++++
2 files changed, 66 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-39826.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 952c0e4638..77e6bcd59d 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -50,6 +50,7 @@ SRC_URI += "\
file://CVE-2026-39819.patch \
file://CVE-2026-39820.patch \
file://CVE-2026-39825.patch \
+ file://CVE-2026-39826.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-39826.patch b/meta/recipes-devtools/go/go/CVE-2026-39826.patch
new file mode 100644
index 0000000000..d9fa751adc
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-39826.patch
@@ -0,0 +1,65 @@
+From 0d41a827f4d691be89c0285cd136cc45640341d4 Mon Sep 17 00:00:00 2001
+From: Neal Patel <nealpatel@google.com>
+Date: Mon, 27 Apr 2026 17:34:58 -0400
+Subject: [PATCH] html/template: fix escaper bypass by treating empty script
+ type as JavaScript
+
+Thank you to Mundur (https://github.com/M0nd0R) for reporting this issue.
+
+Fixes #78981
+Fixes CVE-2026-39826
+
+Change-Id: I3f2e06496020ece655d156fb099ff556af8cc836
+Reviewed-on: https://go-review.googlesource.com/c/go/+/771180
+Reviewed-by: Roland Shoemaker <roland@golang.org>
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+
+CVE: CVE-2026-39826
+Upstream-Status: Backport [https://github.com/golang/go/commit/a63b23ffb2eebc9ca3a14c369b615ca623bb20f7]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/html/template/escape_test.go | 15 +++++++++++++++
+ src/html/template/js.go | 1 +
+ 2 files changed, 16 insertions(+)
+
+diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
+index 435c83378f..ce06440738 100644
+--- a/src/html/template/escape_test.go
++++ b/src/html/template/escape_test.go
+@@ -231,6 +231,21 @@ func TestEscape(t *testing.T) {
+ "<script>alert({{.A}})</script>",
+ `<script>alert(["\u003ca\u003e","\u003cb\u003e"])</script>`,
+ },
++ {
++ "scriptTypeSpace",
++ "<script type=\" \">{{.H}}</script>",
++ "<script type=\" \">\"\\u003cHello\\u003e\"</script>",
++ },
++ {
++ "scriptTypeTab",
++ "<script type=\"\t\">{{.H}}</script>",
++ "<script type=\"\t\">\"\\u003cHello\\u003e\"</script>",
++ },
++ {
++ "scriptTypeEmpty",
++ "<script type=\"\">{{.H}}</script>",
++ "<script type=\"\">\"\\u003cHello\\u003e\"</script>",
++ },
+ {
+ "jsObjValueNotOverEscaped",
+ "<button onclick='alert({{.A | html}})'>",
+diff --git a/src/html/template/js.go b/src/html/template/js.go
+index d911ada26d..90cf2dc982 100644
+--- a/src/html/template/js.go
++++ b/src/html/template/js.go
+@@ -459,6 +459,7 @@ func isJSType(mimeType string) bool {
+ mimeType = strings.TrimSpace(mimeType)
+ switch mimeType {
+ case
++ "",
+ "application/ecmascript",
+ "application/javascript",
+ "application/json",
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 17/21] go: patch CVE-2026-42499
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (15 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 16/21] go: patch CVE-2026-39826 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 18/21] go: patch CVE-2026-42501 Jeremy Rosen
` (3 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/771520
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-42499.patch | 91 +++++++++++++++++++
2 files changed, 92 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-42499.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 77e6bcd59d..85f75f0d89 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -51,6 +51,7 @@ SRC_URI += "\
file://CVE-2026-39820.patch \
file://CVE-2026-39825.patch \
file://CVE-2026-39826.patch \
+ file://CVE-2026-42499.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-42499.patch b/meta/recipes-devtools/go/go/CVE-2026-42499.patch
new file mode 100644
index 0000000000..d4ac9b3823
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-42499.patch
@@ -0,0 +1,91 @@
+From dd339e72189d59f249786afd4021b9fb391f3562 Mon Sep 17 00:00:00 2001
+From: Neal Patel <nealpatel@google.com>
+Date: Tue, 28 Apr 2026 12:10:24 -0400
+Subject: [PATCH] net/mail: fix quadratic consumePhrase behavior
+
+Updates #78987
+Fixes CVE-2026-42499
+
+Change-Id: I8438e5dee7e6433573d4161baf8fb2151e7fbc2f
+Reviewed-on: https://go-review.googlesource.com/c/go/+/771520
+Reviewed-by: Nicholas Husin <husin@google.com>
+Reviewed-by: Nicholas Husin <nsh@golang.org>
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+
+CVE: CVE-2026-42499
+Upstream-Status: Backport [https://github.com/golang/go/commit/2c59389fcc5194aeae742fb413e55b656c22343f]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/net/mail/message.go | 23 +++++++++++++++++------
+ src/net/mail/message_test.go | 11 +++++++++++
+ 2 files changed, 28 insertions(+), 6 deletions(-)
+
+diff --git a/src/net/mail/message.go b/src/net/mail/message.go
+index 37d7ff5df1..f57742068e 100644
+--- a/src/net/mail/message.go
++++ b/src/net/mail/message.go
+@@ -567,8 +567,10 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
+ func (p *addrParser) consumePhrase() (phrase string, err error) {
+ debug.Printf("consumePhrase: [%s]", p.s)
+ // phrase = 1*word
+- var words []string
+- var isPrevEncoded bool
++ var (
++ words []string
++ sb strings.Builder
++ )
+ for {
+ // obs-phrase allows CFWS after one word
+ if len(words) > 0 {
+@@ -600,13 +602,22 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
+ break
+ }
+ debug.Printf("consumePhrase: consumed %q", word)
+- if isPrevEncoded && isEncoded {
+- words[len(words)-1] += word
+- } else {
++ switch {
++ case isEncoded:
++ sb.WriteString(word)
++ case !isEncoded && sb.Len() > 0:
++ words = append(words, sb.String())
++ sb.Reset()
++ words = append(words, word)
++ default:
+ words = append(words, word)
+ }
+- isPrevEncoded = isEncoded
+ }
++
++ if sb.Len() > 0 {
++ words = append(words, sb.String())
++ }
++
+ // Ignore any error if we got at least one word.
+ if err != nil && len(words) == 0 {
+ debug.Printf("consumePhrase: hit err: %v", err)
+diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
+index 1b165317f9..27837a9cbd 100644
+--- a/src/net/mail/message_test.go
++++ b/src/net/mail/message_test.go
+@@ -1219,6 +1219,17 @@ func TestEmptyAddress(t *testing.T) {
+ }
+ }
+
++func BenchmarkConsumePhrase(b *testing.B) {
++ for _, n := range []int{10, 100, 1000, 10000} {
++ b.Run(fmt.Sprintf("words-%d", n), func(b *testing.B) {
++ input := strings.Repeat("=?utf-8?q?hello?= ", n) + "<user@example.com>"
++ for b.Loop() {
++ (&addrParser{s: input}).consumePhrase()
++ }
++ })
++ }
++}
++
+ func BenchmarkConsumeComment(b *testing.B) {
+ for _, n := range []int{10, 100, 1000, 10000} {
+ b.Run(fmt.Sprintf("depth-%d", n), func(b *testing.B) {
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 18/21] go: patch CVE-2026-42501
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (16 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 17/21] go: patch CVE-2026-42499 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 19/21] go: patch CVE-2026-42504 Jeremy Rosen
` (2 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/775321
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-42501.patch | 127 ++++++++++++++++++
2 files changed, 128 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-42501.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 85f75f0d89..03a1a81fc3 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -52,6 +52,7 @@ SRC_URI += "\
file://CVE-2026-39825.patch \
file://CVE-2026-39826.patch \
file://CVE-2026-42499.patch \
+ file://CVE-2026-42501.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-42501.patch b/meta/recipes-devtools/go/go/CVE-2026-42501.patch
new file mode 100644
index 0000000000..82b2fa02a1
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-42501.patch
@@ -0,0 +1,127 @@
+From 52d8958ce7e102a5ebd3b4748aa03989b5469084 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 30 Apr 2026 13:10:49 -0700
+Subject: [PATCH] cmd/go: reject sumdb response lacking module hash
+
+Report an error when a sumdb /lookup/ request does not
+include a hash for the requested module, rather than
+silently proceeding.
+
+Previously, we would verify that a returned sum matched
+the expected module hash, but did not verify that the
+response contained a sum. This permits a malicous
+proxy to serve a corrupted module along with a
+valid-but-irrelevant sumdb response for some other
+module. We now ensure that the sumdb response contains
+a valid hash for the module we are validating.
+
+Thanks to Mundur (https://github.com/M0nd0R) for reporting this issue.
+
+Fixes CVE-2026-42501
+Fixes #79070
+
+Change-Id: I7d9a367deb237aa70cade2434495998f6a6a6964
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/4340
+Reviewed-by: Nicholas Husin <husin@google.com>
+Reviewed-by: Neal Patel <nealpatel@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/775321
+Reviewed-by: Michael Pratt <mpratt@google.com>
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+
+CVE: CVE-2026-42501
+Upstream-Status: Backport [https://github.com/golang/go/commit/1a9af07120312d368815712a4dce2dd2070342e5]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/cmd/go/internal/modfetch/fetch.go | 15 ++++++++++++++-
+ src/cmd/go/proxy_test.go | 17 +++++++++++++++++
+ src/cmd/go/testdata/script/mod_sum_absent.txt | 17 +++++++++++++++++
+ 3 files changed, 48 insertions(+), 1 deletion(-)
+ create mode 100644 src/cmd/go/testdata/script/mod_sum_absent.txt
+
+diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go
+index eeab6da62a..75769d7c61 100644
+--- a/src/cmd/go/internal/modfetch/fetch.go
++++ b/src/cmd/go/internal/modfetch/fetch.go
+@@ -740,7 +740,7 @@ func checkSumDB(mod module.Version, h string) error {
+ return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, noun, h, db, line[len(prefix)-len("h1:"):]))
+ }
+ }
+- return nil
++ return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: checksum missing from sumdb response"+sumdbAbsent, noun))
+ }
+
+ // Sum returns the checksum for the downloaded copy of the given module,
+@@ -931,6 +931,19 @@ have intercepted the download attempt.
+ For more information, see 'go help module-auth'.
+ `
+
++const sumdbAbsent = `
++
++SECURITY ERROR
++This download does NOT match one reported by the checksum server.
++The checksum server has provided checksums, but the checksums do
++not contain an entry for the download.
++The checksum server may be malfunctioning, or an attacker may have
++intercepted the checksum request.
++The download cannot be verified.
++
++For more information, see 'go help module-auth'.
++`
++
+ const hashVersionMismatch = `
+
+ SECURITY WARNING
+diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go
+index cb3d9f92f1..88e5052b89 100644
+--- a/src/cmd/go/proxy_test.go
++++ b/src/cmd/go/proxy_test.go
+@@ -172,6 +172,23 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
+ return
+ }
+
++ // Request for $GOPROXY/sumdb-redirect/module@version:/lookup/...
++ // performs a lookup for module@version rather than the requested module.
++ if strings.HasPrefix(path, "sumdb-redirect/") {
++ redirect, rest, ok := strings.Cut(path[len("sumdb-redirect"):], ":")
++ if !ok {
++ w.WriteHeader(500)
++ return
++ }
++ if strings.HasPrefix(rest, "/lookup/") {
++ r.URL.Path = "/lookup" + redirect
++ } else {
++ r.URL.Path = rest
++ }
++ sumdbServer.ServeHTTP(w, r)
++ return
++ }
++
+ // Request for $GOPROXY/redirect/<count>/... goes to redirects.
+ if strings.HasPrefix(path, "redirect/") {
+ path = path[len("redirect/"):]
+diff --git a/src/cmd/go/testdata/script/mod_sum_absent.txt b/src/cmd/go/testdata/script/mod_sum_absent.txt
+new file mode 100644
+index 0000000000..c2dd814542
+--- /dev/null
++++ b/src/cmd/go/testdata/script/mod_sum_absent.txt
+@@ -0,0 +1,17 @@
++# When the sumdb returns a response which does not
++# include a sum for the requested module,
++# we should report an error.
++# Verifies CVE-2026-42501.
++env sumdb=$GOSUMDB
++env proxy=$GOPROXY
++env GOPROXY GONOPROXY GOSUMDB GONOSUMDB
++
++# /sumdb-redirect/ causes the sumdb to return /lookup/ responses
++# for rsc.io/quote@v1.0.0, not for the requested module.
++env GOSUMDB=$sumdb' '$proxy/sumdb-redirect/rsc.io/quote@v1.0.0:
++
++! go get rsc.io/fortune@v1.0.0
++stderr 'SECURITY ERROR'
++! grep rsc.io go.sum
++-- go.mod --
++module m
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 19/21] go: patch CVE-2026-42504
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (17 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 18/21] go: patch CVE-2026-42501 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 20/21] go: patch CVE-2026-42507 Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 21/21] meta/lib/oe/package.py: fix path to kernel sources in save_debugsources_info Jeremy Rosen
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/774481
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-42504.patch | 58 +++++++++++++++++++
2 files changed, 59 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-42504.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index 03a1a81fc3..ba4fe9a734 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -53,6 +53,7 @@ SRC_URI += "\
file://CVE-2026-39826.patch \
file://CVE-2026-42499.patch \
file://CVE-2026-42501.patch \
+ file://CVE-2026-42504.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-42504.patch b/meta/recipes-devtools/go/go/CVE-2026-42504.patch
new file mode 100644
index 0000000000..1ae104ae19
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-42504.patch
@@ -0,0 +1,58 @@
+From 41ca50d68cd74e0a68f3917cd902885c84fedbf7 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Tue, 5 May 2026 15:20:34 -0700
+Subject: [PATCH] mime: avoid quadratic complexity in WordDecoder.DecodeHeader
+
+When encountering an undecodable encoded-word,
+skip over the entire word rather than just the initial "=?".
+
+Fixes #79217
+Fixes CVE-2026-42504
+
+Change-Id: I28605faa235459d2ba71bd0f3ae3dce96a6a6964
+Reviewed-on: https://go-review.googlesource.com/c/go/+/774481
+Reviewed-by: Nicholas Husin <nsh@golang.org>
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Nicholas Husin <husin@google.com>
+
+CVE: CVE-2026-42504
+Upstream-Status: Backport [https://github.com/golang/go/commit/f230dd8a1d0a63d73e92685e378dcd725f7aac00]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/mime/encodedword.go | 4 ++--
+ src/mime/encodedword_test.go | 4 ++++
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/mime/encodedword.go b/src/mime/encodedword.go
+index e6b470b1fb..a7059f3bc4 100644
+--- a/src/mime/encodedword.go
++++ b/src/mime/encodedword.go
+@@ -275,8 +275,8 @@ func (d *WordDecoder) DecodeHeader(header string) (string, error) {
+ content, err := decode(encoding, text)
+ if err != nil {
+ betweenWords = false
+- buf.WriteString(header[:start+2])
+- header = header[start+2:]
++ buf.WriteString(header[:end])
++ header = header[end:]
+ continue
+ }
+
+diff --git a/src/mime/encodedword_test.go b/src/mime/encodedword_test.go
+index 2a98794380..befc3cd996 100644
+--- a/src/mime/encodedword_test.go
++++ b/src/mime/encodedword_test.go
+@@ -140,6 +140,10 @@ func TestDecodeHeader(t *testing.T) {
+ {"=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=", "ab"},
+ {"=?ISO-8859-1?Q?a?= \r\n\t =?ISO-8859-1?Q?b?=", "ab"},
+ {"=?ISO-8859-1?Q?a_b?=", "a b"},
++ // Undecodable words
++ {"=?UTF-8?b?garbage?= =?UTF-8?b?QW5kcsOp?= =?UTF-8?b?garbage?=", "=?UTF-8?b?garbage?= André =?UTF-8?b?garbage?="},
++ {"=?UTF-8?b?QW5kcsOp", "=?UTF-8?b?QW5kcsOp"},
++ {"=?UTF-8?x?y?=?UTF-8?x?y=?", "=?UTF-8?x?y?=?UTF-8?x?y=?"},
+ }
+
+ for _, test := range tests {
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 20/21] go: patch CVE-2026-42507
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (18 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 19/21] go: patch CVE-2026-42504 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
2026-06-12 14:26 ` [OE-core][scarthgap 21/21] meta/lib/oe/package.py: fix path to kernel sources in save_debugsources_info Jeremy Rosen
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>
Backport patch from [1]
[1] https://go.dev/cl/777060
Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/recipes-devtools/go/go-1.22.12.inc | 1 +
.../go/go/CVE-2026-42507.patch | 160 ++++++++++++++++++
2 files changed, 161 insertions(+)
create mode 100644 meta/recipes-devtools/go/go/CVE-2026-42507.patch
diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index ba4fe9a734..f67da3e078 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -54,6 +54,7 @@ SRC_URI += "\
file://CVE-2026-42499.patch \
file://CVE-2026-42501.patch \
file://CVE-2026-42504.patch \
+ file://CVE-2026-42507.patch \
"
SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
diff --git a/meta/recipes-devtools/go/go/CVE-2026-42507.patch b/meta/recipes-devtools/go/go/CVE-2026-42507.patch
new file mode 100644
index 0000000000..d48b2b53eb
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-42507.patch
@@ -0,0 +1,160 @@
+From 943e53a7b667a1570648b5f1c4592b9d9d5b4aac Mon Sep 17 00:00:00 2001
+From: "Nicholas S. Husin" <nsh@golang.org>
+Date: Mon, 11 May 2026 18:04:07 -0400
+Subject: [PATCH] net/textproto: escape arbitrary input when including them in
+ errors
+
+When returning errors, functions in the net/textproto package would
+include its input as part of the error, without any escaping. Note that
+said input is often controlled by external parties when using this
+package naturally. For example, a net/http client uses ReadMIMEHeader
+when parsing the headers it receive from a server.
+
+As a result, an attacker could inject arbitrary content into the error.
+Practically, this can result in an attacker injecting misleading
+content, terminal control bytes, etc. into a victim's output or logs.
+
+Fix this issue by making sure that ProtocolError usages within the
+package are properly escaped, and that Error.String will escape its Msg.
+
+Fixes #79346
+Fixes CVE-2026-42507
+
+Change-Id: Ide4c1005d8254f90d95d7a389b8ca3a26a6a6964
+Reviewed-on: https://go-review.googlesource.com/c/go/+/777060
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Roland Shoemaker <roland@golang.org>
+Reviewed-by: Nicholas Husin <husin@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+
+CVE: CVE-2026-42507
+Upstream-Status: Backport [https://github.com/golang/go/commit/1a7e601d07b67aec8d795c8182ee7257ba7d1960]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/net/smtp/smtp_test.go | 6 +++---
+ src/net/textproto/reader.go | 14 +++++++-------
+ src/net/textproto/reader_test.go | 6 ++++--
+ src/net/textproto/textproto.go | 2 +-
+ 4 files changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go
+index 259b10b93d..3e03da5208 100644
+--- a/src/net/smtp/smtp_test.go
++++ b/src/net/smtp/smtp_test.go
+@@ -664,7 +664,7 @@ func TestHello(t *testing.T) {
+ err = c.Hello("customhost")
+ case 1:
+ err = c.StartTLS(nil)
+- if err.Error() == "502 Not implemented" {
++ if err.Error() == `502 "Not implemented"` {
+ err = nil
+ }
+ case 2:
+@@ -922,8 +922,8 @@ func TestAuthFailed(t *testing.T) {
+
+ if err == nil {
+ t.Error("Auth: expected error; got none")
+- } else if err.Error() != "535 Invalid credentials\nplease see www.example.com" {
+- t.Errorf("Auth: got error: %v, want: %s", err, "535 Invalid credentials\nplease see www.example.com")
++ } else if err.Error() != `535 "Invalid credentials\nplease see www.example.com"` {
++ t.Errorf("Auth: got error: %v, want: %s", err, `535 "Invalid credentials\nplease see www.example.com"`)
+ }
+
+ bcmdbuf.Flush()
+diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
+index 0027efe3ca..b4cd22a6ed 100644
+--- a/src/net/textproto/reader.go
++++ b/src/net/textproto/reader.go
+@@ -213,13 +213,13 @@ func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message
+
+ func parseCodeLine(line string, expectCode int) (code int, continued bool, message string, err error) {
+ if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
+- err = ProtocolError("short response: " + line)
++ err = ProtocolError(fmt.Sprintf("short response: %q", line))
+ return
+ }
+ continued = line[3] == '-'
+ code, err = strconv.Atoi(line[0:3])
+ if err != nil || code < 100 {
+- err = ProtocolError("invalid response code: " + line)
++ err = ProtocolError(fmt.Sprintf("invalid response code: %q", line))
+ return
+ }
+ message = line[4:]
+@@ -251,7 +251,7 @@ func parseCodeLine(line string, expectCode int) (code int, continued bool, messa
+ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error) {
+ code, continued, message, err := r.readCodeLine(expectCode)
+ if err == nil && continued {
+- err = ProtocolError("unexpected multi-line response: " + message)
++ err = ProtocolError(fmt.Sprintf("unexpected multi-line response: %q", message))
+ }
+ return
+ }
+@@ -536,7 +536,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+ if err != nil {
+ return m, err
+ }
+- return m, ProtocolError("malformed MIME header initial line: " + string(line))
++ return m, ProtocolError(fmt.Sprintf("malformed MIME header initial line: %q", line))
+ }
+
+ for {
+@@ -548,15 +548,15 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+ // Key ends at first colon.
+ k, v, ok := bytes.Cut(kv, colon)
+ if !ok {
+- return m, ProtocolError("malformed MIME header line: " + string(kv))
++ return m, ProtocolError(fmt.Sprintf("malformed MIME header line: %q", kv))
+ }
+ key, ok := canonicalMIMEHeaderKey(k)
+ if !ok {
+- return m, ProtocolError("malformed MIME header line: " + string(kv))
++ return m, ProtocolError(fmt.Sprintf("malformed MIME header line: %q", kv))
+ }
+ for _, c := range v {
+ if !validHeaderValueByte(c) {
+- return m, ProtocolError("malformed MIME header line: " + string(kv))
++ return m, ProtocolError(fmt.Sprintf("malformed MIME header line: %q", kv))
+ }
+ }
+
+diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
+index 26ff617470..844069a4ad 100644
+--- a/src/net/textproto/reader_test.go
++++ b/src/net/textproto/reader_test.go
+@@ -409,6 +409,8 @@ func TestReadMultiLineError(t *testing.T) {
+ "Unexpected but legal text!\n" +
+ "5.1.1 https://support.google.com/mail/answer/6596 h20si25154304pfd.166 - gsmtp"
+
++ wantError := `550 "5.1.1 The email account that you tried to reach does not exist. Please try\n5.1.1 double-checking the recipient's email address for typos or\n5.1.1 unnecessary spaces. Learn more at\nUnexpected but legal text!\n5.1.1 https://support.google.com/mail/answer/6596 h20si25154304pfd.166 - gsmtp"`
++
+ code, msg, err := r.ReadResponse(250)
+ if err == nil {
+ t.Errorf("ReadResponse: no error, want error")
+@@ -419,8 +421,8 @@ func TestReadMultiLineError(t *testing.T) {
+ if msg != wantMsg {
+ t.Errorf("ReadResponse: msg=%q, want %q", msg, wantMsg)
+ }
+- if err != nil && err.Error() != "550 "+wantMsg {
+- t.Errorf("ReadResponse: error=%q, want %q", err.Error(), "550 "+wantMsg)
++ if err != nil && err.Error() != wantError {
++ t.Errorf("ReadResponse: error=%q, want %q", err.Error(), wantError)
+ }
+ }
+
+diff --git a/src/net/textproto/textproto.go b/src/net/textproto/textproto.go
+index 4ae3ecff74..a2291eff2b 100644
+--- a/src/net/textproto/textproto.go
++++ b/src/net/textproto/textproto.go
+@@ -38,7 +38,7 @@ type Error struct {
+ }
+
+ func (e *Error) Error() string {
+- return fmt.Sprintf("%03d %s", e.Code, e.Msg)
++ return fmt.Sprintf("%03d %q", e.Code, e.Msg)
+ }
+
+ // A ProtocolError describes a protocol violation such
+--
+2.43.0
+
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread* [OE-core][scarthgap 21/21] meta/lib/oe/package.py: fix path to kernel sources in save_debugsources_info
2026-06-12 14:25 [OE-core][scarthgap 00/21] Patch review Jeremy Rosen
` (19 preceding siblings ...)
2026-06-12 14:26 ` [OE-core][scarthgap 20/21] go: patch CVE-2026-42507 Jeremy Rosen
@ 2026-06-12 14:26 ` Jeremy Rosen
20 siblings, 0 replies; 24+ messages in thread
From: Jeremy Rosen @ 2026-06-12 14:26 UTC (permalink / raw)
To: openembedded-core; +Cc: Paul Barker
From: João Marcos Costa (Schneider Electric) <joaomarcos.costa@bootlin.com>
This is no more than a backport of the current (i.e., from 'master')
version of this same chunk in save_debugsources_info(), where BP is used
instead of PF to form the path to the kernel sources.
This replacement in package.py is followed by a similar change in
meta/classes/create-spdx-2.2.bbclass, so that 'BP' is also used in
spdx_get_src() and we don't face any regressions in SPDX v2.2. As a
matter of fact, SPDX3 also uses 'BP' in get_patched_src() (from
spdx_common.py).
Overall, this backport ensures a coherence between Scarthgap and master,
namely regarding the how the kernel sources are provided by package.py
and consumed by SPDX v2.2 and 3.0.
Signed-off-by: João Marcos Costa (Schneider Electric) <joaomarcos.costa@bootlin.com>
Co-authored-by: Benjamin Robin (Schneider Electric) <benjamin.robin@bootlin.com>
Signed-off-by: Jeremy Rosen <jeremy.rosen@smile.fr>
---
meta/classes/create-spdx-2.2.bbclass | 2 +-
meta/lib/oe/package.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass
index 037193bb4b..61bad66ae0 100644
--- a/meta/classes/create-spdx-2.2.bbclass
+++ b/meta/classes/create-spdx-2.2.bbclass
@@ -933,7 +933,7 @@ def spdx_get_src(d):
share_src = d.getVar('WORKDIR')
d.setVar('WORKDIR', spdx_workdir)
d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native)
- src_dir = spdx_workdir + "/" + d.getVar('PN')+ "-" + d.getVar('PV') + "-" + d.getVar('PR')
+ src_dir = spdx_workdir + "/" + d.getVar('BP')
bb.utils.mkdirhier(src_dir)
if bb.data.inherits_class('kernel',d):
share_src = d.getVar('STAGING_KERNEL_DIR')
diff --git a/meta/lib/oe/package.py b/meta/lib/oe/package.py
index ba0d326781..fc5185ced4 100644
--- a/meta/lib/oe/package.py
+++ b/meta/lib/oe/package.py
@@ -1055,13 +1055,13 @@ def save_debugsources_info(debugsrcdir, sources_raw, d):
# we format the sources as expected by spdx by replacing /usr/src/kernel/
# into BP/
kernel_src = d.getVar('KERNEL_SRC_PATH')
- pf = d.getVar('PF')
+ bp = d.getVar('BP')
sources_dict = {}
for file, src_files in sources_raw:
file_clean = file.replace(f"{workdir}/package/","")
sources_clean = [
src.replace(f"{debugsrcdir}/{pn}/", "")
- if not kernel_src else src.replace(f"{kernel_src}/", f"{pf}/")
+ if not kernel_src else src.replace(f"{kernel_src}/", f"{bp}/")
for src in src_files
if not any(keyword in src for keyword in ("<internal>", "<built-in>")) and not src.endswith("/")
]
--
2.53.0
^ permalink raw reply related [flat|nested] 24+ messages in thread