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