I found and fixed yet another use after free bug in pdksh. This bug is likely about 30 years old or so.
- c_eval (shell "eval" command) creates a new "strict source" "s" from current env ATEMP: https://github.com/Orc/pdksh/blob/131021a130337e3313195c9d321c6aa40b4e291d/c_sh.c#L429
- c_eval passes the created source to "shell" function:
https://github.com/Orc/pdksh/blob/131021a130337e3313195c9d321c6aa40b4e291d/c_sh.c#L459
- "shell" calls "compile" function: https://github.com/Orc/pdksh/blob/131021a130337e3313195c9d321c6aa40b4e291d/main.c#L593
- "compile" function assigns the global "source" pointer to the passed source: https://github.com/Orc/pdksh/blob/131021a130337e3313195c9d321c6aa40b4e291d/syn.c#L790
At some point (I didn't bother tracing exactly where and in what circumstances - certain parts of gmp-6.3.0 configure script trigger it, at least on our platform) the ATEMP associated with the "env" gets released via call to "reclaim", but the "source" pointer will continue to point to the already released memory. This leads to classic Use After Free condition and all kinds of havoc and eventually a crash.
The fix is easy enough: Save and restore the original source pointer in c_eval:
--- pdksh-5.2.14/c_sh.c 1999-07-13 19:54:44.000000000 +0300
+++ pdksh-5.2.14-fixed/c_sh.c 2025-05-20 23:08:41.162128448 +0300
@@ -423,6 +423,8 @@
char **wp;
{
register struct source *s;
+ struct source *sold;
+ int ret;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
@@ -456,7 +458,10 @@
exstat = subst_exstat;
}
- return shell(s, FALSE);
+ sold = source;
+ ret = shell(s, FALSE);
+ source = sold;
+ return ret;
}
int