socsvn commit: r240240 - in soc2012/gpf: pefs_head/head/sys/kern pefs_head/head/sys/security/mac pefs_head/head/sys/vm pefs_kmod/sys/fs/pefs

gpf at FreeBSD.org gpf at FreeBSD.org
Fri Aug 10 12:41:53 UTC 2012


Author: gpf
Date: Fri Aug 10 12:41:51 2012
New Revision: 240240
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=240240

Log:
  -introduce new MAC hook mac_vnode_check_exec_noscript() that will not be
  called for scripts; only for regular executables and interpreters.
  
  -use mac_vnode_check_mmap() to see if there's an attempt to mmap a vnode with
  the PROT_EXEC flag turned on.
  
  -introduce new MAC hook mac_vnode_set_mmap_maxprot() in an attempt to control
  mprotect(2) attempts with the PROT_EXEC flag.
  
  Please refer to the large comment headers that can be found in
  pefs_kmod/sys/fs/pefs/pefs_mac.c for a more thorough and up to date
  explanation of this svn commit.
  

Modified:
  soc2012/gpf/pefs_head/head/sys/kern/kern_exec.c
  soc2012/gpf/pefs_head/head/sys/security/mac/mac_framework.h
  soc2012/gpf/pefs_head/head/sys/security/mac/mac_policy.h
  soc2012/gpf/pefs_head/head/sys/security/mac/mac_vfs.c
  soc2012/gpf/pefs_head/head/sys/vm/vm_mmap.c
  soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_mac.c

Modified: soc2012/gpf/pefs_head/head/sys/kern/kern_exec.c
==============================================================================
--- soc2012/gpf/pefs_head/head/sys/kern/kern_exec.c	Fri Aug 10 11:11:04 2012	(r240239)
+++ soc2012/gpf/pefs_head/head/sys/kern/kern_exec.c	Fri Aug 10 12:41:51 2012	(r240240)
@@ -548,21 +548,11 @@
 		goto interpret;
 	}
 
-	//{
-		///* XXXgpf: [TODO] place this in a MAC hook */
-		//int enabled, rval;
-		//size_t enabled_len;
-
-		//rval = kernel_sysctlbyname(td, "vfs.pefs.exec.enable",
-					//&enabled, &enabled_len, NULL, 0, NULL, 0);
-
-		//if (rval == 0 && enabled != 0) {
-			//if ((imgp->attr->va_flags & SF_IMMUTABLE) == 0) {
-				//error = EPERM;
-				//goto exec_fail_dealloc;
-			//}
-		//}
-	//}
+#ifdef MAC
+	error = mac_vnode_check_exec_noscript(td->td_ucred, imgp->vp, imgp);
+	if (error)
+		goto exec_fail_dealloc;
+#endif
 
 	/*
 	 * NB: We unlock the vnode here because it is believed that none

Modified: soc2012/gpf/pefs_head/head/sys/security/mac/mac_framework.h
==============================================================================
--- soc2012/gpf/pefs_head/head/sys/security/mac/mac_framework.h	Fri Aug 10 11:11:04 2012	(r240239)
+++ soc2012/gpf/pefs_head/head/sys/security/mac/mac_framework.h	Fri Aug 10 12:41:51 2012	(r240240)
@@ -91,6 +91,7 @@
 
 #include <sys/acl.h>			/* XXX acl_type_t */
 #include <sys/types.h>			/* accmode_t */
+#include <vm/vm.h>				/* XXX vm_prot_t */
 
 /*
  * Entry points to the TrustedBSD MAC Framework from the remainder of the
@@ -383,6 +384,8 @@
 	    int attrnamespace, const char *name);
 int	mac_vnode_check_exec(struct ucred *cred, struct vnode *vp,
 	    struct image_params *imgp);
+int	mac_vnode_check_exec_noscript(struct ucred *cred, struct vnode *vp,
+	    struct image_params *imgp);
 int	mac_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
 	    acl_type_t type);
 int	mac_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
@@ -395,6 +398,8 @@
  	    struct componentname *cnp);
 int	mac_vnode_check_mmap(struct ucred *cred, struct vnode *vp, int prot,
 	    int flags);
+void mac_vnode_set_mmap_maxprot(struct ucred *cred, struct vnode *vp,
+		vm_prot_t *maxprotp, int flags);
 int	mac_vnode_check_mprotect(struct ucred *cred, struct vnode *vp,
 	    int prot);
 int	mac_vnode_check_open(struct ucred *cred, struct vnode *vp,

Modified: soc2012/gpf/pefs_head/head/sys/security/mac/mac_policy.h
==============================================================================
--- soc2012/gpf/pefs_head/head/sys/security/mac/mac_policy.h	Fri Aug 10 11:11:04 2012	(r240239)
+++ soc2012/gpf/pefs_head/head/sys/security/mac/mac_policy.h	Fri Aug 10 12:41:51 2012	(r240240)
@@ -65,6 +65,7 @@
  */
 #include <sys/acl.h>	/* XXX acl_type_t */
 #include <sys/types.h>	/* XXX accmode_t */
