shithub: riscv

Download patch

ref: f777743b7242e539a8ac806e4e15c4b527be4bb6
parent: 762e98d47e8d812f0dbe4b64ef2a73357bdebeee
parent: 0a5f81a44230cbd562b6d71a0a5be018e24a5ba6
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Aug 27 16:50:55 EDT 2016

merge

--- a/sys/include/pool.h
+++ b/sys/include/pool.h
@@ -35,6 +35,7 @@
 extern void*	poolallocalign(Pool*, ulong, ulong, long, ulong);
 extern void	poolfree(Pool*, void*);
 extern ulong	poolmsize(Pool*, void*);
+extern int	poolisoverlap(Pool*, void*, ulong);
 extern void*	poolrealloc(Pool*, void*, ulong);
 extern void	poolcheck(Pool*);
 extern int	poolcompact(Pool*);
@@ -43,6 +44,7 @@
 
 extern Pool*	mainmem;
 extern Pool*	imagmem;
+extern Pool*	secrmem;
 
 enum {	/* flags */
 	POOL_ANTAGONISM	= 1<<0,
--- a/sys/man/2/pool
+++ b/sys/man/2/pool
@@ -1,6 +1,6 @@
 .TH POOL 2
 .SH NAME
-poolalloc, poolallocalign, poolfree, poolmsize, poolrealloc, poolcompact, poolcheck, poolblockcheck,
+poolalloc, poolallocalign, poolfree, poolmsize, poolisoverlap, poolrealloc, poolcompact, poolcheck, poolblockcheck,
 pooldump \- general memory management routines
 .SH SYNOPSIS
 .B #include <u.h>
@@ -25,6 +25,9 @@
 ulong	poolmsize(Pool* pool, void* ptr)
 .PP
 .B
+int	poolisoverlap(Pool* pool, void* ptr, ulong len)
+.PP
+.B
 void*	poolrealloc(Pool* pool, void* ptr, ulong size)
 .PP
 .B
@@ -108,6 +111,13 @@
 that would usually go unused.
 .IR Poolmsize
 grows the block to encompass this extra space and returns the new size.
+.PP
+.I Poolisoverlap
+checks if the byte span
+.BR [ptr , ptr + len)
+overlaps the arenas of the specified
+.BR pool ,
+returning non-zero when there is overlap or zero if none.
 .PP
 The 
 .I poolblockcheck
--- a/sys/src/9/ip/esp.c
+++ b/sys/src/9/ip/esp.c
@@ -261,8 +261,8 @@
 	ipmove(c->raddr, IPnoaddr);
 
 	ecb = (Espcb*)c->ptcl;
-	free(ecb->espstate);
-	free(ecb->ahstate);
+	secfree(ecb->espstate);
+	secfree(ecb->ahstate);
 	memset(ecb, 0, sizeof(Espcb));
 }
 
@@ -694,7 +694,7 @@
 			return "non-hex character in key";
 	}
 	/* collapse hex digits into complete bytes in reverse order in key */
-	key = smalloc(nbyte);
+	key = secalloc(nbyte);
 	for(i = 0; i < nchar && i/2 < nbyte; i++) {
 		c = f[2][nchar-i-1];
 		if(i&1)
@@ -701,9 +701,9 @@
 			c <<= 4;
 		key[i/2] |= c;
 	}
-
+	memset(f[2], 0, nchar);
 	alg->init(ecb, alg->name, key, alg->keylen);
-	free(key);
+	secfree(key);
 	return nil;
 }
 
@@ -791,7 +791,7 @@
 	ecb->ahblklen = 1;
 	ecb->ahlen = BITS2BYTES(96);
 	ecb->auth = shaauth;
-	ecb->ahstate = smalloc(klen);
+	ecb->ahstate = secalloc(klen);
 	memmove(ecb->ahstate, key, klen);
 }
 
@@ -853,8 +853,10 @@
 	ecb->espblklen = Aesblk;
 	ecb->espivlen = Aesblk;
 	ecb->cipher = aescbccipher;
-	ecb->espstate = smalloc(sizeof(AESstate));
+	ecb->espstate = secalloc(sizeof(AESstate));
 	setupAESstate(ecb->espstate, key, n /* keybytes */, ivec);
+	memset(ivec, 0, sizeof(ivec));
+	memset(key, 0, sizeof(key));
 }
 
 static int
@@ -911,8 +913,10 @@
 	ecb->espblklen = Aesblk;
 	ecb->espivlen = Aesblk;
 	ecb->cipher = aesctrcipher;
-	ecb->espstate = smalloc(sizeof(AESstate));
+	ecb->espstate = secalloc(sizeof(AESstate));
 	setupAESstate(ecb->espstate, key, n /* keybytes */, ivec);
+	memset(ivec, 0, sizeof(ivec));
+	memset(key, 0, sizeof(key));
 }
 
 
@@ -963,7 +967,7 @@
 	ecb->ahblklen = 1;
 	ecb->ahlen = BITS2BYTES(96);
 	ecb->auth = md5auth;
-	ecb->ahstate = smalloc(klen);
+	ecb->ahstate = secalloc(klen);
 	memmove(ecb->ahstate, key, klen);
 }
 
@@ -1020,8 +1024,10 @@
 	ecb->espivlen = Desblk;
 
 	ecb->cipher = descipher;
-	ecb->espstate = smalloc(sizeof(DESstate));
+	ecb->espstate = secalloc(sizeof(DESstate));
 	setupDESstate(ecb->espstate, key, ivec);
+	memset(ivec, 0, sizeof(ivec));
+	memset(key, 0, sizeof(key));
 }
 
 static void
@@ -1042,8 +1048,10 @@
 	ecb->espivlen = Desblk;
 
 	ecb->cipher = des3cipher;
-	ecb->espstate = smalloc(sizeof(DES3state));
+	ecb->espstate = secalloc(sizeof(DES3state));
 	setupDES3state(ecb->espstate, key, ivec);
