Index: contrib/openbsm/etc/audit_class =================================================================== --- contrib/openbsm/etc/audit_class +++ contrib/openbsm/etc/audit_class @@ -17,6 +17,7 @@ 0x00001000:lo:login_logout 0x00002000:aa:authentication and authorization 0x00004000:ap:application +0x00008000:nfs:network file system server 0x20000000:io:ioctl 0x40000000:ex:exec 0x80000000:ot:miscellaneous Index: contrib/openbsm/etc/audit_event =================================================================== --- contrib/openbsm/etc/audit_event +++ contrib/openbsm/etc/audit_event @@ -615,6 +615,30 @@ 43262:AUE_EXECVEAT:execveat(2):pc,ex 43263:AUE_SHMRENAME:shm_rename(2):ip # +# NFS RPC related events. +# +43266:AUE_NFSRPC_GETATTR:nfsrvd_getattr:nfs +43267:AUE_NFSRPC_SETATTR:nfsrvd_setattr:nfs +43268:AUE_NFSRPC_LOOKUP:nfsrvd_lookup:nfs +43269:AUE_NFSRPC_ACCESS:nfsrvd_access:nfs +43270:AUE_NFSRPC_READLINK:nfsrvd_readlink:nfs +43271:AUE_NFSRPC_READ:nfsrvd_read:nfs +43272:AUE_NFSRPC_WRITE:nfsrvd_write:nfs +43273:AUE_NFSRPC_CREATE:nfsrvd_create:nfs +43274:AUE_NFSRPC_MKDIR:nfsrvd_mkdir:nfs +43275:AUE_NFSRPC_SYMLINK:nfsrvd_symlink:nfs +43276:AUE_NFSRPC_MKNOD:nfsrvd_mknod:nfs +43277:AUE_NFSRPC_REMOVE:nfsrvd_remove:nfs +43278:AUE_NFSRPC_RMDIR:nfsrvd_rmdir:nfs +43279:AUE_NFSRPC_RENAME:nfsrvd_rename:nfs +43280:AUE_NFSRPC_LINK:nfsrvd_link:nfs +43281:AUE_NFSRPC_READDIR:nfsrvd_readdir:nfs +43282:AUE_NFSRPC_READDIRPLUS:nfsrvd_readdirplus:nfs +43283:AUE_NFSRPC_FSSTAT:nfsrvd_statfs:nfs +43284:AUE_NFSRPC_FSINFO:nfsrvd_fsinfo:nfs +43285:AUE_NFSRPC_PATHCONF:nfsrvd_pathconf:nfs +43286:AUE_NFSRPC_COMMIT:nfsrvd_commit:nfs +# # Solaris userspace events. # 6144:AUE_at_create:at-create atjob:ad Index: sys/bsm/audit_kevents.h =================================================================== --- sys/bsm/audit_kevents.h +++ sys/bsm/audit_kevents.h @@ -660,6 +660,31 @@ #define AUE_REALPATHAT 43264 /* FreeBSD-specific. */ #define AUE_CLOSERANGE 43265 /* FreeBSD-specific. */ +/* + * NFSv2 and NFSv3 RPC related audit events. + */ +#define AUE_NFSRPC_GETATTR 43266 +#define AUE_NFSRPC_SETATTR 43267 +#define AUE_NFSRPC_LOOKUP 43268 +#define AUE_NFSRPC_ACCESS 43269 +#define AUE_NFSRPC_READLINK 43270 +#define AUE_NFSRPC_READ 43271 +#define AUE_NFSRPC_WRITE 43272 +#define AUE_NFSRPC_CREATE 43273 +#define AUE_NFSRPC_MKDIR 43274 +#define AUE_NFSRPC_SYMLINK 43275 +#define AUE_NFSRPC_MKNOD 43276 +#define AUE_NFSRPC_REMOVE 43277 +#define AUE_NFSRPC_RMDIR 43278 +#define AUE_NFSRPC_RENAME 43279 +#define AUE_NFSRPC_LINK 43280 +#define AUE_NFSRPC_READDIR 43281 +#define AUE_NFSRPC_READDIRPLUS 43282 +#define AUE_NFSRPC_FSSTAT 43283 +#define AUE_NFSRPC_FSINFO 43284 +#define AUE_NFSRPC_PATHCONF 43285 +#define AUE_NFSRPC_COMMIT 43286 + /* * Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the * normal Solaris BSM identifiers. _O_ refers to it being an old, or compat Index: sys/fs/nfs/nfs.h =================================================================== --- sys/fs/nfs/nfs.h +++ sys/fs/nfs/nfs.h @@ -36,6 +36,9 @@ #ifndef _NFS_NFS_H_ #define _NFS_NFS_H_ + +#include + /* * Tunable constants for nfs */ @@ -309,7 +312,7 @@ struct nfsreferral { u_char *nfr_srvlist; /* List of servers */ int nfr_srvcnt; /* number of servers */ - vnode_t nfr_vp; /* vnode for referral */ + struct vnode * nfr_vp; /* vnode for referral */ uint64_t nfr_dfileno; /* assigned dir inode# */ }; @@ -559,6 +562,12 @@ #define NFSV4ROOT_INO 2 /* It's traditional */ #define NFSV4ROOT_GEN 1 +/* + * This array indicates the audit event number corresponding to NFSv3 and + * NFSv2 RPCs. This table doesn't support NFSv4. + */ +extern u_int16_t nfsrv3_auevent[NFS_V3NPROCS]; + /* * The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts. * What should be in this set is open to debate, but I believe that since @@ -671,6 +680,7 @@ nfsv4stateid_t nd_savedcurstateid; /* Saved Current StateID */ uint32_t nd_maxreq; /* Max. request (session). */ uint32_t nd_maxresp; /* Max. reply (session). */ + struct kaudit_record *nd_ar; /* Audit record for NFS server */ int nd_bextpg; /* Current ext_pgs page */ int nd_bextpgsiz; /* Bytes left in page */ int nd_maxextsiz; /* Max ext_pgs mbuf size */ @@ -722,6 +732,7 @@ #define ND_EXTLS 0x8000000000 #define ND_EXTLSCERT 0x10000000000 #define ND_EXTLSCERTUSER 0x20000000000 +#define ND_AUDITREC 0x40000000000 /* * ND_GSS should be the "or" of all GSS type authentications. Index: sys/fs/nfs/nfsdport.h =================================================================== --- sys/fs/nfs/nfsdport.h +++ sys/fs/nfs/nfsdport.h @@ -28,6 +28,9 @@ * $FreeBSD$ */ +#ifndef _NFS_NFSDPORT_H_ +#define _NFS_NFSDPORT_H_ + /* * These macros handle nfsvattr fields. They look a bit silly here, but * are quite different for the Darwin port. @@ -116,3 +119,4 @@ printf(__VA_ARGS__); \ } while (0) +#endif /* _NFS_NFSDPORT_H_ */ Index: sys/fs/nfsserver/nfs_nfsdkrpc.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdkrpc.c +++ sys/fs/nfsserver/nfs_nfsdkrpc.c @@ -46,6 +46,7 @@ #include +#include #include NFSDLOCKMUTEX; @@ -382,7 +383,13 @@ if (cacherep == RC_DOIT) { if ((nd->nd_flag & ND_NFSV41) != 0) nd->nd_xprt = xprt; + if ((nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) != 0) { + AUDIT_NFSRPC_ENTER(nd, curthread); + AUDIT_NFSARG_NETSOCKADDR(nd, nd->nd_nam); + } nfsrvd_dorpc(nd, isdgram, tagstr, taglen, minorvers); + if ((nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) != 0) + AUDIT_NFSRPC_EXIT(nd, curthread); if ((nd->nd_flag & ND_NFSV41) != 0) { if (nd->nd_repstat != NFSERR_REPLYFROMCACHE && (nd->nd_flag & ND_SAVEREPLY) != 0) { Index: sys/fs/nfsserver/nfs_nfsdport.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdport.c +++ sys/fs/nfsserver/nfs_nfsdport.c @@ -46,6 +46,7 @@ */ #include +#include #include #include #include @@ -1974,6 +1975,7 @@ nfsrv_postopattr(nd, getret, &at); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); off = fxdr_unsigned(u_quad_t, *tl++); @@ -2240,6 +2242,7 @@ nfsrv_postopattr(nd, getret, &at); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); off = fxdr_hyper(tl); toff = off; Index: sys/fs/nfsserver/nfs_nfsdserv.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdserv.c +++ sys/fs/nfsserver/nfs_nfsdserv.c @@ -51,6 +51,7 @@ #include #include #include +#include /* Global vars */ extern u_int32_t newnfs_false, newnfs_true; @@ -125,8 +126,10 @@ nfsrv_postopattr(nd, 1, &nva); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); nfsmode = fxdr_unsigned(u_int32_t, *tl); + AUDIT_NFSARG_MODE(nd, nfsmode); if ((nd->nd_flag & ND_NFSV4) && (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | @@ -235,6 +238,7 @@ if (nd->nd_repstat) goto out; + AUDIT_NFSARG_VNODE1(nd, vp); if (nd->nd_flag & ND_NFSV4) { error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); if (error) { @@ -362,6 +366,7 @@ nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); #ifdef NFS4_ACL_EXTATTR_NAME aclp = acl_alloc(M_WAITOK); aclp->acl_cnt = 0; @@ -594,6 +599,8 @@ nfsvno_relpathbuf(&named); goto out; } + AUDIT_NFSARG_UPATH1_VP(nd, p, named.ni_rootdir, dp, + named.ni_cnd.cn_pnbuf); if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); } else { @@ -615,6 +622,7 @@ vrele(named.ni_startdir); nfsvno_relpathbuf(&named); vp = named.ni_vp; + AUDIT_NFSARG_VNODE1(nd, vp); if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && vp->v_type != VDIR && vp->v_type != VLNK) /* @@ -673,6 +681,7 @@ nfsrv_postopattr(nd, getret, &nva); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); if (vnode_vtype(vp) != VLNK) { if (nd->nd_flag & ND_NFSV2) nd->nd_repstat = ENXIO; @@ -739,6 +748,7 @@ nfsrv_postopattr(nd, getret, &nva); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); off = (off_t)fxdr_unsigned(u_int32_t, *tl++); @@ -949,6 +959,7 @@ nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); gotproxystateid = 0; if (nd->nd_flag & ND_NFSV2) { NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); @@ -1140,6 +1151,8 @@ error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) goto nfsmout; + AUDIT_NFSARG_UPATH1_VP(nd, p, named.ni_rootdir, dp, + named.ni_cnd.cn_pnbuf); if (!nd->nd_repstat) { NFSVNO_ATTRINIT(&nva); if (nd->nd_flag & ND_NFSV2) { @@ -1150,6 +1163,7 @@ NFSVNO_SETATTRVAL(&nva, type, vtyp); NFSVNO_SETATTRVAL(&nva, mode, nfstov_mode(sp->sa_mode)); + AUDIT_NFSARG_MODE(nd, nva.na_mode); switch (nva.na_type) { case VREG: tsize = fxdr_unsigned(int32_t, sp->sa_size); @@ -1240,6 +1254,7 @@ &exclusive_flag, cverf, rdev, exp); if (!nd->nd_repstat) { + AUDIT_NFSARG_VNODE1(nd, named.ni_vp); nd->nd_repstat = nfsvno_getfh(vp, &fh, p); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, @@ -1351,6 +1366,8 @@ error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) goto nfsmout; + AUDIT_NFSARG_UPATH1_VP(nd, p, named.ni_rootdir, dp, + named.ni_cnd.cn_pnbuf); if (!nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) { NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); @@ -1366,6 +1383,7 @@ major = fxdr_unsigned(u_int32_t, *tl++); minor = fxdr_unsigned(u_int32_t, *tl); nva.na_rdev = NFSMAKEDEV(major, minor); + AUDIT_NFSARG_DEV(nd, nva.na_rdev); } } @@ -1400,6 +1418,7 @@ else nva.na_mode = 0400; } + AUDIT_NFSARG_MODE(nd, nva.na_mode); if (vtyp == VDIR) named.ni_cnd.cn_flags |= WILLBEDIR; @@ -1447,6 +1466,7 @@ if (!nd->nd_repstat) { vp = named.ni_vp; nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); + AUDIT_NFSARG_VNODE1(nd, vp); nd->nd_repstat = nfsvno_getfh(vp, fhp, p); if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, @@ -1525,6 +1545,8 @@ nfsvno_relpathbuf(&named); goto out; } + AUDIT_NFSARG_UPATH1_VP(nd, p, named.ni_rootdir, dp, + named.ni_cnd.cn_pnbuf); if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); } else { @@ -1541,6 +1563,7 @@ } } if (!nd->nd_repstat) { + AUDIT_NFSARG_VNODE1(nd, named.ni_vp); if (nd->nd_flag & ND_NFSV4) { if (vnode_vtype(named.ni_vp) == VDIR) nd->nd_repstat = nfsvno_rmdirsub(&named, 1, @@ -1618,6 +1641,8 @@ nfsvno_relpathbuf(&fromnd); goto out; } + AUDIT_NFSARG_UPATH1_VP(nd, p, fromnd.ni_rootdir, dp, + fromnd.ni_cnd.cn_pnbuf); /* * Unlock dp in this code section, so it is unlocked before * tdp gets locked. This avoids a potential LOR if tdp is the @@ -1681,6 +1706,8 @@ nfsvno_relpathbuf(&tond); goto out; } + AUDIT_NFSARG_UPATH2_VP(nd, p, tond.ni_rootdir, tdp, + tond.ni_cnd.cn_pnbuf); } if (nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) { @@ -1715,6 +1742,7 @@ nfsvno_relpathbuf(&tond); goto out; } + AUDIT_NFSARG_VNODE1(nd, fromnd.ni_vp); if (vnode_vtype(fromnd.ni_vp) == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); @@ -1772,6 +1800,7 @@ nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); NFSVOPUNLOCK(vp); if (vnode_vtype(vp) == VDIR) { if (nd->nd_flag & ND_NFSV4) @@ -1809,6 +1838,8 @@ nfsvno_relpathbuf(&named); goto out; } + AUDIT_NFSARG_UPATH1_VP(nd, p, named.ni_rootdir, dp, + named.ni_cnd.cn_pnbuf); if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, p, &dirp); @@ -1878,8 +1909,11 @@ LOCKPARENT | SAVESTART | NOCACHE); nfsvno_setpathbuf(&named, &bufp, &hashp); error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); - if (!error && !nd->nd_repstat) + if (!error && !nd->nd_repstat) { + AUDIT_NFSARG_UPATH1_VP(nd, p, named.ni_rootdir, dp, + named.ni_cnd.cn_pnbuf); error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); + } if (error) { vrele(dp); nfsvno_relpathbuf(&named); @@ -1907,6 +1941,7 @@ nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, pathcp, pathlen); + AUDIT_NFSARG_VNODE1(nd, named.ni_vp); } else if (dirp != NULL) { dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); vrele(dirp); @@ -1998,6 +2033,8 @@ error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); if (error) goto nfsmout; + AUDIT_NFSARG_UPATH1_VP(nd, p, named.ni_rootdir, dp, + named.ni_cnd.cn_pnbuf); if (!nd->nd_repstat) { NFSVNO_ATTRINIT(&nva); if (nd->nd_flag & ND_NFSV3) { @@ -2009,6 +2046,7 @@ nva.na_mode = nfstov_mode(*tl++); } } + AUDIT_NFSARG_MODE(nd, nva.na_mode); if (!nd->nd_repstat) { nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); } else { @@ -2039,6 +2077,7 @@ nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp); + AUDIT_NFSARG_VNODE1(nd, named.ni_vp); if (nd->nd_flag & ND_NFSV3) { if (!nd->nd_repstat) { (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); @@ -2119,11 +2158,11 @@ u_int64_t off; struct thread *p = curthread; - if (nd->nd_repstat) { + if (nd->nd_repstat) { nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); goto out; } - + AUDIT_NFSARG_VNODE1(nd, vp); /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ if (vp->v_type != VREG) { if (nd->nd_flag & ND_NFSV3) @@ -2183,6 +2222,7 @@ nfsrv_postopattr(nd, getret, &at); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); nd->nd_repstat = nfsvno_statfs(vp, sf); getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); @@ -2241,6 +2281,7 @@ nfsrv_postopattr(nd, getret, &at); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); nfsvno_getfs(&fs, isdgram); vput(vp); @@ -2281,13 +2322,14 @@ nfsrv_postopattr(nd, getret, &at); goto out; } + AUDIT_NFSARG_VNODE1(nd, vp); nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, nd->nd_cred, p); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, nd->nd_cred, p); if (!nd->nd_repstat) - nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, + nd->nd_repstat = nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, &chownres, nd->nd_cred, p); if (!nd->nd_repstat) nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, Index: sys/fs/nfsserver/nfs_nfsdsocket.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdsocket.c +++ sys/fs/nfsserver/nfs_nfsdsocket.c @@ -460,6 +460,31 @@ NFSV4OP_COMMIT, }; +u_int16_t nfsrv3_auevent[NFS_V3NPROCS] = { + AUE_NULL, + AUE_NFSRPC_GETATTR, + AUE_NFSRPC_SETATTR, + AUE_NFSRPC_LOOKUP, + AUE_NFSRPC_ACCESS, + AUE_NFSRPC_READLINK, + AUE_NFSRPC_READ, + AUE_NFSRPC_WRITE, + AUE_NFSRPC_CREATE, + AUE_NFSRPC_MKDIR, + AUE_NFSRPC_SYMLINK, + AUE_NFSRPC_MKNOD, + AUE_NFSRPC_REMOVE, + AUE_NFSRPC_RMDIR, + AUE_NFSRPC_RENAME, + AUE_NFSRPC_LINK, + AUE_NFSRPC_READDIR, + AUE_NFSRPC_READDIRPLUS, + AUE_NFSRPC_FSSTAT, + AUE_NFSRPC_FSINFO, + AUE_NFSRPC_PATHCONF, + AUE_NFSRPC_COMMIT, +}; + static struct mtx nfsrvd_statmtx; MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF); Index: sys/kern/vfs_cache.c =================================================================== --- sys/kern/vfs_cache.c +++ sys/kern/vfs_cache.c @@ -2619,6 +2619,7 @@ struct namecache *ncp; struct mtx *vlp; int error; + bool islocked; vlp = VP2VNODELOCK(*vp); mtx_lock(vlp); @@ -2630,10 +2631,14 @@ } else { ncp = vn_dd_from_dst(*vp); } + islocked = (VOP_ISLOCKED(*vp)) ? true : false; if (ncp != NULL) { if (*buflen < ncp->nc_nlen) { mtx_unlock(vlp); - vrele(*vp); + if (!islocked) + vrele(*vp); + else + vunref(*vp); counter_u64_add(numfullpathfail4, 1); error = ENOMEM; SDT_PROBE3(vfs, namecache, fullpath, return, error, @@ -2648,15 +2653,23 @@ *vp = ncp->nc_dvp; vref(*vp); mtx_unlock(vlp); - vrele(dvp); + if (!islocked) + vrele(dvp); + else + vunref(dvp); return (0); } SDT_PROBE1(vfs, namecache, fullpath, miss, vp); mtx_unlock(vlp); - vn_lock(*vp, LK_SHARED | LK_RETRY); + if (!islocked) + vn_lock(*vp, LK_SHARED | LK_RETRY); + KASSERT(VOP_ISLOCKED(*vp) != 0, ("vn_vptocnp: vnode not locked")); error = VOP_VPTOCNP(*vp, &dvp, cred, buf, buflen); - vput(*vp); + if (!islocked) + vput(*vp); + else + vunref(*vp); if (error) { counter_u64_add(numfullpathfail2, 1); SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL); @@ -2697,6 +2710,7 @@ struct vnode *vp1; size_t buflen; int error; + bool islocked; VNPASS(vp->v_type == VDIR || VN_IS_DOOMED(vp), vp); VNPASS(vp->v_usecount > 0, vp); @@ -2713,6 +2727,7 @@ SDT_PROBE1(vfs, namecache, fullpath, entry, vp); counter_u64_add(numfullpathcalls, 1); + islocked = (VOP_ISLOCKED(vp)) ? true : false; while (vp != rdir && vp != rootvnode) { /* * The vp vnode must be already fully constructed, @@ -2721,7 +2736,8 @@ * without obtaining the vnode lock. */ if ((vp->v_vflag & VV_ROOT) != 0) { - vn_lock(vp, LK_RETRY | LK_SHARED); + if (!islocked) + vn_lock(vp, LK_RETRY | LK_SHARED); /* * With the vnode locked, check for races with @@ -2734,7 +2750,10 @@ if (VN_IS_DOOMED(vp) || (vp1 = vp->v_mount->mnt_vnodecovered) == NULL || vp1->v_mountedhere != vp->v_mount) { - vput(vp); + if (!islocked) + vput(vp); + else + vunref(vp); error = ENOENT; SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL); @@ -2742,12 +2761,20 @@ } vref(vp1); - vput(vp); + if (!islocked) + vput(vp); + else + vunref(vp); vp = vp1; + islocked = false; continue; } + islocked = (VOP_ISLOCKED(vp)) ? true : false; if (vp->v_type != VDIR) { - vrele(vp); + if (!islocked) + vrele(vp); + else + vunref(vp); counter_u64_add(numfullpathfail1, 1); error = ENOTDIR; SDT_PROBE3(vfs, namecache, fullpath, return, @@ -2755,10 +2782,14 @@ break; } error = vn_vptocnp(&vp, curthread->td_ucred, buf, &buflen); + islocked = (VOP_ISLOCKED(vp)) ? true : false; if (error) break; if (buflen == 0) { - vrele(vp); + if (!islocked) + vrele(vp); + else + vunref(vp); error = ENOMEM; SDT_PROBE3(vfs, namecache, fullpath, return, error, startvp, NULL); @@ -2771,7 +2802,10 @@ return (error); if (!slash_prefixed) { if (buflen == 0) { - vrele(vp); + if (!islocked) + vrele(vp); + else + vunref(vp); counter_u64_add(numfullpathfail4, 1); SDT_PROBE3(vfs, namecache, fullpath, return, ENOMEM, startvp, NULL); @@ -2780,7 +2814,10 @@ buf[--buflen] = '/'; } counter_u64_add(numfullpathfound, 1); - vrele(vp); + if (!islocked) + vrele(vp); + else + vunref(vp); *retbuf = buf + buflen; SDT_PROBE3(vfs, namecache, fullpath, return, 0, startvp, *retbuf); @@ -2956,7 +2993,10 @@ if (error) return (error); if (*buflen == 0) { - vrele(vp); + if (VOP_ISLOCKED(vp) == 0) + vrele(vp); + else + vunref(vp); return (ENOMEM); } *buflen -= 1; Index: sys/security/audit/audit.h =================================================================== --- sys/security/audit/audit.h +++ sys/security/audit/audit.h @@ -49,11 +49,29 @@ #error "no user-serviceable parts inside" #endif +/* + * These macro defintions are required for NFS part and including their + * NFS header files cause conflict with other structure declarations. + */ +#ifndef NFSMUTEX_T +#define NFSMUTEX_T struct mtx +#endif /* NFSMUTEX_T */ +#ifndef NFSOCKADDR_T +#define NFSSOCKADDR_T struct sockaddr * +#endif /* NFSOCKADDR_T */ + #include +#include + #include +#include #include +#include +#include +#include + /* * Audit subsystem condition flags. The audit_trail_enabled flag is set and * removed automatically as a result of configuring log files, and can be @@ -67,6 +85,10 @@ * * XXXRW: Move trail flags to audit_private.h, as they no longer need to be * visible outside the audit code...? + * + * XXX: For NFS audit, we check audit_sycalls_enabled flag to decide whether + * we should audit NFS RPCs or not. Audit NFS RPCs only if we are auditing the + * syscalls. We can probably rename the flag to audit_enabled? */ extern u_int audit_dtrace_enabled; extern int audit_trail_enabled; @@ -76,6 +98,8 @@ void audit_syscall_enter(unsigned short code, struct thread *td); void audit_syscall_exit(int error, struct thread *td); +void audit_nfsrpc_enter(struct nfsrv_descript *nd, struct thread *td); +void audit_nfsrpc_exit(struct nfsrv_descript *nd, 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 @@ -150,6 +174,19 @@ void audit_thread_alloc(struct thread *td); void audit_thread_free(struct thread *td); +void audit_nfsarg_dev(struct kaudit_record *ar, int dev); +void audit_nfsarg_mode(struct kaudit_record *ar, mode_t mode); +void audit_nfsarg_netsockaddr(struct kaudit_record *ar, + struct sockaddr *sa); +void audit_nfsarg_socket(struct kaudit_record *ar, int sodomain, + int sotype, int soprotocol); +void audit_nfsarg_text(struct kaudit_record *ar, const char *text); +void audit_nfsarg_upath1_vp(struct kaudit_record *ar, struct thread *td, + struct vnode *rdir, struct vnode *cdir, char *upath); +void audit_nfsarg_upath2_vp(struct kaudit_record *ar, struct thread *td, + struct vnode *rdir, struct vnode *cdir, char *upath); +void audit_nfsarg_value(struct kaudit_record *ar, long value); +void audit_nfsarg_vnode1(struct kaudit_record *ar, struct vnode *vp); /* * Define macros to wrap the audit_arg_* calls by checking the global * audit_syscalls_enabled flag before performing the actual call. @@ -410,6 +447,74 @@ audit_syscall_exit(error, td); \ } while (0) +/* + * Macros for wrapping audit_nfsarg_* calls. It checks the global + * audit_syscalls_enabled flag before performing the actual call. + */ +#define AUDITING_NFS(nd) (__predict_false((nd)->nd_flag & ND_AUDITREC)) + +#define AUDIT_NFSARG_DEV(nd, dev) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_dev((nd)->nd_ar, (dev)); \ +} while (0) + +#define AUDIT_NFSARG_MODE(nd, mode) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_mode((nd)->nd_ar, (mode)); \ +} while (0) + +#define AUDIT_NFSARG_NETSOCKADDR(nd, sa) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_netsockaddr((nd)->nd_ar, (sa)); \ +} while (0) + +#define AUDIT_NFSARG_SOCKET(nd, sodomain, sotype, soprotocol) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_socket((nd)->nd_ar, (sodomain), (sotype), \ + (soprotocol)); \ +} while (0) + +#define AUDIT_NFSARG_TEXT(nd, text) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_text((nd)->nd_ar, (text)); \ +} while (0) + +#define AUDIT_NFSARG_UPATH1_VP(nd, td, rdir, cdir, upath) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_upath1_vp((nd)->nd_ar, (td), (rdir), \ + (cdir), (upath)); \ +} while (0) + +#define AUDIT_NFSARG_UPATH2_VP(nd, td, rdir, cdir, upath) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_upath2_vp((nd)->nd_ar, (td), (rdir), \ + (cdir), (upath)); \ +} while (0) + +#define AUDIT_NFSARG_VALUE(nd, value) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_value((nd)->nd_ar, (value)); \ +} while (0) + +#define AUDIT_NFSARG_VNODE1(nd, vp) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsarg_vnode1((nd)->nd_ar, (vp)); \ +} while (0) + +#define AUDIT_NFSRPC_ENTER(nd, td) ({ \ + bool _audit_entered = false; \ + if (__predict_false(audit_syscalls_enabled)) { \ + audit_nfsrpc_enter((nd), (td)); \ + _audit_entered = true; \ + } \ + _audit_entered; \ +}) + +#define AUDIT_NFSRPC_EXIT(nd, td) do { \ + if (AUDITING_NFS(nd)) \ + audit_nfsrpc_exit((nd), (td)); \ +} while (0) + /* * A Macro to wrap the audit_sysclose() function. */ @@ -473,6 +578,21 @@ #define AUDIT_SYSCALL_ENTER(code, td) 0 #define AUDIT_SYSCALL_EXIT(error, td) +#define AUDIT_NFSARG_DEV(nd, dev) +#define AUDIT_NFSARG_MODE(nd, mode) +#define AUDIT_NFSARG_NETSOCKADDR(nd, sa) +#define AUDIT_NFSARG_SOCKET(nd, sodomain, sotype, soprotocol) +#define AUDIT_NFSARG_TEXT(nd, text) +#define AUDIT_NFSARG_UPATH1_VP(nd, td, rdir, cdir, upath) +#define AUDIT_NFSARG_UPATH2_VP(nd, td, rdir, cdir, upath) +#define AUDIT_NFSARG_VALUE(nd, value) +#define AUDIT_NFSARG_VNODE1(nd, vp) + +#define AUDITING_NFS(nd) 0 + +#define AUDIT_NFSRPC_ENTER(nd, td) 0 +#define AUDIT_NFSRPC_EXIT(nd, td) + #define AUDIT_SYSCLOSE(p, fd) #endif /* AUDIT */ Index: sys/security/audit/audit.c =================================================================== --- sys/security/audit/audit.c +++ sys/security/audit/audit.c @@ -84,6 +84,7 @@ FEATURE(audit, "BSM audit support"); static uma_zone_t audit_record_zone; +static uma_zone_t audit_nfsrecord_zone; static MALLOC_DEFINE(M_AUDITCRED, "audit_cred", "Audit cred storage"); MALLOC_DEFINE(M_AUDITDATA, "audit_data", "Audit data storage"); MALLOC_DEFINE(M_AUDITPATH, "audit_path", "Audit path storage"); @@ -274,6 +275,7 @@ bzero(ar, sizeof(*ar)); ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC; nanotime(&ar->k_ar.ar_starttime); + ar->kaudit_record_type = AUDIT_SYSCALL_RECORD; /* * Export the subject credential. @@ -326,6 +328,44 @@ free(ar->k_ar.ar_arg_groups.gidset, M_AUDITGIDSET); } +/* + * Construct an audit record for the passed nfs server + * request description. + */ +static int +audit_nfsrecord_ctor(void *mem, int size, void *arg, int flags) +{ + struct kaudit_record *ar; + struct nfsrv_descript *nd; + struct ucred *cred; + + KASSERT(sizeof(*ar) == size, ("audit_nfsrecord_ctor: wrong size")); + + nd = arg; + ar = mem; + bzero(ar, sizeof(*ar)); + ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC; + nanotime(&ar->k_ar.ar_starttime); + ar->kaudit_record_type = AUDIT_NFSRPC_RECORD; + + /* + * Export the subject credential. + */ + cred = nd->nd_cred; + cru2x(cred, &ar->k_ar.ar_subj_cred); + ar->k_ar.ar_subj_ruid = cred->cr_ruid; + ar->k_ar.ar_subj_rgid = cred->cr_rgid; + ar->k_ar.ar_subj_egid = cred->cr_groups[0]; + ar->k_ar.ar_subj_auid = cred->cr_audit.ai_auid; + ar->k_ar.ar_subj_asid = cred->cr_audit.ai_asid; + ar->k_ar.ar_subj_pid = 0; + ar->k_ar.ar_subj_amask = cred->cr_audit.ai_mask; + ar->k_ar.ar_subj_term_addr = cred->cr_audit.ai_termid; + ar->k_ar.ar_jailname[0] = '\0'; + + return (0); +} + /* * Initialize the Audit subsystem: configuration state, work queue, * synchronization primitives, worker thread, and trigger device node. Also @@ -370,6 +410,10 @@ sizeof(struct kaudit_record), audit_record_ctor, audit_record_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); + audit_nfsrecord_zone = uma_zcreate("audit_nfsrecord", + sizeof(struct kaudit_record), audit_nfsrecord_ctor, + audit_record_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); + /* First initialisation of audit_syscalls_enabled. */ audit_syscalls_enabled_update(); @@ -437,11 +481,44 @@ return (ar); } +struct kaudit_record * +audit_nfs_new(int event, struct nfsrv_descript *nd) +{ + struct kaudit_record *ar; + + /* This below comment statement (copied from audit_new) becomes untrue in case NFS audit + * records are created. Would this create any problem?? + * Note: the number of outstanding uncommitted audit records is + * limited to the number of concurrent threads servicing system calls + * in the kernel. + */ + + ar = uma_zalloc_arg(audit_nfsrecord_zone, nd, M_WAITOK); + ar->k_ar.ar_event = event; + + mtx_lock(&audit_mtx); + audit_pre_q_len++; + mtx_unlock(&audit_mtx); + + return (ar); +} + void audit_free(struct kaudit_record *ar) { - uma_zfree(audit_record_zone, ar); + switch (ar->kaudit_record_type) { + case AUDIT_SYSCALL_RECORD: + uma_zfree(audit_record_zone, ar); + break; + + case AUDIT_NFSRPC_RECORD: + uma_zfree(audit_nfsrecord_zone, ar); + break; + + default: + panic("audit_free: invalid case"); + } } void @@ -731,6 +808,93 @@ td->td_pflags &= ~TDP_AUDITREC; } +/* + * audit_nfsrpc_enter is called before NFS server is about to do a RPC. + * This function is very similiar to audit_syscall_enter. + */ +void +audit_nfsrpc_enter(struct nfsrv_descript *nd, struct thread *td) +{ + struct au_mask *aumask; + au_class_t class; + au_event_t event; + au_id_t auid; + int record_needed; + + KASSERT(nd->nd_ar == NULL, ("audit_nfsrpc_enter: nd->nd_ar != NULL")); + KASSERT((nd->nd_flag & ND_AUDITREC) == 0, + ("audit_nfsrpc_enter: ND_AUDITREC set")); + + /* Currently, NFSv4 code is in its feature branch currently. */ + if (!(nd->nd_flag & ND_NFSV4)) + event = nfsrv3_auevent[nd->nd_procnum]; + else + event = AUE_NULL; + /* NFS Procedure NULL do nothing. So, no need to audit this event. */ + if (event == AUE_NULL) + return; + + memcpy(&(nd->nd_cred->cr_audit), &(td->td_ucred->cr_audit), + sizeof(struct auditinfo_addr)); + + /* + * The auid for NFS Audit events is AU_DEFAUDITID. The kernel + * non-attributable event mask is used as audit mask as all NFS Audit + * events are triggered from within the kernel. + */ + auid = nd->nd_cred->cr_audit.ai_auid; + + KASSERT(auid == AU_DEFAUDITID, + ("audit_nfsrpc_enter: NFS auid != AU_DEFAUDITID")); + + aumask = &audit_nae_mask; + class = au_event_class(event); + if (au_preselect(event, class, aumask, AU_PRS_BOTH)) { + /* + * If we're out of space and need to suspend unprivileged + * processes, do that here rather than trying to allocate + * another audit record. + */ + if (audit_in_failure && + priv_check(td, PRIV_AUDIT_FAILSTOP) != 0) { + cv_wait(&audit_fail_cv, &audit_mtx); + panic("audit_failing_stop: thread continued"); + } + record_needed = 1; + } else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) { + record_needed = 1; + } else { + record_needed = 0; + } + if (record_needed) { + nd->nd_ar = audit_nfs_new(event, nd); + if (nd->nd_ar != NULL) + nd->nd_flag |= ND_AUDITREC; + } else + nd->nd_ar = NULL; +} + +/* + * audit_nfsrpc_exit is called each time after NFS server has completed a + * RPC call. This function is very similiar to audit_syscall_exit. + */ +void +audit_nfsrpc_exit(struct nfsrv_descript *nd, __unused struct thread *td) +{ + int retval; + int error; + + error = nd->nd_repstat; + if (error) + retval = -1; + else + retval = *(nd->nd_errp); + + audit_commit(nd->nd_ar, error, retval); + nd->nd_ar = NULL; + nd->nd_flag &= ~ND_AUDITREC; +} + void audit_cred_copy(struct ucred *src, struct ucred *dest) { Index: sys/security/audit/audit_arg.c =================================================================== --- sys/security/audit/audit_arg.c +++ sys/security/audit/audit_arg.c @@ -59,6 +59,9 @@ #include #include +#include "opt_inet.h" +#include "opt_inet6.h" + /* * Calls to manipulate elements of the audit record structure from system * call code. Macro wrappers will prevent this functions from being entered @@ -1019,3 +1022,157 @@ VOP_UNLOCK(vp); fdrop(fp, td); } + +/* NFS RPC related audit args */ +void +audit_nfsarg_dev(struct kaudit_record *ar, int dev) +{ + + if (ar == NULL) + return; + + ar->k_ar.ar_arg_dev = dev; + ARG_SET_VALID(ar, ARG_DEV); +} + +void +audit_nfsarg_mode(struct kaudit_record *ar, mode_t mode) +{ + + if (ar == NULL) + return; + + ar->k_ar.ar_arg_mode = mode; + ARG_SET_VALID(ar, ARG_MODE); +} + +void +audit_nfsarg_netsockaddr(struct kaudit_record *ar, struct sockaddr *sa) +{ + + KASSERT(sa != NULL, ("audit_nfsarg_sockaddr: sa == NULL")); + + if (ar == NULL) + return; + + bcopy(sa, &ar->k_ar.ar_arg_sockaddr, sa->sa_len); + switch (sa->sa_family) { +#ifdef INET + case AF_INET: + ARG_SET_VALID(ar, ARG_SADDRINET); + break; +#endif +#ifdef INET6 + case AF_INET6: + ARG_SET_VALID(ar, ARG_SADDRINET6); + break; +#endif + default: + panic("audit_nfsarg_netsockaddr: invalid sa_family"); + } +} + +void +audit_nfsarg_socket(struct kaudit_record *ar, int sodomain, int sotype, + int soprotocol) +{ + + if (ar == NULL) + return; + + ar->k_ar.ar_arg_sockinfo.so_domain = sodomain; + ar->k_ar.ar_arg_sockinfo.so_type = sotype; + ar->k_ar.ar_arg_sockinfo.so_protocol = soprotocol; + ARG_SET_VALID(ar, ARG_SOCKINFO); +} + +void +audit_nfsarg_text(struct kaudit_record *ar, const char *text) +{ + + KASSERT(text != NULL, ("audit_arg_text: text == NULL")); + if (ar == NULL) + return; + + /* Invalidate the text string */ + ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_TEXT); + + if (ar->k_ar.ar_arg_text == NULL) + ar->k_ar.ar_arg_text = malloc(MAXPATHLEN, M_AUDITTEXT, + M_WAITOK); + + strncpy(ar->k_ar.ar_arg_text, text, MAXPATHLEN); + ARG_SET_VALID(ar, ARG_TEXT); +} + +void +audit_nfsarg_upath1_vp(struct kaudit_record *ar, struct thread *td, + struct vnode *rdir, struct vnode *cdir, char *upath) +{ + + if (ar == NULL) + return; + + audit_arg_upath_vp(td, rdir, cdir, upath, &ar->k_ar.ar_arg_upath1); + + ARG_SET_VALID(ar, ARG_UPATH1); +} + +void +audit_nfsarg_upath2_vp(struct kaudit_record *ar, struct thread *td, + struct vnode *rdir, struct vnode *cdir, char *upath) +{ + + if (ar == NULL) + return; + + audit_arg_upath_vp(td, rdir, cdir, upath, &ar->k_ar.ar_arg_upath2); + + ARG_SET_VALID(ar, ARG_UPATH2); +} + +void +audit_nfsarg_value(struct kaudit_record *ar, long value) +{ + + if(ar == NULL) + return; + + ar->k_ar.ar_arg_value = value; + ARG_SET_VALID(ar,ARG_VALUE); +} + +void +audit_nfsarg_vnode1(struct kaudit_record *ar, struct vnode *vp) +{ + int error, lktype = 0; + + /* Page fault panic occur if vnode *vp is NULL. */ + KASSERT(vp != NULL, ("audit_nfsarg_vnode1: vp == NULL")); + + if (ar == NULL) + return; + + lktype = VOP_ISLOCKED(vp); + /* + * As well as returning 0 for unlocked, VOP_ISLOCKED can return + * LK_EXCLOTHER for another thread holding a lock on it. + * + * XXX: audit_arg_vnode uses td_ucread. do we need nd_cr for NFS? + */ + ARG_CLEAR_VALID(ar, ARG_VNODE1); + /* Hold the vnode lock for VOP_GETTR call. */ + if (lktype != LK_EXCLUSIVE && lktype != LK_SHARED) { + vref(vp); + if (vn_lock(vp, LK_SHARED | LK_NOWAIT)) { + vrele(vp); + return; + } + } + error = audit_arg_vnode(vp, &ar->k_ar.ar_arg_vnode1); + if (lktype != LK_EXCLUSIVE && lktype != LK_SHARED) { + vput(vp); + } + if (error == 0) + ARG_SET_VALID(ar, ARG_VNODE1); +} Index: sys/security/audit/audit_bsm.c =================================================================== --- sys/security/audit/audit_bsm.c +++ sys/security/audit/audit_bsm.c @@ -1783,6 +1783,95 @@ case AUE_THR_EXIT: break; + /* TODO XXX: Should I also log NFS file handle? The sycalls events generally log + * FD VNODE and UPATH tokens. Following that analogy the NFS RPC event can + * can log filehandle. */ + /* + * XXX TODO: fix NFS error code in bsm_errno. */ + case AUE_NFSRPC_GETATTR: + case AUE_NFSRPC_SETATTR: + if (ARG_IS_VALID(kar, ARG_VNODE1)) { + tok = au_to_attr32(&ar->ar_arg_vnode1); + kau_write(rec, tok); + } + break; + + case AUE_NFSRPC_LOOKUP: + UPATH1_VNODE1_TOKENS; + break; + + case AUE_NFSRPC_ACCESS: + if (ARG_IS_VALID(kar, ARG_VNODE1)) { + tok = au_to_attr32(&ar->ar_arg_vnode1); + kau_write(rec, tok); + } + /* XXX: argument # in this case? */ + if (ARG_IS_VALID(kar, ARG_MODE)) { + tok = au_to_arg32(3, "mode", ar->ar_arg_mode); + kau_write(rec, tok); + } + break; + + case AUE_NFSRPC_READLINK: + case AUE_NFSRPC_READ: + case AUE_NFSRPC_WRITE: + if (ARG_IS_VALID(kar, ARG_VNODE1)) { + tok = au_to_attr32(&ar->ar_arg_vnode1); + kau_write(rec, tok); + } + break; + + case AUE_NFSRPC_CREATE: + case AUE_NFSRPC_MKDIR: + if (ARG_IS_VALID(kar, ARG_MODE)) { + tok = au_to_arg32(3, "mode", ar->ar_arg_mode); + kau_write(rec, tok); + } + UPATH1_VNODE1_TOKENS; + break; + + case AUE_NFSRPC_SYMLINK: + UPATH1_VNODE1_TOKENS; + break; + + case AUE_NFSRPC_MKNOD: + if (ARG_IS_VALID(kar, ARG_MODE)) { + tok = au_to_arg32(2, "mode", ar->ar_arg_mode); + kau_write(rec, tok); + } + if (ARG_IS_VALID(kar, ARG_DEV)) { + tok = au_to_arg32(3, "dev", ar->ar_arg_dev); + kau_write(rec, tok); + } + UPATH1_VNODE1_TOKENS; + break; + + case AUE_NFSRPC_REMOVE: + case AUE_NFSRPC_RMDIR: + UPATH1_VNODE1_TOKENS; + break; + + case AUE_NFSRPC_RENAME: + UPATH1_VNODE1_TOKENS; + UPATH2_TOKENS; + break; + + case AUE_NFSRPC_LINK: + UPATH1_VNODE1_TOKENS; + break; + + case AUE_NFSRPC_READDIR: + case AUE_NFSRPC_READDIRPLUS: + case AUE_NFSRPC_FSSTAT: + case AUE_NFSRPC_FSINFO: + case AUE_NFSRPC_PATHCONF: + case AUE_NFSRPC_COMMIT: + if (ARG_IS_VALID(kar, ARG_VNODE1)) { + tok = au_to_attr32(&ar->ar_arg_vnode1); + kau_write(rec, tok); + } + break; + case AUE_NULL: default: printf("BSM conversion requested for unknown event %d\n", @@ -1797,6 +1886,16 @@ kau_free(rec); return (BSM_NOAUDIT); } + /* + * Write common tokens for NFS RPCs. + */ + if (kar->kaudit_record_type == AUDIT_NFSRPC_RECORD) { + if (ARG_IS_VALID(kar, ARG_SADDRINET)) { + tok = au_to_sock_inet((struct sockaddr_in *) + &ar->ar_arg_sockaddr); + kau_write(rec, tok); + } + } if (jail_tok != NULL) kau_write(rec, jail_tok); Index: sys/security/audit/audit_bsm_db.c =================================================================== --- sys/security/audit/audit_bsm_db.c +++ sys/security/audit/audit_bsm_db.c @@ -189,6 +189,13 @@ if (sysent[i].sy_auevent != AUE_NULL) au_evclassmap_insert(sysent[i].sy_auevent, 0); } + + /* + * Set up the initial event to class mapping for NFS RPCs. + */ + for (i = 0; i < NFS_V3NPROCS; i++) { + au_evclassmap_insert(nfsrv3_auevent[i], 0); + } } /* Index: sys/security/audit/audit_private.h =================================================================== --- sys/security/audit/audit_private.h +++ sys/security/audit/audit_private.h @@ -82,6 +82,10 @@ #define BSM_FAILURE 1 #define BSM_NOAUDIT 2 +/* Audit record type to differentiate between syscall and NFS record. */ +#define AUDIT_SYSCALL_RECORD 0 +#define AUDIT_NFSRPC_RECORD 1 + /* * Defines for the kernel audit record k_ar_commit field. Flags are set to * indicate what sort of record it is, and which preselection mechanism @@ -330,6 +334,7 @@ u_int k_ulen; /* User data length. */ struct uthread *k_uthread; /* Audited thread. */ void *k_dtaudit_state; + int kaudit_record_type; TAILQ_ENTRY(kaudit_record) k_q; }; TAILQ_HEAD(kaudit_queue, kaudit_record); @@ -342,6 +347,7 @@ void audit_commit(struct kaudit_record *ar, int error, int retval); struct kaudit_record *audit_new(int event, struct thread *td); +struct kaudit_record *audit_nfs_new(int event, struct nfsrv_descript *nd); /* * Function to update the audit_syscalls_enabled flag, whose value is affected