PERFORCE change 177776 for review

Efstratios Karatzas gpf at FreeBSD.org
Wed May 5 19:48:28 UTC 2010


http://p4web.freebsd.org/@@177776?ac=10

Change 177776 by gpf at gpf_desktop on 2010/05/05 19:47:55

	Integration of my older patches.
	Able to audit file creation, read & write.
	Fixed a deadlock in my patches, everything seems ok now.
	procedures serviced: 3/23

Affected files ...

.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/bsm/audit_kevents.h#2 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/nfsserver/nfs_serv.c#2 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/nfsserver/nfs_srvkrpc.c#2 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.c#2 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.h#2 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_bsm.c#2 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_private.h#2 edit

Differences ...

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/bsm/audit_kevents.h#2 (text) ====

@@ -385,6 +385,33 @@
 #define	AUE_DARWIN_COPYFILE	361	/* Darwin-specific. */
 
 /*
+ * NFS RPC events
+ */
+#define	AUE_NFS_NULL 2000
+#define	AUE_NFS_GETATTR 2001
+#define	AUE_NFS_SETATTR 2002
+#define	AUE_NFS_LOOKUP 2003
+#define	AUE_NFS_ACCESS 2004
+#define	AUE_NFS_REALINK 2005
+#define	AUE_NFS_READ 2006
+#define	AUE_NFS_WRITE 2007
+#define	AUE_NFS_CREATE 2008
+#define	AUE_NFS_MKDIR 2009
+#define	AUE_NFS_SYMLINK 2010
+#define	AUE_NFS_MKNODE 2011
+#define	AUE_NFS_REMOVE 2012
+#define	AUE_NFS_RMDIR 2013
+#define	AUE_NFS_RENAME 2014
+#define	AUE_NFS_LINK 2015
+#define	AUE_NFS_READDIR 2016
+#define	AUE_NFS_READDIR_PLUS 2017
+#define	AUE_NFS_STATFS 2018
+#define	AUE_NFS_FSINFO 2019
+#define	AUE_NFS_PATHCONF 2020
+#define	AUE_NFS_COMMIT 2021
+#define	AUE_NFS_NOOP 2022
+
+/*
  * Audit event identifiers added as part of OpenBSM, generally corresponding
  * to events in FreeBSD, Darwin, and Linux that were not present in Solaris.
  * These often duplicate events added to the Solaris set by Darwin, but use

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/nfsserver/nfs_serv.c#2 (text+ko) ====

@@ -88,6 +88,8 @@
 #include <sys/bio.h>
 #include <sys/buf.h>
 
+#include <security/audit/audit.h>
+
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vm_object.h>
@@ -778,7 +780,7 @@
 	int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
 	struct mbuf *mb, *mreq;
 	struct mbuf *m2;
-	struct vnode *vp = NULL;
+	struct vnode *vp = NULL, *vp_alt = NULL;
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct uio io, *uiop = &io;
@@ -818,7 +820,9 @@
 		error = 0;
 		goto nfsmout;
 	}
-
+	
+	vp_alt = vp;
+	
 	if (vp->v_type != VREG) {
 		if (v3)
 			error = EINVAL;
@@ -1003,6 +1007,21 @@
 	if (vp)
 		vput(vp);
 	VFS_UNLOCK_GIANT(vfslocked);
+	
+	/* XXX AUDIT */	
+	if (vp_alt != NULL) {
+		char *fullpath, *freepath;
+		struct thread *td = curthread;
+
+		freepath = NULL;
+		vn_fullpath_global(td, vp_alt, &fullpath, &freepath);
+
+		if (freepath != NULL) {
+			AUDIT_ARG_UPATH1(td, fullpath);
+			free(freepath, M_TEMP);
+		}
+	}
+	
 	return(error);
 }
 
@@ -1031,7 +1050,7 @@
 	int stable = NFSV3WRITE_FILESYNC;
 	int v3 = (nfsd->nd_flag & ND_NFSV3);
 	struct mbuf *mb, *mreq;
-	struct vnode *vp = NULL;
+	struct vnode *vp = NULL, *vp_alt = NULL;;
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	struct uio io, *uiop = &io;
@@ -1120,6 +1139,9 @@
 		error = 0;
 		goto nfsmout;
 	}
