fnematch: fix out-of-bounds access on EOF
authormillert <millert@openbsd.org>
Wed, 15 Nov 2023 18:48:13 +0000 (18:48 +0000)
committermillert <millert@openbsd.org>
Wed, 15 Nov 2023 18:48:13 +0000 (18:48 +0000)
fnematch() expects to store a NUL byte when EOF is encountered.
However, the rewrite broke this assumption because r.len from getrune()
is zero on EOF.  This results in j becoming negative on EOF, causing an
out-of-bounds access.  It is simplest to just force r.len to 1 on EOF
to copy a single NUL byte--the rune is initialized to zero even for EOF.

This also fixes the call to adjbuf().  We cannot use 'k' to determine
when we need to expand the buffer now that we are potentially reading
more than a single byte at a time.

https://github.com/onetrueawk/awk/pull/211

usr.bin/awk/b.c

index 6ab51ba..ab0228b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: b.c,v 1.45 2023/10/30 17:52:54 millert Exp $  */
+/*     $OpenBSD: b.c,v 1.46 2023/11/15 18:48:13 millert Exp $  */
 /****************************************************************
 Copyright (C) Lucent Technologies 1997
 All Rights Reserved
@@ -861,13 +861,15 @@ bool fnematch(fa *pfa, FILE *f, char **pbuf, int *pbufsize, int quantum)
                j = i++;
                do {
                        r = getrune(f);
-                       if ((++j + r.len) >= k) {
-                               if (k >= bufsize)
-                                       if (!adjbuf(&buf, &bufsize, bufsize+1, quantum, 0, "fnematch"))
-                                               FATAL("stream '%.30s...' too long", buf);
+                       if (r.len == 0) {
+                               r.len = 1;      // store NUL byte for EOF
+                       }
+                       j += r.len;
+                       if (j >= bufsize) {
+                               if (!adjbuf(&buf, &bufsize, j+1, quantum, 0, "fnematch"))
+                                       FATAL("stream '%.30s...' too long", buf);
                        }
                        memcpy(buf + k, r.bytes, r.len);
-                       j += r.len - 1; // incremented next time around the loop
                        k += r.len;
 
                        if ((ns = get_gototab(pfa, s, r.rune)) != 0)