diff -u libx11-1.6.2/debian/changelog libx11-1.6.2/debian/changelog --- libx11-1.6.2/debian/changelog +++ libx11-1.6.2/debian/changelog @@ -1,3 +1,26 @@ +libx11 (2:1.6.2-1ubuntu2.1) trusty-security; urgency=medium + + * SECURITY UPDATE: Out-of-bounds read + - debian/patches/CVE-2016-7942.patch: fix in src/GetImage.c. + - CVE-2016-7942 + * SECURITY UPDATE: Out-of-bounds read + - debian/patches/CVE-2016-7943.patch: fix in src/FontNames.c, + src/ListExt.c, src/ModMap.c. + - CVE-2016-7943 + * SECURITY UPDATE: Denial of service + - debian/patches/CVE-2018-14598.patch: fix in src/GetFPath.c, + src/ListExt.c. + - CVE-2018-14598 + * SECURITY UPDATE: Denial of service + - debian/patches/CVE-2018-14599.patch: fix in src/FontNames.c, + src/GetFPath.c, src/ListExt.c. + - CVE-2018-14599 + * SECURITY UPDATE: Denial of service + - debian/patches/CVE-2018-14600.patch: fix in src/GetFPath. + - CVE-2018-14600 + + -- Leonidas S. Barbosa Thu, 30 Aug 2018 10:34:11 -0300 + libx11 (2:1.6.2-1ubuntu2) trusty; urgency=low * Update libx11 symbols file. diff -u libx11-1.6.2/debian/patches/series libx11-1.6.2/debian/patches/series --- libx11-1.6.2/debian/patches/series +++ libx11-1.6.2/debian/patches/series @@ -6,0 +7,5 @@ +CVE-2016-7942.patch +CVE-2016-7943.patch +CVE-2018-14598.patch +CVE-2018-14599.patch +CVE-2018-14600.patch only in patch2: unchanged: --- libx11-1.6.2.orig/debian/patches/CVE-2016-7942.patch +++ libx11-1.6.2/debian/patches/CVE-2016-7942.patch @@ -0,0 +1,68 @@ +From 8ea762f94f4c942d898fdeb590a1630c83235c17 Mon Sep 17 00:00:00 2001 +From: Tobias Stoeckmann +Date: Sun, 25 Sep 2016 21:25:25 +0200 +Subject: Validation of server responses in XGetImage() + +Check if enough bytes were received for specified image type and +geometry. Otherwise GetPixel and other functions could trigger an +out of boundary read later on. + +Signed-off-by: Tobias Stoeckmann +Reviewed-by: Matthieu Herrb +--- + src/GetImage.c | 29 ++++++++++++++++++++--------- + 1 file changed, 20 insertions(+), 9 deletions(-) + +diff --git a/src/GetImage.c b/src/GetImage.c +index c461abc..ff32d58 100644 +--- a/src/GetImage.c ++++ b/src/GetImage.c +@@ -59,6 +59,7 @@ XImage *XGetImage ( + char *data; + unsigned long nbytes; + XImage *image; ++ int planes; + LockDisplay(dpy); + GetReq (GetImage, req); + /* +@@ -91,18 +92,28 @@ XImage *XGetImage ( + return (XImage *) NULL; + } + _XReadPad (dpy, data, nbytes); +- if (format == XYPixmap) +- image = XCreateImage(dpy, _XVIDtoVisual(dpy, rep.visual), +- Ones (plane_mask & +- (((unsigned long)0xFFFFFFFF) >> (32 - rep.depth))), +- format, 0, data, width, height, dpy->bitmap_pad, 0); +- else /* format == ZPixmap */ +- image = XCreateImage (dpy, _XVIDtoVisual(dpy, rep.visual), +- rep.depth, ZPixmap, 0, data, width, height, +- _XGetScanlinePad(dpy, (int) rep.depth), 0); ++ if (format == XYPixmap) { ++ image = XCreateImage(dpy, _XVIDtoVisual(dpy, rep.visual), ++ Ones (plane_mask & ++ (((unsigned long)0xFFFFFFFF) >> (32 - rep.depth))), ++ format, 0, data, width, height, dpy->bitmap_pad, 0); ++ planes = image->depth; ++ } else { /* format == ZPixmap */ ++ image = XCreateImage (dpy, _XVIDtoVisual(dpy, rep.visual), ++ rep.depth, ZPixmap, 0, data, width, height, ++ _XGetScanlinePad(dpy, (int) rep.depth), 0); ++ planes = 1; ++ } + + if (!image) + Xfree(data); ++ if (planes < 1 || image->height < 1 || image->bytes_per_line < 1 || ++ INT_MAX / image->height <= image->bytes_per_line || ++ INT_MAX / planes <= image->height * image->bytes_per_line || ++ nbytes < planes * image->height * image->bytes_per_line) { ++ XDestroyImage(image); ++ image = NULL; ++ } + UnlockDisplay(dpy); + SyncHandle(); + return (image); +-- +cgit v1.1 + only in patch2: unchanged: --- libx11-1.6.2.orig/debian/patches/CVE-2016-7943.patch +++ libx11-1.6.2/debian/patches/CVE-2016-7943.patch @@ -0,0 +1,104 @@ +From 8c29f1607a31dac0911e45a0dd3d74173822b3c9 Mon Sep 17 00:00:00 2001 +From: Tobias Stoeckmann +Date: Sun, 25 Sep 2016 21:22:57 +0200 +Subject: The validation of server responses avoids out of boundary accesses. + +v2: FontNames.c return a NULL list whenever a single +length field from the server is incohent. + +Signed-off-by: Tobias Stoeckmann +Reviewed-by: Matthieu Herrb +--- + src/FontNames.c | 23 +++++++++++++++++------ + src/ListExt.c | 12 ++++++++---- + src/ModMap.c | 3 ++- + 3 files changed, 27 insertions(+), 11 deletions(-) + +diff --git a/src/FontNames.c b/src/FontNames.c +index 21dcafe..e55f338 100644 +--- a/src/FontNames.c ++++ b/src/FontNames.c +@@ -66,7 +66,7 @@ int *actualCount) /* RETURN */ + + if (rep.nFonts) { + flist = Xmalloc (rep.nFonts * sizeof(char *)); +- if (rep.length < (INT_MAX >> 2)) { ++ if (rep.length > 0 && rep.length < (INT_MAX >> 2)) { + rlen = rep.length << 2; + ch = Xmalloc(rlen + 1); + /* +1 to leave room for last null-terminator */ +@@ -93,11 +93,22 @@ int *actualCount) /* RETURN */ + if (ch + length < chend) { + flist[i] = ch + 1; /* skip over length */ + ch += length + 1; /* find next length ... */ +- length = *(unsigned char *)ch; +- *ch = '\0'; /* and replace with null-termination */ +- count++; +- } else +- flist[i] = NULL; ++ if (ch <= chend) { ++ length = *(unsigned char *)ch; ++ *ch = '\0'; /* and replace with null-termination */ ++ count++; ++ } else { ++ Xfree(flist); ++ flist = NULL; ++ count = 0; ++ break; ++ } ++ } else { ++ Xfree(flist); ++ flist = NULL; ++ count = 0; ++ break; ++ } + } + } + *actualCount = count; +diff --git a/src/ListExt.c b/src/ListExt.c +index be6b989..0516e45 100644 +--- a/src/ListExt.c ++++ b/src/ListExt.c +@@ -55,7 +55,7 @@ char **XListExtensions( + + if (rep.nExtensions) { + list = Xmalloc (rep.nExtensions * sizeof (char *)); +- if (rep.length < (INT_MAX >> 2)) { ++ if (rep.length > 0 && rep.length < (INT_MAX >> 2)) { + rlen = rep.length << 2; + ch = Xmalloc (rlen + 1); + /* +1 to leave room for last null-terminator */ +@@ -80,9 +80,13 @@ char **XListExtensions( + if (ch + length < chend) { + list[i] = ch+1; /* skip over length */ + ch += length + 1; /* find next length ... */ +- length = *ch; +- *ch = '\0'; /* and replace with null-termination */ +- count++; ++ if (ch <= chend) { ++ length = *ch; ++ *ch = '\0'; /* and replace with null-termination */ ++ count++; ++ } else { ++ list[i] = NULL; ++ } + } else + list[i] = NULL; + } +diff --git a/src/ModMap.c b/src/ModMap.c +index a809aa2..49a5d08 100644 +--- a/src/ModMap.c ++++ b/src/ModMap.c +@@ -42,7 +42,8 @@ XGetModifierMapping(register Display *dpy) + GetEmptyReq(GetModifierMapping, req); + (void) _XReply (dpy, (xReply *)&rep, 0, xFalse); + +- if (rep.length < (INT_MAX >> 2)) { ++ if (rep.length < (INT_MAX >> 2) && ++ (rep.length >> 1) == rep.numKeyPerModifier) { + nbytes = (unsigned long)rep.length << 2; + res = Xmalloc(sizeof (XModifierKeymap)); + if (res) +-- +cgit v1.1 + only in patch2: unchanged: --- libx11-1.6.2.orig/debian/patches/CVE-2018-14598.patch +++ libx11-1.6.2/debian/patches/CVE-2018-14598.patch @@ -0,0 +1,56 @@ +Backported of: + +From e83722768fd5c467ef61fa159e8c6278770b45c2 Mon Sep 17 00:00:00 2001 +From: Tobias Stoeckmann +Date: Fri, 27 Jul 2018 16:38:00 +0200 +Subject: [PATCH] Fixed crash on invalid reply (CVE-2018-14598). + +If the server sends a reply in which even the first string would +overflow the transmitted bytes, list[0] (or flist[0]) will be set to +NULL and a count of 0 is returned. + +If the resulting list is freed with XFreeExtensionList or +XFreeFontPath later on, the first Xfree call: + + Xfree (list[0]-1) + turns into + Xfree (NULL-1) + +which will most likely trigger a segmentation fault. + +I have modified the code to return NULL if the first string would +overflow, thus protecting the freeing functions later on. + +Signed-off-by: Tobias Stoeckmann +diff --git a/src/GetFPath.c b/src/GetFPath.c +index 8c3f49c..aa740df 100644 +--- a/src/GetFPath.c ++++ b/src/GetFPath.c +@@ -78,6 +78,11 @@ char **XGetFontPath( + length = *ch; + *ch = '\0'; /* and replace with null-termination */ + count++; ++ } else if (i == 0) { ++ Xfree(flist); ++ Xfree(ch); ++ flist = NULL; ++ break; + } else + flist[i] = NULL; + } +diff --git a/src/ListExt.c b/src/ListExt.c +index 0516e45..56263a1 100644 +--- a/src/ListExt.c ++++ b/src/ListExt.c +@@ -84,6 +84,11 @@ char **XListExtensions( + length = *ch; + *ch = '\0'; /* and replace with null-termination */ + count++; ++ } else if (i == 0) { ++ Xfree(list); ++ Xfree(ch); ++ list = NULL; ++ break; + } else { + list[i] = NULL; + } only in patch2: unchanged: --- libx11-1.6.2.orig/debian/patches/CVE-2018-14599.patch +++ libx11-1.6.2/debian/patches/CVE-2018-14599.patch @@ -0,0 +1,117 @@ +Backported of: + +From b469da1430cdcee06e31c6251b83aede072a1ff0 Mon Sep 17 00:00:00 2001 +From: Tobias Stoeckmann +Date: Fri, 27 Jul 2018 16:36:34 +0200 +Subject: [PATCH] Fixed off-by-one writes (CVE-2018-14599). + +The functions XGetFontPath, XListExtensions, and XListFonts are +vulnerable to an off-by-one override on malicious server responses. + +The server replies consist of chunks consisting of a length byte +followed by actual string, which is not NUL-terminated. + +While parsing the response, the length byte is overridden with '\0', +thus the memory area can be used as storage of C strings later on. To +be able to NUL-terminate the last string, the buffer is reserved with +an additional byte of space. + +For a boundary check, the variable chend (end of ch) was introduced, +pointing at the end of the buffer which ch initially points to. +Unfortunately there is a difference in handling "the end of ch". + +While chend points at the first byte that must not be written to, +the for-loop uses chend as the last byte that can be written to. + +Therefore, an off-by-one can occur. + +I have refactored the code so chend actually points to the last byte +that can be written to without an out of boundary access. As it is not +possible to achieve "ch + length < chend" and "ch + length + 1 > chend" +with the corrected chend meaning, I removed the inner if-check. + +Signed-off-by: Tobias Stoeckmann +diff --git a/src/FontNames.c b/src/FontNames.c +index 2dbca40..dc09fe4 100644 +--- a/src/FontNames.c ++++ b/src/FontNames.c +@@ -86,23 +86,16 @@ int *actualCount) /* RETURN */ + /* + * unpack into null terminated strings. + */ +- chend = ch + (rlen + 1); ++ chend = ch + rlen; + length = *(unsigned char *)ch; + *ch = 1; /* make sure it is non-zero for XFreeFontNames */ + for (i = 0; i < rep.nFonts; i++) { + if (ch + length < chend) { + flist[i] = ch + 1; /* skip over length */ + ch += length + 1; /* find next length ... */ +- if (ch <= chend) { +- length = *(unsigned char *)ch; +- *ch = '\0'; /* and replace with null-termination */ +- count++; +- } else { +- Xfree(flist); +- flist = NULL; +- count = 0; +- break; +- } ++ length = *(unsigned char *)ch; ++ *ch = '\0'; /* and replace with null-termination */ ++ count++; + } else { + Xfree(flist); + flist = NULL; +diff --git a/src/GetFPath.c b/src/GetFPath.c +index 69eeada..a36f083 100644 +--- a/src/GetFPath.c ++++ b/src/GetFPath.c +@@ -69,7 +69,7 @@ char **XGetFontPath( + /* + * unpack into null terminated strings. + */ +- chend = ch + (nbytes + 1); ++ chend = ch + nbytes; + length = *ch; + for (i = 0; i < rep.nPaths; i++) { + if (ch + length < chend) { +diff --git a/src/ListExt.c b/src/ListExt.c +index b49db62..642afcf 100644 +--- a/src/ListExt.c ++++ b/src/ListExt.c +@@ -74,24 +74,20 @@ char **XListExtensions( + /* + * unpack into null terminated strings. + */ +- chend = ch + (rlen + 1); +- length = *ch; ++ chend = ch + rlen; ++ length = *(unsigned char *)ch; + for (i = 0; i < rep.nExtensions; i++) { + if (ch + length < chend) { + list[i] = ch+1; /* skip over length */ + ch += length + 1; /* find next length ... */ +- if (ch <= chend) { +- length = *ch; +- *ch = '\0'; /* and replace with null-termination */ +- count++; +- } else if (i == 0) { +- Xfree(list); +- Xfree(ch); +- list = NULL; +- break; +- } else { +- list[i] = NULL; +- } ++ length = *(unsigned char *)ch; ++ *ch = '\0'; /* and replace with null-termination */ ++ count++; ++ } else if (i == 0) { ++ Xfree(list); ++ Xfree(ch); ++ list = NULL; ++ break; + } else + list[i] = NULL; + } only in patch2: unchanged: --- libx11-1.6.2.orig/debian/patches/CVE-2018-14600.patch +++ libx11-1.6.2/debian/patches/CVE-2018-14600.patch @@ -0,0 +1,35 @@ +Backported of: + +From dbf72805fd9d7b1846fe9a11b46f3994bfc27fea Mon Sep 17 00:00:00 2001 +From: Tobias Stoeckmann +Date: Fri, 27 Jul 2018 16:37:17 +0200 +Subject: [PATCH] Fixed out of boundary write (CVE-2018-14600). + +The length value is interpreted as signed char on many systems +(depending on default signedness of char), which can lead to an out of +boundary write up to 128 bytes in front of the allocated storage, but +limited to NUL byte(s). + +Casting the length value to unsigned char fixes the problem and allows +string values with up to 255 characters. + +Signed-off-by: Tobias Stoeckmann +diff --git a/src/GetFPath.c b/src/GetFPath.c +index b071393..dac553e 100644 +--- a/src/GetFPath.c ++++ b/src/GetFPath.c +@@ -70,12 +70,12 @@ char **XGetFontPath( + * unpack into null terminated strings. + */ + chend = ch + nbytes; +- length = *ch; ++ length = *(unsigned char *)ch; + for (i = 0; i < rep.nPaths; i++) { + if (ch + length < chend) { + flist[i] = ch+1; /* skip over length */ + ch += length + 1; /* find next length ... */ +- length = *ch; ++ length = *(unsigned char *)ch; + *ch = '\0'; /* and replace with null-termination */ + count++; + } else if (i == 0) {