diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2017-02-17 03:03:03 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2017-02-17 03:03:03 +0000 |
commit | 43757c82b3a7a65d2481fe9ff6efb2970e685827 (patch) | |
tree | 1dea4e21cc3c7f041c2a1f473a3f65883e130820 | |
parent | fa4c0272e4f32857c55289b94ac6986d26909487 (diff) | |
download | mandoc-43757c82b3a7a65d2481fe9ff6efb2970e685827.tar.gz |
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.
-rw-r--r-- | roff.c | 14 |
1 files changed, 11 insertions, 3 deletions
@@ -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); |