shithub: riscv

Download patch

ref: 0f97eb3a609cd892a0de1d61ef61e5b48be082d8
parent: 8a73650874a68575fb7b93a44f3bba352c50288a
author: cinap_lenrek <[email protected]>
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);