+	memset(ivec, 0, sizeof(ivec));
+	memset(key, 0, sizeof(key));
 }
 
 
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -872,6 +872,11 @@
 		fprestore = fpx87restore;
 	}
 
+	if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0)
+		hwrandbuf = rdrandbuf;
+	else
+		hwrandbuf = nil;
+
 	cputype = t;
 	return t->family;
 }
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -32,6 +32,7 @@
 	proc.$O\
 	qio.$O\
 	qlock.$O\
+	random.$O\
 	rdb.$O\
 	rebootcmd.$O\
 	segment.$O\
@@ -52,7 +53,6 @@
 	memory.$O\
 	mmu.$O\
 	trap.$O\
-	pcrandom.$O\
 	$CONF.root.$O\
 	$CONF.rootc.$O\
 	$DEVS\
--- a/sys/src/9/pc/pcrandom.c
+++ /dev/null
@@ -1,152 +1,0 @@
-#include	"u.h"
-#include	"../port/lib.h"
-#include	"mem.h"
-#include	"dat.h"
-#include	"fns.h"
-#include	"../port/error.h"
-
-static int haverdrand;
-
-struct Rb
-{
-	QLock;
-	Rendez	producer;
-	Rendez	consumer;
-	ulong	randomcount;
-	uchar	buf[128];
-	uchar	*ep;
-	uchar	*rp;
-	uchar	*wp;
-	uchar	next;
-	uchar	wakeme;
-	ushort	bits;
-	ulong	randn;
-} rb;
-
-static int
-rbnotfull(void*)
-{
-	int i;
-
-	i = rb.rp - rb.wp;
-	return i != 1 && i != (1 - sizeof(rb.buf));
-}
-
-static int
-rbnotempty(void*)
-{
-	return rb.wp != rb.rp;
-}
-
-static void
-genrandom(void*)
-{
-	up->basepri = PriNormal;
-	up->priority = up->basepri;
-
-	while(waserror())
-		;
-	for(;;){
-		if(++rb.randomcount <= 100000)
-			continue;
-		if(anyhigher())
-			sched();
-		if(!rbnotfull(0))
-			sleep(&rb.producer, rbnotfull, 0);
-	}
-}
-
-/*
- *  produce random bits in a circular buffer
- */
-static void
-randomclock(void)
-{
-	if(rb.randomcount == 0 || !rbnotfull(0))
-		return;
-
-	rb.bits = (rb.bits<<2) ^ rb.randomcount;
-	rb.randomcount = 0;
-
-	rb.next++;
-	if(rb.next != 8/2)
-		return;
-	rb.next = 0;
-
-	*rb.wp ^= rb.bits;
-	if(rb.wp+1 == rb.ep)
-		rb.wp = rb.buf;
-	else
-		rb.wp = rb.wp+1;
-
-	if(rb.wakeme)
-		wakeup(&rb.consumer);
-}
-
-void
-randominit(void)
-{
-	if(!strcmp(m->cpuidid, "GenuineIntel")
-		 && (m->cpuidcx & Rdrnd)){
-		haverdrand = 1;
-	}
-	else{
-		/* Frequency close but not equal to HZ */
-		addclock0link(randomclock, MS2HZ+3);
-		rb.ep = rb.buf + sizeof(rb.buf);
-		rb.rp = rb.wp = rb.buf;
-		kproc("genrandom", genrandom, 0);
-	}
-}
-
-/*
- *  consume random bytes from a circular buffer
- */
-ulong
-randomread(void *xp, ulong n)
-{
-	uchar *e, *p;
-	ulong x;
-
-	p = xp;
-
-	if(haverdrand){
-		rdrandbuf(p, n);
-		return n;
-	}
-
-	if(waserror()){
-		qunlock(&rb);
-		nexterror();
-	}
-
-	qlock(&rb);
-	for(e = p + n; p < e; ){
-		if(rb.wp == rb.rp){
-			rb.wakeme = 1;
-			wakeup(&rb.producer);
-			sleep(&rb.consumer, rbnotempty, 0);
-			rb.wakeme = 0;
-			continue;
-		}
-
-		/*
-		 *  beating clocks will be predictable if
-		 *  they are synchronized.  Use a cheap pseudo-
-		 *  random number generator to obscure any cycles.
-		 */
-		x = rb.randn*1103515245 ^ *rb.rp;
-		*p++ = rb.randn = x;
-
-		if(rb.rp+1 == rb.ep)
-			rb.rp = rb.buf;
-		else
-			rb.rp = rb.rp+1;
-	}
-	qunlock(&rb);
-	poperror();
-
-	wakeup(&rb.producer);
-
-	return n;
-}
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -48,6 +48,7 @@
 
 static Block* wifidecrypt(Wifi *, Wnode *, Block *);
 static Block* wifiencrypt(Wifi *, Wnode *, Block *);
+static void freewifikeys(Wifi *, Wnode *);
 
 static uchar*
 srcaddr(Wifipkt *w)
@@ -197,6 +198,7 @@
 	}
 	if(!new)
 		return nil;
+	freewifikeys(wifi, nn);
 	memset(nn, 0, sizeof(Wnode));
 	memmove(nn->bssid, bssid, Eaddrlen);
 	nn->lastseen = MACHP(0)->ticks;
@@ -466,6 +468,23 @@
 }
 
 static void
