tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

secmodel_register(9) API



Dear all,

A few weeks back I tried adding a sysctl knob to allow users to control
their CPU affinity. However, while implementing checks to restrict usage
of this sysctl, I hit a limitation regarding secmodel(9): the current
design cannot allow a secmodel to query the state/properties of other
secmodels.

So, when one wants to create sysctls that can only be changed when
securelevel is below a certain level, you end up adding more hooks to
secmodel_securelevel(9)... which is problematic, because the sysctl does
not necessarily belong to this secmodel (consider curtain and suser, as
an exemple).

elad@ contacted me off-list; he noticed this shortcoming a while back and we agreed that the secmodel_register(9) had to be extended to cope with this. So, after a number of mail exchanges, here's a patch.

--- CAUTION -- NOTES ---

All consumers of the secmodel(9) API should now use the secmodel_register(9) API to register a secmodel(9). Otherwise, you can end up with a system without any secmodel registered. Kauth(9) listeners will work as usual, but a DEFER decision with no registered secmodel is equivalent to ALLOW.

--- Explanations ---

This API allows any secmodel(9) to register callbacks that can be used later on for cross-secmodel "safe" communication.

When a secmodel wishes to know a property maintained by another secmodel, it has to submit a request to it so the other secmodel can proceed to evaluating the request. This is done through the secmodel_eval(9) call; example:

error = secmodel_eval("org.netbsd.secmodel.suser", "is-root",
    cred, &isroot, NULL);
if (!error && !isroot)
    result = KAUTH_RESULT_DENY;

This one asks the suser module if the user cred is assumed to be root when evaluated by suser module. If the module is present, it will respond. If absent, the call will return an error.

Args and command are arbitrarily defined; it's up to the secmodel(9) to explain what it expects.

Typical example is securelevel testing: when someone wants to know whether securelevel is raised above a certain level or not, the caller has to request this property to the secmodel_securelevel(9) module. Given that securelevel module may be absent from system's context (thus making access to the global "securelevel" variable impossible or unsafe), this API can cope with this absence and return an error.

We are using it to implement a secmodel_extensions(9) module, which plugs with the bsd44, suser and securelevel secmodels to provide the logic behind curtain, usermount and user_set_cpu_affinity modes, without adding hooks to traditional secmodels. This solves a real issue with the current secmodel(9) code.

Regarding sysctl(7) entries:
curtain and usermount are now found under security.models.extensions tree. The security.curtain and vfs.generic.usermount are still accessible for backwards compat.

The secmodel_eval(9) will also be used in an upcoming patch (with the documentation) to restrict security.models settings when securelevel is above 0.

Written by elad@, reviewed and tested (anita + basic rights tests) by me. ok elad@.

Reviews before merge welcome. If nobody raises his voice, I'll proceed to commit it at the end of the week.

Cheers all,

--
Jean-Yves Migeon
jym%NetBSD.org@localhost
Index: kern/init_main.c
===================================================================
RCS file: /cvsroot/src/sys/kern/init_main.c,v
retrieving revision 1.437
diff -u -p -r1.437 init_main.c
--- kern/init_main.c    19 Nov 2011 22:51:25 -0000      1.437
+++ kern/init_main.c    29 Nov 2011 01:20:12 -0000
@@ -211,6 +211,8 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,
 #include <sys/pax.h>
 #endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */
 
+#include <secmodel/secmodel.h>
+
 #include <ufs/ufs/quota.h>
 
 #include <miscfs/genfs/genfs.h>
@@ -346,6 +348,8 @@ main(void)
        /* Initialize the kernel authorization subsystem. */
        kauth_init();
 
+       secmodel_init();
+
        spec_init();
 
        /*
Index: kern/kern_auth.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_auth.c,v
retrieving revision 1.65
diff -u -p -r1.65 kern_auth.c
--- kern/kern_auth.c    31 Dec 2009 02:20:36 -0000      1.65
+++ kern/kern_auth.c    29 Nov 2011 01:20:12 -0000
@@ -70,11 +70,13 @@ __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,
 #include <sys/specificdata.h>
 #include <sys/vnode.h>
 
+#include <secmodel/secmodel.h>
+
 /*
  * Secmodel-specific credentials.
  */
 struct kauth_key {
-       const char *ks_secmodel;        /* secmodel */
+       secmodel_t ks_secmodel;         /* secmodel */
        specificdata_key_t ks_key;      /* key */
 };
 
@@ -145,8 +147,6 @@ static kauth_scope_t kauth_builtin_scope
 static kauth_scope_t kauth_builtin_scope_cred;
 static kauth_scope_t kauth_builtin_scope_vnode;
 
-static unsigned int nsecmodels = 0;
-
 static specificdata_domain_t kauth_domain;
 static pool_cache_t kauth_cred_cache;
 
@@ -507,7 +507,7 @@ kauth_cred_getgroups(kauth_cred_t cred, 
 }
 
 int
