socsvn commit: r272131 - in soc2014/op/freebsd-base/sys: kern sys

op at FreeBSD.org op at FreeBSD.org
Sat Aug 9 15:33:13 UTC 2014


Author: op
Date: Sat Aug  9 15:33:11 2014
New Revision: 272131
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=272131

Log:
  KSP: check securelevel before do anything
  
  Signed-off-by: Oliver Pinter <oliver.pntr at gmail.com>
  
  git: https://github.com/opntr/opBSD/tree/op/gsoc2014/smap+kpatch

Modified:
  soc2014/op/freebsd-base/sys/kern/kern_linker.c
  soc2014/op/freebsd-base/sys/kern/kern_selfpatch.c
  soc2014/op/freebsd-base/sys/sys/selfpatch.h

Modified: soc2014/op/freebsd-base/sys/kern/kern_linker.c
==============================================================================
--- soc2014/op/freebsd-base/sys/kern/kern_linker.c	Sat Aug  9 15:33:02 2014	(r272130)
+++ soc2014/op/freebsd-base/sys/kern/kern_linker.c	Sat Aug  9 15:33:11 2014	(r272131)
@@ -421,7 +421,11 @@
 				return (error);
 			}
 			modules = !TAILQ_EMPTY(&lf->modules);
-			lf_selfpatch(lf, KSP_MODULE);
+			error = lf_selfpatch(lf, KSP_MODULE);
+			if (error != 0) {
+				linker_file_unload(lf, LINKER_UNLOAD_FORCE);
+				return (error);
+			}
 			linker_file_register_sysctls(lf);
 			linker_file_sysinit(lf);
 			lf->flags |= LINKER_FILE_LINKED;
@@ -1611,7 +1615,12 @@
 		}
 		linker_file_register_modules(lf);
 		/* XXXOP */
-		lf_selfpatch(lf, KSP_MODULE);
+		error = lf_selfpatch(lf, KSP_MODULE);
+		if (error != 0) {
+			printf("KLD file %s - could not selfpatching\n",
+			    lf->filename);
+			goto fail;
+		}
 		if (linker_file_lookup_set(lf, "sysinit_set", &si_start,
 		    &si_stop, NULL) == 0)
 			sysinit_add(si_start, si_stop);

Modified: soc2014/op/freebsd-base/sys/kern/kern_selfpatch.c
==============================================================================
--- soc2014/op/freebsd-base/sys/kern/kern_selfpatch.c	Sat Aug  9 15:33:02 2014	(r272130)
+++ soc2014/op/freebsd-base/sys/kern/kern_selfpatch.c	Sat Aug  9 15:33:11 2014	(r272131)
@@ -36,6 +36,7 @@
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 
+#include <sys/jail.h>
 #include <sys/linker.h>
 #include <sys/linker_set.h>
 #include <sys/selfpatch.h>
@@ -115,7 +116,7 @@
 	return (false);
 }
 
-void
+int
 lf_selfpatch(linker_file_t lf, int mod)
 {
 	struct lf_selfpatch *patch, *start, *stop;
@@ -128,7 +129,7 @@
 		ret = linker_file_lookup_set(lf, "selfpatch_set", &start, &stop, NULL);
 		if (ret != 0) {
 			DBG("failed to locate selfpatch_set\n");
-			return;
+			return (0);
 		}
 		DBG("start: %p stop: %p\n", start, stop);
 	} else {
@@ -143,25 +144,36 @@
 
 	for (patch = start; patch != stop; patch++) {
 		DBG("apply: %p\n", patch);
-		if (mod == KSP_MODULE)
-			lf_selfpatch_apply_module(lf, patch);
-		else
-			lf_selfpatch_apply(lf, patch);
+		if (mod == KSP_MODULE) {
+			ret = lf_selfpatch_apply_module(lf, patch);
+			if (ret != 0)
+				return (ret);
+		} else {
+			ret = lf_selfpatch_apply(lf, patch);
+			if (ret != 0)
+				return (ret);
+		}
 	}
 
 	/*
 	 * when selfpatch does not works, the system should crash
 	 */
 	lf_selfpatch_selftest();
+
+	return (0);
 }
 
-void
+int
 lf_selfpatch_apply(linker_file_t lf, struct lf_selfpatch *p)
 {
 	vm_paddr_t pages[4];
 	vm_offset_t page_offset;
 	int i, page_number;
 
+	/* Refuse to patch if securelevel raised */
+	if (prison0.pr_securelevel > 0)
+		return (EPERM);
+
 	DBG("patchable: %p\n", p->patchable);
 	DBG("patch: %p\n", p->patch);
 	DBG("feature selector: %d\n", p->feature_selector);
@@ -173,7 +185,7 @@
 	if (!lf_selfpatch_patch_needed(p)) {
 		DBG("not needed.\n");
 
-		return;
+		return (0);
 	}
 
 	if (p->patch_size != p->patchable_size)
@@ -212,12 +224,18 @@
 		pmap_kenter_attr(kva, pages[i], VM_PROT_READ | VM_PROT_EXECUTE);
 	}
 	DBG("done.\n");
+
+	return (0);
 }
 
-void
+int
 lf_selfpatch_apply_module(linker_file_t lf, struct lf_selfpatch *p)
 {
 
+	/* Refuse to patch if securelevel raised */
+	if (prison0.pr_securelevel > 0)
+		return (EPERM);
+
 	DBG("patchable: %p\n", p->patchable);
 	DBG("patch: %p\n", p->patch);
 	DBG("feature selector: %d\n", p->feature_selector);
@@ -229,7 +247,7 @@
 	if (!lf_selfpatch_patch_needed(p)) {
 		DBG("not needed.\n");
 
-		return;
+		return (0);
 	}
 
 	if (p->patch_size != p->patchable_size)
@@ -238,6 +256,8 @@
 	memcpy(p->patchable, p->patch, p->patchable_size);
 
 	DBG("patched.\n");
+
+	return (0);
 }
 
 __noinline void

Modified: soc2014/op/freebsd-base/sys/sys/selfpatch.h
==============================================================================
--- soc2014/op/freebsd-base/sys/sys/selfpatch.h	Sat Aug  9 15:33:02 2014	(r272130)
+++ soc2014/op/freebsd-base/sys/sys/selfpatch.h	Sat Aug  9 15:33:11 2014	(r272131)
@@ -52,8 +52,8 @@
 
 extern char *selfpatch_nop_table[];
 
-void lf_selfpatch(linker_file_t lf, int mod);
-void lf_selfpatch_apply(linker_file_t lf, struct lf_selfpatch *patch);
-void lf_selfpatch_apply_module(linker_file_t lf, struct lf_selfpatch *patch);
+int lf_selfpatch(linker_file_t lf, int mod);
+int lf_selfpatch_apply(linker_file_t lf, struct lf_selfpatch *patch);
+int lf_selfpatch_apply_module(linker_file_t lf, struct lf_selfpatch *patch);
 
 #endif /* __SELFPATH_H__ */


More information about the svn-soc-all mailing list