diff mbox series

[scarthgap,v2] libxpm: fix CVE-2026-4367

Message ID 20260722135401.2013448-1-enoch.ng@windriver.com
State New
Headers show
Series [scarthgap,v2] libxpm: fix CVE-2026-4367 | expand

Commit Message

Enoch Ng July 22, 2026, 1:53 p.m. UTC
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
diff mbox series

Patch

diff --git a/meta/recipes-graphics/xorg-lib/libxpm/0001-Fix-CVE-2026-4367-Out-of-bounds-read-in-xpmNextWord.patch b/meta/recipes-graphics/xorg-lib/libxpm/0001-Fix-CVE-2026-4367-Out-of-bounds-read-in-xpmNextWord.patch
new file mode 100644
index 0000000000..e9989a5012
--- /dev/null
+++ b/meta/recipes-graphics/xorg-lib/libxpm/0001-Fix-CVE-2026-4367-Out-of-bounds-read-in-xpmNextWord.patch
@@ -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;
diff --git a/meta/recipes-graphics/xorg-lib/libxpm_3.5.17.bb b/meta/recipes-graphics/xorg-lib/libxpm_3.5.17.bb
index 8e15ecc0d4..9d1dd47742 100644
--- a/meta/recipes-graphics/xorg-lib/libxpm_3.5.17.bb
+++ b/meta/recipes-graphics/xorg-lib/libxpm_3.5.17.bb
@@ -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"