[PATCH] ash: fix out-of-bounds read in ifsbreakup()

Sanghyun Park sanghyun.park.cnu at gmail.com
Tue Jun 16 03:19:01 UTC 2026


ifsbreakup() skips over CTLESC before testing the following byte against
IFS. If CTLESC is the last byte in the recorded region, the scan
advances to the region end and can dereference one byte past it.

The recorded region can also be stale after error unwinding, so cap each
scan to the current stack block before walking it and make the final
empty-string check respect the same bound.

Signed-off-by: Sanghyun Park <sanghyun.park.cnu at gmail.com>
---
 shell/ash.c | 30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index fb887f3..cda6c85 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6412,13 +6412,16 @@ ifsbreakup(char *string, struct arglist *arglist)
 	struct ifsregion *ifsp;
 	struct strlist *sp;
 	char *start;
+	char *end;
 	char *p;
 	char *q;
+	char *stack_end;
 	const char *ifs, *realifs;
 	int ifsspc;
 	int nulonly;
 
 	start = string;
+	stack_end = (char *)stackblock() + stackblocksize();
 	if (ifslastp != NULL) {
 		ifsspc = 0;
 		nulonly = 0;
@@ -6428,14 +6431,26 @@ ifsbreakup(char *string, struct arglist *arglist)
 			int afternul;
 
 			p = string + ifsp->begoff;
+			end = string + ifsp->endoff;
+			if (end > stack_end)
+				end = stack_end;
+			if (p >= end) {
+				ifsp = ifsp->next;
+				continue;
+			}
 			afternul = nulonly;
 			nulonly = ifsp->nulonly;
 			ifs = nulonly ? nullstr : realifs;
 			ifsspc = 0;
-			while (p < string + ifsp->endoff) {
+			while (p < end) {
 				q = p;
-				if ((unsigned char)*p == CTLESC)
+				if ((unsigned char)*p == CTLESC) {
 					p++;
+					if (p >= end) {
+						p = q;
+						break;
+					}
+				}
 				if (!strchr(ifs, *p)) {
 					p++;
 					continue;
@@ -6456,12 +6471,17 @@ ifsbreakup(char *string, struct arglist *arglist)
 				p++;
 				if (!nulonly) {
 					for (;;) {
-						if (p >= string + ifsp->endoff) {
+						if (p >= end) {
 							break;
 						}
 						q = p;
-						if ((unsigned char)*p == CTLESC)
+						if ((unsigned char)*p == CTLESC) {
 							p++;
+							if (p >= end) {
+								p = q;
+								break;
+							}
+						}
 						if (strchr(ifs, *p) == NULL) {
 							p = q;
 							break;
@@ -6486,7 +6506,7 @@ ifsbreakup(char *string, struct arglist *arglist)
 			goto add;
 	}
 
-	if (!*start)
+	if (start >= stack_end || !*start)
 		return;
 
  add:
-- 
2.48.1


More information about the busybox mailing list