summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2017-02-17 03:03:03 +0000
committerIngo Schwarze <schwarze@openbsd.org>2017-02-17 03:03:03 +0000
commit43757c82b3a7a65d2481fe9ff6efb2970e685827 (patch)
tree1dea4e21cc3c7f041c2a1f473a3f65883e130820
parentfa4c0272e4f32857c55289b94ac6986d26909487 (diff)
downloadmandoc-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.c14
1 files 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);