-kauth_register_key(const char *secmodel, kauth_key_t *result)
+kauth_register_key(secmodel_t secmodel, kauth_key_t *result)
 {
        kauth_key_t k;
        specificdata_key_t key;
@@ -993,7 +993,7 @@ kauth_authorize_action(kauth_scope_t sco
        if (r == KAUTH_RESULT_ALLOW)
                return (0);
 
-       if (!nsecmodels)
+       if (secmodel_nsecmodels() == 0)
                return (0);
 
        return (EPERM);
@@ -1141,23 +1141,3 @@ kauth_cred_hook(kauth_cred_t cred, kauth
 
        return (r);
 }
-
-void
-secmodel_register(void)
-{
-       KASSERT(nsecmodels + 1 != 0);
-
-       rw_enter(&kauth_lock, RW_WRITER);
-       nsecmodels++;
-       rw_exit(&kauth_lock);
-}
-
-void
-secmodel_deregister(void)
-{
-       KASSERT(nsecmodels != 0);
-
-       rw_enter(&kauth_lock, RW_WRITER);
-       nsecmodels--;
-       rw_exit(&kauth_lock);
-}
Index: kern/kern_module.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_module.c,v
retrieving revision 1.85
diff -u -p -r1.85 kern_module.c
--- kern/kern_module.c  28 Nov 2011 03:13:31 -0000      1.85
+++ kern/kern_module.c  29 Nov 2011 01:20:13 -0000
@@ -795,8 +795,6 @@ module_do_builtin(const char *name, modu
        if (modp != NULL) {
                *modp = mod;
        }
-       if (mi->mi_class == MODULE_CLASS_SECMODEL)
-               secmodel_register();
        module_enqueue(mod);
        return 0;
 }
@@ -1071,9 +1069,6 @@ module_do_load(const char *name, bool is
                goto fail;
        }
 
-       if (mi->mi_class == MODULE_CLASS_SECMODEL)
-               secmodel_register();
-
        /*
         * Good, the module loaded successfully.  Put it onto the
         * list and add references to its requisite modules.
@@ -1150,8 +1145,6 @@ module_do_unload(const char *name, bool 
                    error);
                return error;
        }
-       if (mod->mod_info->mi_class == MODULE_CLASS_SECMODEL)
-               secmodel_deregister();
        module_count--;
        TAILQ_REMOVE(&module_list, mod, mod_chain);
        for (i = 0; i < mod->mod_nrequired; i++) {
Index: sys/kauth.h
===================================================================
RCS file: /cvsroot/src/sys/sys/kauth.h,v
retrieving revision 1.65
diff -u -p -r1.65 kauth.h
--- sys/kauth.h 23 Nov 2011 10:47:49 -0000      1.65
+++ sys/kauth.h 29 Nov 2011 01:20:13 -0000
@@ -35,6 +35,8 @@
 #ifndef _SYS_KAUTH_H_
 #define        _SYS_KAUTH_H_
 
+#include <secmodel/secmodel.h> /* for secmodel_t type */
+
 struct uucred;
 struct ki_ucred;
 struct ki_pcred;
@@ -402,7 +404,7 @@ int kauth_cred_getgroups(kauth_cred_t, g
 /* This is for sys_setgroups() */
 int kauth_proc_setgroups(struct lwp *, kauth_cred_t);
 
-int kauth_register_key(const char *, kauth_key_t *);
+int kauth_register_key(secmodel_t, kauth_key_t *);
 int kauth_deregister_key(kauth_key_t);
 void kauth_cred_setdata(kauth_cred_t, kauth_key_t, void *);
 void *kauth_cred_getdata(kauth_cred_t, kauth_key_t);
@@ -419,8 +421,4 @@ kauth_action_t kauth_mode_to_action(mode
 kauth_cred_t kauth_cred_get(void);
 
 void kauth_proc_fork(struct proc *, struct proc *);
-
-void secmodel_register(void);
-void secmodel_deregister(void);
-
 #endif /* !_SYS_KAUTH_H_ */
Index: secmodel/files.secmodel
===================================================================
RCS file: /cvsroot/src/sys/secmodel/files.secmodel,v
retrieving revision 1.4
diff -u -p -r1.4 files.secmodel
--- secmodel/files.secmodel     2 Oct 2009 18:50:13 -0000       1.4
+++ secmodel/files.secmodel     29 Nov 2011 01:20:13 -0000
@@ -1,5 +1,7 @@
 # $NetBSD: files.secmodel,v 1.4 2009/10/02 18:50:13 elad Exp $
 
+file   secmodel/secmodel.c
+
 #
 # Traditional 4.4BSD - Superuser ("root" as effective user-id 0)
 #
@@ -11,6 +13,11 @@ include "secmodel/suser/files.suser"
 include "secmodel/securelevel/files.securelevel"
 
 #
+# NetBSD Extensions 
+#
+include "secmodel/extensions/files.extensions"
+
+#
 # Traditional NetBSD (derived from 4.4BSD)
 #
 include        "secmodel/bsd44/files.bsd44"
Index: secmodel/bsd44/files.bsd44
===================================================================
RCS file: /cvsroot/src/sys/secmodel/bsd44/files.bsd44,v
retrieving revision 1.3
diff -u -p -r1.3 files.bsd44
--- secmodel/bsd44/files.bsd44  2 Oct 2009 18:50:13 -0000       1.3
+++ secmodel/bsd44/files.bsd44  29 Nov 2011 01:20:13 -0000
@@ -1,6 +1,6 @@
 # $NetBSD: files.bsd44,v 1.3 2009/10/02 18:50:13 elad Exp $
 
 defflag secmodel_bsd44_logic
-defflag secmodel_bsd44 : secmodel_bsd44_logic, secmodel_suser, 
secmodel_securelevel
+defflag secmodel_bsd44 : secmodel_bsd44_logic, secmodel_suser, 
secmodel_securelevel,secmodel_extensions
 
 file   secmodel/bsd44/secmodel_bsd44.c                 secmodel_bsd44
Index: secmodel/bsd44/secmodel_bsd44.c
===================================================================
RCS file: /cvsroot/src/sys/secmodel/bsd44/secmodel_bsd44.c,v
retrieving revision 1.14
diff -u -p -r1.14 secmodel_bsd44.c
--- secmodel/bsd44/secmodel_bsd44.c     28 Nov 2011 22:28:33 -0000      1.14
+++ secmodel/bsd44/secmodel_bsd44.c     29 Nov 2011 01:20:14 -0000
@@ -41,9 +41,11 @@ __KERNEL_RCSID(0, "$NetBSD: secmodel_bsd
 #include <secmodel/bsd44/bsd44.h>
 #include <secmodel/suser/suser.h>
 #include <secmodel/securelevel/securelevel.h>
+#include <secmodel/extensions/extensions.h>
 
-MODULE(MODULE_CLASS_SECMODEL, secmodel_bsd44, "suser,securelevel");
+MODULE(MODULE_CLASS_SECMODEL, secmodel_bsd44, "suser,securelevel,extensions");
 
+static secmodel_t bsd44_sm;
 static struct sysctllog *sysctl_bsd44_log;
 
 void
@@ -72,7 +74,8 @@ sysctl_security_bsd44_setup(struct sysct
        sysctl_createv(clog, 0, &rnode, NULL,
                       CTLFLAG_PERMANENT,
                       CTLTYPE_STRING, "name", NULL,
-                      NULL, 0, __UNCONST("Traditional NetBSD (derived from 
4.4BSD)"), 0,
+                      NULL, 0,
+                      __UNCONST("Traditional NetBSD (derived from 4.4BSD)"), 0,
                       CTL_CREATE, CTL_EOL);
 }
 
@@ -101,6 +104,14 @@ secmodel_bsd44_modcmd(modcmd_t cmd, void
 
        switch (cmd) {
        case MODULE_CMD_INIT:
+
+               error = secmodel_register(&bsd44_sm,
+                   "org.netbsd.secmodel.bsd44",
+                   "Traditional NetBSD: 4.4BSD", NULL, NULL, NULL);
+               if (error != 0)
+                       printf("secmodel_bsd44_modcmd::init: "
+                           "secmodel_register returned %d\n", error);
+
                secmodel_bsd44_init();
                secmodel_bsd44_start();
                sysctl_security_bsd44_setup(&sysctl_bsd44_log);
@@ -109,6 +120,11 @@ secmodel_bsd44_modcmd(modcmd_t cmd, void
        case MODULE_CMD_FINI:
                sysctl_teardown(&sysctl_bsd44_log);
                secmodel_bsd44_stop();
+
+               error = secmodel_deregister(bsd44_sm);
+               if (error != 0)
+                       printf("secmodel_bsd44_modcmd::fini: "
+                           "secmodel_deregister returned %d\n", error);
                break;
 
        default:
Index: secmodel/keylock/secmodel_keylock.c
===================================================================
RCS file: /cvsroot/src/sys/secmodel/keylock/secmodel_keylock.c,v
retrieving revision 1.5
diff -u -p -r1.5 secmodel_keylock.c
--- secmodel/keylock/secmodel_keylock.c 19 Oct 2009 08:20:21 -0000      1.5
+++ secmodel/keylock/secmodel_keylock.c 29 Nov 2011 01:20:14 -0000
@@ -108,6 +108,12 @@ SYSCTL_SETUP(sysctl_security_keylock_set
 void
 secmodel_keylock_init(void)
 {
+       int error = secmodel_register(&keylock_sm,
+           "org.netbsd.secmodel.keylock",
+           "NetBSD Security Model: Keylock", NULL, NULL, NULL);
+       if (error != 0)
+               printf("secmodel_keylock_init: secmodel_register "
+                   "returned %d\n", error);
 }
 
 void
@@ -128,11 +134,18 @@ secmodel_keylock_start(void)
 void
 secmodel_keylock_stop(void)
 {
+       int error;
+
        kauth_unlisten_scope(l_system);
        kauth_unlisten_scope(l_process);
        kauth_unlisten_scope(l_network);
        kauth_unlisten_scope(l_machdep);
        kauth_unlisten_scope(l_device);
+
+       error = secmodel_deregister(&keylock_sm);
+       if (error != 0)
+               printf("secmodel_keylock_stop: secmodel_deregister "
+                   "returned %d\n", error);
 }
 
 /*
Index: secmodel/overlay/secmodel_overlay.c
===================================================================
RCS file: /cvsroot/src/sys/secmodel/overlay/secmodel_overlay.c,v
retrieving revision 1.11
diff -u -p -r1.11 secmodel_overlay.c
--- secmodel/overlay/secmodel_overlay.c 28 Nov 2011 22:28:34 -0000      1.11
+++ secmodel/overlay/secmodel_overlay.c 29 Nov 2011 01:20:14 -0000
@@ -36,8 +36,9 @@ __KERNEL_RCSID(0, "$NetBSD: secmodel_ove
 
 #include <sys/sysctl.h>
 
-#include <secmodel/overlay/overlay.h>
+#include <secmodel/secmodel.h>
 
+#include <secmodel/overlay/overlay.h>
 #include <secmodel/bsd44/bsd44.h>
 #include <secmodel/suser/suser.h>
 #include <secmodel/securelevel/securelevel.h>
@@ -66,6 +67,7 @@ static kauth_scope_t secmodel_overlay_is
 static kauth_listener_t l_generic, l_system, l_process, l_network, l_machdep,
     l_device, l_vnode;
 
+static secmodel_t overlay_sm;
 static struct sysctllog *sysctl_overlay_log;
 
 /*
@@ -200,6 +202,13 @@ secmodel_overlay_modcmd(modcmd_t cmd, vo
 
        switch (cmd) {
        case MODULE_CMD_INIT:
+               error = secmodel_register(&overlay_sm,
+                   "org.netbsd.secmodel.overlay",
+                   "Overlay security model", NULL, NULL, NULL);
+               if (error != 0)
+                       printf("secmodel_overlay_modcmd::init: "
+                           "secmodel_register returned %d\n", error);
+
                secmodel_overlay_init();
                secmodel_suser_stop();
                secmodel_securelevel_stop();
@@ -210,6 +219,11 @@ secmodel_overlay_modcmd(modcmd_t cmd, vo
        case MODULE_CMD_FINI:
                sysctl_teardown(&sysctl_overlay_log);
                secmodel_overlay_stop();
+
+               error = secmodel_deregister(overlay_sm);
+               if (error != 0)
+                       printf("secmodel_overlay_modcmd::fini: "
+                           "secmodel_deregister returned %d\n", error);
                break;
 
        case MODULE_CMD_AUTOUNLOAD:
Index: secmodel/securelevel/secmodel_securelevel.c
===================================================================
RCS file: /cvsroot/src/sys/secmodel/securelevel/secmodel_securelevel.c,v
retrieving revision 1.22
diff -u -p -r1.22 secmodel_securelevel.c
--- secmodel/securelevel/secmodel_securelevel.c 28 Nov 2011 20:57:51 -0000      
1.22
+++ secmodel/securelevel/secmodel_securelevel.c 29 Nov 2011 01:20:14 -0000
@@ -54,6 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: secmodel_sec
 
 #include <miscfs/specfs/specdev.h>
 
+#include <secmodel/secmodel.h>
 #include <secmodel/securelevel/securelevel.h>
 
 MODULE(MODULE_CLASS_SECMODEL, securelevel, NULL);
@@ -63,6 +64,7 @@ static int securelevel;
 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device,
     l_vnode;
 
+static secmodel_t securelevel_sm;
 static struct sysctllog *securelevel_sysctl_log;
 
 /*
@@ -180,12 +182,37 @@ secmodel_securelevel_stop(void)
 }
 
 static int
+securelevel_eval(const char *what, void *arg, void *ret)
+{
+       int error = 0;
+
+       if (strcasecmp(what, "is-securelevel-above") == 0) {
+               int level = (int)(uintptr_t)arg;
+               bool *bp = ret;
+
+               *bp = (securelevel > level);
+       } else {
+               error = ENOENT;
+       }
+
+       return error;
+}
+
+static int
 securelevel_modcmd(modcmd_t cmd, void *arg)
 {
        int error = 0;
 
        switch (cmd) {
        case MODULE_CMD_INIT:
+               error = secmodel_register(&securelevel_sm,
+                   "org.netbsd.secmodel.securelevel",
+                   "Traditional NetBSD: Securelevel", NULL, securelevel_eval,
+                   NULL);
+               if (error != 0)
+                       printf("securelevel_modcmd::init: secmodel_register "
+                           "returned %d\n", error);
+
                secmodel_securelevel_init();
                secmodel_securelevel_start();
                sysctl_security_securelevel_setup(&securelevel_sysctl_log);
@@ -194,6 +221,12 @@ securelevel_modcmd(modcmd_t cmd, void *a
        case MODULE_CMD_FINI:
                sysctl_teardown(&securelevel_sysctl_log);
                secmodel_securelevel_stop();
+
+               error = secmodel_deregister(securelevel_sm);
+               if (error != 0)
+                       printf("securelevel_modcmd::fini: secmodel_deregister "
+                           "returned %d\n", error);
+
                break;
 
        case MODULE_CMD_AUTOUNLOAD:
Index: secmodel/suser/secmodel_suser.c
===================================================================
RCS file: /cvsroot/src/sys/secmodel/suser/secmodel_suser.c,v
retrieving revision 1.35
diff -u -p -r1.35 secmodel_suser.c
--- secmodel/suser/secmodel_suser.c     23 Nov 2011 10:47:49 -0000      1.35
+++ secmodel/suser/secmodel_suser.c     29 Nov 2011 01:20:14 -0000
@@ -52,16 +52,15 @@ __KERNEL_RCSID(0, "$NetBSD: secmodel_sus
 #include <sys/proc.h>
 #include <sys/module.h>
 
+#include <secmodel/secmodel.h>
 #include <secmodel/suser/suser.h>
 
 MODULE(MODULE_CLASS_SECMODEL, suser, NULL);
 
-static int secmodel_suser_curtain;
-/* static */ int dovfsusermount;
-
 static kauth_listener_t l_generic, l_system, l_process, l_network, l_machdep,
     l_device, l_vnode;
 
+static secmodel_t suser_sm;
 static struct sysctllog *suser_sysctl_log;
 
 void
@@ -92,65 +91,12 @@ sysctl_security_suser_setup(struct sysct
                       CTLTYPE_STRING, "name", NULL,
                       NULL, 0, __UNCONST("Traditional NetBSD: Superuser"), 0,
                       CTL_CREATE, CTL_EOL);
-
-       sysctl_createv(clog, 0, &rnode, NULL,
-                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
-                      CTLTYPE_INT, "curtain",
-                      SYSCTL_DESCR("Curtain information about objects to "\
-                                   "users not owning them."),
-                      NULL, 0, &secmodel_suser_curtain, 0,
-                      CTL_CREATE, CTL_EOL);
-
-       sysctl_createv(clog, 0, &rnode, NULL,
-                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
-                      CTLTYPE_INT, "usermount",
-                      SYSCTL_DESCR("Whether unprivileged users may mount "
-                                   "filesystems"),
-                      NULL, 0, &dovfsusermount, 0,
-                      CTL_CREATE, CTL_EOL);
-
-       /* Compatibility: security.curtain */
-       sysctl_createv(clog, 0, NULL, &rnode,
-                      CTLFLAG_PERMANENT,
-                      CTLTYPE_NODE, "security", NULL,
-                      NULL, 0, NULL, 0,
-                      CTL_SECURITY, CTL_EOL);
-
-       sysctl_createv(clog, 0, &rnode, NULL,
-                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
-                      CTLTYPE_INT, "curtain",
-                      SYSCTL_DESCR("Curtain information about objects to "\
-                                   "users not owning them."),
-                      NULL, 0, &secmodel_suser_curtain, 0,
-                      CTL_CREATE, CTL_EOL);
-
-       /* Compatibility: vfs.generic.usermount */
-       sysctl_createv(clog, 0, NULL, NULL,
-                      CTLFLAG_PERMANENT,
-                      CTLTYPE_NODE, "vfs", NULL,
-                      NULL, 0, NULL, 0,
-                      CTL_VFS, CTL_EOL);
-
-       sysctl_createv(clog, 0, NULL, NULL,
-                      CTLFLAG_PERMANENT,
-                      CTLTYPE_NODE, "generic",
-                      SYSCTL_DESCR("Non-specific vfs related information"),
-                      NULL, 0, NULL, 0,
-                      CTL_VFS, VFS_GENERIC, CTL_EOL);
-
-       sysctl_createv(clog, 0, NULL, NULL,
-                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
-                      CTLTYPE_INT, "usermount",
-                      SYSCTL_DESCR("Whether unprivileged users may mount "
-                                   "filesystems"),
-                      NULL, 0, &dovfsusermount, 0,
-                      CTL_VFS, VFS_GENERIC, VFS_USERMOUNT, CTL_EOL);
 }
 
 void
 secmodel_suser_init(void)
 {
-       secmodel_suser_curtain = 0;
+
 }
 
 void
@@ -184,6 +130,29 @@ secmodel_suser_stop(void)
        kauth_unlisten_scope(l_vnode);
 }
 
+static bool
+suser_isroot(kauth_cred_t cred)
+{
+       return kauth_cred_geteuid(cred) == 0;
+}
+
+static int
+suser_eval(const char *what, void *arg, void *ret)
+{
+       int error = 0;
+
+       if (strcasecmp(what, "is-root") == 0) {
+               kauth_cred_t cred = arg;
+               bool *bp = ret;
+
+               *bp = suser_isroot(cred);
+       } else {
+               error = ENOENT;
+       }
+
+       return error;
+}
+
 static int
 suser_modcmd(modcmd_t cmd, void *arg)
 {
@@ -191,6 +160,13 @@ suser_modcmd(modcmd_t cmd, void *arg)
 
        switch (cmd) {
        case MODULE_CMD_INIT:
+               error = secmodel_register(&suser_sm,
+                   "org.netbsd.secmodel.suser",
+                   "Traditional NetBSD: Superuser", NULL, suser_eval, NULL);
+               if (error != 0)
+                       printf("suser_modcmd::init: secmodel_register "
+                           "returned %d\n", error);
+
                secmodel_suser_init();
                secmodel_suser_start();
                sysctl_security_suser_setup(&suser_sysctl_log);
@@ -199,6 +175,12 @@ suser_modcmd(modcmd_t cmd, void *arg)
        case MODULE_CMD_FINI:
                sysctl_teardown(&suser_sysctl_log);
                secmodel_suser_stop();
+
+               error = secmodel_deregister(suser_sm);
+               if (error != 0)
+                       printf("suser_modcmd::fini: secmodel_deregister "
+                           "returned %d\n", error);
+
                break;
 
        case MODULE_CMD_AUTOUNLOAD:
@@ -227,7 +209,7 @@ secmodel_suser_generic_cb(kauth_cred_t c
        bool isroot;
        int result;
 
-       isroot = (kauth_cred_geteuid(cred) == 0);
+       isroot = suser_isroot(cred);
        result = KAUTH_RESULT_DEFER;
 
        switch (action) {
@@ -243,64 +225,6 @@ secmodel_suser_generic_cb(kauth_cred_t c
        return (result);
 }
 
-static int
-suser_usermount_policy(kauth_cred_t cred, enum kauth_system_req req, void 
*arg1,
-    void *arg2)
-{
-       struct mount *mp;
-       u_long flags;
-       int result;
-
-       result = KAUTH_RESULT_DEFER;
-
-       if (!dovfsusermount)
-               return result;
-
-       switch (req) {
-       case KAUTH_REQ_SYSTEM_MOUNT_NEW:
-               mp = ((struct vnode *)arg1)->v_mount;
-               flags= (u_long)arg2;
-
-               if (usermount_common_policy(mp, flags) != 0)
-                       break;
-
-               result = KAUTH_RESULT_ALLOW;
-                       
-               break;
-
-       case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT:
-               mp = arg1;
-
-               /* Must own the mount. */
-               if (mp->mnt_stat.f_owner != kauth_cred_geteuid(cred))
-                       break;
-
-               result = KAUTH_RESULT_ALLOW;
-
-               break;
-
-       case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
-               mp = arg1;
-               flags = (u_long)arg2;
-
-               /* Must own the mount. */
-               if (mp->mnt_stat.f_owner != kauth_cred_geteuid(cred))
-                       break;
-
-               if (usermount_common_policy(mp, flags) != 0)
-                       break;
-
-               result = KAUTH_RESULT_ALLOW;
-
-               break;
-
-       default:
-               break;
-       }
-
-       return result;
-}
-
 /*
  * kauth(9) listener
  *
@@ -316,7 +240,7 @@ secmodel_suser_system_cb(kauth_cred_t cr
        int result;
        enum kauth_system_req req;
 
-       isroot = (kauth_cred_geteuid(cred) == 0);
+       isroot = suser_isroot(cred);
        result = KAUTH_RESULT_DEFER;
        req = (enum kauth_system_req)arg0;
 
@@ -369,8 +293,6 @@ secmodel_suser_system_cb(kauth_cred_t cr
                                break;
                        }
 
-                       result = suser_usermount_policy(cred, req, arg1, arg2);
-
                        break;
 
                default:
@@ -489,7 +411,7 @@ secmodel_suser_process_cb(kauth_cred_t c
        bool isroot;
        int result;
 
-       isroot = (kauth_cred_geteuid(cred) == 0);
+       isroot = suser_isroot(cred);
        result = KAUTH_RESULT_DEFER;
        p = arg0;
 
@@ -527,11 +449,6 @@ secmodel_suser_process_cb(kauth_cred_t c
                                break;
                        }
 
-                       if (secmodel_suser_curtain) {
-                               if (!kauth_cred_uidmatch(cred, p->p_cred))
-                                       result = KAUTH_RESULT_DENY;
-                       }
-
                        break;
 
                case KAUTH_REQ_PROCESS_CANSEE_ENV:
@@ -589,7 +506,7 @@ secmodel_suser_network_cb(kauth_cred_t c
        int result;
        enum kauth_network_req req;
 
-       isroot = (kauth_cred_geteuid(cred) == 0);
+       isroot = suser_isroot(cred);
        result = KAUTH_RESULT_DEFER;
        req = (enum kauth_network_req)arg0;
 
@@ -749,15 +666,6 @@ secmodel_suser_network_cb(kauth_cred_t c
                                break;
                        }
 
-                       if (secmodel_suser_curtain) {
-                               struct socket *so;
-
-                               so = (struct socket *)arg1;
-
-                               if (!proc_uidmatch(cred, so->so_cred))
-                                       result = KAUTH_RESULT_DENY;
-                       }
-
                        break;
 
                default:
@@ -788,7 +696,7 @@ secmodel_suser_machdep_cb(kauth_cred_t c
         bool isroot;
         int result;
 
-        isroot = (kauth_cred_geteuid(cred) == 0);
+        isroot = suser_isroot(cred);
         result = KAUTH_RESULT_DEFER;
 
         switch (action) {
@@ -827,7 +735,7 @@ secmodel_suser_device_cb(kauth_cred_t cr
         bool isroot;
         int result;
 
-        isroot = (kauth_cred_geteuid(cred) == 0);
+        isroot = suser_isroot(cred);
         result = KAUTH_RESULT_DEFER;
 
        switch (action) {
@@ -887,7 +795,7 @@ secmodel_suser_vnode_cb(kauth_cred_t cre
        bool isroot;
        int result;
 
-       isroot = (kauth_cred_geteuid(cred) == 0);
+       isroot = suser_isroot(cred);
        result = KAUTH_RESULT_DEFER;
 
        if (isroot)
--- /dev/null   2011-11-29 02:01:24.000000000 +0100
+++ secmodel/secmodel.c 2011-11-29 01:01:19.000000000 +0100
@@ -0,0 +1,270 @@
+/* $NetBSD$ */
+/*-
+ * Copyright (c) 2011 Elad Efrat <elad%NetBSD.org@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+
+#include <sys/atomic.h>
+#include <sys/kauth.h>
+#include <sys/kmem.h>
+#include <sys/queue.h>
+#include <sys/rwlock.h>
+#include <secmodel/secmodel.h>
+#include <prop/proplib.h>
+
+/* List of secmodels, parameters, and lock. */
+static LIST_HEAD(, secmodel_descr) secmodels =
+    LIST_HEAD_INITIALIZER(secmodels);
+static unsigned int secmodel_copy_cred_on_fork = false;
+static krwlock_t secmodels_lock;
+static int nsecmodels = 0; /* number of registered secmodels */
+
+static int secmodel_plug(secmodel_t);
+static int secmodel_unplug(secmodel_t);
+
+int
+secmodel_nsecmodels(void)
+{
+       return nsecmodels;
+}
+
+void
+secmodel_init(void)
+{
+
+       rw_init(&secmodels_lock);
+
+       secmodel_copy_cred_on_fork = false;
+}
+
+/*
+ * Register a new secmodel.
+ */
+int
+secmodel_register(secmodel_t *secmodel, const char *id, const char *name,
+                 prop_dictionary_t behavior,
+                 secmodel_eval_t eval, secmodel_setinfo_t setinfo)
+{
+       int err;
+       secmodel_t sm;
+
+       sm = kmem_alloc(sizeof(*sm), KM_SLEEP);
+
+       sm->sm_id = id;
+       sm->sm_name = name;
+       sm->sm_behavior = behavior;
+       sm->sm_eval = eval;
+       sm->sm_setinfo = setinfo;
+
+       err = secmodel_plug(sm);
+       if (err == 0) {
+               atomic_inc_uint(&nsecmodels);
+       } else {
+               kmem_free(sm, sizeof(*sm));
+               sm = NULL;
+       }
+
+       *secmodel = sm;
+       return err;
+}
+
+/*
+ * Deregister a secmodel.
+ */
+int
+secmodel_deregister(secmodel_t sm)
+{
+       int error;
+
+       error = secmodel_unplug(sm);
+       if (error == 0) {
+               atomic_dec_uint(&nsecmodels);
+               kmem_free(sm, sizeof(*sm));
+       }
+
+       return error;
+}
+
+/*
+ * Lookup a secmodel by its id.
+ *
+ * Requires "secmodels_lock" handling by the caller.
+ */
+static secmodel_t
+secmodel_lookup(const char *id)
+{
+       secmodel_t tsm;
+
+       KASSERT(rw_lock_held(&secmodels_lock));
+
+       LIST_FOREACH(tsm, &secmodels, sm_list) {
+               if (strcasecmp(tsm->sm_id, id) == 0) {
+                       return tsm;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Adjust system-global secmodel behavior following the addition
+ * or removal of a secmodel.
+ *
+ * Requires "secmodels_lock" to be held by the caller.
+ */
+static void
+secmodel_adjust_behavior(secmodel_t sm, bool added)
+{
+       bool r, b;
+
+       KASSERT(rw_write_held(&secmodels_lock));
+
+#define        ADJUST_COUNTER(which, added)            \
+       do {                                    \
+               if (added) {                    \
+                       (which)++;              \
+               } else {                        \
+                       if ((which) > 0)        \
+                               (which)--;      \
+               }                               \
+       } while (/*CONSTCOND*/0)
+
+       /* Copy credentials on fork? */
+       r = prop_dictionary_get_bool(sm->sm_behavior, "copy-cred-on-fork", &b);
+       if (r) {
+               ADJUST_COUNTER(secmodel_copy_cred_on_fork, added);
+       }
+
+#undef ADJUST_COUNTER
+}
+
+static int
+secmodel_plug(secmodel_t sm)
+{
+       secmodel_t tsm;
+       int error = 0;
+
+       if (sm == NULL) {
+               error = EFAULT;
+               goto out;
+       }
+
+       /* Check if the secmodel is already present. */
+       rw_enter(&secmodels_lock, RW_WRITER);
+       tsm = secmodel_lookup(sm->sm_id);
+       if (tsm != NULL) {
+               error = EEXIST;
+               goto out;
+       }
+
+       /* Add the secmodel. */
+       LIST_INSERT_HEAD(&secmodels, sm, sm_list);
+
+       /* Adjust behavior. */
+       secmodel_adjust_behavior(sm, true);
+
+ out:
+       /* Unlock the secmodels list. */
+       rw_exit(&secmodels_lock);
+
+       return error;
+}
+
+static int
+secmodel_unplug(secmodel_t sm)
+{
+       secmodel_t tsm;
+       int error = 0;
+
+       if (sm == NULL) {
+               error = EFAULT;
+               goto out;
+       }
+
+       /* Make sure the secmodel is present. */
+       rw_enter(&secmodels_lock, RW_WRITER);
+       tsm = secmodel_lookup(sm->sm_id);
+       if (tsm == NULL) {
+               error = ENOENT;
+               goto out;
+       }
+
+       /* Remove the secmodel. */
+       LIST_REMOVE(tsm, sm_list);
+
+       /* Adjust behavior. */
+       secmodel_adjust_behavior(tsm, false);
+
+ out:
+       /* Unlock the secmodels list. */
+       rw_exit(&secmodels_lock);
+
+       return error;
+}
+
+/* XXX TODO */
+int
+secmodel_setinfo(const char *id, void *v, int *err)
+{
+
+       return EOPNOTSUPP;
+}
+
+int
+secmodel_eval(const char *id, const char *what, void *arg, void *ret, int *err)
+{
+       secmodel_t sm;
+       int error = 0, sm_err;
+
+       rw_enter(&secmodels_lock, RW_READER);
+       sm = secmodel_lookup(id);
+       if (sm == NULL) {
+               error = EINVAL;
+               goto out;
+       }
+
+       if (sm->sm_eval == NULL) {
+               error = ENOENT;
+               goto out;
+       }
+
+       if (ret == NULL) {
+               error = EFAULT;
+               goto out;
+       }
+
+       sm_err = sm->sm_eval(what, arg, ret);
+       if (err != NULL)
+               *err = sm_err;
+
+ out:
+       rw_exit(&secmodels_lock);
+
+       return error;
+}
--- /dev/null   2011-11-29 02:01:24.000000000 +0100
+++ secmodel/secmodel.h 2011-11-29 00:46:43.000000000 +0100
@@ -0,0 +1,63 @@
+/* $NetBSD$ */
+/*-
+ * Copyright (c) 2006, 2011 Elad Efrat <elad%NetBSD.org@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SECMODEL_SECMODEL_H_
+#define        _SECMODEL_SECMODEL_H_
+
+#include <prop/proplib.h>
+
+void secmodel_init(void);
+
+/*
+ * Functions used for inter-secmodel communication, allowing evaluation
+ * or setting information.
+ */
+typedef int (*secmodel_eval_t)(const char *, void *, void *);
+typedef int (*secmodel_setinfo_t)(void *); /* XXX TODO */
+
+/*
+ * Secmodel entry.
+ */
+struct secmodel_descr {
+       LIST_ENTRY(secmodel_descr) sm_list;
+       const char *sm_id;
+       const char *sm_name;
+       prop_dictionary_t sm_behavior;
+       secmodel_eval_t sm_eval;
+       secmodel_setinfo_t sm_setinfo;
+};
+typedef struct secmodel_descr *secmodel_t;
+
+int secmodel_register(secmodel_t *, const char *, const char *,
+    prop_dictionary_t, secmodel_eval_t, secmodel_setinfo_t);
+int secmodel_deregister(secmodel_t);
+int secmodel_nsecmodels(void);
+
+int secmodel_eval(const char *, const char *, void *, void *, int *);
+int secmodel_setinfo(const char *, void *, int *); /* XXX TODO */
+#endif /* !_SECMODEL_SECMODEL_H_ */
--- /dev/null   2011-11-29 02:01:24.000000000 +0100
+++ secmodel/extensions/extensions.h    2011-11-29 00:20:49.000000000 +0100
@@ -0,0 +1,39 @@
+/* $NetBSD$ */
+/*-
+ * Copyright (c) 2011 Elad Efrat <elad%NetBSD.org@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SECMODEL_EXTENSIONS_EXTENSIONS_H_
+#define        _SECMODEL_EXTENSIONS_EXTENSIONS_H_
+
+int secmodel_extensions_system_cb(kauth_cred_t, kauth_action_t, void *,
+    void *, void *, void *, void *);
+int secmodel_extensions_process_cb(kauth_cred_t, kauth_action_t, void *,
+    void *, void *, void *, void *);
+int secmodel_extensions_network_cb(kauth_cred_t, kauth_action_t, void *,
+    void *, void *, void *, void *);
+
+#endif /* !_SECMODEL_EXTENSIONS_EXTENSIONS_H_ */
--- /dev/null   2011-11-29 02:01:24.000000000 +0100
+++ secmodel/extensions/files.extensions        2011-11-29 00:20:08.000000000 
+0100
@@ -0,0 +1,5 @@
+# $NetBSD$
+
+defflag secmodel_extensions
+
+file   secmodel/extensions/secmodel_extensions.c       secmodel_extensions
--- /dev/null   2011-11-29 02:01:24.000000000 +0100
+++ secmodel/extensions/secmodel_extensions.c   2011-11-29 02:08:22.000000000 
+0100
@@ -0,0 +1,361 @@
+/* $NetBSD$ */
+/*-
+ * Copyright (c) 2011 Elad Efrat <elad%NetBSD.org@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kauth.h>
+
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/module.h>
+
+#include <secmodel/secmodel.h>
+#include <secmodel/extensions/extensions.h>
+
+MODULE(MODULE_CLASS_SECMODEL, extensions, NULL);
+
+/* static */ int dovfsusermount;
+static int curtain;
+static int user_set_cpu_affinity;
+
+static kauth_listener_t l_system, l_process, l_network;
+
+static secmodel_t extensions_sm;
+static struct sysctllog *extensions_sysctl_log;
+
+static void secmodel_extensions_init(void);
+static void secmodel_extensions_start(void);
+static void secmodel_extensions_stop(void);
+static void sysctl_security_extensions_setup(struct sysctllog **);
+
+static void
+sysctl_security_extensions_setup(struct sysctllog **clog)
+{
+       const struct sysctlnode *rnode;
+
+       sysctl_createv(clog, 0, NULL, &rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "security", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_SECURITY, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, &rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "models", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, &rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "extensions", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_STRING, "name", NULL,
+                      NULL, 0, __UNCONST("Traditional NetBSD: Extensions"), 0,
+                      CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, NULL,
+                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+                      CTLTYPE_INT, "usermount",
+                      SYSCTL_DESCR("Whether unprivileged users may mount "
+                                   "filesystems"),
+                      NULL, 0, &dovfsusermount, 0,
+                      CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, NULL,
+                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+                      CTLTYPE_INT, "curtain",
+                      SYSCTL_DESCR("Curtain information about objects to "\
+                                   "users not owning them."),
+                      NULL, 0, &curtain, 0,
+                      CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, NULL,
+                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+                      CTLTYPE_INT, "user_set_cpu_affinity",
+                      SYSCTL_DESCR("Whether unprivileged users may control "\
+                                   "CPU affinity."),
+                      NULL, 0, &user_set_cpu_affinity, 0,
+                      CTL_CREATE, CTL_EOL);
+
+       /* Compatibility: vfs.generic.usermount */
+       sysctl_createv(clog, 0, NULL, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "vfs", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_VFS, CTL_EOL);
+
+       sysctl_createv(clog, 0, NULL, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "generic",
+                      SYSCTL_DESCR("Non-specific vfs related information"),
+                      NULL, 0, NULL, 0,
+                      CTL_VFS, VFS_GENERIC, CTL_EOL);
+
+       sysctl_createv(clog, 0, NULL, NULL,
+                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+                      CTLTYPE_INT, "usermount",
+                      SYSCTL_DESCR("Whether unprivileged users may mount "
+                                   "filesystems"),
+                      NULL, 0, &dovfsusermount, 0,
+                      CTL_VFS, VFS_GENERIC, VFS_USERMOUNT, CTL_EOL);
+
+       /* Compatibility: security.curtain */
+       sysctl_createv(clog, 0, NULL, &rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "security", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_SECURITY, CTL_EOL);
+
+       sysctl_createv(clog, 0, &rnode, NULL,
+                      CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+                      CTLTYPE_INT, "curtain",
+                      SYSCTL_DESCR("Curtain information about objects to "\
+                                   "users not owning them."),
+                      NULL, 0, &curtain, 0,
+                      CTL_CREATE, CTL_EOL);
+}
+
+static void
+secmodel_extensions_init(void)
+{
+
+       curtain = 0;
+       user_set_cpu_affinity = 0;
+}
+
+static void
+secmodel_extensions_start(void)
+{
+
+       l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
+           secmodel_extensions_system_cb, NULL);
+       l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
+           secmodel_extensions_process_cb, NULL);
+       l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
+           secmodel_extensions_network_cb, NULL);
+}
+
+static void
+secmodel_extensions_stop(void)
+{
+
+       kauth_unlisten_scope(l_system);
+       kauth_unlisten_scope(l_process);
+       kauth_unlisten_scope(l_network);
+}
+
+static int
+extensions_modcmd(modcmd_t cmd, void *arg)
+{
+       int error = 0;
+
+       switch (cmd) {
+       case MODULE_CMD_INIT:
+               error = secmodel_register(&extensions_sm,
+                   "org.netbsd.secmodel.extensions",
+                   "Traditional NetBSD: Extensions", NULL, NULL, NULL);
+               if (error != 0)
+                       printf("extensions_modcmd::init: secmodel_register "
+                           "returned %d\n", error);
+
+               secmodel_extensions_init();
+               secmodel_extensions_start();
+               sysctl_security_extensions_setup(&extensions_sysctl_log);
+               break;
+
+       case MODULE_CMD_FINI:
+               sysctl_teardown(&extensions_sysctl_log);
+               secmodel_extensions_stop();
+
+               error = secmodel_deregister(extensions_sm);
+               if (error != 0)
+                       printf("extensions_modcmd::fini: secmodel_deregister "
+                           "returned %d\n", error);
+
+               break;
+
+       case MODULE_CMD_AUTOUNLOAD:
+               error = EPERM;
+               break;
+
+       default:
+               error = ENOTTY;
+               break;
+       }
+
+       return (error);
+}
+
+int
+secmodel_extensions_system_cb(kauth_cred_t cred, kauth_action_t action,
+    void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
+{
+       struct mount *mp;
+       u_long flags;
+       int result;
+       enum kauth_system_req req;
+
+       req = (enum kauth_system_req)arg0;
+       result = KAUTH_RESULT_DEFER;
+
+       if (action != KAUTH_SYSTEM_MOUNT || !dovfsusermount)
+               return result;
+
+       switch (req) {
+       case KAUTH_REQ_SYSTEM_MOUNT_NEW:
+               mp = ((struct vnode *)arg1)->v_mount;
+               flags = (u_long)arg2;
+
+               if (usermount_common_policy(mp, flags) == 0)
+                       result = KAUTH_RESULT_ALLOW;
+
+               break;
+
+       case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT:
+               mp = arg1;
+
+               /* Must own the mount. */
+               if (mp->mnt_stat.f_owner == kauth_cred_geteuid(cred))
+                       result = KAUTH_RESULT_ALLOW;
+
+               break;
+
+       case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
+               mp = arg1;
+               flags = (u_long)arg2;
+
+               /* Must own the mount. */
+               if (mp->mnt_stat.f_owner == kauth_cred_geteuid(cred) &&
+                   usermount_common_policy(mp, flags) == 0)
+                       result = KAUTH_RESULT_ALLOW;
+
+               break;
+
+       default:
+               break;
+       }
+
+       return (result);
+}
+
+int
+secmodel_extensions_process_cb(kauth_cred_t cred, kauth_action_t action,
+    void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
+{
+       int result;
+       enum kauth_process_req req;
+
+       result = KAUTH_RESULT_DEFER;
+       req = (enum kauth_process_req)arg1;
+
+       switch (action) {
+       case KAUTH_PROCESS_CANSEE:
+               switch (req) {
+               case KAUTH_REQ_PROCESS_CANSEE_ARGS:
+               case KAUTH_REQ_PROCESS_CANSEE_ENTRY:
+               case KAUTH_REQ_PROCESS_CANSEE_OPENFILES:
+                       if (curtain) {
+                               struct proc *p = arg0;
+
+                               /*
+                                * Only process' owner and root can see
+                                * through curtain
+                                */
+                               if (!kauth_cred_uidmatch(cred, p->p_cred)) {
+                                       int error;
+                                       bool isroot = false;
+
+                                       error = secmodel_eval(
+                                           "org.netbsd.secmodel.suser",
+                                           "is-root", cred, &isroot, NULL);
+                                       if (!error && !isroot)
+                                               result = KAUTH_RESULT_DENY;
+                               }
+                       }
+
+                       break;
+
+               default:
+                       break;
+               }
+
+               break;
+
+       case KAUTH_PROCESS_SCHEDULER_SETAFFINITY:
+               if (user_set_cpu_affinity != 0) {
+                       result = KAUTH_RESULT_ALLOW;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return (result);
+}
+
+int
+secmodel_extensions_network_cb(kauth_cred_t cred, kauth_action_t action,
+    void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
+{
+       int result;
+       enum kauth_network_req req;
+
+       result = KAUTH_RESULT_DEFER;
+       req = (enum kauth_network_req)arg0;
+
+       if (action != KAUTH_NETWORK_SOCKET ||
+           req != KAUTH_REQ_NETWORK_SOCKET_CANSEE)
+               return result;
+
+       if (curtain != 0) {
+               struct socket *so = (struct socket *)arg1;
+
+               if (!kauth_cred_uidmatch(cred, so->so_cred)) {
+                       int error;
+                       bool isroot = false;
+
+                       error = secmodel_eval("org.netbsd.secmodel.suser",
+                           "is-root", cred, &isroot, NULL);
+                       if (!error && !isroot)
+                               result = KAUTH_RESULT_DENY;
+               }
+       }
+
+       return (result);
+}


Home | Main Index | Thread Index | Old Index