code: plan9front

Download patch

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();
 }