tech-kern archive

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

Re: Vnode scope implementation



YAMAMOTO Takashi wrote:
On Mon, Jul 13, 2009 at 11:27 AM, Elad Efrat<elad%netbsd.org@localhost> wrote:
Following up on the thread, attached is a diff that introduces the
vnode scope without any actions on it, along with the bsd44/suser
listener.
I've received no comments so far on this diff. I'm giving it four more
days and then I'll just check it in...

without any users of the code, you mean?  i don't understand the point.

Okay. Attached is a diff implementing the vnode scope along with changes
to tmpfs so it uses it where it currently uses KAUTH_GENERIC_ISSUSER.

-e.
Index: sys/kern/kern_auth.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/kern_auth.c,v
retrieving revision 1.62
diff -u -p -r1.62 kern_auth.c
--- sys/kern/kern_auth.c        5 Apr 2009 11:50:51 -0000       1.62
+++ sys/kern/kern_auth.c        15 Jul 2009 22:14:36 -0000
@@ -68,6 +68,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_auth.c,
 #include <sys/sysctl.h>                /* for pi_[p]cread */
 #include <sys/atomic.h>
 #include <sys/specificdata.h>
+#include <sys/vnode.h>
 
 /*
  * Secmodel-specific credentials.
@@ -142,6 +143,7 @@ static kauth_scope_t kauth_builtin_scope
 static kauth_scope_t kauth_builtin_scope_machdep;
 static kauth_scope_t kauth_builtin_scope_device;
 static kauth_scope_t kauth_builtin_scope_cred;
+static kauth_scope_t kauth_builtin_scope_vnode;
 
 static unsigned int nsecmodels = 0;
 
@@ -830,6 +832,10 @@ kauth_init(void)
        /* Register device scope. */
        kauth_builtin_scope_device = kauth_register_scope(KAUTH_SCOPE_DEVICE,
            NULL, NULL);
