diff --git a/sys/include/pool.h b/sys/include/pool.h index 571373e9f..5f7fada45 100644 --- a/sys/include/pool.h +++ b/sys/include/pool.h @@ -35,6 +35,7 @@ extern void* poolalloc(Pool*, ulong); 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 void pooldump(Pool*); extern Pool* mainmem; extern Pool* imagmem; +extern Pool* secrmem; enum { /* flags */ POOL_ANTAGONISM = 1<<0, diff --git a/sys/man/2/pool b/sys/man/2/pool index a44b57d4d..b637e3d7c 100644 --- 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 @@ -25,6 +25,9 @@ void poolfree(Pool* pool, void* ptr) 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 @@ -109,6 +112,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 and diff --git a/sys/src/9/ip/esp.c b/sys/src/9/ip/esp.c index 75c48a1ff..1e93f6f75 100644 --- a/sys/src/9/ip/esp.c +++ b/sys/src/9/ip/esp.c @@ -261,8 +261,8 @@ espclose(Conv *c) 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,16 +694,16 @@ setalg(Espcb *ecb, char **f, int n, Algorithm *alg) 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) 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 @@ shaahinit(Espcb *ecb, char *name, uchar *key, unsigned klen) 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 @@ aescbcespinit(Espcb *ecb, char *name, uchar *k, unsigned n) 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 @@ aesctrespinit(Espcb *ecb, char *name, uchar *k, unsigned n) 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 @@ md5ahinit(Espcb *ecb, char *name, uchar *key, unsigned klen) 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 @@ desespinit(Espcb *ecb, char *name, uchar *k, unsigned n) 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 @@ des3espinit(Espcb *ecb, char *name, uchar *k, unsigned n) 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)); } diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index f3be061cb..0b4cad252 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -872,6 +872,11 @@ cpuidentify(void) fprestore = fpx87restore; } + if(strcmp(m->cpuidid, "GenuineIntel") == 0 && (m->cpuidcx & Rdrnd) != 0) + hwrandbuf = rdrandbuf; + else + hwrandbuf = nil; + cputype = t; return t->family; } diff --git a/sys/src/9/pc/mkfile b/sys/src/9/pc/mkfile index 96ab2c623..c6e683e22 100644 --- a/sys/src/9/pc/mkfile +++ b/sys/src/9/pc/mkfile @@ -32,6 +32,7 @@ PORT=\ proc.$O\ qio.$O\ qlock.$O\ + random.$O\ rdb.$O\ rebootcmd.$O\ segment.$O\ @@ -52,7 +53,6 @@ OBJ=\ memory.$O\ mmu.$O\ trap.$O\ - pcrandom.$O\ $CONF.root.$O\ $CONF.rootc.$O\ $DEVS\ diff --git a/sys/src/9/pc/pcrandom.c b/sys/src/9/pc/pcrandom.c deleted file mode 100644 index 386d7bf8e..000000000 --- a/sys/src/9/pc/pcrandom.c +++ /dev/null @@ -1,152 +0,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; -} diff --git a/sys/src/9/pc/wifi.c b/sys/src/9/pc/wifi.c index 8155b25e3..8325c0aa7 100644 --- a/sys/src/9/pc/wifi.c +++ b/sys/src/9/pc/wifi.c @@ -48,6 +48,7 @@ static uchar basicrates[] = { 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 @@ nodelookup(Wifi *wifi, uchar *bssid, int new) } if(!new) return nil; + freewifikeys(wifi, nn); memset(nn, 0, sizeof(Wnode)); memmove(nn->bssid, bssid, Eaddrlen); nn->lastseen = MACHP(0)->ticks; @@ -465,6 +467,23 @@ recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len) } } +static void +freewifikeys(Wifi *wifi, Wnode *wn) +{ + int i; + + wlock(&wifi->crypt); + for(i=0; irxkey); i++){ + secfree(wn->rxkey[i]); + wn->rxkey[i] = nil; + } + for(i=0; itxkey); i++){ + secfree(wn->txkey[i]); + wn->txkey[i] = nil; + } + wunlock(&wifi->crypt); +} + static void wifideauth(Wifi *wifi, Wnode *wn) { @@ -474,8 +493,7 @@ wifideauth(Wifi *wifi, Wnode *wn) /* 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 @@ static char *ciphers[] = { [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 @@ parsekey(Wkey *k, char *s) *p++ = 0; else p = buf; - for(i=0; ikey, 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 @@ wifictl(Wifi *wifi, void *buf, long n) Cmdbuf *cb; Cmdtab *ct; Wnode *wn; - Wkey *k; + Wkey *k, **kk; cb = nil; if(waserror()){ @@ -931,8 +966,7 @@ wifictl(Wifi *wifi, void *buf, long n) 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 @@ wifictl(Wifi *wifi, void *buf, long n) break; case CMrxkey0: case CMrxkey1: case CMrxkey2: case CMrxkey3: case CMrxkey4: case CMtxkey0: - if(ct->index < CMtxkey0) - k = &wn->rxkey[ct->index - CMrxkey0]; - else - k = &wn->txkey[ct->index - CMtxkey0]; - if(cb->f[1] == nil || parsekey(k, cb->f[1]) != 0) + 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) + kk = &wn->rxkey[ct->index - CMrxkey0]; + else + 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 @@ wifistat(Wifi *wifi, void *buf, long n, ulong off) static uchar zeros[Eaddrlen]; char *s, *p, *e; Wnode *wn; + Wkey *k; long now; int i; @@ -982,12 +1029,18 @@ wifistat(Wifi *wifi, void *buf, long n, ulong off) p = seprint(p, e, "channel: %.2d\n", wn->channel); /* only print key ciphers and key length */ - for(i = 0; irxkey); i++) - p = seprint(p, e, "rxkey%d: %s:[%d]\n", i, - ciphers[wn->rxkey[i].cipher], wn->rxkey[i].len); - for(i = 0; itxkey); 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; irxkey); 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; itxkey); 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,17 +1071,21 @@ static void ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc); 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; 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 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b) 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 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b) 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,13 +1132,15 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b) } static Block* -wifidecrypt(Wifi *, Wnode *wn, Block *b) +wifidecrypt(Wifi *wifi, Wnode *wn, Block *b) { uvlong tsc; int n, kid; Wifipkt *w; Wkey *k; + rlock(&wifi->crypt); + w = (Wifipkt*)b->rp; n = wifihdrlen(w); b->rp += n; @@ -1101,7 +1153,9 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b) 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 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b) (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,16 +1178,18 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b) (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; break; default: drop: + runlock(&wifi->crypt); freeb(b); return nil; } + runlock(&wifi->crypt); k->tsc = tsc; b->rp -= n; @@ -1564,12 +1620,10 @@ aesCCMdecrypt(int L, int M, uchar *N /* N[15-L] */, } 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 @@ static void 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,13 +1664,12 @@ static int ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc) { uchar auth[32], nonce[13]; - AESstate as; if(BLEN(b) < 8) return -1; 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); } diff --git a/sys/src/9/pc/wifi.h b/sys/src/9/pc/wifi.h index bca2e07e9..2171afd21 100644 --- a/sys/src/9/pc/wifi.h +++ b/sys/src/9/pc/wifi.h @@ -15,10 +15,10 @@ enum { 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 @@ struct Wnode 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 @@ struct Wifi int debug; + RWlock crypt; Queue *iq; ulong watchdog; ulong lastauth; diff --git a/sys/src/9/pc64/mkfile b/sys/src/9/pc64/mkfile index 30b40daf1..16aae0a68 100644 --- a/sys/src/9/pc64/mkfile +++ b/sys/src/9/pc64/mkfile @@ -29,6 +29,7 @@ PORT=\ proc.$O\ qio.$O\ qlock.$O\ + random.$O\ rdb.$O\ rebootcmd.$O\ segment.$O\ @@ -49,7 +50,6 @@ OBJ=\ memory.$O\ mmu.$O\ trap.$O\ - pcrandom.$O\ $CONF.root.$O\ $CONF.rootc.$O\ $DEVS\ diff --git a/sys/src/9/port/alloc.c b/sys/src/9/port/alloc.c index fc562bc55..963d60fd2 100644 --- a/sys/src/9/port/alloc.c +++ b/sys/src/9/port/alloc.c @@ -53,8 +53,27 @@ static Pool pimagmem = { .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 @@ mallocsummary(void) { poolsummary(mainmem); poolsummary(imagmem); + poolsummary(secrmem); } /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */ @@ -171,12 +191,9 @@ smalloc(ulong size) { 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(); } } @@ -278,6 +295,34 @@ calloc(ulong n, ulong szelem) 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 setmalloctag(void *v, uintptr pc) { diff --git a/sys/src/9/port/devcons.c b/sys/src/9/port/devcons.c index b09df91f2..7f287610f 100644 --- 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 #include void (*consdebug)(void) = nil; @@ -21,7 +21,6 @@ int panicking; 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 @@ consread(Chan *c, void *buf, long n, vlong off) "%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 @@ consread(Chan *c, void *buf, long n, vlong off) (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,31 +848,22 @@ Dev consdevtab = { static ulong randn; -static void -seedrand(void) +int +rand(void) { - if(!waserror()){ + if(randn == 0) randomread((void*)&randn, sizeof(randn)); - poperror(); - } + randn = randn*1103515245 + 12345 + MACHP(0)->ticks; + return randn; } int nrand(int n) { - if(randn == 0) - seedrand(); - randn = randn*1103515245 + 12345 + MACHP(0)->ticks; + rand(); return (randn>>16) % n; } -int -rand(void) -{ - nrand(1); - return randn; -} - static uvlong uvorder = 0x0001020304050607ULL; static uchar* diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c index 49340adbb..9f9b9380b 100644 --- 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 + enum { Qdir, @@ -789,7 +791,7 @@ procread(Chan *c, void *va, long n, vlong off) 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 */ diff --git a/sys/src/9/port/devsdp.c b/sys/src/9/port/devsdp.c index 2be928d66..6443212e4 100644 --- a/sys/src/9/port/devsdp.c +++ b/sys/src/9/port/devsdp.c @@ -1056,10 +1056,8 @@ onewaycleanup(OneWay *ow) { 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 @@ cipherfree(Conv *c) 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 @@ descipherinit(Conv *c) 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 @@ descipherinit(Conv *c) 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 @@ rc4cipherinit(Conv *c) 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 @@ rc4cipherinit(Conv *c) 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 @@ md5auth(OneWay *ow, uchar *t, int tlen) 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,14 +2206,14 @@ md5authinit(Conv *c) 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; 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; diff --git a/sys/src/9/port/devssl.c b/sys/src/9/port/devssl.c index 32b207618..ef3cd6fb6 100644 --- a/sys/src/9/port/devssl.c +++ b/sys/src/9/port/devssl.c @@ -373,14 +373,10 @@ sslclose(Chan *c) 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 @@ sslput(Dstate *s, Block * volatile b) 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 @@ setsecret(OneWay *w, uchar *secret, int n) 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 @@ initDESkey_40(OneWay *w) { 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 @@ initDESkey_40(OneWay *w) 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 @@ initRC4key(OneWay *w) 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 @@ initRC4key_40(OneWay *w) 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 @@ sslwrite(Chan *c, void *a, long n, vlong) 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(); diff --git a/sys/src/9/port/devtls.c b/sys/src/9/port/devtls.c index 81f50d3a6..3f864a7fc 100644 --- a/sys/src/9/port/devtls.c +++ b/sys/src/9/port/devtls.c @@ -1471,7 +1471,7 @@ struct Encalg 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 @@ initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *) 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 @@ initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv) 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 @@ initAESkey(Encalg *ea, Secret *s, uchar *p, uchar *iv) 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 @@ initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv) 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 @@ tlswrite(Chan *c, void *a, long n, vlong off) 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 @@ tlswrite(Chan *c, void *a, long n, vlong off) 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 @@ tlsstate(int s) 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 @@ ccpoly_aead_setiv(Secret *sec, uchar seq[8]) iv[i+(ChachaIVlen-8)] ^= seq[i]; chacha_setiv(cs, iv); + + memset(iv, 0, sizeof(iv)); } static int @@ -2196,6 +2192,7 @@ aesgcm_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, 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 @@ aesgcm_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, 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; diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 4b639c3a1..6f84fc691 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -126,6 +126,7 @@ void gotolabel(Label*); 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 sched(void); 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); diff --git a/sys/src/9/port/random.c b/sys/src/9/port/random.c index f578d68cc..012424aa6 100644 --- 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 + +/* 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; } diff --git a/sys/src/libc/port/pool.c b/sys/src/libc/port/pool.c index 25ad52c57..546d5776a 100644 --- a/sys/src/libc/port/pool.c +++ b/sys/src/libc/port/pool.c @@ -1332,6 +1332,19 @@ poolmsize(Pool *p, void *v) 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 */