+	
+	vp_alt = vp;
+	
 	if (v3)
 		forat_ret = VOP_GETATTR(vp, &forat, cred);
 	if (vp->v_type != VREG) {
@@ -1221,6 +1243,36 @@
 		vput(vp);
 	vn_finished_write(mntp);
 	VFS_UNLOCK_GIANT(vfslocked);
+	
+	/* XXX AUDIT */	
+	
+	/* 
+	 * another way we could go about re-obtaining the vp from the file handle.
+	 * right now, I think i like the vp_alt method better
+	 */
+	/*
+	if (vp == NULL) {
+		tvfslocked = 0;	
+		error = nfsrv_fhtovp(fhp, 0, &vp, &tvfslocked, 
+			nfsd, slp, nam, &rdonly, TRUE);
+		if (error) 
+			vp = NULL;
+	}
+	*/
+	
+	if (vp_alt != NULL) {		
+		char *fullpath, *freepath;
+		struct thread *td = curthread;
+
+		freepath = NULL;
+		vn_fullpath_global(td, vp_alt, &fullpath, &freepath);
+
+		if (freepath != NULL) {
+			AUDIT_ARG_UPATH1(td, fullpath);
+			free(freepath, M_TEMP);
+		}
+	}	
+	
 	return(error);
 }
 
@@ -1519,6 +1571,38 @@
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
+	
+	/* XXX AUDIT */	
+	if (nd.ni_vp != NULL && nd.ni_dvp != NULL) {
+		struct thread *td = curthread;
+		char *fullpath, *freepath;
+		char path[PATH_MAX];
+	
+		AUDIT_ARG_VNODE1(nd.ni_vp);
+		
+		freepath = NULL;
+		vn_fullpath_global(td, nd.ni_vp, &fullpath, &freepath);
+		
+		if (freepath != NULL) {
+			strlcpy(path, fullpath, sizeof(path));
+			free(freepath, M_TEMP);
+		}
+		/* if we fail to acquire a path from the new vnode, use the directory vnode instead */
+		else {
+			vn_fullpath_global(td, nd.ni_dvp, &fullpath, &freepath);		
+			if (freepath != NULL) {
+				snprintf(path, sizeof(path), "%s/%s", fullpath, nd.ni_cnd.cn_pnbuf);
+				free(freepath, M_TEMP);
+			}
+			/* last resort: just save the name of the new file */
+			else {
+				strlcpy(path, nd.ni_cnd.cn_pnbuf, sizeof(path));
+			}
+		}
+		
+		AUDIT_ARG_UPATH1(td, path);
+	}
+	
 	return (error);
 }
 

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/nfsserver/nfs_srvkrpc.c#2 (text+ko) ====

@@ -63,6 +63,8 @@
 #include <sys/lockf.h>
 #include <sys/eventhandler.h>
 
+#include <security/audit/audit.h>
+
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #ifdef INET6
@@ -254,6 +256,7 @@
 	struct nfsrv_descript nd;
 	struct mbuf *mreq, *mrep;
 	int error;
+	struct thread *td = curthread;
 
 	if (rqst->rq_vers == NFS_VER2) {
 		if (rqst->rq_proc > NFSV2PROC_STATFS) {
@@ -349,7 +352,9 @@
 	}
 	nfsrvstats.srvrpccnt[nd.nd_procnum]++;
 
+	AUDIT_NFS_ENTER(procnum, td);
 	error = proc(&nd, NULL, &mrep);
+	AUDIT_NFS_EXIT(error, td);
 
 	if (nd.nd_cr)
 		crfree(nd.nd_cr);

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.c#2 (text) ====

@@ -60,6 +60,9 @@
 #include <sys/unistd.h>
 #include <sys/vnode.h>
 
+/* XXX gpf: for debuging */
+#include <sys/types.h>
+
 #include <bsm/audit.h>
 #include <bsm/audit_internal.h>
 #include <bsm/audit_kevents.h>
@@ -589,6 +592,234 @@
 	td->td_pflags &= ~TDP_AUDITREC;
 }
 
