• overhaul handling of special variables

• use a combination of the one-at-a-time hash and an LCG for handling
  the $RANDOM special if !HAVE_ARC4RANDOM instead of rand(3)/srand(3)
  and get rid of time(3) usage to reduce import footprint
• raise entropy state (mostly in the !HAVE_ARC4RANDOM case though…)
• simplify handling of the $RANDOM_SPECIAL generally
• tweak hash() to save a temp var for non-optimising compilers
• some int → mksh_ari_t and other type fixes
• general tweaking of code and comments
This commit is contained in:
tg 2009-10-17 21:16:05 +00:00
parent 9f4376d2ad
commit eafe88aa74
6 changed files with 200 additions and 172 deletions

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.332 2009/10/15 16:36:25 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.333 2009/10/17 21:16:01 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 $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R39 2009/10/15
@(#)MIRBSD KSH R39 2009/10/17
description:
Check version of shell.
stdin:

43
jobs.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.61 2009/09/26 03:39:59 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.62 2009/10/17 21:16:02 tg Exp $");
#if HAVE_KILLPG
#define mksh_killpg killpg
@ -339,15 +339,18 @@ exchild(struct op *t, int flags,
volatile int *xerrok,
/* used if XPCLOSE or XCCLOSE */ int close_fd)
{
static Proc *last_proc; /* for pipelines */
static Proc *last_proc; /* for pipelines */
int i;
sigset_t omask;
Proc *p;
Job *j;
int rv = 0;
int forksleep;
int ischild;
int i, rv = 0, forksleep;
sigset_t omask;
Proc *p;
Job *j;
struct {
#if !HAVE_ARC4RANDOM
pid_t thepid;
#endif
unsigned char ischild;
} pi;
if (flags & XEXEC)
/* Clear XFORK|XPCLOSE|XCCLOSE|XCOPROC|XPIPEO|XPIPEI|XXCOM|XBGND
@ -410,15 +413,17 @@ exchild(struct op *t, int flags,
sigprocmask(SIG_SETMASK, &omask, NULL);
errorf("cannot fork - try again");
}
ischild = i == 0;
if (ischild)
p->pid = procpid = getpid();
else
p->pid = i;
#if !HAVE_ARC4RANDOM
pi.thepid =
#endif
p->pid = (pi.ischild = i == 0) ? (procpid = getpid()) : i;
#if !HAVE_ARC4RANDOM
/* ensure next child gets a (slightly) different $RANDOM sequence */
change_random(((unsigned long)p->pid << 1) | (ischild ? 1 : 0));
/*
* ensure next child gets a (slightly) different $RANDOM sequence
* from its parent process and other child processes
*/
change_random(&pi, sizeof(pi));
#endif
#ifndef MKSH_UNEMPLOYED
@ -440,10 +445,10 @@ exchild(struct op *t, int flags,
#endif
/* used to close pipe input fd */
if (close_fd >= 0 && (((flags & XPCLOSE) && !ischild) ||
((flags & XCCLOSE) && ischild)))
if (close_fd >= 0 && (((flags & XPCLOSE) && !pi.ischild) ||
((flags & XCCLOSE) && pi.ischild)))
close(close_fd);
if (ischild) { /* child */
if (pi.ischild) { /* child */
/* Do this before restoring signal */
if (flags & XCOPROC)
coproc_cleanup(false);

27
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h>
#endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.152 2009/10/02 18:08:34 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.153 2009/10/17 21:16:02 tg Exp $");
extern char **environ;
@ -93,7 +93,6 @@ main(int argc, const char *argv[])
struct block *l;
unsigned char restricted, errexit;
const char **wp;
pid_t ppid;
struct tbl *vp;
struct stat s_stdin;
#if !defined(_PATH_DEFPATH) && defined(_CS_PATH)
@ -104,11 +103,10 @@ main(int argc, const char *argv[])
kshpid = procpid = getpid();
ksheuid = geteuid();
kshpgrp = getpgrp();
ppid = getppid();
kshppid = getppid();
#if !HAVE_ARC4RANDOM
change_random((unsigned long)time(NULL));
change_random(((unsigned long)ksheuid << 16) | kshpid);
change_random(&kshstate_, sizeof(kshstate_));
#endif
/* make sure argv[] is sane */
@ -267,15 +265,6 @@ main(int argc, const char *argv[])
setint(global("COLUMNS"), 0);
setint(global("LINES"), 0);
setint(global("OPTIND"), 1);
vp = global("RANDOM");
#if HAVE_ARC4RANDOM
Flag(FARC4RANDOM) = 1;
/* avoid calling setspec */
vp->flag |= ISSET | INT_U;
#else
vp->flag |= INT_U;
setint(vp, (mksh_ari_t)((unsigned long)kshname + 33 * ppid));
#endif
safe_prompt = ksheuid ? "$ " : "# ";
vp = global("PS1");
@ -286,10 +275,15 @@ main(int argc, const char *argv[])
setstr(vp, safe_prompt, KSH_RETURN_ERROR);
setint((vp = global("PGRP")), (mksh_uari_t)kshpgrp);
vp->flag |= INT_U;
setint((vp = global("PPID")), (mksh_uari_t)ppid);
setint((vp = global("PPID")), (mksh_uari_t)kshppid);
vp->flag |= INT_U;
setint((vp = global("RANDOM")), (mksh_uari_t)hash(kshname));
vp->flag |= INT_U;
setint((vp = global("USER_ID")), (mksh_uari_t)ksheuid);
vp->flag |= INT_U;
#if HAVE_ARC4RANDOM
Flag(FARC4RANDOM) = 1; /* initialised */
#endif
/* Set this before parsing arguments */
#if HAVE_SETRESUGID
@ -1261,11 +1255,10 @@ static struct tbl *ktscan(struct table *, const char *, uint32_t,
/* Bob Jenkins' one-at-a-time hash */
uint32_t
hash(const char *cp)
oaathash_full(register const uint8_t *bp)
{
register uint32_t h = 0;
register uint8_t c;
register const uint8_t *bp = (const uint8_t *)cp;
while ((c = *bp++)) {
h += c;

8
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.194 2009/10/10 21:17:30 tg Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.195 2009/10/17 21:16:03 tg Exp $
.\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
@ -48,7 +48,7 @@
.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
..
.\"-
.Dd $Mdocdate: October 10 2009 $
.Dd $Mdocdate: October 17 2009 $
.Dt MKSH 1
.Os MirBSD
.Sh NAME
@ -1810,7 +1810,7 @@ is referenced, it is assigned a 15-bit pseudo-random number, i.e. between
0 and 32767, first, which is taken from
.Xr arc4random 3
if available,
.Xr rand 3
a Linear Congruential PRNG
otherwise.
.It Ev REPLY
Default parameter for the
@ -5736,10 +5736,8 @@ Privileged shell profile.
.Xr arc4random 3 ,
.Xr getopt 3 ,
.Xr nl_langinfo 3 ,
.Xr rand 3 ,
.Xr setlocale 3 ,
.Xr signal 3 ,
.Xr srand 3 ,
.Xr system 3 ,
.Xr tty 4 ,
.Xr shells 5 ,

39
sh.h
View File

@ -134,9 +134,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.355 2009/10/15 16:36:27 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.356 2009/10/17 21:16:04 tg Exp $");
#endif
#define MKSH_VERSION "R39 2009/10/15"
#define MKSH_VERSION "R39 2009/10/17"
#ifndef MKSH_INCLUDES_ONLY
@ -348,13 +348,25 @@ typedef uint32_t mksh_uari_t;
#define PATH_MAX 1024 /* pathname size */
#endif
EXTERN const char *kshname; /* $0 */
EXTERN pid_t kshpid; /* $$, shell pid */
EXTERN pid_t procpid; /* pid of executing process */
EXTERN pid_t kshpgrp; /* process group of shell */
EXTERN uid_t ksheuid; /* effective uid of shell */
EXTERN int exstat; /* exit status */
EXTERN int subst_exstat; /* exit status of last $(..)/`..` */
EXTERN struct {
const char *kshname_; /* $0 */
pid_t kshpid_; /* $$, shell PID */
pid_t procpid_; /* PID of executing process */
pid_t kshpgrp_; /* process group of shell */
uid_t ksheuid_; /* effective UID of shell */
pid_t kshppid_; /* PID of parent of shell */
int exstat_; /* exit status */
int subst_exstat_; /* exit status of last $(..)/`..` */
} kshstate_;
#define kshname kshstate_.kshname_
#define kshpid kshstate_.kshpid_
#define procpid kshstate_.procpid_
#define kshpgrp kshstate_.kshpgrp_
#define ksheuid kshstate_.ksheuid_
#define kshppid kshstate_.kshppid_
#define exstat kshstate_.exstat_
#define subst_exstat kshstate_.subst_exstat_
EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
EXTERN const char initvsn[] I__("KSH_VERSION=@(#)MIRBSD KSH " MKSH_VERSION);
#define KSH_VERSION (initvsn + /* "KSH_VERSION=@(#)" */ 16)
@ -735,8 +747,8 @@ EXTERN size_t current_wd_size;
*/
#define MIN_COLS (2 + MIN_EDIT_SPACE + 3)
#define MIN_LINS 3
EXTERN int x_cols I__(80); /* tty columns */
EXTERN int x_lins I__(-1); /* tty lines */
EXTERN mksh_ari_t x_cols I__(80); /* tty columns */
EXTERN mksh_ari_t x_lins I__(-1); /* tty lines */
/* These to avoid bracket matching problems */
#define OPAREN '('
@ -1505,7 +1517,8 @@ void coproc_write_close(int);
int coproc_getfd(int, const char **);
void coproc_cleanup(int);
struct temp *maketemp(Area *, Temp_type, struct temp **);
uint32_t hash(const char *);
#define hash(s) oaathash_full((const uint8_t *)(s))
uint32_t oaathash_full(register const uint8_t *);
uint32_t hashmem(const void *, size_t);
void ktinit(struct table *, Area *, size_t);
struct tbl *ktsearch(struct table *, const char *, uint32_t);
@ -1601,7 +1614,7 @@ int is_wdvarname(const char *, int);
int is_wdvarassign(const char *);
char **makenv(void);
#if !HAVE_ARC4RANDOM
void change_random(unsigned long);
void change_random(const void *, size_t);
#endif
void change_winsz(void);
int array_ref_len(const char *);

251
var.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.94 2009/09/27 10:31:06 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.95 2009/10/17 21:16:05 tg Exp $");
/*
* Variables
@ -46,11 +46,11 @@ static int getint(struct tbl *, mksh_ari_t *, bool);
static mksh_ari_t intval(struct tbl *);
static struct tbl *arraysearch(struct tbl *, uint32_t);
static const char *array_index_calc(const char *, bool *, uint32_t *);
static int rnd_get(void);
#if HAVE_ARC4RANDOM
static void rnd_set(unsigned long);
#else
#define rnd_set change_random
#if !HAVE_ARC4RANDOM
static uint32_t oaathash_update(register uint32_t, register const uint8_t *,
register size_t);
static uint32_t lcg_seed = 5381;
#endif
uint8_t set_refflag = 0;
@ -972,58 +972,45 @@ makenv(void)
return ((char **)XPclose(denv));
}
#if HAVE_ARC4RANDOM
static int
rnd_get(void)
#if !HAVE_ARC4RANDOM
static uint32_t
oaathash_update(register uint32_t h, register const uint8_t *cp,
register size_t n)
{
return (arc4random() & 0x7FFF);
}
static void
rnd_set(unsigned long newval)
{
#if HAVE_ARC4RANDOM_PUSHB
if (Flag(FARC4RANDOM))
/* initialisation, environment import, etc. already done */
arc4random_pushb(&newval, sizeof(newval));
else
/* during start-up phase or somesuch */
#endif
arc4random_addrandom((void *)&newval, sizeof(newval));
}
#else
static int
rnd_get(void)
{
return (rand() & 0x7FFF);
}
/*
* Called after a fork to bump the random number generator.
* Done to ensure children will not get the same random number sequence
* as the parent processes.
* Also called as rnd_set - mksh R40+ no longer has the traditional
* repeatability of randomness sequences, state is always retained.
*/
void
change_random(unsigned long newval)
{
register unsigned int h;
h = rand();
while (newval) {
h += (newval & 0xFF);
while (n--) {
h += *cp++;
h += h << 10;
h ^= h >> 6;
newval >>= 8;
}
return (h);
}
void
change_random(const void *vp, size_t n)
{
register uint32_t h;
struct {
const void *sp, *bp, *dp;
size_t dsz;
struct timeval tv;
uint32_t s;
} i;
i.dp = vp;
i.dsz = n;
i.s = lcg_seed;
i.bp = &lcg_seed;
i.sp = &i;
gettimeofday(&i.tv, NULL);
h = oaathash_update(oaathash_update(1, (void *)&i, sizeof(i)), vp, n);
/* oaathash_finalise */
h += h << 3;
h ^= h >> 11;
h += h << 15;
/* pass all of it, in case RAND_MAX is large */
srand(h);
lcg_seed = h;
}
#endif
@ -1058,82 +1045,84 @@ static int user_lineno; /* what user set $LINENO to */
static void
getspec(struct tbl *vp)
{
int i;
register mksh_ari_t i;
int st;
switch ((i = special(vp->name))) {
switch ((st = special(vp->name))) {
case V_SECONDS:
vp->flag &= ~SPECIAL;
/* On start up the value of SECONDS is used before seconds
* has been set - don't do anything in this case
/*
* On start up the value of SECONDS is used before
* it has been set - don't do anything in this case
* (see initcoms[] in main.c).
*/
if (vp->flag & ISSET) {
struct timeval tv;
gettimeofday(&tv, NULL);
setint(vp, tv.tv_sec - seconds);
}
vp->flag |= SPECIAL;
i = tv.tv_sec - seconds;
} else
return;
break;
case V_RANDOM:
vp->flag &= ~SPECIAL;
setint(vp, rnd_get());
vp->flag |= SPECIAL;
#if HAVE_ARC4RANDOM
i = arc4random() & 0x7FFF;
#else
/*
* this is the same Linear Congruential PRNG as Borland
* C/C++ allegedly uses in its built-in rand() function
*/
i = ((lcg_seed = 22695477 * lcg_seed + 1) >> 16) & 0x7FFF;
#endif
break;
case V_HISTSIZE:
vp->flag &= ~SPECIAL;
setint(vp, (mksh_ari_t)histsize);
vp->flag |= SPECIAL;
i = histsize;
break;
case V_OPTIND:
vp->flag &= ~SPECIAL;
setint(vp, (mksh_ari_t)user_opt.uoptind);
vp->flag |= SPECIAL;
i = user_opt.uoptind;
break;
case V_LINENO:
vp->flag &= ~SPECIAL;
setint(vp, (mksh_ari_t)current_lineno + user_lineno);
vp->flag |= SPECIAL;
i = current_lineno + user_lineno;
break;
case V_COLUMNS:
case V_LINES:
/* Do NOT export COLUMNS/LINES. Many applications
/*
* Do NOT export COLUMNS/LINES. Many applications
* check COLUMNS/LINES before checking ws.ws_col/row,
* so if the app is started with C/L in the environ
* and the window is then resized, the app won't
* see the change cause the environ doesn't change.
*/
vp->flag &= ~SPECIAL;
change_winsz();
setint(vp, i == V_COLUMNS ? x_cols : x_lins);
vp->flag |= SPECIAL;
i = st == V_COLUMNS ? x_cols : x_lins;
break;
default:
/* do nothing, do not touch vp at all */
return;
}
vp->flag &= ~SPECIAL;
setint(vp, i);
vp->flag |= SPECIAL;
}
static void
setspec(struct tbl *vp)
{
int i;
mksh_ari_t i;
char *s;
int st;
switch (special(vp->name)) {
switch ((st = special(vp->name))) {
case V_PATH:
if (path)
afree(path, APERM);
s = str_val(vp);
strdupx(path, s, APERM);
flushcom(1); /* clear tracked aliases */
break;
return;
case V_IFS:
setctypes(s = str_val(vp), C_IFS);
ifs0 = *s;
break;
case V_OPTIND:
vp->flag &= ~SPECIAL;
getopts_reset((int)intval(vp));
vp->flag |= SPECIAL;
break;
return;
case V_TMPDIR:
if (tmpdir) {
afree(tmpdir, APERM);
@ -1151,54 +1140,84 @@ setspec(struct tbl *vp)
strdupx(tmpdir, s, APERM);
}
break;
case V_HISTSIZE:
vp->flag &= ~SPECIAL;
sethistsize((int)intval(vp));
vp->flag |= SPECIAL;
break;
#if HAVE_PERSISTENT_HISTORY
case V_HISTFILE:
sethistfile(str_val(vp));
break;
#endif
case V_COLUMNS:
vp->flag &= ~SPECIAL;
if ((i = intval(vp)) >= MIN_COLS)
x_cols = i;
vp->flag |= SPECIAL;
break;
case V_LINES:
vp->flag &= ~SPECIAL;
if ((i = intval(vp)) >= MIN_LINS)
x_lins = i;
vp->flag |= SPECIAL;
break;
case V_RANDOM:
vp->flag &= ~SPECIAL;
rnd_set(intval(vp));
vp->flag |= SPECIAL;
break;
case V_SECONDS:
vp->flag &= ~SPECIAL;
{
struct timeval tv;
gettimeofday(&tv, NULL);
seconds = tv.tv_sec - intval(vp);
}
vp->flag |= SPECIAL;
break;
case V_TMOUT:
/* AT&T ksh seems to do this (only listen if integer) */
if (vp->flag & INTEGER)
ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;
break;
/* common sub-cases */
case V_OPTIND:
case V_HISTSIZE:
case V_COLUMNS:
case V_LINES:
case V_RANDOM:
case V_SECONDS:
case V_LINENO:
vp->flag &= ~SPECIAL;
/* The -1 is because line numbering starts at 1. */
user_lineno = (unsigned int)intval(vp) - current_lineno - 1;
i = intval(vp);
vp->flag |= SPECIAL;
break;
default:
/* do nothing, do not touch vp at all */
return;
}
/* process the singular parts of the common cases */
switch (st) {
case V_OPTIND:
getopts_reset((int)i);
break;
case V_HISTSIZE:
sethistsize((int)i);
break;
case V_COLUMNS:
if (i >= MIN_COLS)
x_cols = i;
break;
case V_LINES:
if (i >= MIN_LINS)
x_lins = i;
break;
case V_RANDOM:
#if HAVE_ARC4RANDOM
#if HAVE_ARC4RANDOM_PUSHB
if (Flag(FARC4RANDOM))
/*
* things like initialisation, environment import,
* etc. are already done
*/
arc4random_pushb(&i, sizeof(i));
else
/* during start-up phase or somesuch */
#endif /* HAVE_ARC4RANDOM_PUSHB */
arc4random_addrandom((void *)&i, sizeof(i));
#else /* !HAVE_ARC4RANDOM */
/*
* mksh R40+ no longer has the traditional repeatability
* of $RANDOM sequences, but always retains state
*/
change_random(&i, sizeof(i));
#endif /* !HAVE_ARC4RANDOM */
break;
case V_SECONDS:
{
struct timeval tv;
gettimeofday(&tv, NULL);
seconds = tv.tv_sec - i;
}
break;
case V_LINENO:
/* The -1 is because line numbering starts at 1. */
user_lineno = (unsigned int)i - current_lineno - 1;
break;
}
}