+freewifikeys(Wifi *wifi, Wnode *wn)
+{
+	int i;
+
+	wlock(&wifi->crypt);
+	for(i=0; i<nelem(wn->rxkey); i++){
+		secfree(wn->rxkey[i]);
+		wn->rxkey[i] = nil;
+	}
+	for(i=0; i<nelem(wn->txkey); i++){
+		secfree(wn->txkey[i]);
+		wn->txkey[i] = nil;
+	}
+	wunlock(&wifi->crypt);
+}
+
+static void
 wifideauth(Wifi *wifi, Wnode *wn)
 {
 	Ether *ether;
@@ -474,8 +493,7 @@
 
 	/* deassociate node, clear keys */
 	setstatus(wifi, wn, Sunauth);
-	memset(wn->rxkey, 0, sizeof(wn->rxkey));
-	memset(wn->txkey, 0, sizeof(wn->txkey));
+	freewifikeys(wifi, wn);
 	wn->aid = 0;
 
 	if(wn == wifi->bss){
@@ -789,11 +807,13 @@
 	[CCMP]	"ccmp",
 };
 
-static int
-parsekey(Wkey *k, char *s)
+static Wkey*
+parsekey(char *s)
 {
 	char buf[256], *p;
-	int i;
+	uchar key[32];
+	int i, n;
+	Wkey *k;
 
 	strncpy(buf, s, sizeof(buf)-1);
 	buf[sizeof(buf)-1] = 0;
@@ -801,20 +821,35 @@
 		*p++ = 0;
 	else
 		p = buf;
-	for(i=0; i<nelem(ciphers); i++){
-		if(ciphers[i] == nil)
-			continue;
+	n = hextob(p, &p, key, sizeof(key));
+	for(i=0; i<nelem(ciphers); i++)
 		if(strcmp(ciphers[i], buf) == 0)
 			break;
+	switch(i){
+	case 0:
+		k = secalloc(sizeof(Wkey));
+		break;
+	case TKIP:
+		if(n != 32)
+			return nil;	
+		k = secalloc(sizeof(Wkey) + n);
+		memmove(k->key, key, n);
+		break;
+	case CCMP:
+		if(n != 16)
+			return nil;
+		k = secalloc(sizeof(Wkey) + sizeof(AESstate));
+		setupAESstate((AESstate*)k->key, key, n, nil);
+		break;
+	default:
+		return nil;
 	}
-	if(i >= nelem(ciphers))
-		return -1;
-	memset(k, 0, sizeof(Wkey));
-	k->len = hextob(p, &p, k->key, sizeof(k->key));
+	memset(key, 0, sizeof(key));
 	if(*p == '@')
 		k->tsc = strtoull(++p, nil, 16);
+	k->len = n;
 	k->cipher = i;
-	return 0;
+	return k;
 }
 
 void
@@ -874,7 +909,7 @@
 	Cmdbuf *cb;
 	Cmdtab *ct;
 	Wnode *wn;
-	Wkey *k;
+	Wkey *k, **kk;
 
 	cb = nil;
 	if(waserror()){
@@ -931,8 +966,7 @@
 		memmove(wifi->bssid, addr, Eaddrlen);
 		goto Findbss;
 	case CMauth:
-		memset(wn->rxkey, 0, sizeof(wn->rxkey));
-		memset(wn->txkey, 0, sizeof(wn->txkey));
+		freewifikeys(wifi, wn);
 		if(cb->f[1] == nil)
 			wn->rsnelen = 0;
 		else
@@ -947,12 +981,24 @@
 		break;
 	case CMrxkey0: case CMrxkey1: case CMrxkey2: case CMrxkey3: case CMrxkey4:
 	case CMtxkey0:
+		if(cb->f[1] == nil)
+			error(Ebadarg);
+		k = parsekey(cb->f[1]);
+		if(k == nil)
+			error("bad key");
+		memset(cb->f[1], 0, strlen(cb->f[1]));
+		if(k->cipher == 0){
+			secfree(k);
+			k = nil;
+		}
 		if(ct->index < CMtxkey0)
-			k = &wn->rxkey[ct->index - CMrxkey0];
+			kk = &wn->rxkey[ct->index - CMrxkey0];
 		else
-			k = &wn->txkey[ct->index - CMtxkey0];
-		if(cb->f[1] == nil || parsekey(k, cb->f[1]) != 0)
-			error("bad key");
+			kk = &wn->txkey[ct->index - CMtxkey0];
+		wlock(&wifi->crypt);
+		secfree(*kk);
+		*kk = k;
+		wunlock(&wifi->crypt);
 		if(ct->index >= CMtxkey0 && wn->status == Sblocked)
 			setstatus(wifi, wn, Sassoc);
 		break;
@@ -968,6 +1014,7 @@
 	static uchar zeros[Eaddrlen];
 	char *s, *p, *e;
 	Wnode *wn;
+	Wkey *k;
 	long now;
 	int i;
 
@@ -982,12 +1029,18 @@
 		p = seprint(p, e, "channel: %.2d\n", wn->channel);
 
 		/* only print key ciphers and key length */
-		for(i = 0; i<nelem(wn->rxkey); i++)
-			p = seprint(p, e, "rxkey%d: %s:[%d]\n", i,
-				ciphers[wn->rxkey[i].cipher], wn->rxkey[i].len);
-		for(i = 0; i<nelem(wn->txkey); i++)
-			p = seprint(p, e, "txkey%d: %s:[%d]\n", i,
-				ciphers[wn->txkey[i].cipher], wn->txkey[i].len);
+		rlock(&wifi->crypt);
+		for(i = 0; i<nelem(wn->rxkey); i++){
+			if((k = wn->rxkey[i]) != nil)
+				p = seprint(p, e, "rxkey%d: %s:[%d]\n", i,
+					ciphers[k->cipher], k->len);
+		}
+		for(i = 0; i<nelem(wn->txkey); i++){
+			if((k = wn->txkey[i]) != nil)
+				p = seprint(p, e, "txkey%d: %s:[%d]\n", i,
+					ciphers[k->cipher], k->len);
+		}
+		runlock(&wifi->crypt);
 
 		if(wn->brsnelen > 0){
 			p = seprint(p, e, "brsne: ");
@@ -1018,7 +1071,7 @@
 static int ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
 
 static Block*
-wifiencrypt(Wifi *, Wnode *wn, Block *b)
+wifiencrypt(Wifi *wifi, Wnode *wn, Block *b)
 {
 	uvlong tsc;
 	int n, kid;
@@ -1025,10 +1078,14 @@
 	Wifipkt *w;
 	Wkey *k;
 
+	rlock(&wifi->crypt);
+
 	kid = 0;
-	k = &wn->txkey[kid];
-	if(k->cipher == 0)
+	k = wn->txkey[kid];
+	if(k == nil){
+		runlock(&wifi->crypt);
 		return b;
+	}
 
 	n = wifihdrlen((Wifipkt*)b->rp);
 
@@ -1052,8 +1109,6 @@
 		b->rp[6] = tsc>>32;
 		b->rp[7] = tsc>>40;
 		b->rp += 8;
-		if(k->len != 32)
-			goto drop;
 		tkipencrypt(k, w, b, tsc);
 		break;
 	case CCMP:
@@ -1066,15 +1121,10 @@
 		b->rp[6] = tsc>>32;
 		b->rp[7] = tsc>>40;
 		b->rp += 8;
-		if(k->len != 16)
-			goto drop;
 		ccmpencrypt(k, w, b, tsc);
 		break;
-	default:
-	drop:
-		free(b);
-		return nil;
 	}
+	runlock(&wifi->crypt);
 
 	b->rp = (uchar*)w;
 	w->fc[1] |= 0x40;
@@ -1082,7 +1132,7 @@
 }
 
 static Block*
-wifidecrypt(Wifi *, Wnode *wn, Block *b)
+wifidecrypt(Wifi *wifi, Wnode *wn, Block *b)
 {
 	uvlong tsc;
 	int n, kid;
@@ -1089,6 +1139,8 @@
 	Wifipkt *w;
 	Wkey *k;
 
+	rlock(&wifi->crypt);
+
 	w = (Wifipkt*)b->rp;
 	n = wifihdrlen(w);
 	b->rp += n;
@@ -1101,7 +1153,9 @@
 	if((w->a1[0] & 1) == 0)
 		kid = 4;	/* use peerwise key for non-unicast */
 
-	k = &wn->rxkey[kid];
+	k = wn->rxkey[kid];
+	if(k == nil)
+		goto drop;
 	switch(k->cipher){
 	case TKIP:
 		tsc =	(uvlong)b->rp[7]<<40 |
@@ -1111,7 +1165,7 @@
 			(uvlong)b->rp[0]<<8 |
 			(uvlong)b->rp[2];
 		b->rp += 8;
-		if(tsc <= k->tsc || k->len != 32)
+		if(tsc <= k->tsc)
 			goto drop;
 		if(tkipdecrypt(k, w, b, tsc) != 0)
 			goto drop;
@@ -1124,7 +1178,7 @@
 			(uvlong)b->rp[1]<<8 |
 			(uvlong)b->rp[0];
 		b->rp += 8;
-		if(tsc <= k->tsc || k->len != 16)
+		if(tsc <= k->tsc)
 			goto drop;
 		if(ccmpdecrypt(k, w, b, tsc) != 0)
 			goto drop;
@@ -1131,9 +1185,11 @@
 		break;
 	default:
 	drop:
+		runlock(&wifi->crypt);
 		freeb(b);
 		return nil;
 	}
+	runlock(&wifi->crypt);
 
 	k->tsc = tsc;
 	b->rp -= n;
@@ -1564,12 +1620,10 @@
 }
 
 static int
-setupCCMP(Wkey *k, Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32], AESstate *as)
+setupCCMP(Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32])
 {
 	uchar *p;
 
-	setupAESstate(as, k->key, k->len, nil);
-
 	nonce[0] = ((w->fc[0] & 0x0c) == 0x00) << 4;
 	memmove(&nonce[1], w->a2, Eaddrlen);
 	nonce[7]  = tsc >> 40;
@@ -1599,11 +1653,10 @@
 ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
 {
 	uchar auth[32], nonce[13];
-	AESstate as;
 
 	aesCCMencrypt(2, 8, nonce, auth,
-		setupCCMP(k, w, tsc, nonce, auth, &as),
-		b->rp, BLEN(b), &as);
+		setupCCMP(w, tsc, nonce, auth),
+		b->rp, BLEN(b), (AESstate*)k->key);
 	b->wp += 8;
 }
 
@@ -1611,7 +1664,6 @@
 ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
 {
 	uchar auth[32], nonce[13];
-	AESstate as;
 
 	if(BLEN(b) < 8)
 		return -1;
@@ -1618,6 +1670,6 @@
 
 	b->wp -= 8;
 	return aesCCMdecrypt(2, 8, nonce, auth,
-		setupCCMP(k, w, tsc, nonce, auth, &as),
-		b->rp, BLEN(b), &as);
+		setupCCMP(w, tsc, nonce, auth),
+		b->rp, BLEN(b), (AESstate*)k->key);
 }
