git: 9front

Download patch

ref: ccf13d8bc560f4acd4a2028c952e07f001555ecf
parent: 8c9105b655dc3913c04334e9e750894f03502f72
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Aug 27 16:33:03 EDT 2016

kernel: add secalloc() and secfree() functions for secret memory allocation

The kernel needs to keep cryptographic keys and cipher states
confidential. secalloc() allocates memory from the secret pool
which is protected from debuggers reading the memory thru devproc.
secfree() releases the memory, overriding the data with garbage.

--- 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/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/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -308,6 +308,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);
--