shithub: trueawk

Download patch

ref: 77c8ffa70db4e9819881ec676d3f13f550d02055
parent: 6a07a6d3bb6313714625f667470290e71545b270
author: ozan yigit <ozan.yigit@gmail.com>
date: Mon Mar 11 15:46:47 EDT 2024

fix for fnematch use-after-free bug resulting from adjbuf invalidating
the pointers to buf. this is Miguel Pineiro Jr.'s code.
thanks to github user caffe for spotting this.
this code demonstrates the problem:

printf "%8192s\n" | tr " " "=" | ./a.out 'BEGIN{RS="th[^h]+"}{}'

MAX_UTF_BYTES in fnematch has been replaced with awk_mb_cur_max.

--- a/b.c
+++ b/b.c
@@ -830,8 +830,6 @@
 }
 
 
-#define MAX_UTF_BYTES	4	// UTF-8 is up to 4 bytes long
-
 /*
  * NAME
  *     fnematch
@@ -868,16 +866,28 @@
 
 	do {
 		/*
-		 * Call u8_rune with at least MAX_UTF_BYTES ahead in
+		 * Call u8_rune with at least awk_mb_cur_max ahead in
 		 * the buffer until EOF interferes.
 		 */
-		if (k - j < MAX_UTF_BYTES) {
-			if (k + MAX_UTF_BYTES > buf + bufsize) {
+		if (k - j < awk_mb_cur_max) {
+			if (k + awk_mb_cur_max > buf + bufsize) {
+				char *obuf = buf;
 				adjbuf((char **) &buf, &bufsize,
-				    bufsize + MAX_UTF_BYTES,
+				    bufsize + awk_mb_cur_max,
 				    quantum, 0, "fnematch");
+
+				/* buf resized, maybe moved. update pointers */
+				*pbufsize = bufsize;
+				if (obuf != buf) {
+					i = buf + (i - obuf);
+					j = buf + (j - obuf);
+					k = buf + (k - obuf);
+					*pbuf = buf;
+					if (patlen)
+						patbeg = buf + (patbeg - obuf);
+				}
 			}
-			for (n = MAX_UTF_BYTES ; n > 0; n--) {
+			for (n = awk_mb_cur_max ; n > 0; n--) {
 				*k++ = (c = getc(f)) != EOF ? c : 0;
 				if (c == EOF) {
 					if (ferror(f))
@@ -913,10 +923,6 @@
 		j = i;
 		s = 2;
 	} while (1);
-
-	/* adjbuf() may have relocated a resized buffer. Inform the world. */
-	*pbuf = buf;
-	*pbufsize = bufsize;
 
 	if (patlen) {
 		/*
--