--- a/sys/src/9/pc/wifi.h
+++ b/sys/src/9/pc/wifi.h
@@ -15,10 +15,10 @@
 
 struct Wkey
 {
-	int	cipher;
-	int	len;
-	uchar	key[32];
-	uvlong	tsc;
+	int		cipher;
+	int		len;
+	uvlong		tsc;
+	uchar		key[];
 };
 
 struct Wnode
@@ -30,8 +30,8 @@
 
 	int	rsnelen;
 	uchar	rsne[258];
-	Wkey	txkey[1];
-	Wkey	rxkey[5];
+	Wkey	*txkey[1];
+	Wkey	*rxkey[5];
 
 	int	aid;		/* association id */
 	ulong	lastsend;
@@ -58,6 +58,7 @@
 
 	int	debug;
 
+	RWlock	crypt;
 	Queue	*iq;
 	ulong	watchdog;
 	ulong	lastauth;
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -29,6 +29,7 @@
 	proc.$O\
 	qio.$O\
 	qlock.$O\
+	random.$O\
 	rdb.$O\
 	rebootcmd.$O\
 	segment.$O\
@@ -49,7 +50,6 @@
 	memory.$O\
 	mmu.$O\
 	trap.$O\
-	pcrandom.$O\
 	$CONF.root.$O\
 	$CONF.rootc.$O\
 	$DEVS\
--- a/sys/src/9/port/alloc.c
+++ b/sys/src/9/port/alloc.c
@@ -53,8 +53,27 @@
 	.private=	&pimagpriv,
 };
 
