vi(1)/ex(1): size_t underflow in +cmd parser (ex.c:804)

[email protected]
Newsgroups gmane.os.openbsd.bugs
Message-ID <[email protected]>
ex_cmd() in usr.bin/vi/ex/ex.c computes the remaining command
length with unsigned arithmetic that underflows when the +cmd
inner loop consumes every byte and "discard" (escape pairs)
reaches save_cmd - cp:

	ecp->clen = ((ecp->save_cmd - ecp->cp) - 1) - discard;

The resulting (size_t)-1 flows into argv_exp2() -> argv_fexp()
at ex_argv.c:305 which loops until cmd walks off mapped memory.

Minimum reproducer (7 bytes, \x16 = literal-next):

	$ printf 'x\n' > t
	$ printf 'e+"p\x16o\n' | MALLOC_OPTIONS=S vi -e t
	Segmentation fault (core dumped)

Reproduced on OpenBSD 7.9 arm64, amd64 and i386.  Found by
AFL++ fuzzing of ex(1).

OK?

Index: usr.bin/vi/ex/ex.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/ex/ex.c,v
retrieving revision 1.23
diff -u -p -r1.23 ex.c
--- usr.bin/vi/ex/ex.c	23 Jun 2023 15:06:45 -0000	1.23
+++ usr.bin/vi/ex/ex.c
@@ -801,7 +801,8 @@ ex_cmd(SCR *sp)
 	ecp->cp = ecp->save_cmd;
 	ecp->save_cmd = p;
 	ecp->save_cmdlen = ecp->clen;
-	ecp->clen = ((ecp->save_cmd - ecp->cp) - 1) - discard;
+	len = ecp->save_cmd - ecp->cp;
+	ecp->clen = (len > 1 + discard) ? len - 1 - discard : 0;

 	/*
 	 * QUOTING NOTE:
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.