Page MenuHomeFreeBSD

D25869.id76035.diff
No OneTemporary

D25869.id76035.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. */
+/*
+ * NFS RPC related 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# */
};
@@ -558,6 +561,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 nfsrv_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
@@ -670,6 +679,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 */
@@ -721,6 +731,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,10 @@
if (cacherep == RC_DOIT) {
if ((nd->nd_flag & ND_NFSV41) != 0)
nd->nd_xprt = xprt;
+ AUDIT_NFSRPC_ENTER(nd, curthread);
+ AUDIT_NFSARG_NETSOCKADDR(nd, nd->nd_nam);
nfsrvd_dorpc(nd, isdgram, tagstr, taglen, minorvers);
+ 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>
@@ -1897,6 +1898,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++);
@@ -2151,6 +2153,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)
/*
@@ -672,6 +680,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;
@@ -723,6 +732,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++);
@@ -910,6 +920,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);
@@ -1101,6 +1112,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) {
@@ -1111,6 +1124,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);
@@ -1201,6 +1215,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,
@@ -1312,6 +1327,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);
@@ -1327,6 +1344,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);
}
}
@@ -1361,6 +1379,7 @@
else
nva.na_mode = 0400;
}
+ AUDIT_NFSARG_MODE(nd, nva.na_mode);
if (vtyp == VDIR)
named.ni_cnd.cn_flags |= WILLBEDIR;
@@ -1408,6 +1427,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,
@@ -1486,6 +1506,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 {
@@ -1502,6 +1524,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,
@@ -1579,6 +1602,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
@@ -1642,6 +1667,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) {
@@ -1676,6 +1703,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);
@@ -1733,6 +1761,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)
@@ -1770,6 +1799,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);
@@ -1839,8 +1870,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);
@@ -1868,6 +1902,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);
@@ -1959,6 +1994,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) {
@@ -1970,6 +2007,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 {
@@ -2000,6 +2038,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);
@@ -2080,11 +2119,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)
@@ -2144,6 +2183,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);
@@ -2202,6 +2242,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);
@@ -2242,13 +2283,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 nfsrv_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
@@ -457,6 +457,11 @@
char *buf, char **retbuf, size_t *buflen);
static int vn_fullpath_dir(struct thread *td, struct vnode *vp, struct vnode *rdir,
char *buf, char **retbuf, size_t *len, bool slash_prefixed, size_t addend);
+static int vn_fullpath_any_locked(struct thread *td, struct vnode *vp,
+ struct vnode *rdir, char *buf, char **retbuf, size_t *buflen);
+static int vn_fullpath_dir_locked(struct thread *td, struct vnode *vp,
+ struct vnode *rdir, char *buf, char **retbuf, size_t *len,
+ bool slash_prefixed, size_t addend);
static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
@@ -2386,13 +2391,23 @@
{
char *buf;
size_t buflen;
- int error;
+ int error, lktype;
if (__predict_false(vn == NULL))
return (EINVAL);
+ lktype = VOP_ISLOCKED(vn);
buflen = MAXPATHLEN;
buf = malloc(buflen, M_TEMP, M_WAITOK);
- error = vn_fullpath_any(td, vn, rootvnode, buf, retbuf, &buflen);
+ /*
+ * Should I check != LK_EXCLUSIVE && != LK_SHARED, because of
+ * LK_EXCLOTHER. Same doubt for everywhere I added VOP_ISLOCKED.
+ */
+ if (lktype)
+ error = vn_fullpath_any_locked(td, vn, rootvnode, buf, retbuf,
+ &buflen);
+ else
+ error = vn_fullpath_any(td, vn, rootvnode, buf, retbuf,
+ &buflen);
if (!error)
*freebuf = buf;
else
@@ -2462,6 +2477,72 @@
return (0);
}
+/*
+ * The function works same as vn_vptocnp but for locked *vp.
+ */
+static int
+vn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf, size_t *buflen)
+{
+ struct vnode *dvp;
+ struct namecache *ncp;
+ struct mtx *vlp;
+ int error;
+
+ vlp = VP2VNODELOCK(*vp);
+ mtx_lock(vlp);
+ TAILQ_FOREACH(ncp, &((*vp)->v_cache_dst), nc_dst) {
+ if ((ncp->nc_flag & NCF_ISDOTDOT) == 0)
+ break;
+ }
+ if (ncp != NULL) {
+ if (*buflen < ncp->nc_nlen) {
+ mtx_unlock(vlp);
+ vunref(*vp);
+ counter_u64_add(numfullpathfail4, 1);
+ error = ENOMEM;
+ SDT_PROBE3(vfs, namecache, fullpath, return, error,
+ vp, NULL);
+ return (error);
+ }
+ *buflen -= ncp->nc_nlen;
+ memcpy(buf + *buflen, ncp->nc_name, ncp->nc_nlen);
+ SDT_PROBE3(vfs, namecache, fullpath, hit, ncp->nc_dvp,
+ ncp->nc_name, vp);
+ dvp = *vp;
+ *vp = ncp->nc_dvp;
+ vref(*vp);
+ mtx_unlock(vlp);
+ vrele(dvp);
+ return (0);
+ }
+ SDT_PROBE1(vfs, namecache, fullpath, miss, vp);
+
+ mtx_unlock(vlp);
+ KASSERT(VOP_ISLOCKED(*vp) != 0,
+ ("vn_vptocnp_locked: vnode not locked"));
+ error = VOP_VPTOCNP(*vp, &dvp, cred, buf, buflen);
+ vunref(*vp);
+ if (error) {
+ counter_u64_add(numfullpathfail2, 1);
+ SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL);
+ return (error);
+ }
+
+ *vp = dvp;
+ if (VN_IS_DOOMED(dvp)) {
+ /* forced unmount */
+ vrele(dvp);
+ error = ENOENT;
+ SDT_PROBE3(vfs, namecache, fullpath, return, error, vp, NULL);
+ return (error);
+ }
+ /*
+ * *vp has its use count incremented still.
+ */
+
+ return (0);
+}
+
/*
* Resolve a directory to a pathname.
*
@@ -2573,6 +2654,139 @@
return (0);
}
+/*
+ * This function works same as vn_fullpath_dir but for locked vnode *vp.
+ */
+static int
+vn_fullpath_dir_locked(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, size_t *len, bool slash_prefixed, size_t addend)
+{
+#ifdef KDTRACE_HOOKS
+ struct vnode *startvp = vp;
+#endif
+ struct vnode *vp1;
+ size_t buflen;
+ int error;
+ bool islocked = true;
+
+ VNPASS(vp->v_type == VDIR || VN_IS_DOOMED(vp), vp);
+ VNPASS(vp->v_usecount > 0, vp);
+ KASSERT(VOP_ISLOCKED(vp) != 0,
+ ("vn_fullpath_dir_locked: vp not locked"));
+ buflen = *len;
+
+ if (!slash_prefixed) {
+ MPASS(*len >= 2);
+ buflen--;
+ buf[buflen] = '\0';
+ }
+
+ error = 0;
+
+ SDT_PROBE1(vfs, namecache, fullpath, entry, vp);
+ counter_u64_add(numfullpathcalls, 1);
+ while (vp != rdir && vp != rootvnode) {
+ /*
+ * The vp vnode must be already fully constructed,
+ * since it is either found in namecache or obtained
+ * from VOP_VPTOCNP(). We may test for VV_ROOT safely
+ * without obtaining the vnode lock.
+ */
+ if ((vp->v_vflag & VV_ROOT) != 0) {
+ if (!islocked)
+ vn_lock(vp, LK_RETRY | LK_SHARED);
+
+ /*
+ * With the vnode locked, check for races with
+ * unmount, forced or not. Note that we
+ * already verified that vp is not equal to
+ * the root vnode, which means that
+ * mnt_vnodecovered can be NULL only for the
+ * case of unmount.
+ */
+ if (VN_IS_DOOMED(vp) ||
+ (vp1 = vp->v_mount->mnt_vnodecovered) == NULL ||
+ vp1->v_mountedhere != vp->v_mount) {
+ if (!islocked)
+ vput(vp);
+ else
+ vunref(vp);
+ error = ENOENT;
+ SDT_PROBE3(vfs, namecache, fullpath, return,
+ error, vp, NULL);
+ break;
+ }
+
+ vref(vp1);
+ if (!islocked)
+ vput(vp);
+ else
+ vunref(vp);
+ vp = vp1;
+ islocked = false;
+ continue;
+ }
+ islocked = (VOP_ISLOCKED(vp)) ? true : false;
+ if (vp->v_type != VDIR) {
+ if (!islocked)
+ vrele(vp);
+ else
+ vunref(vp);
+ counter_u64_add(numfullpathfail1, 1);
+ error = ENOTDIR;
+ SDT_PROBE3(vfs, namecache, fullpath, return,
+ error, vp, NULL);
+ break;
+ }
+ if (!islocked)
+ error = vn_vptocnp(&vp, td->td_ucred, buf, &buflen);
+ else
+ error = vn_vptocnp_locked(&vp, td->td_ucred, buf,
+ &buflen);
+ islocked = (VOP_ISLOCKED(vp)) ? true : false;
+ if (error)
+ break;
+ if (buflen == 0) {
+ if (!islocked)
+ vrele(vp);
+ else
+ vunref(vp);
+ error = ENOMEM;
+ SDT_PROBE3(vfs, namecache, fullpath, return, error,
+ startvp, NULL);
+ break;
+ }
+ buf[--buflen] = '/';
+ slash_prefixed = true;
+ }
+ if (error)
+ return (error);
+ if (!slash_prefixed) {
+ if (buflen == 0) {
+ if (!islocked)
+ vrele(vp);
+ else
+ vunref(vp);
+ counter_u64_add(numfullpathfail4, 1);
+ SDT_PROBE3(vfs, namecache, fullpath, return, ENOMEM,
+ startvp, NULL);
+ return (ENOMEM);
+ }
+ buf[--buflen] = '/';
+ }
+ counter_u64_add(numfullpathfound, 1);
+ if (!islocked)
+ vrele(vp);
+ else
+ vunref(vp);
+
+ *retbuf = buf + buflen;
+ SDT_PROBE3(vfs, namecache, fullpath, return, 0, startvp, *retbuf);
+ *len -= buflen;
+ *len += addend;
+ return (0);
+}
+
/*
* Resolve an arbitrary vnode to a pathname.
*
@@ -2616,6 +2830,49 @@
orig_buflen - *buflen));
}
+/*
+ * This function works same as vn_fullpath_any but for locked vnode.
+ */
+static int
+vn_fullpath_any_locked(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, size_t *buflen)
+{
+ size_t orig_buflen;
+ bool slash_prefixed;
+ int error, lktype;
+
+ if (*buflen < 2)
+ return (EINVAL);
+
+ orig_buflen = *buflen;
+ vref(vp);
+ slash_prefixed = false;
+ if (vp->v_type != VDIR) {
+ *buflen -= 1;
+ buf[*buflen] = '\0';
+ error = vn_vptocnp_locked(&vp, td->td_ucred, buf, buflen);
+ if (error)
+ return (error);
+ lktype = VOP_ISLOCKED(vp);
+ if (*buflen == 0) {
+ if (lktype)
+ vunref(vp);
+ else
+ vrele(vp);
+ return (ENOMEM);
+ }
+ *buflen -= 1;
+ buf[*buflen] = '/';
+ slash_prefixed = true;
+ if (lktype == 0)
+ return (vn_fullpath_dir(td, vp, rdir, buf, retbuf,
+ buflen, slash_prefixed, orig_buflen - *buflen));
+ }
+
+ return (vn_fullpath_dir_locked(td, vp, rdir, buf, retbuf, buflen,
+ slash_prefixed, orig_buflen - *buflen));
+}
+
/*
* Resolve an arbitrary vnode to a pathname (taking care of hardlinks).
*
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,19 @@
#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 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 is not supported. */
+ if (!(nd->nd_flag & ND_NFSV4))
+ event = nfsrv_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
@@ -1019,3 +1019,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:
+ printf/*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,93 @@
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. */
+ 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 +1884,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 RPC calls.
+ */
+ for (i = 0; i < NFS_V3NPROCS; i++) {
+ au_evclassmap_insert(nfsrv_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
Mon, Mar 9, 7:15 PM (5 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29454026
Default Alt Text
D25869.id76035.diff (42 KB)

Event Timeline