Theo's diff inspired me to look for other cases of modulo bias. The following diff converts most modulus operations on a random number to use arc4random_uniform or & as appropriate. I excluded
lib/libsqlite3/src/resolve.c regress/lib/libevent/test-time.c usr.sbin/nsd/rrl.c usr.sbin/nsd/util.c usr.sbin/nsd/xfrd.c as they seem to have upstreams. The only other case is games/wump/wump.c which has if (arc4random() % 2 == 1) This is safe and seems obvious enough to me. - Matthew Martin Index: games/atc/update.c =================================================================== RCS file: /cvs/src/games/atc/update.c,v retrieving revision 1.16 diff -u -p -r1.16 update.c --- games/atc/update.c 9 Dec 2014 05:01:14 -0000 1.16 +++ games/atc/update.c 7 Dec 2015 06:42:17 -0000 @@ -59,6 +59,15 @@ atcrandom() return arc4random(); } +uint32_t +atcrandom_uniform(uint32_t upper_bound) +{ + if (seeded) + return random() % upper_bound; + else + return arc4random_uniform(upper_bound); +} + void update(int dummy) { @@ -212,7 +221,7 @@ update(int dummy) * Otherwise, prop jobs show up *on* entrance. Remember that * we don't update props on odd updates. */ - if ((atcrandom() % sp->newplane_time) == 0) + if (atcrandom_uniform(sp->newplane_time) == 0) addplane(); } @@ -308,10 +317,10 @@ addplane(void) memset(&p, 0, sizeof (p)); p.status = S_MARKED; - p.plane_type = atcrandom() % 2; + p.plane_type = atcrandom_uniform(2); num_starts = sp->num_exits + sp->num_airports; - rnd = atcrandom() % num_starts; + rnd = atcrandom_uniform(num_starts); if (rnd < sp->num_exits) { p.dest_type = T_EXIT; @@ -324,7 +333,7 @@ addplane(void) /* loop until we get a plane not near another */ for (i = 0; i < num_starts; i++) { /* loop till we get a different start point */ - while ((rnd2 = atcrandom() % num_starts) == rnd) + while ((rnd2 = atcrandom_uniform(num_starts)) == rnd) ; if (rnd2 < sp->num_exits) { p.orig_type = T_EXIT; Index: games/hack/hack.mklev.c =================================================================== RCS file: /cvs/src/games/hack/hack.mklev.c,v retrieving revision 1.7 diff -u -p -r1.7 hack.mklev.c --- games/hack/hack.mklev.c 27 Oct 2009 23:59:25 -0000 1.7 +++ games/hack/hack.mklev.c 7 Dec 2015 06:42:17 -0000 @@ -66,8 +66,8 @@ #include <unistd.h> #include "hack.h" -#define somex() ((random()%(croom->hx-croom->lx+1))+croom->lx) -#define somey() ((random()%(croom->hy-croom->ly+1))+croom->ly) +#define somex() (arc4random_uniform(croom->hx-croom->lx+1)+croom->lx) +#define somey() (arc4random_uniform(croom->hy-croom->ly+1)+croom->ly) #define XLIM 4 /* define minimum required space around a room */ #define YLIM 3 Index: games/hack/rnd.c =================================================================== RCS file: /cvs/src/games/hack/rnd.c,v retrieving revision 1.5 diff -u -p -r1.5 rnd.c --- games/hack/rnd.c 27 Oct 2009 23:59:25 -0000 1.5 +++ games/hack/rnd.c 7 Dec 2015 06:42:17 -0000 @@ -61,7 +61,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define RND(x) ((random()>>3) % x) +#define RND(x) (arc4random_uniform(x)) #include <stdlib.h> Index: lib/libc/stdlib/rand.c =================================================================== RCS file: /cvs/src/lib/libc/stdlib/rand.c,v retrieving revision 1.15 diff -u -p -r1.15 rand.c --- lib/libc/stdlib/rand.c 13 Sep 2015 08:31:47 -0000 1.15 +++ lib/libc/stdlib/rand.c 7 Dec 2015 06:42:17 -0000 @@ -50,7 +50,7 @@ int rand(void) { if (rand_deterministic == 0) - return (arc4random() % ((u_int)RAND_MAX + 1)); + return (arc4random_uniform((u_int)RAND_MAX + 1)); return (rand_r(&next)); } Index: sbin/dhclient/dhclient.c =================================================================== RCS file: /cvs/src/sbin/dhclient/dhclient.c,v retrieving revision 1.367 diff -u -p -r1.367 dhclient.c --- sbin/dhclient/dhclient.c 5 Dec 2015 13:09:11 -0000 1.367 +++ sbin/dhclient/dhclient.c 7 Dec 2015 06:42:18 -0000 @@ -1285,15 +1285,13 @@ send_discover(void) */ if (!client->interval) client->interval = config->initial_interval; - else { - client->interval += (arc4random() >> 2) % - (2 * client->interval); - } + else + client->interval += arc4random_uniform(2 * client->interval); /* Don't backoff past cutoff. */ if (client->interval > config->backoff_cutoff) - client->interval = ((config->backoff_cutoff / 2) + - ((arc4random() >> 2) % config->backoff_cutoff)); + client->interval = (config->backoff_cutoff / 2) + + arc4random_uniform(config->backoff_cutoff); /* If the backoff would take us to the panic timeout, just use that as the interval. */ @@ -1410,13 +1408,12 @@ send_request(void) if (!client->interval) client->interval = config->initial_interval; else - client->interval += ((arc4random() >> 2) % - (2 * client->interval)); + client->interval += arc4random_uniform(2 * client->interval); /* Don't backoff past cutoff. */ if (client->interval > config->backoff_cutoff) - client->interval = ((config->backoff_cutoff / 2) + - ((arc4random() >> 2) % client->interval)); + client->interval = (config->backoff_cutoff / 2) + + arc4random_uniform(client->interval); /* * If the backoff would take us to the expiry time, just set the Index: sys/dev/ic/sili.c =================================================================== RCS file: /cvs/src/sys/dev/ic/sili.c,v retrieving revision 1.57 diff -u -p -r1.57 sili.c --- sys/dev/ic/sili.c 9 Sep 2015 18:24:26 -0000 1.57 +++ sys/dev/ic/sili.c 7 Dec 2015 06:42:18 -0000 @@ -377,7 +377,7 @@ sili_simulate_error(struct sili_ccb *ccb case ATA_C_READDMA_EXT: case ATA_C_WRITEDMA: case ATA_C_READDMA: - if ((arc4random() % sili_error_test_inv_p) == 0) { + if (arc4random_uniform(sili_error_test_inv_p) == 0) { printf("%s: faking error on slot %d\n", PORTNAME(sp), ccb->ccb_xa.tag); ccb->ccb_xa.state = ATA_S_ERROR; Index: sys/netinet6/nd6_rtr.c =================================================================== RCS file: /cvs/src/sys/netinet6/nd6_rtr.c,v retrieving revision 1.136 diff -u -p -r1.136 nd6_rtr.c --- sys/netinet6/nd6_rtr.c 3 Dec 2015 21:57:59 -0000 1.136 +++ sys/netinet6/nd6_rtr.c 7 Dec 2015 06:42:18 -0000 @@ -1951,7 +1951,7 @@ in6_ifadd(struct nd_prefix *pr, int priv ifra.ifra_lifetime.ia6t_vltime = ND6_PRIV_VALID_LIFETIME; if (ifra.ifra_lifetime.ia6t_pltime > ND6_PRIV_PREFERRED_LIFETIME) ifra.ifra_lifetime.ia6t_pltime = ND6_PRIV_PREFERRED_LIFETIME - - (arc4random() % ND6_PRIV_MAX_DESYNC_FACTOR); + - arc4random_uniform(ND6_PRIV_MAX_DESYNC_FACTOR); } /* XXX: scope zone ID? */ Index: sys/ufs/ffs/ffs_alloc.c =================================================================== RCS file: /cvs/src/sys/ufs/ffs/ffs_alloc.c,v retrieving revision 1.106 diff -u -p -r1.106 ffs_alloc.c --- sys/ufs/ffs/ffs_alloc.c 28 Nov 2015 21:52:02 -0000 1.106 +++ sys/ufs/ffs/ffs_alloc.c 7 Dec 2015 06:42:19 -0000 @@ -937,7 +937,7 @@ ffs_dirpref(struct inode *pip) * Force allocation in another cg if creating a first level dir. */ if (ITOV(pip)->v_flag & VROOT) { - prefcg = (arc4random() & INT_MAX) % fs->fs_ncg; + prefcg = arc4random_uniform(fs->fs_ncg); mincg = prefcg; minndir = fs->fs_ipg; for (cg = prefcg; cg < fs->fs_ncg; cg++) Index: usr.bin/awk/run.c =================================================================== RCS file: /cvs/src/usr.bin/awk/run.c,v retrieving revision 1.39 diff -u -p -r1.39 run.c --- usr.bin/awk/run.c 5 Sep 2015 22:07:10 -0000 1.39 +++ usr.bin/awk/run.c 7 Dec 2015 06:42:19 -0000 @@ -1581,7 +1581,7 @@ Cell *bltin(Node **a, int n) /* builtin u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ break; case FRAND: - u = (Awkfloat) (random() % RAND_MAX) / RAND_MAX; + u = (Awkfloat) arc4random_uniform(RAND_MAX) / RAND_MAX; break; case FSRAND: if (isrec(x)) { /* no argument provided */ Index: usr.sbin/npppd/common/slist.c =================================================================== RCS file: /cvs/src/usr.sbin/npppd/common/slist.c,v retrieving revision 1.6 diff -u -p -r1.6 slist.c --- usr.sbin/npppd/common/slist.c 5 Dec 2015 18:43:36 -0000 1.6 +++ usr.sbin/npppd/common/slist.c 7 Dec 2015 06:42:20 -0000 @@ -434,7 +434,7 @@ slist_shuffle(slist *list) len = slist_length(list); for (i = len; i > 1; i--) - slist_swap0(list, i - 1, (int)(arc4random() % i)); + slist_swap0(list, i - 1, (int)arc4random_uniform(i)); } /** Init an iterator. Only one iterator exists. */ Index: usr.sbin/npppd/l2tp/l2tpd.c =================================================================== RCS file: /cvs/src/usr.sbin/npppd/l2tp/l2tpd.c,v retrieving revision 1.17 diff -u -p -r1.17 l2tpd.c --- usr.sbin/npppd/l2tp/l2tpd.c 5 Dec 2015 18:43:36 -0000 1.17 +++ usr.sbin/npppd/l2tp/l2tpd.c 7 Dec 2015 06:42:20 -0000 @@ -113,11 +113,11 @@ l2tpd_init(l2tpd *_this) __func__); return 1; } - off = arc4random() % L2TP_SESSION_ID_MASK; + off = arc4random() & L2TP_SESSION_ID_MASK; for (i = 0; i < L2TP_NCALL; i++) { - id = (i + off) % L2TP_SESSION_ID_MASK; + id = (i + off) & L2TP_SESSION_ID_MASK; if (id == 0) - id = (off - 1) % L2TP_SESSION_ID_MASK; + id = (off - 1) & L2TP_SESSION_ID_MASK; if (slist_add(&_this->free_session_id_list, (void *)(uintptr_t)id) == NULL) { l2tpd_log(_this, LOG_ERR, Index: usr.sbin/npppd/pppoe/pppoed.c =================================================================== RCS file: /cvs/src/usr.sbin/npppd/pppoe/pppoed.c,v retrieving revision 1.18 diff -u -p -r1.18 pppoed.c --- usr.sbin/npppd/pppoe/pppoed.c 11 Oct 2015 07:32:06 -0000 1.18 +++ usr.sbin/npppd/pppoe/pppoed.c 7 Dec 2015 06:42:20 -0000 @@ -147,11 +147,11 @@ pppoed_init(pppoed *_this) #if PPPOE_NSESSION > 0xffff #error PPPOE_NSESSION must be less than 65536 #endif - off = arc4random() % 0xffff; + off = arc4random() & 0xffff; for (i = 0; i < PPPOE_NSESSION; i++) { - id = (i + off) % 0xffff; + id = (i + off) & 0xffff; if (id == 0) - id = (off - 1) % 0xffff; + id = (off - 1) & 0xffff; if (slist_add(&_this->session_free_list, (void *)(intptr_t)id) == NULL) { pppoed_log(_this, LOG_ERR, Index: usr.sbin/npppd/pptp/pptpd.c =================================================================== RCS file: /cvs/src/usr.sbin/npppd/pptp/pptpd.c,v retrieving revision 1.28 diff -u -p -r1.28 pptpd.c --- usr.sbin/npppd/pptp/pptpd.c 5 Dec 2015 18:43:36 -0000 1.28 +++ usr.sbin/npppd/pptp/pptpd.c 7 Dec 2015 06:42:20 -0000 @@ -122,7 +122,7 @@ pptpd_init(pptpd *_this) for (i = 0; i < countof(call) ; i++) call[i] = i + 1; for (i = countof(call); i > 1; i--) { - m = arc4random() % i; + m = arc4random_uniform(i); call0 = call[m]; call[m] = call[i - 1]; call[i - 1] = call0;