+static Private psecrpriv;
+static Pool psecrmem = {
+	.name=	"Secrets",
+	.maxsize=	16*1024*1024,
+	.minarena=	64*1024,
+	.quantum=	32,
+	.alloc=	xalloc,
+	.merge=	xmerge,
+	.flags=	POOL_ANTAGONISM,
+
+	.lock=	plock,
+	.unlock=	punlock,
+	.print=	poolprint,
+	.panic=	ppanic,
+
+	.private=	&psecrpriv,
+};
+
 Pool*	mainmem = &pmainmem;
 Pool*	imagmem = &pimagmem;
+Pool*	secrmem = &psecrmem;
 
 /*
  * because we can't print while we're holding the locks, 
@@ -129,6 +148,7 @@
 {
 	poolsummary(mainmem);
 	poolsummary(imagmem);
+	poolsummary(secrmem);
 }
 
 /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
@@ -171,12 +191,9 @@
 {
 	void *v;
 
-	for(;;) {
-		v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
-		if(v != nil)
-			break;
+	while((v = poolalloc(mainmem, size+Npadlong*sizeof(ulong))) == nil){
 		if(!waserror()){
-			resrcwait(0);
+			resrcwait(nil);
 			poperror();
 		}
 	}
@@ -276,6 +293,34 @@
 	if(v = mallocz(n*szelem, 1))
 		setmalloctag(v, getcallerpc(&n));
 	return v;
+}
+
+/* secret memory, used to back cryptographic keys and cipher states */
+void*
+secalloc(ulong size)
+{
+	void *v;
+
+	while((v = poolalloc(secrmem, size+Npadlong*sizeof(ulong))) == nil){
+		if(!waserror()){
+			resrcwait(nil);
+			poperror();
+		}
+	}
+	if(Npadlong){
+		v = (ulong*)v+Npadlong;
+		setmalloctag(v, getcallerpc(&size));
+		setrealloctag(v, 0);
+	}
+	memset(v, 0, size);
+	return v;
+}
+
+void
+secfree(void *v)
+{
+	if(v != nil)
+		poolfree(secrmem, (ulong*)v-Npadlong);
 }
 
 void
--- a/sys/src/9/port/devcons.c
+++ b/sys/src/9/port/devcons.c
@@ -4,8 +4,8 @@
 #include	"dat.h"
 #include	"fns.h"
 #include	"../port/error.h"
-#include	"pool.h"
 
+#include	<pool.h>
 #include	<authsrv.h>
 
 void	(*consdebug)(void) = nil;
@@ -21,7 +21,6 @@
 char	*sysname;
 vlong	fasthz;
 
-static void	seedrand(void);
 static int	readtime(ulong, char*, int);
 static int	readbintime(char*, int);
 static int	writetime(char*, int);
@@ -616,7 +615,8 @@
 			"%lud/%lud user\n"
 			"%lud/%lud swap\n"
 			"%llud/%llud/%llud kernel malloc\n"
-			"%llud/%llud/%llud kernel draw\n",
+			"%llud/%llud/%llud kernel draw\n"
+			"%llud/%llud/%llud kernel secret\n",
 			(uvlong)conf.npage*BY2PG,
 			(uvlong)BY2PG,
 			conf.npage-conf.upages,
@@ -627,7 +627,10 @@
 			(uvlong)mainmem->maxsize,
 			(uvlong)imagmem->curalloc,
 			(uvlong)imagmem->cursize,
-			(uvlong)imagmem->maxsize);
+			(uvlong)imagmem->maxsize,
+			(uvlong)secrmem->curalloc,
+			(uvlong)secrmem->cursize,
+			(uvlong)secrmem->maxsize);
 
 		return readstr((ulong)offset, buf, n, tmp);
 
@@ -845,29 +848,20 @@
 
 static	ulong	randn;
 
-static void
-seedrand(void)
-{
-	if(!waserror()){
-		randomread((void*)&randn, sizeof(randn));
-		poperror();
-	}
-}
-
 int
-nrand(int n)
+rand(void)
 {
 	if(randn == 0)
-		seedrand();
+		randomread((void*)&randn, sizeof(randn));
 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
-	return (randn>>16) % n;
+	return randn;
 }
 
 int
-rand(void)
+nrand(int n)
 {
-	nrand(1);
-	return randn;
+	rand();
+	return (randn>>16) % n;
 }
 
 static uvlong uvorder = 0x0001020304050607ULL;
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -9,6 +9,8 @@
 #include	"ureg.h"
 #include	"edf.h"
 
