From 43757c82b3a7a65d2481fe9ff6efb2970e685827 Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Fri, 17 Feb 2017 03:03:03 +0000 Subject: Fix a read buffer overrun that copied random data from memory into text nodes when a string passed to deroff() ended in a backslash and the byte after the terminating NUL was non-NUL, found by tb@ with afl(1). Invalid bytes so copied with the high bit set could later sometimes trigger another out of bounds read access to static memory in roff_strdup(), so add an assertion there to abort safely in case of similar data corruption. --- roff.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/roff.c b/roff.c index 542272ba..17dd8457 100644 --- a/roff.c +++ b/roff.c @@ -1226,15 +1226,22 @@ deroff(char **dest, const struct roff_node *n) /* Skip leading whitespace. */ for (cp = n->string; *cp != '\0'; cp++) { - if (cp[0] == '\\' && strchr(" %&0^|~", cp[1]) != NULL) + if (cp[0] == '\\' && cp[1] != '\0' && + strchr(" %&0^|~", cp[1]) != NULL) cp++; else if ( ! isspace((unsigned char)*cp)) break; } + /* Skip trailing backslash. */ + + sz = strlen(cp); + if (cp[sz - 1] == '\\') + sz--; + /* Skip trailing whitespace. */ - for (sz = strlen(cp); sz; sz--) + for (; sz; sz--) if ( ! isspace((unsigned char)cp[sz-1])) break; @@ -3358,7 +3365,8 @@ roff_strdup(const struct roff *r, const char *p) ssz = 0; while ('\0' != *p) { - if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) { + assert((unsigned int)*p < 128); + if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) { sz = r->xtab[(int)*p].sz; res = mandoc_realloc(res, ssz + sz + 1); memcpy(res + ssz, r->xtab[(int)*p].p, sz); -- cgit