Subject: adding fileop kauth(9) scope
To: None <tech-kern@netbsd.org>
From: Elad Efrat <elad@NetBSD.org>
List: tech-kern
Date: 06/17/2006 20:03:39
This is a multi-part message in MIME format.
--------------090108090403030102010008
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Hi,

Adding a subsystem such as metahook(9) (or whatever name you'd like,
and regardless of underlying implementation :) will require some help
to let it know when a file it keeps meta-data for is gone.

So... it might be a good time to add the fileop scope. See attached
diffs for the backend (fileop.kauth.diff) and relevent triggers
(fileop.kern.diff).

The fileop scope is notification only, so special care is taken in
kauth_authorize_action() to ignore whatever return value the listeners
return.

While I'm at it.. any suggestions on where (and if it's possible) to
do the same for NFS?

Please CC me on replies.

Thanks,

-e.

-- 
Elad Efrat

--------------090108090403030102010008
Content-Type: text/plain;
 name="fileop.kauth.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="fileop.kauth.diff"

Index: kern/kern_auth.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/kern_auth.c,v
retrieving revision 1.8
diff -u -p -r1.8 kern_auth.c
--- kern/kern_auth.c	13 Jun 2006 22:56:46 -0000	1.8
+++ kern/kern_auth.c	16 Jun 2006 13:39:25 -0000
@@ -97,6 +97,7 @@ static struct simplelock scopes_lock;
 /* Built-in scopes: generic, process. */
 static kauth_scope_t kauth_builtin_scope_generic;
 static kauth_scope_t kauth_builtin_scope_process;
+static kauth_scope_t kauth_builtin_scope_fileop;
 
 /* Allocate new, empty kauth credentials. */
 kauth_cred_t
@@ -592,6 +593,10 @@ kauth_init(void)
 	/* Register process scope. */
 	kauth_builtin_scope_process = kauth_register_scope(KAUTH_SCOPE_PROCESS,
 	    kauth_authorize_cb_process, NULL);
+
+	/* Register fileop scope. */
+	kauth_builtin_scope_fileop = kauth_register_scope(KAUTH_SCOPE_FILEOP,
+	    kauth_authorize_cb_fileop, NULL);
 }
 
 /*
@@ -702,6 +707,12 @@ kauth_authorize_action(kauth_scope_t sco
 			fail = 1;
 	}
 
+	/* The fileop scope is only used for notification; ignore return. */
+	if (scope == kauth_builtin_scope_fileop) {
+		allow = 1;
+		fail = 0;
+	}
+
 	return ((allow && !fail) ? 0 : EPERM);
 };
 
@@ -808,3 +819,24 @@ kauth_authorize_process(kauth_cred_t cre
 	return (kauth_authorize_action(kauth_builtin_scope_process, cred,
 	    action, p, arg1, arg2, arg3));
 }
