[PATCH] awk: fix stack overflow in evaluate()

Sanghyun Park via busybox <[email protected]> Tue, 16 Jun 2026 12:16:05 +0900
Newsgroups gmane.linux.busybox
Message-ID <[email protected]>
Recursive awk functions can keep re-entering evaluate() until the
process stack is exhausted. Track active function-call depth and report a
normal awk error once the limit is reached instead of overflowing the
stack.

Signed-off-by: Sanghyun Park <[email protected]>
---
 editors/awk.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/editors/awk.c b/editors/awk.c
index dd8f4ac..f15832b 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -633,6 +633,7 @@ struct globals {
 	smalluint exitcode;
 
 	unsigned evaluate__seed;
+	unsigned evaluate__func_depth;
 	var *evaluate__fnargs;
 	regex_t evaluate__sreg;
 
@@ -703,6 +704,7 @@ static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
 static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
 static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
 static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments";
+static const char EMSG_RECURSION[] ALIGN1 = "Recursion limit exceeded";
 static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
 static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
 static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
@@ -2988,6 +2990,7 @@ static var *evaluate(node *op, var *res)
 #define fnargs (G.evaluate__fnargs)
 /* seed is initialized to 1 */
 #define seed   (G.evaluate__seed)
+#define func_depth (G.evaluate__func_depth)
 #define sreg   (G.evaluate__sreg)
 
 	var *tmpvars;
@@ -3299,13 +3302,17 @@ static var *evaluate(node *op, var *res)
 			var *argvars, *sv_fnargs;
 			const char *sv_progname;
 			int nargs, i;
+			enum { MAX_AWK_FUNC_DEPTH = 1000 };
 
 			debug_printf_eval("FUNC\n");
 
 			if (!op->r.f->defined)
 				syntax_error(EMSG_UNDEF_FUNC);
+			if (func_depth >= MAX_AWK_FUNC_DEPTH)
+				syntax_error(EMSG_RECURSION);
 
 			/* The body might be empty, still has to eval the args */
+			func_depth++;
 			nargs = op->r.f->nargs;
 			argvars = nvalloc(nargs);
 			i = 0;
@@ -3333,6 +3340,7 @@ static var *evaluate(node *op, var *res)
 
 			g_progname = sv_progname;
 			fnargs = sv_fnargs;
+			func_depth--;
 
 			break;
 		}
@@ -3690,6 +3698,7 @@ static var *evaluate(node *op, var *res)
 	return res;
 #undef fnargs
 #undef seed
+#undef func_depth
 #undef sreg
 }
 
-- 
2.48.1