+#include <vm/vm.h>		/* XXX vm_prot_t */
 
 struct acl;
 struct auditinfo;
@@ -566,6 +567,9 @@
 typedef int	(*mpo_vnode_check_exec_t)(struct ucred *cred,
 		    struct vnode *vp, struct label *vplabel,
 		    struct image_params *imgp, struct label *execlabel);
+typedef int	(*mpo_vnode_check_exec_noscript_t)(struct ucred *cred,
+		    struct vnode *vp, struct label *vplabel,
+		    struct image_params *imgp, struct label *execlabel);
 typedef int	(*mpo_vnode_check_getacl_t)(struct ucred *cred,
 		    struct vnode *vp, struct label *vplabel,
 		    acl_type_t type);
@@ -585,6 +589,9 @@
 typedef int	(*mpo_vnode_check_mmap_t)(struct ucred *cred,
 		    struct vnode *vp, struct label *label, int prot,
 		    int flags);
+typedef void	(*mpo_vnode_set_mmap_maxprot_t)(struct ucred *cred,
+		    struct vnode *vp, struct label *label, vm_prot_t *maxprotp,
+		    int flags);
 typedef void	(*mpo_vnode_check_mmap_downgrade_t)(struct ucred *cred,
 		    struct vnode *vp, struct label *vplabel, int *prot);
 typedef int	(*mpo_vnode_check_mprotect_t)(struct ucred *cred,
@@ -922,12 +929,14 @@
 	mpo_vnode_check_deleteacl_t		mpo_vnode_check_deleteacl;
 	mpo_vnode_check_deleteextattr_t		mpo_vnode_check_deleteextattr;
 	mpo_vnode_check_exec_t			mpo_vnode_check_exec;
+	mpo_vnode_check_exec_noscript_t		mpo_vnode_check_exec_noscript;
 	mpo_vnode_check_getacl_t		mpo_vnode_check_getacl;
 	mpo_vnode_check_getextattr_t		mpo_vnode_check_getextattr;
 	mpo_vnode_check_link_t			mpo_vnode_check_link;
 	mpo_vnode_check_listextattr_t		mpo_vnode_check_listextattr;
 	mpo_vnode_check_lookup_t		mpo_vnode_check_lookup;
 	mpo_vnode_check_mmap_t			mpo_vnode_check_mmap;
+	mpo_vnode_set_mmap_maxprot_t	mpo_vnode_set_mmap_maxprot;
 	mpo_vnode_check_mmap_downgrade_t	mpo_vnode_check_mmap_downgrade;
 	mpo_vnode_check_mprotect_t		mpo_vnode_check_mprotect;
 	mpo_vnode_check_open_t			mpo_vnode_check_open;

Modified: soc2012/gpf/pefs_head/head/sys/security/mac/mac_vfs.c
==============================================================================
--- soc2012/gpf/pefs_head/head/sys/security/mac/mac_vfs.c	Fri Aug 10 11:11:04 2012	(r240239)
+++ soc2012/gpf/pefs_head/head/sys/security/mac/mac_vfs.c	Fri Aug 10 12:41:51 2012	(r240240)
@@ -489,6 +489,24 @@
 	return (error);
 }
 
+MAC_CHECK_PROBE_DEFINE3(vnode_check_exec_noscript, "struct ucred *",
+	"struct vnode *", "struct image_params *");
+
+int
+mac_vnode_check_exec_noscript(struct ucred *cred, struct vnode *vp,
+    struct image_params *imgp)
+{
+	int error;
+
+	ASSERT_VOP_LOCKED(vp, "mac_vnode_check_exec_noscript");
+
+	MAC_POLICY_CHECK(vnode_check_exec_noscript, cred, vp, vp->v_label, imgp,
+	    imgp->execlabel);
+	MAC_CHECK_PROBE3(vnode_check_exec_noscript, error, cred, vp, imgp);
+
+	return (error);
+}
+
 MAC_CHECK_PROBE_DEFINE3(vnode_check_getacl, "struct ucred *",
     "struct vnode *", "acl_type_t");
 
