summaryrefslogtreecommitdiff
path: root/usr.bin/mandoc
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2022-06-01 23:20:20 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2022-06-01 23:20:20 +0000
commitb893410f946842bdec21628b2c0cd360fbbcc432 (patch)
tree2efe26a7e5074a329b627df05bc1b13c42dba6ee /usr.bin/mandoc
parentba1647d4688debf6a2e04518af4057c9a4fd4323 (diff)
Fix a buffer overrun in the roff(7) escape sequence parser that could
be triggered by macro arguments ending in double backslashes, for example if people wrote .Sq "\\" instead of the correct .Sq "\e". The bug was hard to find because it caused a segfault only very rarely, according to my measurements with a probability of less than one permille. I'm sorry that the first one to hit the bug was an arm64 release build run by deraadt@. Thanks to bluhm@ for providing access to an arm64 machine for debugging purposes. In the end, the bug turned out to be architecture-independent. The reason for the bug was that i assumed an invariant that does not exist. The function roff_parse_comment() is very careful to make sure that the input buffer does not end in an escape character before passing it on, so i assumed this is still true when reaching roff_expand() immediately afterwards. But roff_expand() can also be reached from roff_getarg(), in which case there *can* be a lone escape character at the end of the buffer in case copy mode processing found and converted a double backslash. Fix this by handling a trailing escape character correctly in the function roff_escape(). The lesson here probably is to refrain from assuming an invariant unless verifying that the invariant actually holds is reasonably simple. In some cases, in particular for invariants that are important but not simple, it might also make sense to assert(3) rather than just assume the invariant. An assertion failure is so much better than a buffer overrun...
Diffstat (limited to 'usr.bin/mandoc')
-rw-r--r--usr.bin/mandoc/roff_escape.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/usr.bin/mandoc/roff_escape.c b/usr.bin/mandoc/roff_escape.c
index 041a5357c0e..34a09f3df6b 100644
--- a/usr.bin/mandoc/roff_escape.c
+++ b/usr.bin/mandoc/roff_escape.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: roff_escape.c,v 1.5 2022/05/31 20:21:40 schwarze Exp $ */
+/* $OpenBSD: roff_escape.c,v 1.6 2022/06/01 23:20:19 schwarze Exp $ */
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2017, 2018, 2020, 2022
* Ingo Schwarze <schwarze@openbsd.org>
@@ -124,6 +124,9 @@ roff_escape(const char *buf, const int ln, const int aesc,
rval = ESCAPE_IGNORE;
goto out;
+ case '\0':
+ iendarg = --iend;
+ /* FALLTHROUGH */
case '\\':
default:
iarg--;