From 499327f7b8201449abb95ced2ede1f814044d9ca Mon Sep 17 00:00:00 2001 From: tg Date: Sun, 12 Aug 2007 13:42:23 +0000 Subject: [PATCH] =?UTF-8?q?add=20=E2=80=9Cset=20-o=20arc4random=E2=80=9D,?= =?UTF-8?q?=20RTFM=20for=20details?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Build.sh | 18 ++++++---- Makefile | 6 ++-- check.t | 4 +-- jobs.c | 7 ++-- main.c | 7 ++-- misc.c | 7 ++-- mksh.1 | 29 ++++++++------- sh.h | 15 ++++---- var.c | 108 +++++++++++++++++++++++++++++++++++++++++++------------ 9 files changed, 140 insertions(+), 61 deletions(-) diff --git a/Build.sh b/Build.sh index 9debba0..8be6fa5 100644 --- a/Build.sh +++ b/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $MirOS: src/bin/mksh/Build.sh,v 1.250 2007/07/31 11:11:23 tg Exp $ +# $MirOS: src/bin/mksh/Build.sh,v 1.251 2007/08/12 13:42:19 tg Exp $ #- # Environment used: CC CFLAGS CPPFLAGS LDFLAGS LIBS NOWARN NROFF TARGET_OS # CPPFLAGS recognised: MKSH_SMALL MKSH_ASSUME_UTF8 MKSH_NEED_MKNOD MKSH_NOPWNAM @@ -760,9 +760,13 @@ if test $HAVE_ARC4RANDOM = 0 && test -f "$srcdir/arc4random.c"; then fi ac_cppflags ARC4RANDOM -ac_test arc4random_push arc4random 0 <<-'EOF' - extern void arc4random_push(int); - int main(void) { arc4random_push(1); return (0); } +ac_test arc4random_pushb arc4random 0 <<-'EOF' + #include + #if HAVE_STDINT_H + #include + #endif + extern uint32_t arc4random_pushb(void *, size_t); + int main(int ac, char *av[]) { return (arc4random_pushb(*av, ac)); } EOF ac_test flock_ex '' 'flock and mmap' <<-'EOF' @@ -853,11 +857,11 @@ ac_test '!' arc4random_decl arc4random 1 'if arc4random() does not need to be de long arc4random(void); /* this clashes if defined before */ int main(void) { return (arc4random()); } EOF -ac_test '!' arc4random_push_decl arc4random_push 1 'if arc4random_push() does not need to be declared' <<-'EOF' +ac_test '!' arc4random_pushb_decl arc4random_pushb 1 'if arc4random_pushb() does not need to be declared' <<-'EOF' #define MKSH_INCLUDES_ONLY #include "sh.h" - void arc4random_push(long); /* this clashes if defined before */ - int main(void) { arc4random_push(1); return (0); } + int arc4random_pushb(char, int); /* this clashes if defined before */ + int main(int ac, char *av[]) { return (arc4random_pushb(**av, ac)); } EOF ac_test sys_siglist_decl sys_siglist 1 'if sys_siglist[] does not need to be declared' <<-'EOF' #define MKSH_INCLUDES_ONLY diff --git a/Makefile b/Makefile index 4034d9e..bbad806 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/Makefile,v 1.45 2007/07/31 11:11:23 tg Exp $ +# $MirOS: src/bin/mksh/Makefile,v 1.46 2007/08/12 13:42:20 tg Exp $ #- # use CPPFLAGS=-DDEBUG __CRAZY=Yes to check for certain more stuff @@ -17,12 +17,12 @@ CPPFLAGS+= -DMKSH_ASSUME_UTF8 \ -DHAVE_GRP_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 \ -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_SIGNAME=1 \ -DHAVE_SYS_SIGLIST=1 -DHAVE_STRSIGNAL=0 -DHAVE_ARC4RANDOM=1 \ - -DHAVE_ARC4RANDOM_PUSH=1 -DHAVE_FLOCK_EX=1 \ + -DHAVE_ARC4RANDOM_PUSHB=1 -DHAVE_FLOCK_EX=1 \ -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 \ -DHAVE_MKNOD=1 -DHAVE_REVOKE=1 -DHAVE_SETMODE=1 \ -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRCASESTR=1 \ -DHAVE_STRLCPY=1 -DHAVE_ARC4RANDOM_DECL=1 \ - -DHAVE_ARC4RANDOM_PUSH_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \ + -DHAVE_ARC4RANDOM_PUSHB_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \ -DHAVE_PERSISTENT_HISTORY=1 COPTS+= -std=gnu99 -Wall .endif diff --git a/check.t b/check.t index 0b9ea23..86333f5 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.132 2007/07/31 11:11:23 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.133 2007/08/12 13:42:20 tg Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ @@ -7,7 +7,7 @@ # http://www.research.att.com/~gsf/public/ifs.sh expected-stdout: - @(#)MIRBSD KSH R30 2007/07/31 + @(#)MIRBSD KSH R30 2007/08/12 description: Check version of shell. category: pdksh diff --git a/jobs.c b/jobs.c index 14fba66..1098d4e 100644 --- a/jobs.c +++ b/jobs.c @@ -2,7 +2,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.25 2007/07/22 13:34:50 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.26 2007/08/12 13:42:21 tg Exp $"); /* Order important! */ #define PRUNNING 0 @@ -369,6 +369,9 @@ exchild(struct op *t, int flags, else p->pid = i; + /* Ensure next child gets a (slightly) different $RANDOM sequence */ + change_random((p->pid << 1) | (ischild ? 1 : 0)); + /* job control set up */ if (Flag(FMONITOR) && !(flags&XXCOM)) { int dotty = 0; @@ -437,8 +440,6 @@ exchild(struct op *t, int flags, } /* shell (parent) stuff */ - /* Ensure next child gets a (slightly) different $RANDOM sequence */ - change_random(); if (!(flags & XPIPEO)) { /* last process in a job */ j_startjob(j); if (flags & XCOPROC) { diff --git a/main.c b/main.c index be48939..7608250 100644 --- a/main.c +++ b/main.c @@ -13,7 +13,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.84 2007/07/22 13:34:51 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.85 2007/08/12 13:42:21 tg Exp $"); extern char **environ; @@ -222,8 +222,9 @@ main(int argc, const char *argv[]) setstr(pwd_v, current_wd, KSH_RETURN_ERROR); } ppid = getppid(); -#if !HAVE_ARC4RANDOM - srand(((long)kshname) ^ ((long)time(NULL) * kshpid * ppid)); + change_random(((u_long)kshname) ^ ((u_long)time(NULL) * kshpid * ppid)); +#if HAVE_ARC4RANDOM + Flag(FARC4RANDOM) = 2; /* use arc4random(3) until $RANDOM is written */ #endif setint(global("PPID"), (long)ppid); diff --git a/misc.c b/misc.c index 7dbf1eb..f319d0e 100644 --- a/misc.c +++ b/misc.c @@ -6,7 +6,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.64 2007/07/26 13:23:51 tg Exp $\t" +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.65 2007/08/12 13:42:21 tg Exp $\t" MKSH_SH_H_ID); #undef USE_CHVT @@ -104,6 +104,9 @@ const struct shoption options[] = { * entries MUST match the order of sh_flag F* enumerations in sh.h. */ { "allexport", 'a', OF_ANY }, +#if HAVE_ARC4RANDOM + { "arc4random", 0, OF_ANY }, +#endif { "braceexpand", 0, OF_ANY }, /* non-standard */ { "bgnice", 0, OF_ANY }, { NULL, 'c', OF_CMDLINE }, @@ -232,7 +235,7 @@ change_flag(enum sh_flag f, char oldval; oldval = Flag(f); - Flag(f) = newval; + Flag(f) = newval ? 1 : 0; /* needed for tristates */ if (f == FMONITOR) { if (what != OF_CMDLINE && newval != oldval) j_change(); diff --git a/mksh.1 b/mksh.1 index 7d21260..228bfa9 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,7 +1,7 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.93 2007/07/31 15:29:40 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.94 2007/08/12 13:42:22 tg Exp $ .\" $OpenBSD: ksh.1,v 1.120 2007/05/31 20:47:44 otto Exp $ .\" -.Dd July 31, 2007 +.Dd August 12, 2007 .Dt MKSH 1 .Os MirBSD .Sh NAME @@ -1590,16 +1590,9 @@ if the shell doesn't know where it is. Every time .Ev RANDOM is referenced, it is assigned a pseudo-random number first. -By default, -.Xr arc4random 3 -is used to produce unsigned 15\-bit values (0\-32767) -whose quality depends on the operating environment. -If -.Ev RANDOM -is assigned a value, it is used as the seed to -.Xr srand 3 -and subsequent references yield a semi-predictable sequence from -.Xr rand 3 . +See the description of +.Ic set -o Ic arc4random +below for details. .It Ev REPLY Default parameter for the .Ic read @@ -3344,6 +3337,18 @@ during file name generation. Print commands and parameter assignments when they are executed, preceded by the value of .Ev PS4 . +.It Ic arc4random +Use +.Xr arc4random 3 +high-quality random numbers for the value of +.Ev RANDOM +if set (to either 1 or 2), or a semi-predictable sequence from +.Xr rand 3 +if unset. +Setting this flag will change its value to 1; the default value is 2, +which means it automatically switches to 0 if +.Ev RANDOM +is written to. .It Ic bgnice Background jobs are run with lower priority. .It Ic braceexpand diff --git a/sh.h b/sh.h index 10d4339..a78404d 100644 --- a/sh.h +++ b/sh.h @@ -8,8 +8,8 @@ /* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */ /* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */ -#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.167 2007/08/06 12:02:39 tg Exp $" -#define MKSH_VERSION "R30 2007/07/31" +#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.168 2007/08/12 13:42:23 tg Exp $" +#define MKSH_VERSION "R30 2007/08/12" #if HAVE_SYS_PARAM_H #include @@ -194,8 +194,8 @@ typedef int bool; extern u_int32_t arc4random(void); #endif -#if !HAVE_ARC4RANDOM_PUSH_DECL -extern void arc4random_push(int); +#if !HAVE_ARC4RANDOM_PUSHB_DECL +extern uint32_t arc4random_pushb(void *, size_t); #endif #if !HAVE_SETMODE @@ -393,6 +393,9 @@ extern const struct shoption options[]; */ enum sh_flag { FEXPORT = 0, /* -a: export all */ +#if HAVE_ARC4RANDOM + FARC4RANDOM, /* use 0:rand(3) 1:arc4random(3) 2:switch on write */ +#endif FBRACEEXPAND, /* enable {} globbing */ FBGNICE, /* bgnice */ FCOMMAND, /* -c: (invocation) execute specified command */ @@ -431,7 +434,7 @@ enum sh_flag { FNFLAGS /* (place holder: how many flags are there) */ }; -#define Flag(f) (shell_flags[(int) (f)]) +#define Flag(f) (shell_flags[(int)(f)]) EXTERN char shell_flags[FNFLAGS]; @@ -1479,7 +1482,7 @@ const char *skip_wdvarname(const char *, int); int is_wdvarname(const char *, int); int is_wdvarassign(const char *); char **makenv(void); -void change_random(void); +void change_random(uint64_t); int array_ref_len(const char *); char *arrayname(const char *); void set_array(const char *, int, const char **); diff --git a/var.c b/var.c index 4fa3c09..f8471d0 100644 --- a/var.c +++ b/var.c @@ -2,7 +2,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.42 2007/07/22 14:01:50 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.43 2007/08/12 13:42:23 tg Exp $"); /* * Variables @@ -23,6 +23,8 @@ static void getspec(struct tbl *); static void setspec(struct tbl *); static void unsetspec(struct tbl *); static struct tbl *arraysearch(struct tbl *, int); +static int rnd_get(void); +static void rnd_set(long); /* * create a new block for function calls and simple commands @@ -849,25 +851,96 @@ makenv(void) } /* - * Someone has set the srand() value, therefore from now on - * we return values from rand() instead of arc4random() + * Get us a random number, either from rand(3) or arc4random(3), with + * the latter being preferred. If Flag(FARC4RANDOM) is 0, we use rand(3), + * otherwise arc4random(3). We have static caches to make change_random + * and writes to $RANDOM a cheap operation. */ #if HAVE_ARC4RANDOM -static int use_rand = 0; +static uint64_t rnd_cache = 0; +static char rnd_lastflag = 2; #endif +static int +rnd_get(void) +{ +#if HAVE_ARC4RANDOM +#if HAVE_ARC4RANDOM_PUSHB + uint32_t rv = 0; +#endif + if (Flag(FARC4RANDOM) != rnd_lastflag) { + if (Flag(FARC4RANDOM) == 0) { + /* transition to 0 by set: srand */ + srand(arc4random() & 0x7FFF); + } else if (rnd_lastflag == 0) { + /* transition from 0: addrandom */ + rnd_cache ^= rand(); + } + rnd_lastflag = Flag(FARC4RANDOM); + } + if (Flag(FARC4RANDOM)) { + if (rnd_cache) +#if HAVE_ARC4RANDOM_PUSHB + rv = arc4random_pushb(&rnd_cache, sizeof (rnd_cache)); +#else + arc4random_addrandom(&rnd_cache, sizeof (rnd_cache)); +#endif + rnd_cache = 0; + return (( +#if HAVE_ARC4RANDOM_PUSHB + rv ? rv : +#endif + arc4random()) & 0x7FFF); + } +#endif + return (rand() & 0x7FFF); +} + +static void +rnd_set(long newval) +{ +#if HAVE_ARC4RANDOM + rnd_cache ^= (((uint64_t)newval) << 15) | rand(); + if (Flag(FARC4RANDOM) == 1) + return; + if (Flag(FARC4RANDOM) == 2) + Flag(FARC4RANDOM) = 0; + /* transition to 0 by write: only srand */ + rnd_lastflag = 0; +#endif + srand(newval & 0x7FFF); +} + /* * Called after a fork in parent to bump the random number generator. * Done to ensure children will not get the same random number sequence * if the parent doesn't use $RANDOM. */ void -change_random(void) +change_random(uint64_t newval) { + int rval = 0; + + newval &= 0x00001FFFFFFFFFFF; + newval |= (uint64_t)rand() << 45; + #if HAVE_ARC4RANDOM - if (use_rand) + if (Flag(FARC4RANDOM)) { + rnd_cache ^= newval; + return; + } #endif - rand(); + + rval += newval & 0x7FFF; + newval >>= 15; + rval += newval & 0x7FFF; + newval >>= 15; + rval += newval & 0x7FFF; + newval >>= 15; + rval += newval; + rval = (rval & 0x7FFF) ^ (rval >> 15); + + srand(rval); } /* @@ -918,12 +991,7 @@ getspec(struct tbl *vp) break; case V_RANDOM: vp->flag &= ~SPECIAL; -#if HAVE_ARC4RANDOM - if (!use_rand) - setint(vp, arc4random() & 0x7FFF); - else -#endif - setint(vp, rand() & 0x7FFF); + setint(vp, rnd_get()); vp->flag |= SPECIAL; break; case V_HISTSIZE: @@ -963,7 +1031,7 @@ setspec(struct tbl *vp) break; case V_OPTIND: vp->flag &= ~SPECIAL; - getopts_reset((int) intval(vp)); + getopts_reset((int)intval(vp)); vp->flag |= SPECIAL; break; case V_TMPDIR: @@ -985,7 +1053,7 @@ setspec(struct tbl *vp) break; case V_HISTSIZE: vp->flag &= ~SPECIAL; - sethistsize((int) intval(vp)); + sethistsize((int)intval(vp)); vp->flag |= SPECIAL; break; #if HAVE_PERSISTENT_HISTORY @@ -999,13 +1067,7 @@ setspec(struct tbl *vp) break; case V_RANDOM: vp->flag &= ~SPECIAL; - srand((unsigned int)intval(vp)); -#if HAVE_ARC4RANDOM - use_rand = 1; -#if HAVE_ARC4RANDOM_PUSH - arc4random_push((unsigned)vp ^ (unsigned)rand()); -#endif -#endif + rnd_set(intval(vp)); vp->flag |= SPECIAL; break; case V_SECONDS: @@ -1026,7 +1088,7 @@ setspec(struct tbl *vp) case V_LINENO: vp->flag &= ~SPECIAL; /* The -1 is because line numbering starts at 1. */ - user_lineno = (unsigned int) intval(vp) - current_lineno - 1; + user_lineno = (unsigned int)intval(vp) - current_lineno - 1; vp->flag |= SPECIAL; break; }