+
+       /* Register vnode scope. */
+       kauth_builtin_scope_vnode = kauth_register_scope(KAUTH_SCOPE_VNODE,
+           NULL, NULL);
 }
 
 /*
@@ -1052,6 +1058,39 @@ kauth_authorize_device_passthru(kauth_cr
            data, NULL));
 }
 
+kauth_action_t
+kauth_mode_to_action(mode_t mode)
+{
+       kauth_action_t action = 0;
+
+       if (mode & VREAD)
+               action |= KAUTH_VNODE_READ_DATA;
+       if (mode & VWRITE)
+               action |= KAUTH_VNODE_WRITE_DATA;
+       if (mode & VEXEC)
+               action |= KAUTH_VNODE_EXECUTE;
+
+       return action;
+}
+
+int
+kauth_authorize_vnode(kauth_cred_t cred, kauth_action_t action,
+    struct vnode *vp, struct vnode *dvp, int fs_decision)
+{
+       int error;
+
+       error = kauth_authorize_action(kauth_builtin_scope_vnode, cred,
+           action, vp, dvp, KAUTH_ARG(fs_decision), NULL);
+
+       if (error)
+               error = EACCES;
+
+       if (!nsecmodels)
+               error = fs_decision;
+
+       return error;
+}
+
 static int
 kauth_cred_hook(kauth_cred_t cred, kauth_action_t action, void *arg0,
     void *arg1)
Index: sys/sys/kauth.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/kauth.h,v
retrieving revision 1.59
diff -u -p -r1.59 kauth.h
--- sys/sys/kauth.h     8 May 2009 11:09:43 -0000       1.59
+++ sys/sys/kauth.h     15 Jul 2009 22:14:40 -0000
@@ -67,6 +67,7 @@ typedef       struct kauth_key       *kauth_ke
 #define        KAUTH_SCOPE_MACHDEP     "org.netbsd.kauth.machdep"
 #define        KAUTH_SCOPE_DEVICE      "org.netbsd.kauth.device"
 #define        KAUTH_SCOPE_CRED        "org.netbsd.kauth.cred"
+#define        KAUTH_SCOPE_VNODE       "org.netbsd.kauth.vnode"
 
 /*
  * Generic scope - actions.
@@ -282,6 +283,36 @@ enum {
 };
 
 /*
+ * Vnode scope - action bits.
+ */
+#define        KAUTH_VNODE_READ_DATA           (1U << 0)
+#define        KAUTH_VNODE_LIST_DIRECTORY      KAUTH_VNODE_READ_DATA
+#define        KAUTH_VNODE_WRITE_DATA          (1U << 1)
+#define        KAUTH_VNODE_ADD_FILE            KAUTH_VNODE_WRITE_DATA
+#define        KAUTH_VNODE_EXECUTE             (1U << 2)
+#define        KAUTH_VNODE_SEARCH              KAUTH_VNODE_EXECUTE
+#define        KAUTH_VNODE_DELETE              (1U << 3)
+#define        KAUTH_VNODE_APPEND_DATA         (1U << 4)
+#define        KAUTH_VNODE_ADD_SUBDIRECTORY    KAUTH_VNODE_APPEND_DATA
+#define        KAUTH_VNODE_READ_TIMES          (1U << 5)
+#define        KAUTH_VNODE_WRITE_TIMES         (1U << 6)
+#define        KAUTH_VNODE_READ_FLAGS          (1U << 7)
+#define        KAUTH_VNODE_WRITE_FLAGS         (1U << 8)
+#define        KAUTH_VNODE_READ_SYSFLAGS       (1U << 9)
+#define        KAUTH_VNODE_WRITE_SYSFLAGS      (1U << 10)
+#define        KAUTH_VNODE_RENAME              (1U << 11)
+#define        KAUTH_VNODE_CHANGE_OWNERSHIP    (1U << 12)
+#define        KAUTH_VNODE_READ_SECURITY       (1U << 13)
+#define        KAUTH_VNODE_WRITE_SECURITY      (1U << 14)
+#define        KAUTH_VNODE_READ_ATTRIBUTES     (1U << 15)
+#define        KAUTH_VNODE_WRITE_ATTRIBUTES    (1U << 16)
+#define        KAUTH_VNODE_READ_EXTATTRIBUTES  (1U << 17)
+#define        KAUTH_VNODE_WRITE_EXTATTRIBUTES (1U << 18)
+
+#define        KAUTH_VNODE_HAS_SYSFLAGS        (1U << 30)
+#define        KAUTH_VNODE_ACCESS              (1U << 31)
+
+/*
  * Device scope, passthru request - identifiers.
  */
 #define        KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READ            0x00000001
