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 | 73d13e32f24d114d25e566580496bd3b8c246ce6 (patch) | |
tree | b364b2d59e1a2c9a4a0b283b6188b9575b918834 | |
parent | 5d300ed80a7af7469ecdab91d541d5282a5288b5 (diff) | |
download | mandoc-73d13e32f24d114d25e566580496bd3b8c246ce6.tar.gz mandoc-73d13e32f24d114d25e566580496bd3b8c246ce6.tar.zst mandoc-73d13e32f24d114d25e566580496bd3b8c246ce6.zip |
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 | 16 |
1 files changed, 12 insertions, 4 deletions
@@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.288 2017/01/12 18:02:20 schwarze Exp $ */ +/* $Id: roff.c,v 1.289 2017/02/17 03:03:03 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org> @@ -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); |