Skip to contentSkip to conversation

Validate psfu headers to avoid integer overflows.

PATCH In review Tobias Stoeckmann 2 participants 2 messages Nov 20, 2016 – Dec 26, 2016

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Validate psfu headers to avoid integer overflows.

The psfu parser does not properly validate parsed values:

* unsigned int values are casted to signed int values when parameters are supplied, therefore they must be checked against INT_MAX (local size_t variables are used)
* fontwidth must not be larger than INT_MAX - 7, otherwise later alignment codes would overflow, e.g. (fontwidth + 7) / 8
* "ftoffset + fontlen * charsize" is prone to overflow, make sure that it does not; later on it will be checked against file size
* when parsing multiple files, make sure that the sum of all fonts won't overflow

---
I've sent this mail in August 2015 already. Based on the upcoming release, it might be a good idea to re-evaluate it.

Attached are two files which will crash the current code:

$ setfont setfont-fpe.psfu # font width too large
Floating point exception
$ psfxtable -i psfxtable-segfault.psfu # on 32 bit archs
Segmentation fault

Maybe there are more ways to trigger overflows, which makes it a good target for fuzzing.

---
 src/psffontop.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
src/psffontop.c +22 -0
index 9d7ee54..e86d3cd 100644
@@ -2,6 +2,7 @@
  * psffontop.c - [email protected], 990921
  */
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -275,6 +276,27 @@ readpsffont(FILE *fontf, char **allbufp, int *allszp,
 		fprintf(stderr, u, progname);
 		exit(EX_DATAERR);
 	}
+	if (INT_MAX - 7 < fontwidth) {
+		char *u = _("%s: Input file: font width too large\n");
+		fprintf(stderr, u, progname);
+		exit(EX_DATAERR);
+	}
+
+	/* validate header to avoid integer overflows */
+	if ((size_t)(INT_MAX - fontpos0) < fontlen ||
+	    INT_MAX / sizeof(struct unicode_list) < fontpos0 + fontlen ||
+	    INT_MAX / charsize < fontlen) {
+		char *u = _("%s: too many glyphs to load\n");
+		fprintf(stderr, u, progname);
+		exit(EX_DATAERR);
+	}
+	if (ftoffset > inputbuflth ||
+	    INT_MAX - ftoffset < fontlen * charsize) {
+		char *u = _("%s: Input file: bad offset\n");
+		fprintf(stderr, u, progname);
+		exit(EX_DATAERR);
+	}
+
 	i = ftoffset + fontlen * charsize;
 	if (i > inputlth || (!hastable && i != inputlth)) {
 		char *u = _("%s: Input file: bad input length (%d)\n");
Signature · 1 line
2.10.2
#1 lore raw
Quoted 11 lines · Tobias Stoeckmann

The psfu parser does not properly validate parsed values:

* unsigned int values are casted to signed int values when parameters are supplied, therefore they must be checked against INT_MAX (local size_t variables are used)
* fontwidth must not be larger than INT_MAX - 7, otherwise later alignment codes would overflow, e.g. (fontwidth + 7) / 8
* "ftoffset + fontlen * charsize" is prone to overflow, make sure that it does not; later on it will be checked against file size
* when parsing multiple files, make sure that the sum of all fonts won't overflow

I like the idea, but I don't like this patch. I consider it a bad idea to collect all the checks in one place. Most of them looks like black magic if you don't know the rest of source code.

Right now Oleg is developing the implementation of the library which will replace this buggy code. I hope this library will be ready for next release (not upcoming release).

Quoted 3 lines

---
I've sent this mail in August 2015 already. Based on the upcoming release, it might be a good idea to re-evaluate it.

I guess I lost it. Sorry.

Quoted 6 lines

Attached are two files which will crash the current code:

$ setfont setfont-fpe.psfu # font width too large
Floating point exception
$ psfxtable -i psfxtable-segfault.psfu # on 32 bit archs
Segmentation fault

Thanks for test cases!

Signature · 1 line
Rgrds, legion