ref: 60b1a2f82dc96b254d6dec1bfd1c14ca056c21dd
parent: bd43bd6f1ae1b1ec7ee6873d9fd6766b049802e9
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Apr 8 16:30:47 EDT 2023
kernel: Clear secrets on reboot The idea is that when we reboot, we zero out memory written by processes that have the private flag set (such as factotum and keyfs), and also clear the secrmem pool, which contains TLS keys and the state of the random number generator. This is so the newly booted kernel or firmware will not find these secret keys in memory.
--- a/sys/src/9/bcm/main.c
+++ b/sys/src/9/bcm/main.c
@@ -281,9 +281,14 @@
{
cpushutdown();
splfhi();
- if(m->machno == 0)
- archreboot();
- rebootjump(0, 0, 0);
+ if(m->machno)
+ rebootjump(0, 0, 0);
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
+ archreboot();
}
/*
@@ -322,6 +327,10 @@
/* stop the clock (and watchdog if any) */
clockshutdown();
wdogoff();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* off we go - never to return */
rebootjump(entry, code, size);
--- a/sys/src/9/bcm64/main.c
+++ b/sys/src/9/bcm64/main.c
@@ -230,9 +230,15 @@
{
cpushutdown();
splfhi();
- if(m->machno == 0)
- archreboot();
- rebootjump(0, 0, 0);
+
+ if(m->machno)
+ rebootjump(0, 0, 0);
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
+ archreboot();
}
void
@@ -239,11 +245,11 @@
reboot(void *entry, void *code, ulong size)
{
writeconf();
+
while(m->machno != 0){
procwired(up, 0);
sched();
}
-
cpushutdown();
delay(2000);
@@ -259,6 +265,10 @@
clockshutdown();
wdogoff();
intrsoff();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* off we go - never to return */
rebootjump(entry, code, size);
--- a/sys/src/9/cycv/main.c
+++ b/sys/src/9/cycv/main.c
@@ -20,6 +20,12 @@
exit(int)
{
cpushutdown();
+ splhi();
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+ }
for(;;) idlehands();
}
--- a/sys/src/9/imx8/main.c
+++ b/sys/src/9/imx8/main.c
@@ -357,8 +357,13 @@
cpushutdown();
splfhi();
- if(m->machno == 0)
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
u.r0 = 0x84000009; /* SYSTEM RESET */
+ }
smccall(&u);
}
@@ -407,6 +412,10 @@
/* stop the clock */
clockshutdown();
intrsoff();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* off we go - never to return */
rebootjump((void*)(KTZERO-KZERO), code, size);
--- a/sys/src/9/kw/main.c
+++ b/sys/src/9/kw/main.c
@@ -308,6 +308,13 @@
{
cpushutdown();
splhi();
+
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+ }
+
archreboot();
}
@@ -333,6 +340,10 @@
clockshutdown();
splhi();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* setup reboot trampoline function */
f = (void*)REBOOTADDR;
--- a/sys/src/9/mt7688/main.c
+++ b/sys/src/9/mt7688/main.c
@@ -247,10 +247,14 @@
void
exit(int)
{
- iprint("main exit called\n");
- delay(50);
cpushutdown();
splhi();
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+ }
+ for(;;);
}
void
--- a/sys/src/9/omap/main.c
+++ b/sys/src/9/omap/main.c
@@ -253,6 +253,11 @@
{
cpushutdown();
splhi();
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+ }
archreboot();
}
@@ -318,6 +323,10 @@
splhi();
intrsoff();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* setup reboot trampoline function */
f = (void*)REBOOTADDR;
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -316,7 +316,6 @@
void (*f)(uintptr, uintptr, ulong);
ulong *pdb;
- splhi();
arch->introff();
/*
@@ -342,8 +341,15 @@
exit(int)
{
cpushutdown();
+ splhi();
+
if(m->machno)
rebootjump(0, 0, 0);
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
arch->reset();
}
@@ -359,7 +365,7 @@
* because the hardware has a notion of which processor was the
* boot processor and we look at it at start up.
*/
- if (m->machno != 0) {
+ if(m->machno){
procwired(up, 0);
sched();
}
@@ -372,6 +378,10 @@
/* shutdown devices */
chandevshutdown();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* disable pci devices */
pcireset();
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -225,7 +225,6 @@
void (*f)(uintptr, uintptr, ulong);
uintptr *pte;
- splhi();
arch->introff();
/*
@@ -252,13 +251,19 @@
for(;;);
}
-
void
exit(int)
{
cpushutdown();
+ splhi();
+
if(m->machno)
rebootjump(0, 0, 0);
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
arch->reset();
}
@@ -274,7 +279,7 @@
* because the hardware has a notion of which processor was the
* boot processor and we look at it at start up.
*/
- if (m->machno != 0) {
+ while(m->machno != 0){
procwired(up, 0);
sched();
}
@@ -287,6 +292,10 @@
/* shutdown devices */
chandevshutdown();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* disable pci devices */
pcireset();
--- a/sys/src/9/port/alloc.c
+++ b/sys/src/9/port/alloc.c
@@ -171,7 +171,7 @@
/* non tracing
*
enum {
- Npadlong = 0,
+ Npadlong = 0,
MallocOffset = 0,
ReallocOffset = 0,
};
@@ -180,7 +180,7 @@
/* tracing */
enum {
- Npadlong = 2,
+ Npadlong = 2,
MallocOffset = 0,
ReallocOffset = 1
};
@@ -228,12 +228,14 @@
void *v;
v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
- if(Npadlong && v != nil){
+ if(v == nil)
+ return nil;
+ if(Npadlong){
v = (ulong*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
setrealloctag(v, 0);
}
- if(clr && v != nil)
+ if(clr)
memset(v, 0, size);
return v;
}
@@ -244,13 +246,14 @@
void *v;
v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
- if(Npadlong && v != nil){
+ if(v == nil)
+ return nil;
+ if(Npadlong){
v = (ulong*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
setrealloctag(v, 0);
}
- if(v)
- memset(v, 0, size);
+ memset(v, 0, size);
return v;
}
@@ -268,10 +271,10 @@
if(v != nil)
v = (ulong*)v-Npadlong;
- if(Npadlong !=0 && size != 0)
+ if(Npadlong && size != 0)
size += Npadlong*sizeof(ulong);
-
- if(nv = poolrealloc(mainmem, v, size)){
+ nv = poolrealloc(mainmem, v, size);
+ if(nv != nil){
nv = (ulong*)nv+Npadlong;
setrealloctag(nv, getcallerpc(&v));
if(v == nil)
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -1474,6 +1474,14 @@
break;
case CMprivate:
p->privatemem = 1;
+ /*
+ * pages will now get marked private
+ * when faulted in for writing
+ * so force a tlb flush.
+ */
+ p->newtlb = 1;
+ if(p == up)
+ flushmmu();
break;
case CMprofile:
s = p->seg[TSEG];
--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -467,7 +467,6 @@
static Segment*
fixedseg(uintptr va, ulong len)
{
- KMap *k;
Segment *s;
Page **f, *p, *l, *h, *t;
ulong n, i;
@@ -522,15 +521,11 @@
p++;
p->ref = 1;
p->va = va;
+ va += BY2PG;
p->modref = 0;
settxtflush(p, 1);
-
- k = kmap(p);
- memset((void*)VA(k), 0, BY2PG);
- kunmap(k);
-
+ zeropage(p);
segpage(s, p);
- va += BY2PG;
} while(p != l);
poperror();
return s;
--- a/sys/src/9/port/devswap.c
+++ b/sys/src/9/port/devswap.c
@@ -245,7 +245,7 @@
continue;
for(pg = l->first; pg <= l->last; pg++) {
entry = *pg;
- if(pagedout(entry))
+ if(pagedout(entry) || entry->modref & PG_PRIV)
continue;
if(entry->modref & PG_REF) {
entry->modref &= ~PG_REF;
--- a/sys/src/9/port/edf.c
+++ b/sys/src/9/port/edf.c
@@ -134,7 +134,6 @@
deadlineintr(Ureg*, Timer *t)
{
/* Proc reached deadline */
- extern int panicking;
Proc *p;
void (*pt)(Proc*, int, vlong);
@@ -210,7 +209,6 @@
releaseintr(Ureg *u, Timer *t)
{
Proc *p;
- extern int panicking;
Schedq *rq;
if(panicking || active.exiting)
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -209,12 +209,12 @@
/* wet floor */
case SG_STICKY: /* Never paged out */
mmuphys = PPN((*pg)->pa) | PTEWRITE | PTECACHED | PTEVALID;
- (*pg)->modref = PG_MOD|PG_REF;
+ (*pg)->modref |= up->privatemem? PG_PRIV|PG_MOD|PG_REF: PG_MOD|PG_REF;
break;
case SG_FIXED: /* Never paged out */
mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEUNCACHED | PTEVALID;
- (*pg)->modref = PG_MOD|PG_REF;
+ (*pg)->modref |= up->privatemem? PG_PRIV|PG_MOD|PG_REF: PG_MOD|PG_REF;
break;
}
--- a/sys/src/9/port/page.c
+++ b/sys/src/9/port/page.c
@@ -169,7 +169,6 @@
newpage(int clear, Segment **s, uintptr va)
{
Page *p, **l;
- KMap *k;
int color;
lock(&palloc);
@@ -229,11 +228,8 @@
p->modref = 0;
inittxtflush(p);
- if(clear) {
- k = kmap(p);
- memset((void*)VA(k), 0, BY2PG);
- kunmap(k);
- }
+ if(clear)
+ zeropage(p);
return p;
}
@@ -266,6 +262,16 @@
}
void
+zeropage(Page *p)
+{
+ KMap *k;
+
+ k = kmap(p);
+ memset((void*)VA(k), 0, BY2PG);
+ kunmap(k);
+}
+
+void
cachepage(Page *p, Image *i)
{
Page **h;
@@ -391,4 +397,30 @@
pg++;
}
free(p);
+}
+
+void
+zeroprivatepages(void)
+{
+ Page *p, *pe;
+
+ /*
+ * in case of a panic, we might not have a process
+ * context to do the clearing of the private pages.
+ */
+ if(up == nil){
+ assert(panicking);
+ return;
+ }
+
+ lock(&palloc);
+ pe = palloc.pages + palloc.user;
+ for(p = palloc.pages; p != pe; p++) {
+ if(p->modref & PG_PRIV){
+ incref(p);
+ zeropage(p);
+ decref(p);
+ }
+ }
+ unlock(&palloc);
}
--- a/sys/src/9/port/portclock.c
+++ b/sys/src/9/port/portclock.c
@@ -164,7 +164,7 @@
return;
if(active.exiting)
- exit(0);
+ exit(panicking);
if(m->machno == 0)
checkalarms();
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -322,6 +322,7 @@
{
PG_MOD = 0x01, /* software modified bit */
PG_REF = 0x02, /* software referenced bit */
+ PG_PRIV = 0x04, /* private page */
};
struct Page
@@ -808,6 +809,7 @@
extern Queue* kprintoq;
extern int nsyscall;
extern Palloc palloc;
+extern int panicking;
extern Queue* serialoq;
extern char* statename[];
extern Image swapimage;
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -407,6 +407,8 @@
void* xspanalloc(ulong, int, ulong);
void xsummary(void);
void yield(void);
+void zeropage(Page*);
+void zeroprivatepages(void);
Segment* data2txt(Segment*);
Segment* dupseg(Segment**, int, int);
Segment* newseg(int, uintptr, ulong);
--- a/sys/src/9/port/rebootcmd.c
+++ b/sys/src/9/port/rebootcmd.c
@@ -33,8 +33,18 @@
ulong magic, text, rtext, entry, data, size, align;
uchar *p;
- if(argc == 0)
+ if(argc == 0){
+ /*
+ * call exit() from cpu0, so zeroprivatepages()
+ * has our user process for kmap().
+ */
+ while(m->machno != 0){
+ procwired(up, 0);
+ sched();
+ }
exit(0);
+ return;
+ }
c = namec(argv[0], Aopen, OEXEC, 0);
if(waserror()){
--- a/sys/src/9/port/taslock.c
+++ b/sys/src/9/port/taslock.c
@@ -36,7 +36,6 @@
void
lockloop(Lock *l, uintptr pc)
{
- extern int panicking;
Proc *p;
if(panicking)
--- a/sys/src/9/sgi/main.c
+++ b/sys/src/9/sgi/main.c
@@ -266,6 +266,11 @@
{
cpushutdown();
splhi();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
arcs(0x18); /* reboot */
}
--- a/sys/src/9/teg2/main.c
+++ b/sys/src/9/teg2/main.c
@@ -427,14 +427,19 @@
{
cpushutdown();
splhi();
- if (m->machno == 0)
- archreboot();
- else {
+
+ if(m->machno){
intrcpushutdown();
stopcpu(m->machno);
for (;;)
idlehands();
}
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
+ archreboot();
}
int
@@ -489,7 +494,7 @@
* the boot processor is cpu0. execute this function on it
* so that the new kernel has the same cpu0.
*/
- if (m->machno != 0) {
+ while(m->machno != 0){
procwired(up, 0);
sched();
}
@@ -513,6 +518,10 @@
splhi();
intrshutdown();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
/* setup reboot trampoline function */
f = (void*)REBOOTADDR;
--- a/sys/src/9/xen/main.c
+++ b/sys/src/9/xen/main.c
@@ -380,6 +380,10 @@
/* shutdown devices */
chandevshutdown();
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
/* reboot(0, ...) on Xen causes domU shutdown */
if(entry == 0)
HYPERVISOR_shutdown(0);
@@ -398,5 +402,11 @@
exit(int)
{
cpushutdown();
+ splhi();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
arch->reset();
}
--- a/sys/src/9/zynq/main.c
+++ b/sys/src/9/zynq/main.c
@@ -20,6 +20,12 @@
exit(int)
{
cpushutdown();
+ splhi();
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+ }
for(;;) idlehands();
}