diff --git a/src/cmd/ksh93/include/shell.h b/src/cmd/ksh93/include/shell.h index 2fc39a33c008..fe702785cfbf 100644 --- a/src/cmd/ksh93/include/shell.h +++ b/src/cmd/ksh93/include/shell.h @@ -312,6 +312,7 @@ struct Shell_s int savesig; unsigned char *sigflag; /* pointer to signal states */ char intrap; /* set while executing a trap action */ + uint32_t srand_upper_bound; char forked; char binscript; char funload; diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c index 05aaa0dfd9fa..844466c356cc 100644 --- a/src/cmd/ksh93/sh/init.c +++ b/src/cmd/ksh93/sh/init.c @@ -725,7 +725,6 @@ void sh_reseed_rand(struct rand *rp) /* * The following three functions are for SRANDOM */ -static uint32_t srand_upper_bound; static void put_srand(Namval_t* np,const char *val,int flags,Namfun_t *fp) { @@ -740,19 +739,19 @@ static void put_srand(Namval_t* np,const char *val,int flags,Namfun_t *fp) if(sh_isstate(SH_INIT)) return; if(flags&NV_INTEGER) - srand_upper_bound = *(Sfdouble_t*)val; + sh.srand_upper_bound = *(Sfdouble_t*)val; else - srand_upper_bound = sh_arith(val); + sh.srand_upper_bound = sh_arith(val); } static Sfdouble_t nget_srand(Namval_t* np, Namfun_t *fp) { - return (Sfdouble_t)(srand_upper_bound ? arc4random_uniform(srand_upper_bound) : arc4random()); + return (Sfdouble_t)(sh.srand_upper_bound ? arc4random_uniform(sh.srand_upper_bound) : arc4random()); } static char* get_srand(Namval_t* np, Namfun_t *fp) { - intmax_t n = (intmax_t)(srand_upper_bound ? arc4random_uniform(srand_upper_bound) : arc4random()); + intmax_t n = (intmax_t)(sh.srand_upper_bound ? arc4random_uniform(sh.srand_upper_bound) : arc4random()); return fmtbase(n, 10, 0); } diff --git a/src/cmd/ksh93/sh/subshell.c b/src/cmd/ksh93/sh/subshell.c index 45e92ce7add9..8b1dd39591c4 100644 --- a/src/cmd/ksh93/sh/subshell.c +++ b/src/cmd/ksh93/sh/subshell.c @@ -88,9 +88,10 @@ static struct subshell int cpipe; char subshare; char comsub; - unsigned int rand_seed; /* parent shell $RANDOM seed */ - int rand_last; /* last random number from $RANDOM in parent shell */ - int rand_state; /* 0 means sp->rand_seed hasn't been set, 1 is the opposite */ + unsigned int rand_seed; /* parent shell $RANDOM seed */ + int rand_last; /* last random number from $RANDOM in parent shell */ + int rand_state; /* 0 means sp->rand_seed hasn't been set, 1 is the opposite */ + uint32_t srand_upper_bound; /* parent shell's upper bound for $SRANDOM */ #if _lib_fchdir int pwdfd; /* file descriptor for PWD */ char pwdclose; @@ -585,6 +586,8 @@ Sfio_t *sh_subshell(Shnode_t *t, volatile int flags, int comsub) sh_sigreset(0); if(save_debugtrap) sh.st.trap[SH_DEBUGTRAP] = save_debugtrap; + /* save upper bound for $SRANDOM */ + sp->srand_upper_bound = sh.srand_upper_bound; } jmpval = sigsetjmp(checkpoint.buff,0); if(jmpval==0) @@ -857,6 +860,8 @@ Sfio_t *sh_subshell(Shnode_t *t, volatile int flags, int comsub) srand(rp->rand_seed = sp->rand_seed); rp->rand_last = sp->rand_last; } + /* restore $SRANDOM upper bound */ + sh.srand_upper_bound = sp->srand_upper_bound; /* Real subshells have their exit status truncated to 8 bits by the kernel. * Since virtual subshells should be indistinguishable, do the same here. */ sh.exitval &= SH_EXITMASK; diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index 306c239b21f1..28695d2f1e24 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -1647,6 +1647,16 @@ while read i do ((got = i>=bound)) && break done ((got)) || err_exit "SRANDOM upper bound inherited from environment" +# SRANDOM upper bound leaks out of virtual subshells +for i in 0 10000; do + (SRANDOM=$i) + for ((i=0; i= bound" + then err_exit "SRANDOM upper bound leads out of virtual subshells ($got >= $bound)" + break + fi + done +done unset i got bound SRANDOM=0