diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2017-03-07 20:00:08 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2017-03-07 20:00:08 +0000 |
commit | 0048f6b4d138a5084ab0895e54f81bfa74d70f76 (patch) | |
tree | ec3e7d582b64f0f9f1ef6029f20f4a4a52806f1a /read.c | |
parent | 26f4474f228f82cd5061c568f57cb6fec975c194 (diff) | |
download | mandoc-0048f6b4d138a5084ab0895e54f81bfa74d70f76.tar.gz |
If a user-defined macro is aborted because it exceeds the stack
limit, usually due to infinite recursion, discard whatever remains
in all those open stack levels. Otherwise, insane constructions
like the following could generate macros of enormous size, causing
mandoc(1) to die from memory exhaustion:
.de m \" original macro definition
.m \" recursion to blow up the stack
.de m \" definition to be run during the call of .m marked (*)
very long plain text (some kilobytes)
.m \" expand the above a thousand times while unwinding the stack
.. \" end of the original definition
.m \" (*) recursively generate a ridiculously large macro
.. \" end of recursively generated definition
.m \" execute the giant macro, exhausting memory
Very creative abuse found by tb@ with afl(1).
Diffstat (limited to 'read.c')
-rw-r--r-- | read.c | 20 |
1 files changed, 12 insertions, 8 deletions
@@ -66,7 +66,7 @@ struct mparse { static void choose_parser(struct mparse *); static void resize_buf(struct buf *, size_t); -static void mparse_buf_r(struct mparse *, struct buf, size_t, int); +static int mparse_buf_r(struct mparse *, struct buf, size_t, int); static int read_whole_file(struct mparse *, const char *, int, struct buf *, int *); static void mparse_end(struct mparse *); @@ -310,7 +310,7 @@ choose_parser(struct mparse *curp) * macros, inline equations, and input line traps) * and indirectly (for .so file inclusion). */ -static void +static int mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) { const struct tbl_span *span; @@ -511,13 +511,16 @@ rerun: switch (rr) { case ROFF_REPARSE: - if (REPARSE_LIMIT >= ++curp->reparse_count) - mparse_buf_r(curp, ln, of, 0); - else + if (++curp->reparse_count > REPARSE_LIMIT) mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, pos, NULL); - pos = 0; - continue; + else if (mparse_buf_r(curp, ln, of, 0) == 1 || + start == 1) { + pos = 0; + continue; + } + free(ln.buf); + return 0; case ROFF_APPEND: pos = strlen(ln.buf); continue; @@ -531,7 +534,7 @@ rerun: (i >= blk.sz || blk.buf[i] == '\0')) { curp->sodest = mandoc_strdup(ln.buf + of); free(ln.buf); - return; + return 1; } /* * We remove `so' clauses from our lookaside @@ -597,6 +600,7 @@ rerun: } free(ln.buf); + return 1; } static int |