@@ -597,6 +615,17 @@
 }
 
 void
+mac_vnode_set_mmap_maxprot(struct ucred *cred, struct vnode *vp,
+	vm_prot_t *maxprotp, int flags)
+{
+
+	ASSERT_VOP_LOCKED(vp, "mac_vnode_set_mmap_maxprot");
+
+	MAC_POLICY_PERFORM(vnode_set_mmap_maxprot, cred, vp, vp->v_label,
+		maxprotp, flags);
+}
+
+void
 mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
     int *prot)
 {

Modified: soc2012/gpf/pefs_head/head/sys/vm/vm_mmap.c
==============================================================================
--- soc2012/gpf/pefs_head/head/sys/vm/vm_mmap.c	Fri Aug 10 11:11:04 2012	(r240239)
+++ soc2012/gpf/pefs_head/head/sys/vm/vm_mmap.c	Fri Aug 10 12:41:51 2012	(r240240)
@@ -1295,6 +1295,7 @@
 	error = mac_vnode_check_mmap(cred, vp, prot, flags);
 	if (error != 0)
 		goto done;
+	mac_vnode_set_mmap_maxprot(cred, vp, maxprotp, flags);
 #endif
 	if ((flags & MAP_SHARED) != 0) {
 		if ((va.va_flags & (SF_SNAPSHOT|IMMUTABLE|APPEND)) != 0) {

Modified: soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_mac.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_mac.c	Fri Aug 10 11:11:04 2012	(r240239)
+++ soc2012/gpf/pefs_kmod/sys/fs/pefs/pefs_mac.c	Fri Aug 10 12:41:51 2012	(r240240)
@@ -33,6 +33,7 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/dirent.h>
+#include <sys/mman.h>
 #include <sys/module.h>
 #include <sys/mount.h>
 #include <sys/sysctl.h>
@@ -40,6 +41,8 @@
 #include <sys/vnode.h>
 #include <sys/imgact.h>
 
+#include <vm/vm.h>
+
 #include <fs/pefs/pefs.h>
 
 #include <security/mac/mac_policy.h>
@@ -49,24 +52,24 @@
  * The problem with this MAC hook is that the hook is called before
  * do_execve() checks if our executable requires an interpreter.
  * Therefore, the script file will itself be checked for the schg flag.
- * 
+ *
  * We could:
- * 
+ *
  * a) allow this because it's a feature! During development of a script,
- * user will have to pass it as an argument to the interpreter and when it's 
+ * user will have to pass it as an argument to the interpreter and when it's
  * complete, continue calling it like that or add the schg flag.
- * 
+ *
  * b) add a brand new MAC hook that will be called at the precise point
- * in do_execve() where only the interpreter or the regular executable 
+ * in do_execve() where only the interpreter or the regular executable
  * will be checked for the schg flag. [don't seem the other devs will go
  * for us modifying MAC framework though]
- * 
- * c) duplicate code from do_execve() and perform the check ourselves. It 
+ *
+ * c) duplicate code from do_execve() and perform the check ourselves. It
  * could be done I guess but I'm not sure since image activators seem to have
  * their own custom functions that are called in order to figure out whether
  * the interpreted flag should be turned on. Don't know how much they are
  * allowed to tamper with imgp, besides that flag.
- * 
+ *
  */
 static int
 pefs_vnode_check_exec(struct ucred *cred, struct vnode *vp,
@@ -88,18 +91,128 @@
 	return (0);
 }
 