@@ -323,6 +354,8 @@ int kauth_authorize_device_tty(kauth_cre
 int kauth_authorize_device_spec(kauth_cred_t, enum kauth_device_req,
     struct vnode *);
 int kauth_authorize_device_passthru(kauth_cred_t, dev_t, u_long, void *);
+int kauth_authorize_vnode(kauth_cred_t, kauth_action_t, struct vnode *,
+    struct vnode *, int);
 
 /* Kauth credentials management routines. */
 kauth_cred_t kauth_cred_alloc(void);
@@ -370,6 +403,8 @@ int kauth_cred_uucmp(kauth_cred_t, const
 void kauth_cred_toucred(kauth_cred_t, struct ki_ucred *);
 void kauth_cred_topcred(kauth_cred_t, struct ki_pcred *);
 
+kauth_action_t kauth_mode_to_action(mode_t mode);
+
 kauth_cred_t kauth_cred_get(void);
 
 void kauth_proc_fork(struct proc *, struct proc *);
Index: sys/secmodel/securelevel/secmodel_securelevel.c
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/securelevel/secmodel_securelevel.c,v
retrieving revision 1.11
diff -u -p -r1.11 secmodel_securelevel.c
--- sys/secmodel/securelevel/secmodel_securelevel.c     6 May 2009 21:10:22 
-0000       1.11
+++ sys/secmodel/securelevel/secmodel_securelevel.c     15 Jul 2009 22:22:23 
-0000
@@ -56,7 +56,8 @@ __KERNEL_RCSID(0, "$NetBSD: secmodel_sec
 
 static int securelevel;
 
-static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
+static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device,
+    l_vnode;
 
 /*
  * sysctl helper routine for securelevel. ensures that the value
@@ -126,6 +127,8 @@ secmodel_securelevel_start(void)
            secmodel_securelevel_machdep_cb, NULL);
        l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
            secmodel_securelevel_device_cb, NULL);
+       l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE,
+           secmodel_securelevel_vnode_cb, NULL);
 }
 
 #if defined(_LKM)
@@ -137,6 +140,7 @@ secmodel_securelevel_stop(void)
        kauth_unlisten_scope(l_network);
        kauth_unlisten_scope(l_machdep);
        kauth_unlisten_scope(l_device);
+       kauth_unlisten_scope(l_vnode);
 }
 #endif /* _LKM */
 
@@ -540,3 +544,22 @@ secmodel_securelevel_device_cb(kauth_cre
 
        return (result);
 }
+
+int
+secmodel_securelevel_vnode_cb(kauth_cred_t cred,
+    kauth_action_t action, void *cookie, void *arg0,
+    void *arg1, void *arg2, void *arg3)
+{
+       int result;
+
+       result = KAUTH_RESULT_DEFER;
+
+       if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) &&
+           (action & KAUTH_VNODE_HAS_SYSFLAGS)) {
+               if (securelevel > 0)
+                       result = KAUTH_RESULT_DENY;
+       }
+
+       return (result);
+}
+
Index: sys/secmodel/securelevel/securelevel.h
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/securelevel/securelevel.h,v
retrieving revision 1.1
diff -u -p -r1.1 securelevel.h
--- sys/secmodel/securelevel/securelevel.h      21 Nov 2007 22:49:09 -0000      
1.1
+++ sys/secmodel/securelevel/securelevel.h      15 Jul 2009 22:23:03 -0000
@@ -49,5 +49,7 @@ int secmodel_securelevel_machdep_cb(kaut
     void *, void *, void *, void *);
 int secmodel_securelevel_device_cb(kauth_cred_t, kauth_action_t, void *,
     void *, void *, void *, void *);
+int secmodel_securelevel_vnode_cb(kauth_cred_t, kauth_action_t, void *,
+    void *, void *, void *, void *);
 
 #endif /* !_SECMODEL_SECURELEVEL_SECURELEVEL_H_ */
Index: sys/secmodel/bsd44/suser.h
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/bsd44/suser.h,v
retrieving revision 1.5
diff -u -p -r1.5 suser.h
--- sys/secmodel/bsd44/suser.h  3 May 2009 21:25:44 -0000       1.5
+++ sys/secmodel/bsd44/suser.h  24 Jun 2009 04:01:51 -0000
@@ -50,5 +50,7 @@ int secmodel_bsd44_suser_machdep_cb(kaut
     void *, void *, void *, void *);
 int secmodel_bsd44_suser_device_cb(kauth_cred_t, kauth_action_t, void *,
     void *, void *, void *, void *);
+int secmodel_bsd44_suser_vnode_cb(kauth_cred_t, kauth_action_t, void *,
+    void *, void *, void *, void *);
 
 #endif /* !_SECMODEL_BSD44_SUSER_H_ */
Index: sys/secmodel/bsd44/secmodel_bsd44_suser.c
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/bsd44/secmodel_bsd44_suser.c,v
retrieving revision 1.67
diff -u -p -r1.67 secmodel_bsd44_suser.c
--- sys/secmodel/bsd44/secmodel_bsd44_suser.c   8 May 2009 11:09:43 -0000       
1.67
+++ sys/secmodel/bsd44/secmodel_bsd44_suser.c   12 Jul 2009 05:54:59 -0000
@@ -65,7 +65,7 @@ __KERNEL_RCSID(0, "$NetBSD: secmodel_bsd
 extern int dovfsusermount;
 
 static kauth_listener_t l_generic, l_system, l_process, l_network, l_machdep,
-    l_device;
+    l_device, l_vnode;
 
 void
 secmodel_bsd44_suser_start(void)
@@ -82,6 +82,8 @@ secmodel_bsd44_suser_start(void)
            secmodel_bsd44_suser_machdep_cb, NULL);
        l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
            secmodel_bsd44_suser_device_cb, NULL);