+#include	<pool.h>
+
 enum
 {
 	Qdir,
@@ -789,7 +791,7 @@
 		if(addr < KZERO)
 			return procctlmemio(c, p, addr, va, n, 1);
 
-		if(!iseve())
+		if(!iseve() || poolisoverlap(secrmem, (uchar*)addr, n))
 			error(Eperm);
 
 		/* validate kernel addresses */
--- a/sys/src/9/port/devsdp.c
+++ b/sys/src/9/port/devsdp.c
@@ -1056,10 +1056,8 @@
 {
 	if(ow->controlpkt)
 		freeb(ow->controlpkt);
-	if(ow->authstate)
-		free(ow->authstate);
-	if(ow->cipherstate)
-		free(ow->cipherstate);
+	secfree(ow->authstate);
+	secfree(ow->cipherstate);
 	if(ow->compstate)
 		free(ow->compstate);
 	memset(ow, 0, sizeof(OneWay));
@@ -1920,14 +1918,10 @@
 static void
 authfree(Conv *c)
 {
-	if(c->in.authstate) {
-		free(c->in.authstate);
-		c->in.authstate = nil;
-	}
-	if(c->out.authstate) {
-		free(c->out.authstate);
-		c->out.authstate = nil;
-	}
+	secfree(c->in.authstate);
+	secfree(c->out.authstate);
+	c->in.authstate = nil;
+	c->out.authstate = nil;
 	c->in.auth = nil;
 	c->in.authlen = 0;
 	c->out.authlen = 0;
@@ -2019,7 +2013,7 @@
 	c->in.cipherblklen = 8;
 	c->in.cipherivlen = 8;
 	c->in.cipher = desdecrypt;
-	c->in.cipherstate = smalloc(sizeof(DESstate));
+	c->in.cipherstate = secalloc(sizeof(DESstate));
 	setupDESstate(c->in.cipherstate, key, ivec);
 	
 	/* out */
@@ -2030,7 +2024,7 @@
 	c->out.cipherblklen = 8;
 	c->out.cipherivlen = 8;
 	c->out.cipher = desencrypt;
-	c->out.cipherstate = smalloc(sizeof(DESstate));
+	c->out.cipherstate = secalloc(sizeof(DESstate));
 	setupDESstate(c->out.cipherstate, key, ivec);
 }
 
@@ -2129,7 +2123,7 @@
 	c->in.cipherblklen = 1;
 	c->in.cipherivlen = 4;
 	c->in.cipher = rc4decrypt;
-	cr = smalloc(sizeof(CipherRc4));
+	cr = secalloc(sizeof(CipherRc4));
 	memset(cr, 0, sizeof(*cr));
 	setupRC4state(&cr->current, key, n);
 	c->in.cipherstate = cr;
@@ -2140,7 +2134,7 @@
 	c->out.cipherblklen = 1;
 	c->out.cipherivlen = 4;
 	c->out.cipher = rc4encrypt;
-	cr = smalloc(sizeof(CipherRc4));
+	cr = secalloc(sizeof(CipherRc4));
 	memset(cr, 0, sizeof(*cr));
 	setupRC4state(&cr->current, key, n);
 	c->out.cipherstate = cr;
@@ -2195,7 +2189,7 @@
 
 	memset(hash, 0, MD5dlen);
 	seanq_hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16);
-	r = memcmp(t+tlen, hash, ow->authlen) == 0;
+	r = tsmemcmp(t+tlen, hash, ow->authlen) == 0;
 	memmove(t+tlen, hash, ow->authlen);
 	return r;
 }
@@ -2212,7 +2206,7 @@
 		keylen = 16;
 
 	/* in */
-	c->in.authstate = smalloc(16);
+	c->in.authstate = secalloc(16);
 	memset(c->in.authstate, 0, 16);
 	setkey(c->in.authstate, keylen, &c->in, "auth");
 	c->in.authlen = 12;
@@ -2219,7 +2213,7 @@
 	c->in.auth = md5auth;
 	
 	/* out */
-	c->out.authstate = smalloc(16);
+	c->out.authstate = secalloc(16);
 	memset(c->out.authstate, 0, 16);
 	setkey(c->out.authstate, keylen, &c->out, "auth");
 	c->out.authlen = 12;
--- a/sys/src/9/port/devssl.c
+++ b/sys/src/9/port/devssl.c
@@ -373,14 +373,10 @@
 		sslhangup(s);
 		if(s->c)
 			cclose(s->c);
-		if(s->in.secret)
-			free(s->in.secret);
-		if(s->out.secret)
-			free(s->out.secret);
-		if(s->in.state)
-			free(s->in.state);
-		if(s->out.state)
-			free(s->out.state);
+		secfree(s->in.secret);
+		secfree(s->out.secret);
+		secfree(s->in.state);
+		secfree(s->out.state);
 		free(s);
 
 	}
@@ -826,10 +822,8 @@
 static void
 setsecret(OneWay *w, uchar *secret, int n)
 {
-	if(w->secret)
-		free(w->secret);
-
-	w->secret = smalloc(n);
+	secfree(w->secret);
+	w->secret = secalloc(n);
 	memmove(w->secret, secret, n);
 	w->slen = n;
 }
