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