+/*
+ * XXXgpf:
+ *
+ * This new hook is placed in do_execve(), found in sys/kern/kern_exec.c.
+ * Its purpose is to only check the interpreter for the schg flag in case
+ * there's an executable that requires an interpreter.
+ *
+ * It is placed after exec_check_permissions() and it will be called after
+ * we've looped back for the interpreter. Therefore, only either the interpeter
+ * or the regular executable itself will ever be checked by this hook; we'll
+ * never check the script file itself.
+ *
+ * It uses a different dbg sysctl var than the above hook for obvious reasons.
+ */
+static int
+pefs_vnode_check_exec_noscript(struct ucred *cred, struct vnode *vp,
+	struct label *vplabel, struct image_params *imgp,
+	struct label *execlabel)
+{
+	int enabled, rval;
+	size_t enabled_len;
+
+	rval = kernel_sysctlbyname(curthread, "vfs.pefs.exec.enable_noscript",
+				&enabled, &enabled_len, NULL, 0, NULL, 0);
+
+	if (rval == 0 && enabled != 0) {
+		if ((imgp->attr->va_flags & SF_IMMUTABLE) == 0)
+			return (EPERM);
+	}
+
+	return (0);
+}
+
+
+/*
+ * XXXgpf: Check if schg is turned on when we mmap() a vnode with
+ * the PROT_EXEC flag.
+ */
+static int
+pefs_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
+	struct label *vplabel, int prot, int flags)
+{
+	struct vattr va;
+	int enabled1, enabled2, error, rval1, rval2;
+	size_t enabled_len;
+
+	if ((prot & PROT_EXEC) == 0)
+		return (0);
+
+	rval1 = kernel_sysctlbyname(curthread, "vfs.pefs.exec.enable",
+				&enabled1, &enabled_len, NULL, 0, NULL, 0);
+
+	rval2 = kernel_sysctlbyname(curthread, "vfs.pefs.exec.enable_noscript",
+				&enabled2, &enabled_len, NULL, 0, NULL, 0);
+
+	if ((rval1 == 0 && enabled1 != 0) || (rval2 == 0 && enabled2 != 0)) {
+		error = VOP_GETATTR(vp, &va, cred);
+		if (error != 0)
+			return (EACCES);
+
+		if ((va.va_flags & SF_IMMUTABLE) == 0)
+			return (EACCES);
+	}
+
+	return (0);
+}
+
+/*
+ * XXXgpf:
+ *
+ * Checking mmap(2) with the above MAC hook is not enough if we wish to
+ * prevent user from mmaping a file and then executing those pages due to
+ * mprotect(2).
+ *
+ * I did notice the existance of mac_vnode_check_mprotect(), but unfortunately
+ * it's not used anywhere in the kernel for some reason(?)! If it ever comes 
+ * back into action, I believe it would be preferable to the following solution.
+ * 
+ * My alternative solution was to set the MAXPROT flag of the mapped area 
+ * during mmap(). If we are mapping a file and we need schg protection, we
+ * remove VM_PROT_EXECUTE from MAXPROT which in turn causes following attempts
+ * to mprotect() with PROT_EXEC to fail.
+ */
+static void
+pefs_vnode_set_mmap_maxprot(struct ucred *cred, struct vnode *vp,
+	struct label *vplabel, vm_prot_t *maxprotp, int flags)
+{
+	int enabled1, enabled2, rval1, rval2;
+	size_t enabled_len;
+
+	if ((*maxprotp & VM_PROT_EXECUTE) == 0)
+		return;
+
+	rval1 = kernel_sysctlbyname(curthread, "vfs.pefs.exec.enable",
+				&enabled1, &enabled_len, NULL, 0, NULL, 0);
+
+	rval2 = kernel_sysctlbyname(curthread, "vfs.pefs.exec.enable_noscript",
+				&enabled2, &enabled_len, NULL, 0, NULL, 0);
+
+	if ((rval1 == 0 && enabled1 != 0) || (rval2 == 0 && enabled2 != 0))
+		*maxprotp &= ~VM_PROT_EXECUTE;
+}
+
 static struct mac_policy_ops pefs_ops =
 {
 	.mpo_vnode_check_exec = pefs_vnode_check_exec,
+	.mpo_vnode_check_exec_noscript = pefs_vnode_check_exec_noscript,
+	.mpo_vnode_check_mmap = pefs_vnode_check_mmap,
+	.mpo_vnode_set_mmap_maxprot = pefs_vnode_set_mmap_maxprot,
 };
 
 MAC_POLICY_SET(&pefs_ops, mac_pefs, "pefs exec protection",
 	MPC_LOADTIME_FLAG_UNLOADOK, NULL);
 
-/* XXXgpf: declare our debugging sysctl for kern_exec.c */
+/* XXXgpf: declare our debugging sysctls for schg execution control */
 SYSCTL_NODE(_vfs_pefs, OID_AUTO, exec, CTLFLAG_RW, 0,
 		"PEFS kern_exec.c stuff");
 
 int	pefs_exec_enable = 0;
 SYSCTL_INT(_vfs_pefs_exec, OID_AUTO, enable, CTLFLAG_RW,
 		&pefs_exec_enable, 0, "Enable exec protection");
+
+int	pefs_exec_enable_noscript = 0;
+SYSCTL_INT(_vfs_pefs_exec, OID_AUTO, enable_noscript, CTLFLAG_RW,
+		&pefs_exec_enable_noscript, 0, "Enable exec protection [no scripts]");


More information about the svn-soc-all mailing list