new file mode 100644
@@ -0,0 +1,140 @@
+From 5448e1bd7252780b16db869c2253d24e0fe0ae18 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Tue, 17 Feb 2026 11:59:56 +0100
+Subject: [PATCH libXpm] Fix CVE-2026-4367: Out-of-bounds read in xpmNextWord()
+
+xpmNextWord() checks for the terminator character to detect the end of
+the file, but a very small malformed XPM file may cause the function to
+read past the end of the buffer, causing out-of-bound reads:
+
+ == Invalid read of size 1
+ == at 0x48AD3A4: xpmParseColors (parse.c:239)
+ == by 0x48AF9D8: xpmParseData (parse.c:783)
+ == by 0x48B1C18: XpmCreateXpmImageFromBuffer (CrIFrBuf.c:101)
+ == by 0x4005A6: main ()
+ == Address 0x4c413bf is 0 bytes after a block of size 15 alloc'd
+ == at 0x4841B26: malloc (vg_replace_malloc.c:447)
+ == by 0x48B2809: XpmReadFileToBuffer (RdFToBuf.c:96)
+ == by 0x400554: main ()
+ ==
+ == Invalid read of size 1
+ == at 0x48AC8D5: xpmNextWord.constprop.0 (data.c:262)
+ == by 0x48AD492: xpmParseColors (parse.c:266)
+ == by 0x48AF9D8: xpmParseData (parse.c:783)
+ == by 0x48B1C18: XpmCreateXpmImageFromBuffer (CrIFrBuf.c:101)
+ == by 0x4005A6: main ()
+ == Address 0x4c413c0 is 1 bytes after a block of size 15 alloc'd
+ == at 0x4841B26: malloc (vg_replace_malloc.c:447)
+ == by 0x48B2809: XpmReadFileToBuffer (RdFToBuf.c:96)
+ == by 0x400554: main ()
+ ==
+ == Invalid read of size 1
+ == at 0x48AC965: xpmNextWord.constprop.0 (data.c:265)
+ == by 0x48AD492: xpmParseColors (parse.c:266)
+ == by 0x48AF9D8: xpmParseData (parse.c:783)
+ == by 0x48B1C18: XpmCreateXpmImageFromBuffer (CrIFrBuf.c:101)
+ == by 0x4005A6: main ()
+ == Address 0x4c413c0 is 1 bytes after a block of size 15 alloc'd
+ == at 0x4841B26: malloc (vg_replace_malloc.c:447)
+ == by 0x48B2809: XpmReadFileToBuffer (RdFToBuf.c:96)
+ == by 0x400554: main ()
+
+The problem actually comes from xpmNextString() and xpmParseColors():
+
+1) xpmNextString() checks for the NULL terminator when looking for the
+ end of the string (Eos) but not when looking for the beginning of the
+ next string (Bos).
+
+2) xpmParseColors() does not check the return value from xpmNextString()
+ and continues even when xpmNextString() raised an invalid XPM file.
+
+To avoid the issue, fix xpmNextString() to check for the NULL string
+terminator when looking for the beginning of the next string and fix
+xpmParseColors() to stop when xpmNextString() reported an invalid XPM
+error.
+
+CVE-2026-4367
+
+This vulnerability was discovered by:
+Naoki Wakamatsu
+
+v2: Fix the XPM 1 code path the same.
+
+Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
+Part-of: <https://gitlab.freedesktop.org/xorg/lib/libxpm/-/merge_requests/31>
+
+CVE: CVE-2026-4367
+Upstream-Status: Backport [https://gitlab.freedesktop.org/xorg/lib/libxpm/-/commit/5448e1bd7252780b16db869c2253d24e0fe0ae18]
+Signed-off-by: Enoch Ng <enoch.ng@windriver.com>
+
+---
+
+ src/data.c | 3 +++
+ src/parse.c | 19 ++++++++++++++-----
+ 2 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/src/data.c b/src/data.c
+index 6e87455..a2b4acc 100644
+--- a/src/data.c
++++ b/src/data.c
+@@ -210,6 +210,9 @@ xpmNextString(xpmData *data)
+ while ((c = *data->cptr++) && c != data->Bos && c != '\0')
+ if (data->Bcmt && c == data->Bcmt[0])
+ ParseComment(data);
++
++ if (c == '\0')
++ return XpmFileInvalid;
+ } else if (data->Bcmt) { /* XPM2 natural */
+ while (((c = *data->cptr++) == data->Bcmt[0]) && c != '\0')
+ ParseComment(data);
+diff --git a/src/parse.c b/src/parse.c
+index cd923f9..268954d 100644
+--- a/src/parse.c
++++ b/src/parse.c
+@@ -216,7 +216,9 @@ xpmParseColors(
+
+ if (!data->format) { /* XPM 2 or 3 */
+ for (a = 0, color = colorTable; a < ncolors; a++, color++) {
+- xpmNextString(data); /* skip the line */
++ ErrorStatus = xpmNextString(data); /* skip the line */
++ if (ErrorStatus != XpmSuccess)
++ goto error;
+
+ /*
+ * read pixel value
+@@ -314,7 +316,9 @@ xpmParseColors(
+ /* get to the beginning of the first string */
+ data->Bos = '"';
+ data->Eos = '\0';
+- xpmNextString(data);
++ ErrorStatus = xpmNextString(data);
++ if (ErrorStatus != XpmSuccess)
++ goto error;
+ data->Eos = '"';
+ for (a = 0, color = colorTable; a < ncolors; a++, color++) {
+
+@@ -354,7 +358,9 @@ xpmParseColors(
+ /*
+ * read color values
+ */
+- xpmNextString(data); /* get to the next string */
++ ErrorStatus = xpmNextString(data); /* get to the next string */
++ if (ErrorStatus != XpmSuccess)
++ goto error;
+ *curbuf = '\0'; /* init curbuf */
+ while ((l = xpmNextWord(data, buf, BUFSIZ))) {
+ if (*curbuf != '\0') {
+@@ -378,8 +384,11 @@ xpmParseColors(
+ memcpy(s, curbuf, len);
+ color->c_color = s;
+ *curbuf = '\0'; /* reset curbuf */
+- if (a < ncolors - 1) /* can we trust ncolors -> leave data's bounds */
+- xpmNextString(data); /* get to the next string */
++ if (a < ncolors - 1) { /* can we trust ncolors -> leave data's bounds */
++ ErrorStatus = xpmNextString(data); /* get to the next string */
++ if (ErrorStatus != XpmSuccess)
++ goto error;
++ }
+ }
+ }
+ *colorTablePtr = colorTable;
@@ -22,6 +22,7 @@ PACKAGES =+ "sxpm cxpm"
FILES:cxpm = "${bindir}/cxpm"
FILES:sxpm = "${bindir}/sxpm"
+SRC_URI += " file://0001-Fix-CVE-2026-4367-Out-of-bounds-read-in-xpmNextWord.patch"
SRC_URI[sha256sum] = "64b31f81019e7d388c822b0b28af8d51c4622b83f1f0cb6fa3fc95e271226e43"
BBCLASSEXTEND = "native"
Backport the upstream fix for CVE-2026-4367, in which the `xpmNextWord()` function could attempt to read beyond the file's end due to improper validation of file boundaries. Reference: https://nvd.nist.gov/vuln/detail/CVE-2026-4367 Signed-off-by: Enoch Ng <enoch.ng@windriver.com> --- v2: Add formatted CVE tag ...67-Out-of-bounds-read-in-xpmNextWord.patch | 140 ++++++++++++++++++ .../xorg-lib/libxpm_3.5.17.bb | 1 + 2 files changed, 141 insertions(+) create mode 100644 meta/recipes-graphics/xorg-lib/libxpm/0001-Fix-CVE-2026-4367-Out-of-bounds-read-in-xpmNextWord.patch