aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/read.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2017-03-07 20:00:08 +0000
committerIngo Schwarze <schwarze@openbsd.org>2017-03-07 20:00:08 +0000
commit8ef8ebcf522a1fcfacc2601f9db3f97a55a3ddfd (patch)
tree6107e43fff96ef06836c6b9439d2a0e8f1d3f938 /read.c
parent25af9c11f6cdc0ec8d58083464b2b38ba11a1426 (diff)
downloadmandoc-8ef8ebcf522a1fcfacc2601f9db3f97a55a3ddfd.tar.gz
mandoc-8ef8ebcf522a1fcfacc2601f9db3f97a55a3ddfd.tar.zst
mandoc-8ef8ebcf522a1fcfacc2601f9db3f97a55a3ddfd.zip
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.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/read.c b/read.c
index b4718e51..883f5412 100644
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/* $Id: read.c,v 1.162 2017/03/06 17:26:05 schwarze Exp $ */
+/* $Id: read.c,v 1.163 2017/03/07 20:00:08 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -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