@@ -837,12 +831,8 @@
 static void
 initDESkey(OneWay *w)
 {
-	if(w->state){
-		free(w->state);
-		w->state = 0;
-	}
-
-	w->state = smalloc(sizeof(DESstate));
+	secfree(w->state);
+	w->state = secalloc(sizeof(DESstate));
 	if(w->slen >= 16)
 		setupDESstate(w->state, w->secret, w->secret+8);
 	else if(w->slen >= 8)
@@ -860,11 +850,6 @@
 {
 	uchar key[8];
 
-	if(w->state){
-		free(w->state);
-		w->state = 0;
-	}
-
 	if(w->slen >= 8){
 		memmove(key, w->secret, 8);
 		key[0] &= 0x0f;
@@ -872,25 +857,14 @@
 		key[4] &= 0x0f;
 		key[6] &= 0x0f;
 	}
-
-	w->state = smalloc(sizeof(DESstate));
-	if(w->slen >= 16)
-		setupDESstate(w->state, key, w->secret+8);
-	else if(w->slen >= 8)
-		setupDESstate(w->state, key, 0);
-	else
-		error("secret too short");
+	initDESkey(w);
 }
 
 static void
 initRC4key(OneWay *w)
 {
-	if(w->state){
-		free(w->state);
-		w->state = 0;
-	}
-
-	w->state = smalloc(sizeof(RC4state));
+	secfree(w->state);
+	w->state = secalloc(sizeof(RC4state));
 	setupRC4state(w->state, w->secret, w->slen);
 }
 
@@ -901,16 +875,9 @@
 static void
 initRC4key_40(OneWay *w)
 {
-	if(w->state){
-		free(w->state);
-		w->state = 0;
-	}
-
 	if(w->slen > 5)
 		w->slen = 5;
-
-	w->state = smalloc(sizeof(RC4state));
-	setupRC4state(w->state, w->secret, w->slen);
+	initRC4key(w);
 }
 
 /*
@@ -920,16 +887,9 @@
 static void
 initRC4key_128(OneWay *w)
 {
-	if(w->state){
-		free(w->state);
-		w->state = 0;
-	}
-
 	if(w->slen > 16)
 		w->slen = 16;
-
-	w->state = smalloc(sizeof(RC4state));
-	setupRC4state(w->state, w->secret, w->slen);
+	initRC4key(w);
 }
 
 
@@ -1177,27 +1137,29 @@
 		break;
 	case Csin:
 		p = cb->f[1];
-		m = (strlen(p)*3)/2;
-		x = smalloc(m);
+		m = (strlen(p)*3)/2 + 1;
+		x = secalloc(m);
 		t = dec64(x, m, p, strlen(p));
+		memset(p, 0, strlen(p));
 		if(t <= 0){
-			free(x);
+			secfree(x);
 			error(Ebadarg);
 		}
 		setsecret(&s->in, x, t);
-		free(x);
+		secfree(x);
 		break;
 	case Csout:
 		p = cb->f[1];
 		m = (strlen(p)*3)/2 + 1;
-		x = smalloc(m);
+		x = secalloc(m);
 		t = dec64(x, m, p, strlen(p));
+		memset(p, 0, strlen(p));
 		if(t <= 0){
-			free(x);
+			secfree(x);
 			error(Ebadarg);
 		}
 		setsecret(&s->out, x, t);
-		free(x);
+		secfree(x);
 		break;
 	}
 	poperror();
--- a/sys/src/9/port/devtls.c
+++ b/sys/src/9/port/devtls.c
@@ -1471,7 +1471,7 @@
 static void
 initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *)
 {
-	s->enckey = smalloc(sizeof(RC4state));
+	s->enckey = secalloc(sizeof(RC4state));
 	s->enc = rc4enc;
 	s->dec = rc4enc;
 	setupRC4state(s->enckey, p, ea->keylen);
@@ -1480,7 +1480,7 @@
 static void
 initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv)
 {
-	s->enckey = smalloc(sizeof(DES3state));
+	s->enckey = secalloc(sizeof(DES3state));
 	s->enc = des3enc;
 	s->dec = des3dec;
 	s->block = 8;
@@ -1490,7 +1490,7 @@
 static void
 initAESkey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
 {
-	s->enckey = smalloc(sizeof(AESstate));
+	s->enckey = secalloc(sizeof(AESstate));
 	s->enc = aesenc;
 	s->dec = aesdec;
 	s->block = 16;
@@ -1500,7 +1500,7 @@
 static void
 initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
 {
-	s->enckey = smalloc(sizeof(Chachastate));
+	s->enckey = secalloc(sizeof(Chachastate));
 	s->aead_enc = ccpoly_aead_enc;
 	s->aead_dec = ccpoly_aead_dec;
 	s->maclen = Poly1305dlen;
@@ -1517,7 +1517,7 @@
 static void
 initaesgcmkey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
 {
-	s->enckey = smalloc(sizeof(AESGCMstate));
+	s->enckey = secalloc(sizeof(AESGCMstate));
 	s->aead_enc = aesgcm_aead_enc;
 	s->aead_dec = aesgcm_aead_dec;
 	s->maclen = 16;
@@ -1673,18 +1673,19 @@
 		ea = parseencalg(cb->f[2]);
 
 		p = cb->f[4];
-		m = (strlen(p)*3)/2;
-		x = smalloc(m);
-		tos = smalloc(sizeof(Secret));
-		toc = smalloc(sizeof(Secret));
+		m = (strlen(p)*3)/2 + 1;
+		x = secalloc(m);
+		tos = secalloc(sizeof(Secret));
+		toc = secalloc(sizeof(Secret));
 		if(waserror()){
+			secfree(x);
 			freeSec(tos);
 			freeSec(toc);
-			free(x);
 			nexterror();
 		}
 
 		m = dec64(x, m, p, strlen(p));
+		memset(p, 0, strlen(p));
 		if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen)
 			error("not enough secret data provided");
 
@@ -1719,7 +1720,7 @@
 		tos->encalg = ea->name;
 		tos->hashalg = ha->name;
 
-		free(x);
+		secfree(x);
 		poperror();
 	}else if(strcmp(cb->f[0], "changecipher") == 0){
 		if(cb->nf != 1)
@@ -2048,17 +2049,10 @@
 static void
 freeSec(Secret *s)
 {
-	void *k;
-
 	if(s == nil)
 		return;
-	k = s->enckey;
-	if(k != nil){
-		memset(k, 0, msize(k));
-		free(k);
-	}
-	memset(s, 0, sizeof(*s));
-	free(s);
+	secfree(s->enckey);
+	secfree(s);
 }
 
 static int
@@ -2162,6 +2156,8 @@
 		iv[i+(ChachaIVlen-8)] ^= seq[i];
 
 	chacha_setiv(cs, iv);
+
+	memset(iv, 0, sizeof(iv));
 }
 
 static int
@@ -2196,6 +2192,7 @@
 	for(i=0; i<8; i++) iv[4+i] ^= aad[i];
 	memmove(reciv, iv+4, 8);
 	aesgcm_setiv(sec->enckey, iv, 12);
+	memset(iv, 0, sizeof(iv));
 	aesgcm_encrypt(data, len, aad, aadlen, data+len, sec->enckey);
 	return len + sec->maclen;
 }
@@ -2211,6 +2208,7 @@
 	memmove(iv, sec->mackey, 4);
 	memmove(iv+4, reciv, 8);
 	aesgcm_setiv(sec->enckey, iv, 12);
+	memset(iv, 0, sizeof(iv));
 	if(aesgcm_decrypt(data, len, aad, aadlen, data+len, sec->enckey) != 0)
 		return -1;
 	return len;
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -126,6 +126,7 @@
 char*		getconfenv(void);
 long		hostdomainwrite(char*, int);
 long		hostownerwrite(char*, int);
+void 		(*hwrandbuf)(void*, ulong);
 void		hzsched(void);
 Block*		iallocb(int);
 void		iallocsummary(void);
@@ -308,6 +309,8 @@
 void		scheddump(void);
 void		schedinit(void);
 void		(*screenputs)(char*, int);
+void*		secalloc(ulong);
+void		secfree(void*);
 long		seconds(void);
 uintptr		segattach(int, char *, uintptr, uintptr);
 void		segclock(uintptr);
--- a/sys/src/9/port/random.c
+++ b/sys/src/9/port/random.c
@@ -5,135 +5,103 @@
 #include	"fns.h"
 #include	"../port/error.h"
 
-struct Rb
+#include	<libsec.h>
+
+/* machine specific hardware random number generator */
+void (*hwrandbuf)(void*, ulong) = nil;
+
+static struct
 {
 	QLock;
-	Rendez	producer;
-	Rendez	consumer;
-	ulong	randomcount;
-	uchar	buf[128];
-	uchar	*ep;
-	uchar	*rp;
-	uchar	*wp;
-	uchar	next;
-	uchar	wakeme;
-	ushort	bits;
-	ulong	randn;
-} rb;
+	Chachastate;
+} *rs;
 