+/*
+ * Convert an NFS RPC procedure number to an audit event
+ */
+int
+audit_nfs_proc_to_event(unsigned int proc, au_event_t *event)
+{
+	switch (proc) {
+	case 0:
+		/* nfsrv_null */
+		*event = AUE_NFS_NULL;
+		break;
+		
+	case 1:
+		/* nfsrv_getattr */
+		*event = AUE_NFS_GETATTR;
+		break;
+		
+	case 2:
+		/* nfsrv_setattr */
+		*event = AUE_NFS_SETATTR;
+		break;
+		
+	case 3:
+		/* nfsrv_lookup */
+		*event = AUE_NFS_LOOKUP;
+		break;
+		
+	case 4:
+		/* nfsrv3_access */
+		*event = AUE_NFS_ACCESS;
+		break;
+		
+	case 5:
+		/* nfsrv_readlink */
+		*event = AUE_NFS_REALINK;
+		break;
+		
+	case 6:
+		/* nfsrv_read */
+		*event = AUE_NFS_READ;
+		break;
+		
+	case 7:
+		/* nfsrv_write */
+		*event = AUE_NFS_WRITE;
+		break;
+
+	case 8:
+		/* nfsrv_create */
+		*event = AUE_NFS_CREATE;
+		break;
+		
+	case 9:
+		/* nfsrv_mkdir */
+		*event = AUE_NFS_MKDIR;
+		break;
+		
+	case 10:
+		/* nfsrv_symlink */
+		*event = AUE_NFS_SYMLINK;
+		break;
+		
+	case 11:
+		/*  nfsrv_mknod */
+		*event = AUE_NFS_MKNODE;
+		break;
+		
+	case 12:
+		/*  nfsrv_remove */
+		*event = AUE_NFS_REMOVE;
+		break;
+		
+	case 13:
+		/* nfsrv_rmdir */
+		*event = AUE_NFS_RMDIR;
+		break;
+		
+	case 14:
+		/* nfsrv_rename */
+		*event = AUE_NFS_RENAME;
+		break;
+		
+	case 15:
+		/* nfsrv_link */
+		*event = AUE_NFS_LINK;
+		break;
+		
+	case 16:
+		/* nfsrv_readdir */
+		*event = AUE_NFS_READDIR;
+		break;
+		
+	case 17:
+		/* nfsrv_readdirplus */
+		*event = AUE_NFS_READDIR_PLUS;
+		break;
+		
+	case 18:
+		/* nfsrv_statfs */
+		*event = AUE_NFS_STATFS;
+		break;
+		
+	case 19:
+		/* nfsrv_fsinfo */
+		*event = AUE_NFS_FSINFO;
+		break;
+		
+	case 20:
+		/* nfsrv_pathconf */
+		*event = AUE_NFS_PATHCONF;
+		break;
+		
+	case 21:
+		/* nfsrv_commit */
+		*event = AUE_NFS_COMMIT;
+		break;
+		
+	case 22:
+		/* nfsrv_noop */
+		*event = AUE_NFS_NOOP;
+		break;		
+	
+	default:		
+		*event = AUE_NFS_NULL;
+		return 1; /* unmatched */
+	}
+	
+	return 0; /* matched */
+}
+
+/*
+ * audit_nfs_enter() is called on entry to each rpc request that *will* 
+ * be serviced by the nfs server. It is responsible for deciding 
+ * whether or not to audit the remote procedure call (preselection),
+ * and if so, allocating a per-thread audit record.  
+ * audit_new() will fill in basic thread/credential properties.
+ */
+void
+audit_nfs_enter(unsigned int proc, struct thread *td)
+{
+	struct au_mask *aumask;
+	au_class_t class;
+	au_event_t event;
+	au_id_t auid;
+	
+	KASSERT(td->td_ar == NULL, ("audit_nfs_enter: td->td_ar != NULL"));
+	KASSERT((td->td_pflags & TDP_AUDITREC) == 0,
+	    ("audit_nfs_enter: TDP_AUDITREC set"));
+	    
+	/* XXXgpf: perhaps log a failure to match a rpc to an audit event? */
+	audit_nfs_proc_to_event(proc, &event);
+	
+	printf("audit_nfs_enter: procedure = %d\n"
+	       "audit_nfs_enter: event = %d\n", proc, event);
+	
+	/*
+	 * Check which audit mask to use; either the kernel non-attributable
+	 * event mask or the process audit mask.
+	 */
+	auid = td->td_ucred->cr_audit.ai_auid;
+	if (auid == AU_DEFAUDITID)
+		aumask = &audit_nae_mask;
+	else
+		aumask = &td->td_ucred->cr_audit.ai_mask;
+
+	/*
+	 * Allocate an audit record, if preselection allows it, and store in
+	 * the thread for later use.
+	 */
+	class = au_event_class(event);
+	if (au_preselect(event, class, aumask, AU_PRS_BOTH)) {
+		printf("audit_nfs_enter: select it!\n\n");
+		/*
+		 * If we're out of space and need to suspend unprivileged
+		 * processes, do that here rather than trying to allocate
+		 * another audit record.
+		 *
+		 * Note: we might wish to be able to continue here in the
+		 * future, if the system recovers.  That should be possible
+		 * by means of checking the condition in a loop around
+		 * cv_wait().  It might be desirable to reevaluate whether an
+		 * audit record is still required for this event by
+		 * re-calling au_preselect().
+		 */
+		if (audit_in_failure &&
+		    priv_check(td, PRIV_AUDIT_FAILSTOP) != 0) {
+			cv_wait(&audit_fail_cv, &audit_mtx);
+			panic("audit_failing_stop: thread continued");
+		}
+		td->td_ar = audit_new(event, td);
+		if (td->td_ar != NULL)
+			td->td_pflags |= TDP_AUDITREC;
+	} else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) {
+		td->td_ar = audit_new(event, td);
+		if (td->td_ar != NULL)
+			td->td_pflags |= TDP_AUDITREC;
+	} else
+		td->td_ar = NULL;
+}
+
+/*
+ * audit_nfs_exit() is called from the return of every NFS pseudo-sys/call 
+ * that services an RPC by performing the various vnode operations.
+ * It is responsible for committing the audit record, if any, along with 
+ * return condition.
+ */
+void
+audit_nfs_exit(int error, struct thread *td)
+{
+	int retval;
+
+	/*
+	 * Commit the audit record as desired; once we pass the record into
+	 * audit_commit(), the memory is owned by the audit subsystem.  The
+	 * return value from the system call is stored on the user thread.
+	 * If there was an error, the return value is set to -1, imitating
+	 * the behavior of the cerror routine.
+	 */
+	if (error)
+		retval = -1;
+	else
+		retval = td->td_retval[0];
+
+	audit_commit(td->td_ar, error, retval);
+	td->td_ar = NULL;
+	td->td_pflags &= ~TDP_AUDITREC;
+}
+
 void
 audit_cred_copy(struct ucred *src, struct ucred *dest)
 {

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.h#2 (text) ====

@@ -59,6 +59,9 @@
 void	 audit_syscall_enter(unsigned short code, struct thread *td);
 void	 audit_syscall_exit(int error, struct thread *td);
 
+void	 audit_nfs_enter(unsigned int proc, struct thread *td);
+void	 audit_nfs_exit(int error, struct thread *td);
+
 /*
  * The remaining kernel functions are conditionally compiled in as they are
  * wrapped by a macro, and the macro should be the only place in the source
@@ -311,6 +314,17 @@
 		audit_syscall_exit(error, td);				\
 } while (0)
 
+#define	AUDIT_NFS_ENTER(proc, td)	do {				\
+	if (audit_enabled) {						\
+		audit_nfs_enter(proc, td);				\
+	}								\
+} while (0)
+
+#define	AUDIT_NFS_EXIT(error, td)	do {				\
+	if (td->td_pflags & TDP_AUDITREC)				\
+		audit_nfs_exit(error, td);				\
+} while (0)
+
 /*
  * A Macro to wrap the audit_sysclose() function.
  */
@@ -360,6 +374,9 @@
 
 #define	AUDIT_SYSCLOSE(p, fd)
 
+#define	AUDIT_NFS_ENTER(proc, td)
+#define	AUDIT_NFS_EXIT(error, td)
+
 #endif /* AUDIT */
 
 #endif /* !_SECURITY_AUDIT_KERNEL_H_ */

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_bsm.c#2 (text) ====

@@ -1581,6 +1581,18 @@
 		kau_write(rec, tok);
 		break;
 
+	case AUE_NFS_CREATE:
+		if (ARG_IS_VALID(kar, ARG_MODE)) {
+			tok = au_to_arg32(3, "mode", ar->ar_arg_mode);
+			kau_write(rec, tok);
+		}
+		/* FALLTHROUGH */
+
+	case AUE_NFS_READ:
+	case AUE_NFS_WRITE:
+		UPATH1_VNODE1_TOKENS;
+		break;
+
 	case AUE_WAIT4:
 		PROCESS_PID_TOKENS(1);
 		if (ARG_IS_VALID(kar, ARG_VALUE)) {

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_private.h#2 (text) ====

@@ -324,6 +324,11 @@
 struct kaudit_record	*audit_new(int event, struct thread *td);
 
 /*
+ * NFS specific functions
+ */
+int			 audit_nfs_proc_to_event(unsigned int proc, au_event_t *event);
+
+/*
  * Functions relating to the conversion of internal kernel audit records to
  * the BSM file format.
  */


More information about the p4-projects mailing list