diff --git a/NEWS b/NEWS index 33b902b10..e3064f29e 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,11 @@ Any uppercase BUG_* names are modernish shell bug IDs. values. Previously, arithmetic $((var=1)) or conditional ${var:=value} assignments were not exported even with allexport on. +- Fixed a memory leak that could occur when using traps. + +- Fixed a use after free issue that could occur when modifying or setting + a SIGCHLD trap. + 2022-02-01: - Upon invocation, the interactive shell no longer leaves the user without diff --git a/src/cmd/ksh93/include/jobs.h b/src/cmd/ksh93/include/jobs.h index e34a6ff85..115c6c9df 100644 --- a/src/cmd/ksh93/include/jobs.h +++ b/src/cmd/ksh93/include/jobs.h @@ -170,7 +170,7 @@ extern int job_post(pid_t,pid_t); extern void *job_subsave(void); extern void job_subrestore(void*); #if SHOPT_BGX -extern void job_chldtrap(const char*,int); +extern void job_chldtrap(int); #endif /* SHOPT_BGX */ #ifdef JOBS extern void job_init(int); diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c index f6b80a94b..5a0087971 100644 --- a/src/cmd/ksh93/sh/fault.c +++ b/src/cmd/ksh93/sh/fault.c @@ -350,6 +350,8 @@ void sh_sigreset(register int mode) } } + if(sh.st.trapcom[0] && sh.st.trapcom[0] != Empty) + free(sh.st.trapcom[0]); sh.st.trapcom[0] = 0; if(mode) sh.st.trapmax = 0; @@ -411,7 +413,7 @@ void sh_chktrap(void) sh_timetraps(); #if SHOPT_BGX if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD]) - job_chldtrap(sh.st.trapcom[SIGCHLD],1); + job_chldtrap(1); #endif /* SHOPT_BGX */ while(--sig>=0) { diff --git a/src/cmd/ksh93/sh/jobs.c b/src/cmd/ksh93/sh/jobs.c index c00dbabc4..1fdbde785 100644 --- a/src/cmd/ksh93/sh/jobs.c +++ b/src/cmd/ksh93/sh/jobs.c @@ -219,7 +219,7 @@ static struct back_save bck; typedef int (*Waitevent_f)(int,long,int); #if SHOPT_BGX -void job_chldtrap(const char *trap, int unpost) +void job_chldtrap(int unpost) { register struct process *pw,*pwnext; pid_t bckpid; @@ -240,7 +240,9 @@ void job_chldtrap(const char *trap, int unpost) sh.savexit = pw->p_exit; if(pw->p_flag&P_SIGNALLED) sh.savexit |= SH_EXITSIG; - sh_trap(trap,0); + /* The trap handler for SIGCHLD may change after sh_trap() because of + 'trap - CHLD', so it's obtained for each iteration of the loop. */ + sh_trap(sh.st.trapcom[SIGCHLD],0); if(pw->p_pid==bckpid && unpost) job_unpost(pw,0); sh.savexit = oldexit; @@ -434,7 +436,7 @@ int job_reap(register int sig) { sh.sigflag[SIGCHLD] |= SH_SIGTRAP; if(sig==0) - job_chldtrap(sh.st.trapcom[SIGCHLD],0); + job_chldtrap(0); else sh.trapnote |= SH_SIGTRAP; }