+       l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE,
+           secmodel_bsd44_suser_vnode_cb, NULL);
 }
 
 #if defined(_LKM)
@@ -94,6 +96,7 @@ secmodel_bsd44_suser_stop(void)
        kauth_unlisten_scope(l_network);
        kauth_unlisten_scope(l_machdep);
        kauth_unlisten_scope(l_device);
+       kauth_unlisten_scope(l_vnode);
 }
 #endif /* _LKM */
 
@@ -1157,3 +1160,27 @@ secmodel_bsd44_suser_device_cb(kauth_cre
 
        return (result);
 }
+
+int
+secmodel_bsd44_suser_vnode_cb(kauth_cred_t cred, kauth_action_t action,
+    void *cookie, void *arg0, void *arg1, void *arg2,
+    void *arg3)
+{
+        bool isroot;
+        int result;
+       struct vnode *vp, *dvp;
+       int fs_decision;
+
+        isroot = (kauth_cred_geteuid(cred) == 0);
+        result = KAUTH_RESULT_DEFER;
+
+       vp = arg0;
+       dvp = arg1;
+       fs_decision = (int)(uintptr_t)arg2;
+
+       if (isroot || fs_decision == 0)
+               result = KAUTH_RESULT_ALLOW;
+
+       return (result);
+}
+
Index: sys/fs/tmpfs/tmpfs_subr.c
===================================================================
RCS file: /usr/cvs/src/sys/fs/tmpfs/tmpfs_subr.c,v
retrieving revision 1.53
diff -u -p -r1.53 tmpfs_subr.c
--- sys/fs/tmpfs/tmpfs_subr.c   7 May 2009 19:30:30 -0000       1.53
+++ sys/fs/tmpfs/tmpfs_subr.c   12 Jul 2009 06:22:43 -0000
@@ -964,6 +964,8 @@ tmpfs_chflags(struct vnode *vp, int flag
 {
        int error;
        struct tmpfs_node *node;
+       kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS;
+       int fs_decision = 0;
 
        KASSERT(VOP_ISLOCKED(vp));
 
@@ -973,30 +975,44 @@ tmpfs_chflags(struct vnode *vp, int flag
        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                return EROFS;
 
-       /* XXX: The following comes from UFS code, and can be found in
-        * several other file systems.  Shouldn't this be centralized
-        * somewhere? */
-       if (kauth_cred_geteuid(cred) != node->tn_uid &&
-           (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
-           NULL)))
+       if (kauth_cred_geteuid(cred) != node->tn_uid)
+               fs_decision = EACCES;
+
+       /*
+        * If the new flags have non-user flags that are different than
+        * those on the node, we need special permission to change them.
+        */
+       if ((flags & SF_SETTABLE) != (node->tn_flags & SF_SETTABLE)) {
+               action |= KAUTH_VNODE_WRITE_SYSFLAGS;
+               if (!fs_decision)
+                       fs_decision = EPERM;
+       }
+
+       /*
+        * Indicate that this node's flags have system attributes in them if
+        * that's the case.
+        */
+       if (node->tn_flags & (SF_IMMUTABLE | SF_APPEND)) {
+               action |= KAUTH_VNODE_HAS_SYSFLAGS;
+       }
+
+       error = kauth_authorize_vnode(cred, action, vp, NULL, fs_decision);
+       if (error)
                return error;
-       if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) {
-               /* The super-user is only allowed to change flags if the file
-                * wasn't protected before and the securelevel is zero. */
-               if ((node->tn_flags & (SF_IMMUTABLE | SF_APPEND)) &&
-                   kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHSYSFLAGS,
-                    0, NULL, NULL, NULL))
-                       return EPERM;
+
+       /*
+        * Set the flags. If we're not setting non-user flags, be careful not
+        * to overwrite them.
+        *
+        * XXX: Can't we always assign here? if the system flags are different,
+        *      the code above should catch attempts to change them without
+        *      proper permissions, and if we're here it means it's okay to
+        *      change them...
+        */
+       if (action & KAUTH_VNODE_WRITE_SYSFLAGS) {
                node->tn_flags = flags;
        } else {
-               /* Regular users can change flags provided they only want to
-                * change user-specific ones, not those reserved for the
-                * super-user. */
-               if ((node->tn_flags & (SF_IMMUTABLE | SF_APPEND)) ||
-                   (flags & UF_SETTABLE) != flags)
-                       return EPERM;
-               if ((node->tn_flags & SF_SETTABLE) != (flags & SF_SETTABLE))
-                       return EPERM;
+               /* Clear all user-settable flags and re-set them. */
                node->tn_flags &= SF_SETTABLE;
                node->tn_flags |= (flags & UF_SETTABLE);
        }
@@ -1036,6 +1052,9 @@ tmpfs_chmod(struct vnode *vp, mode_t mod
 
        error = genfs_can_chmod(vp, cred, node->tn_uid, node->tn_gid,
            mode);
+
+       error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, 
NULL,
+           error);
        if (error)
                return (error);
 
@@ -1087,6 +1106,9 @@ tmpfs_chown(struct vnode *vp, uid_t uid,
 
        error = genfs_can_chown(vp, cred, node->tn_uid, node->tn_gid, uid,
            gid);
+
+       error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
+           NULL, error);
        if (error)
                return (error);
 
@@ -1186,6 +1208,9 @@ tmpfs_chtimes(struct vnode *vp, const st
                return EPERM;
 
        error = genfs_can_chtimes(vp, vaflags, node->tn_uid, cred);
+
+       error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, NULL,
+           error);
        if (error)
                return (error);
 
Index: sys/fs/tmpfs/tmpfs_vnops.c
===================================================================
RCS file: /usr/cvs/src/sys/fs/tmpfs/tmpfs_vnops.c,v
retrieving revision 1.61
diff -u -p -r1.61 tmpfs_vnops.c
--- sys/fs/tmpfs/tmpfs_vnops.c  3 Jul 2009 21:17:41 -0000       1.61
+++ sys/fs/tmpfs/tmpfs_vnops.c  12 Jul 2009 06:22:50 -0000
@@ -209,13 +209,28 @@ tmpfs_lookup(void *v)
                        if ((cnp->cn_flags & ISLASTCN) &&
                            (cnp->cn_nameiop == DELETE ||
                            cnp->cn_nameiop == RENAME)) {
+                               kauth_action_t action = 0;
+
+                               /* This is the file-system's decision. */
                                if ((dnode->tn_mode & S_ISTXT) != 0 &&
-                                   kauth_authorize_generic(cnp->cn_cred,
-                                    KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
                                    kauth_cred_geteuid(cnp->cn_cred) != 
dnode->tn_uid &&
-                                   kauth_cred_geteuid(cnp->cn_cred) != 
tnode->tn_uid)
-                                       return EPERM;
-                               error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
+                                   kauth_cred_geteuid(cnp->cn_cred) != 
tnode->tn_uid) {
+                                       error = EPERM;
+                               } else
+                                       error = 0;
+
+                               /* Only bother if we're not already failing it. 
*/
+                               if (!error) {
+                                       error = VOP_ACCESS(dvp, VWRITE, 
cnp->cn_cred);
+                               }
+
+                               if (cnp->cn_nameiop == DELETE)
+                                       action |= KAUTH_VNODE_DELETE;
+                               else /* if (cnp->cn_nameiop == RENAME) */
+                                       action |= KAUTH_VNODE_RENAME;
+
+                               error = kauth_authorize_vnode(cnp->cn_cred,
+                                   action, *vpp, dvp, error);
                                if (error != 0)
                                        goto out;
                                cnp->cn_flags |= SAVENAME;
@@ -406,6 +421,9 @@ tmpfs_access(void *v)
 
        error = tmpfs_check_permitted(vp, node, mode, cred);
 
+       error = kauth_authorize_vnode(cred, kauth_mode_to_action(mode), vp,
+           NULL, error);
+
 out:
        KASSERT(VOP_ISLOCKED(vp));
 


Home | Main Index | Thread Index | Old Index