Page MenuHomeFreeBSD

D26243.diff
No OneTemporary

D26243.diff

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 <bsm/audit_kevents.h>
+
/*
* 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 <fs/nfsserver/nfs_fha_new.h>
+#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
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 <fs/nfs/nfsport.h>
+#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
#include <sys/filio.h>
#include <sys/hash.h>
@@ -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 <fs/nfs/nfsport.h>
#include <sys/extattr.h>
#include <sys/filio.h>
+#include <security/audit/audit.h>
/* 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, &notrunc,
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 <bsm/audit.h>
+#include <rpc/rpc.h>
+
#include <sys/file.h>
+#include <sys/mount.h>
#include <sys/sysctl.h>
+#include <fs/nfs/nfsdport.h>
+#include <fs/nfs/nfsproto.h>
+#include <fs/nfs/nfs.h>
+
/*
* 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 <security/audit/audit.h>
#include <security/audit/audit_private.h>
+#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

File Metadata

Mime Type
text/plain
Expires
Wed, Jan 15, 1:03 AM (10 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15803481
Default Alt Text
D26243.diff (39 KB)

Event Timeline