-static int
-rbnotfull(void*)
+typedef struct Seedbuf Seedbuf;
+struct Seedbuf
 {
-	int i;
+	ulong		randomcount;
+	uchar		buf[64];
+	uchar		nbuf;
+	uchar		next;
+	ushort		bits;
 
-	i = rb.rp - rb.wp;
-	return i != 1 && i != (1 - sizeof(rb.buf));
-}
+	SHA2_512state	ds;
+};
 
-static int
-rbnotempty(void*)
+static void
+randomsample(Ureg*, Timer *t)
 {
-	return rb.wp != rb.rp;
+	Seedbuf *s = t->ta;
+
+	if(s->randomcount == 0 || s->nbuf >= sizeof(s->buf))
+		return;
+	s->bits = (s->bits<<2) ^ s->randomcount;
+	s->randomcount = 0;
+	if(++s->next < 8/2)
+		return;
+	s->next = 0;
+	s->buf[s->nbuf++] ^= s->bits;
 }
 
 static void
-genrandom(void*)
+randomseed(void*)
 {
-	up->basepri = PriNormal;
-	up->priority = up->basepri;
+	Seedbuf *s;
 
-	while(waserror())
-		;
-	for(;;){
-		if(++rb.randomcount <= 100000)
+	s = secalloc(sizeof(Seedbuf));
+
+	if(hwrandbuf != nil)
+		(*hwrandbuf)(s->buf, sizeof(s->buf));
+
+	/* Frequency close but not equal to HZ */
+	up->tns = (vlong)(MS2HZ+3)*1000000LL;
+	up->tmode = Tperiodic;
+	up->tt = nil;
+	up->ta = s;
+	up->tf = randomsample;
+	timeradd(up);
+	while(s->nbuf < sizeof(s->buf)){
+		if(++s->randomcount <= 100000)
 			continue;
 		if(anyhigher())
 			sched();
-		if(!rbnotfull(0))
-			sleep(&rb.producer, rbnotfull, 0);
 	}
-}
+	timerdel(up);
 
-/*
- *  produce random bits in a circular buffer
- */
-static void
-randomclock(void)
-{
-	if(rb.randomcount == 0 || !rbnotfull(0))
-		return;
+	sha2_512(s->buf, sizeof(s->buf), s->buf, &s->ds);
+	setupChachastate(rs, s->buf, 32, s->buf+32, 12, 20);
+	qunlock(rs);
 
-	rb.bits = (rb.bits<<2) ^ rb.randomcount;
-	rb.randomcount = 0;
+	secfree(s);
 
-	rb.next++;
-	if(rb.next != 8/2)
-		return;
-	rb.next = 0;
-
-	*rb.wp ^= rb.bits;
-	if(rb.wp+1 == rb.ep)
-		rb.wp = rb.buf;
-	else
-		rb.wp = rb.wp+1;
-
-	if(rb.wakeme)
-		wakeup(&rb.consumer);
+	pexit("", 1);
 }
 
 void
 randominit(void)
 {
-	/* Frequency close but not equal to HZ */
-	addclock0link(randomclock, MS2HZ+3);
-	rb.ep = rb.buf + sizeof(rb.buf);
-	rb.rp = rb.wp = rb.buf;
-	kproc("genrandom", genrandom, 0);
+	rs = secalloc(sizeof(*rs));
+	qlock(rs);	/* randomseed() unlocks once seeded */
+	kproc("randomseed", randomseed, nil);
 }
 
-/*
- *  consume random bytes from a circular buffer
- */
 ulong
 randomread(void *xp, ulong n)
 {
-	uchar *e, *p;
-	ulong x;
+	if(n == 0)
+		return 0;
 
-	p = xp;
+	if(hwrandbuf != nil)
+		(*hwrandbuf)(xp, n);
 
 	if(waserror()){
-		qunlock(&rb);
+		qunlock(rs);
 		nexterror();
 	}
-
-	qlock(&rb);
-	for(e = p + n; p < e; ){
-		if(rb.wp == rb.rp){
-			rb.wakeme = 1;
-			wakeup(&rb.producer);
-			sleep(&rb.consumer, rbnotempty, 0);
-			rb.wakeme = 0;
-			continue;
-		}
-
-		/*
-		 *  beating clocks will be predictable if
-		 *  they are synchronized.  Use a cheap pseudo-
-		 *  random number generator to obscure any cycles.
-		 */
-		x = rb.randn*1103515245 ^ *rb.rp;
-		*p++ = rb.randn = x;
-
-		if(rb.rp+1 == rb.ep)
-			rb.rp = rb.buf;
-		else
-			rb.rp = rb.rp+1;
-	}
-	qunlock(&rb);
+	qlock(rs);
+	chacha_encrypt((uchar*)xp, n, rs);
+	qunlock(rs);
 	poperror();
-
-	wakeup(&rb.producer);
 
 	return n;
 }
--- a/sys/src/libc/port/pool.c
+++ b/sys/src/libc/port/pool.c
@@ -1332,6 +1332,19 @@
 	return dsize;
 }
 
+int
+poolisoverlap(Pool *p, void *v, ulong n)
+{
+	Arena *a;
+
+	p->lock(p);
+	for(a = p->arenalist; a != nil; a = a->down)
+		if((uchar*)v+n > (uchar*)a && (uchar*)v < (uchar*)a+a->asize)
+			break;
+	p->unlock(p);
+	return a != nil;
+}
+
 /*
  * Debugging
  */
--