summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Stoeckmann <tobias@stoeckmann.org>2018-07-27 16:36:34 +0200
committerMatthieu Herrb <matthieu@herrb.eu>2018-08-21 16:42:29 +0200
commitb469da1430cdcee06e31c6251b83aede072a1ff0 (patch)
treede86b50e1aec0db052b0b80fbd4cb357868676cd
parentd81da209fd4d0c2c9ad0596a8078e58864479d0d (diff)
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 <tobias@stoeckmann.org>
-rw-r--r--src/FontNames.c16
-rw-r--r--src/GetFPath.c2
-rw-r--r--src/ListExt.c12
3 files changed, 9 insertions, 21 deletions
diff --git a/src/FontNames.c b/src/FontNames.c
index 9ffdfd29..ec7d90fa 100644
--- a/src/FontNames.c
+++ b/src/FontNames.c
@@ -88,24 +88,16 @@ int *actualCount) /* RETURN */
* unpack into null terminated strings.
*/
chstart = ch;
- 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(chstart);
- Xfree(flist);
- flist = NULL;
- count = 0;
- break;
- }
+ length = *(unsigned char *)ch;
+ *ch = '\0'; /* and replace with null-termination */
+ count++;
} else {
Xfree(chstart);
Xfree(flist);
diff --git a/src/GetFPath.c b/src/GetFPath.c
index 3d87e4f6..7ad21e9a 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 7fdf9932..8f344ac0 100644
--- a/src/ListExt.c
+++ b/src/ListExt.c
@@ -74,19 +74,15 @@ char **XListExtensions(
/*
* unpack into null terminated strings.
*/
- chend = ch + (rlen + 1);
+ chend = ch + rlen;
length = *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 {
- list[i] = NULL;
- }
+ length = *ch;
+ *ch = '\0'; /* and replace with null-termination */
+ count++;
} else
list[i] = NULL;
}