summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2010-12-09 23:01:19 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2010-12-09 23:01:19 +0000
commitf1e79ec68713661173a39689ac7ec54384c9e6eb (patch)
treebabcca5dc5a7aa2a2a3fb31ebf9a38d0edbc4f83
parentfbbf922c8d34a7f92addc03a7578776c5853b61c (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/Makefile4
-rw-r--r--regress/usr.bin/mandoc/roff/string/infinite.in8
-rw-r--r--regress/usr.bin/mandoc/roff/string/infinite.out_ascii12
-rw-r--r--share/man/man7/roff.78
-rw-r--r--usr.bin/mandoc/main.c15
-rw-r--r--usr.bin/mandoc/mandoc.h3
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 */