+
+/*
+ * Fileop scope default callback.
+ */
+int
+kauth_authorize_cb_fileop(kauth_cred_t cred, kauth_action_t action,
+    void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
+{
+	return (KAUTH_RESULT_ALLOW);
+}
+
+/*
+ * Fileop scope authorization wrapper.
+ */
+int
+kauth_authorize_fileop(kauth_cred_t cred, kauth_action_t action, void *arg0,
+    void *arg1)
+{
+	return (kauth_authorize_action(kauth_builtin_scope_fileop, cred, 
+	    action, arg0, arg1, NULL, NULL));
+}
Index: sys/kauth.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/kauth.h,v
retrieving revision 1.3
diff -u -p -r1.3 kauth.h
--- sys/kauth.h	28 May 2006 06:49:27 -0000	1.3
+++ sys/kauth.h	16 Jun 2006 13:47:25 -0000
@@ -62,6 +62,7 @@ typedef int (*kauth_scope_callback_t)(ka
  */
 #define	KAUTH_SCOPE_GENERIC	"org.netbsd.kauth.generic"
 #define	KAUTH_SCOPE_PROCESS	"org.netbsd.kauth.process"
+#define	KAUTH_SCOPE_FILEOP	"org.netbsd.kauth.fileop"
 
 /*
  * Process scope - actions.
@@ -79,6 +80,16 @@ typedef int (*kauth_scope_callback_t)(ka
 #define FSCRED ((kauth_cred_t)-2)	/* filesystem credential */
 
 /*
+ * Fileop scope - actions.
+ */
+#define	KAUTH_FILEOP_OPEN	1	/* file opened */
+#define	KAUTH_FILEOP_CLOSE	2	/* file closed */
+#define	KAUTH_FILEOP_RENAME	3	/* file renamed */
+#define	KAUTH_FILEOP_EXCHANGE	4	/* not implemented */
+#define	KAUTH_FILEOP_LINK	5	/* new hard link */
+#define	KAUTH_FILEOP_EXEC	6	/* file executed */
+
+/*
  * Prototypes.
  */
 void kauth_init(void);
@@ -94,11 +105,14 @@ int kauth_authorize_cb_generic(kauth_cre
 			       void *, void *, void *, void *);
 int kauth_authorize_cb_process(kauth_cred_t, kauth_action_t, void *,
 			       void *, void *, void *, void *);
+int kauth_authorize_cb_fileop(kauth_cred_t, kauth_action_t, void *, void *,
+    void *, void *, void *);
 
 /* Authorization wrappers. */
 int kauth_authorize_generic(kauth_cred_t, kauth_action_t, void *);
 int kauth_authorize_process(kauth_cred_t, kauth_action_t, struct proc *,
     void *, void *, void *);
+int kauth_authorize_fileop(kauth_cred_t, kauth_action_t, void *, void *);
 
 /* Kauth credentials management routines. */
 kauth_cred_t kauth_cred_alloc(void);

--------------090108090403030102010008
Content-Type: text/plain;
 name="fileop.kern.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="fileop.kern.diff"

Index: kern_exec.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.218
diff -u -p -r1.218 kern_exec.c
--- kern_exec.c	14 May 2006 21:15:11 -0000	1.218
+++ kern_exec.c	16 Jun 2006 13:51:40 -0000
@@ -830,6 +830,9 @@ execve1(struct lwp *l, const char *path,
 
 	uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE);
 
+	kauth_authorize_fileop(p->p_cred, KAUTH_FILEOP_EXEC, p->p_textvp,
+	    nid.ni_cnd.cn_pnbuf);
+
 	PNBUF_PUT(nid.ni_cnd.cn_pnbuf);
 
 	/* notify others that we exec'd */
Index: vfs_syscalls.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.242
diff -u -p -r1.242 vfs_syscalls.c
--- vfs_syscalls.c	14 May 2006 21:15:12 -0000	1.242
+++ vfs_syscalls.c	16 Jun 2006 16:32:07 -0000
@@ -1638,6 +1638,7 @@ sys_link(struct lwp *l, void *v, registe
 	struct vnode *vp;
 	struct mount *mp;
 	struct nameidata nd;
+	char *path, *link;
 	int error;
 
 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
@@ -1664,6 +1665,15 @@ sys_link(struct lwp *l, void *v, registe
 	VOP_LEASE(nd.ni_dvp, l, p->p_cred, LEASE_WRITE);
 	VOP_LEASE(vp, l, p->p_cred, LEASE_WRITE);
 	error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+	path = PNBUF_GET();
+	link = PNBUF_GET();
+	if (copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL) == 0 &&
+	    copyinstr(SCARG(uap, link), link, MAXPATHLEN, NULL) == 0) {
+		kauth_authorize_fileop(p->p_cred, KAUTH_FILEOP_LINK, path,
+		    link);
+	}
+	PNBUF_PUT(path);
+	PNBUF_PUT(link);
 out:
 	vrele(vp);
 	vn_finished_write(mp, 0);
@@ -3175,6 +3185,10 @@ out:
 		vrele(fromnd.ni_dvp);
 		vrele(fvp);
 	}
+
+	kauth_authorize_fileop(p->p_cred, KAUTH_FILEOP_RENAME,
+	    __UNCONST(fromnd.ni_dirp), __UNCONST(tond.ni_dirp));
+
 	vrele(tond.ni_startdir);
 	PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
 out1:
Index: vfs_vnops.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/vfs_vnops.c,v
retrieving revision 1.112
diff -u -p -r1.112 vfs_vnops.c
--- vfs_vnops.c	27 May 2006 23:46:49 -0000	1.112
+++ vfs_vnops.c	16 Jun 2006 16:26:12 -0000
@@ -104,24 +104,18 @@ vn_open(struct nameidata *ndp, int fmode
 	kauth_cred_t cred = l->l_proc->p_cred;
 	struct vattr va;
 	int error;
-#ifdef VERIFIED_EXEC
-	struct veriexec_hash_entry *vhe = NULL;
-	char pathbuf[MAXPATHLEN];
+	char *pathbuf;
 	size_t pathlen;
 	int (*copyfun)(const void *, void *, size_t, size_t *) =
 	    ndp->ni_segflg == UIO_SYSSPACE ? copystr : copyinstr;
+#ifdef VERIFIED_EXEC
+	struct veriexec_hash_entry *vhe = NULL;
 #endif /* VERIFIED_EXEC */
 
-#ifdef VERIFIED_EXEC
+	pathbuf = PNBUF_GET();
 	error = (*copyfun)(ndp->ni_dirp, pathbuf, sizeof(pathbuf), &pathlen);
-	if (error) {
-		if (veriexec_verbose >= 1)
-			printf("veriexec: Can't copy path. (error=%d)\n",
-			    error);
-
+	if (error)
 		return (error);
-	}
-#endif /* VERIFIED_EXEC */
 
 restart:
 	if (fmode & O_CREAT) {
@@ -130,8 +124,10 @@ restart:
 		if ((fmode & O_EXCL) == 0 &&
 		    ((fmode & O_NOFOLLOW) == 0))
 			ndp->ni_cnd.cn_flags |= FOLLOW;
-		if ((error = namei(ndp)) != 0)
+		if ((error = namei(ndp)) != 0) {
+			PNBUF_PUT(pathbuf);
 			return (error);
+		}
 		if (ndp->ni_vp == NULL) {
 #ifdef VERIFIED_EXEC
 			/* Lockdown mode: Prevent creation of new files. */
@@ -157,16 +153,20 @@ restart:
 				VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
 				vput(ndp->ni_dvp);
 				if ((error = vn_start_write(NULL, &mp,
-				    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
+				    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0) {
+					PNBUF_PUT(pathbuf);
 					return (error);
+				}
 				goto restart;
 			}
 			VOP_LEASE(ndp->ni_dvp, l, cred, LEASE_WRITE);
 			error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
 					   &ndp->ni_cnd, &va);
 			vn_finished_write(mp, 0);
-			if (error)
+			if (error) {
+				PNBUF_PUT(pathbuf);
 				return (error);
+			}
 			fmode &= ~O_TRUNC;
 			vp = ndp->ni_vp;
 		} else {
@@ -188,8 +188,10 @@ restart:
 		ndp->ni_cnd.cn_flags = LOCKLEAF;
 		if ((fmode & O_NOFOLLOW) == 0)
 			ndp->ni_cnd.cn_flags |= FOLLOW;
-		if ((error = namei(ndp)) != 0)
+		if ((error = namei(ndp)) != 0) {
+			PNBUF_PUT(pathbuf);
 			return (error);
+		}
 		vp = ndp->ni_vp;
 	}
 	if (vp->v_type == VSOCK) {
@@ -250,6 +252,7 @@ restart:
 		VOP_UNLOCK(vp, 0);			/* XXX */
 		if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
 			vrele(vp);
+			PNBUF_PUT(pathbuf);
 			return (error);
 		}
 		VOP_LEASE(vp, l, cred, LEASE_WRITE);
@@ -271,8 +274,13 @@ restart:
 	if (fmode & FWRITE)
 		vp->v_writecount++;
 
+	kauth_authorize_fileop(cred, KAUTH_FILEOP_OPEN, vp, pathbuf);
+
+	PNBUF_PUT(pathbuf);
+
 	return (0);
 bad:
+	PNBUF_PUT(pathbuf);
 	vput(vp);
 	return (error);
 }
@@ -338,6 +346,8 @@ vn_close(struct vnode *vp, int flags, ka
 		vp->v_writecount--;
 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 	error = VOP_CLOSE(vp, flags, cred, l);
+	kauth_authorize_fileop(cred, KAUTH_FILEOP_CLOSE, vp,
+	    __UNCONST("XXX")); /* XXX */
 	vput(vp);
 	return (error);
 }

--------------090108090403030102010008--