diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2010-12-09 23:01:19 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2010-12-09 23:01:19 +0000 |
commit | f1e79ec68713661173a39689ac7ec54384c9e6eb (patch) | |
tree | babcca5dc5a7aa2a2a3fb31ebf9a38d0edbc4f83 | |
parent | fbbf922c8d34a7f92addc03a7578776c5853b61c (diff) |
Abort endless loops during roff macro and string expansion.
For now, use the simplest conceivable approach, like groff does:
Just a fixed, ugly input stack limit.
Kristaps@ agrees.
-rw-r--r-- | regress/usr.bin/mandoc/roff/string/Makefile | 4 | ||||
-rw-r--r-- | regress/usr.bin/mandoc/roff/string/infinite.in | 8 | ||||
-rw-r--r-- | regress/usr.bin/mandoc/roff/string/infinite.out_ascii | 12 | ||||
-rw-r--r-- | share/man/man7/roff.7 | 8 | ||||
-rw-r--r-- | usr.bin/mandoc/main.c | 15 | ||||
-rw-r--r-- | usr.bin/mandoc/mandoc.h | 3 |
6 files changed, 43 insertions, 7 deletions
diff --git a/regress/usr.bin/mandoc/roff/string/Makefile b/regress/usr.bin/mandoc/roff/string/Makefile index 38c6c1f5afc..5577da4097e 100644 --- a/regress/usr.bin/mandoc/roff/string/Makefile +++ b/regress/usr.bin/mandoc/roff/string/Makefile @@ -1,5 +1,5 @@ -# $OpenBSD: Makefile,v 1.1 2010/12/09 20:56:30 schwarze Exp $ +# $OpenBSD: Makefile,v 1.2 2010/12/09 23:01:18 schwarze Exp $ -REGRESS_TARGETS=escape +REGRESS_TARGETS=escape infinite .include <bsd.regress.mk> diff --git a/regress/usr.bin/mandoc/roff/string/infinite.in b/regress/usr.bin/mandoc/roff/string/infinite.in new file mode 100644 index 00000000000..6c25f7ca7af --- /dev/null +++ b/regress/usr.bin/mandoc/roff/string/infinite.in @@ -0,0 +1,8 @@ +.TH STRING-INFINITE 1 "December 3, 2010" +.SH NAME +string-infinite - endless recursion in string expansion +.SH DESCRIPTION +.ds recur \\*[recur] +Blow up, +(and do not \*[recur] print this) +but still render following text correctly. diff --git a/regress/usr.bin/mandoc/roff/string/infinite.out_ascii b/regress/usr.bin/mandoc/roff/string/infinite.out_ascii new file mode 100644 index 00000000000..0e1bee3680f --- /dev/null +++ b/regress/usr.bin/mandoc/roff/string/infinite.out_ascii @@ -0,0 +1,12 @@ +STRING-INFINITE(1) STRING-INFINITE(1) + + + +NNAAMMEE + string-infinite - endless recursion in string expansion + +DDEESSCCRRIIPPTTIIOONN + Blow up, but still render following text correctly. + + + diff --git a/share/man/man7/roff.7 b/share/man/man7/roff.7 index f625e83adae..480547812af 100644 --- a/share/man/man7/roff.7 +++ b/share/man/man7/roff.7 @@ -1,4 +1,4 @@ -.\" $OpenBSD: roff.7,v 1.6 2010/12/09 20:56:30 schwarze Exp $ +.\" $OpenBSD: roff.7,v 1.7 2010/12/09 23:01:18 schwarze Exp $ .\" .\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -217,6 +217,12 @@ string interpolation syntax described below .Sx ds , but this is rarely useful because every macro definition contains at least one explicit newline character. +.Pp +In order to prevent endless recursion, both groff and +.Xr mandoc 1 +limit the stack depth for expanding macros and strings +to a large, but finite number. +Do not rely on the exact value of this limit. .Ss \&dei Define a .Nm diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c index c14030f1f2d..ef6d9bb7b88 100644 --- a/usr.bin/mandoc/main.c +++ b/usr.bin/mandoc/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.60 2010/12/02 20:40:43 schwarze Exp $ */ +/* $Id: main.c,v 1.61 2010/12/09 23:01:18 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -34,6 +34,7 @@ #include "man.h" #include "roff.h" +#define REPARSE_LIMIT 1000 #define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) typedef void (*out_mdoc)(void *, const struct mdoc *); @@ -74,6 +75,7 @@ struct curparse { struct mdoc *mdoc; /* mdoc parser */ struct roff *roff; /* roff parser (!NULL) */ struct regset regs; /* roff registers */ + int reparse_count; /* finite interpolation stack */ enum outt outtype; /* which output to use */ out_mdoc outmdoc; /* mdoc output ptr */ out_man outman; /* man output ptr */ @@ -162,6 +164,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "generic error", + "input stack limit exceeded, infinite loop?", "skipping bad character", "skipping text before the first section header", "skipping unknown macro", @@ -651,8 +654,10 @@ parsebuf(struct curparse *curp, struct buf blk, int start) if (0 == pos && '\0' == blk.buf[i]) break; - if (start) + if (start) { curp->line = lnn; + curp->reparse_count = 0; + } while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) { if ('\n' == blk.buf[i]) { @@ -751,7 +756,11 @@ rerun: switch (rr) { case (ROFF_REPARSE): - parsebuf(curp, ln, 0); + if (REPARSE_LIMIT >= ++curp->reparse_count) + parsebuf(curp, ln, 0); + else + mmsg(MANDOCERR_ROFFLOOP, curp, + curp->line, pos, NULL); pos = 0; continue; case (ROFF_APPEND): diff --git a/usr.bin/mandoc/mandoc.h b/usr.bin/mandoc/mandoc.h index b6ce8685677..215f8d53650 100644 --- a/usr.bin/mandoc/mandoc.h +++ b/usr.bin/mandoc/mandoc.h @@ -1,4 +1,4 @@ -/* $Id: mandoc.h,v 1.24 2010/12/07 00:08:52 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.25 2010/12/09 23:01:18 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -101,6 +101,7 @@ enum mandocerr { MANDOCERR_ERROR, /* ===== start of errors ===== */ + MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ MANDOCERR_BADCHAR, /* skipping bad character */ MANDOCERR_NOTEXT, /* skipping text before the first section header */ MANDOCERR_MACRO, /* skipping unknown macro */ |