source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: If a user-defined macro is aborted because it exceeds the stack
@ 2017-03-07 20:00 schwarze
  0 siblings, 0 replies; only message in thread
From: schwarze @ 2017-03-07 20:00 UTC (permalink / raw)
  To: source

Log Message:
-----------
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).

Modified Files:
--------------
    mdocml:
        read.c
    mdocml/regress/roff/de:
        Makefile

Added Files:
-----------
    mdocml/regress/roff/de:
        infinite.in
        infinite.out_ascii
        infinite.out_lint

Revision Data
-------------
Index: read.c
===================================================================
RCS file: /home/cvs/mdocml/mdocml/read.c,v
retrieving revision 1.162
retrieving revision 1.163
diff -Lread.c -Lread.c -u -p -r1.162 -r1.163
--- read.c
+++ read.c
@@ -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
--- /dev/null
+++ regress/roff/de/infinite.out_lint
@@ -0,0 +1 @@
+mandoc: infinite.in:13:5: ERROR: input stack limit exceeded, infinite loop?
Index: Makefile
===================================================================
RCS file: /home/cvs/mdocml/mdocml/regress/roff/de/Makefile,v
retrieving revision 1.1
retrieving revision 1.2
diff -Lregress/roff/de/Makefile -Lregress/roff/de/Makefile -u -p -r1.1 -r1.2
--- regress/roff/de/Makefile
+++ regress/roff/de/Makefile
@@ -1,7 +1,12 @@
 # $OpenBSD: Makefile,v 1.9 2015/02/03 19:37:25 schwarze Exp $
 
-REGRESS_TARGETS = append cond escname factorial indir startde TH Dd
-LINT_TARGETS	= escname indir
+REGRESS_TARGETS	 = append cond escname factorial indir infinite startde TH Dd
+LINT_TARGETS	 = escname indir infinite
+
+# groff-1.22.3 defect:
+# infinite recursion aborts output completely
+
+SKIP_GROFF	 = infinite
 
 .include <bsd.regress.mk>
 
--- /dev/null
+++ regress/roff/de/infinite.out_ascii
@@ -0,0 +1,9 @@
+DE-INFINITE(1)              General Commands Manual             DE-INFINITE(1)
+
+N\bNA\bAM\bME\bE
+     d\bde\be-\b-i\bin\bnf\bfi\bin\bni\bit\bte\be - inifinte recursion in a user-defined macro
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+     initial text final text
+
+OpenBSD                          March 7, 2017                         OpenBSD
--- /dev/null
+++ regress/roff/de/infinite.in
@@ -0,0 +1,14 @@
+.Dd March 7, 2017
+.Dt DE-INFINITE 1
+.Os OpenBSD
+.Sh NAME
+.Nm de-infinite
+.Nd inifinte recursion in a user-defined macro
+.Sh DESCRIPTION
+initial text
+.de mym
+.mym
+not printed
+..
+.mym
+final text
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2017-03-07 20:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-07 20:00 mdocml: If a user-defined macro is aborted because it exceeds the stack schwarze

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).