Audit file descriptors passed to fooat(2) system calls, which are used
instead of the root/current working directory as the starting point for
lookups.  Up to two such descriptors can be audited.  Add audit record
BSM encoding for fooat(2).

Rework vnode argument auditing to follow the same structure, in order
to avoid exposing ARG_ macros/flag values outside of the audit code in
order to name which one of two possible vnodes will be audited for a
system call.

Note: due to an error in the OpenBSM 1.1p1 configuration file, a
further change is required to that file in order to fix openat(2)
auditing.

Reviewed by:	rdivacky
Obtained from:	TrustedBSD Project
MFC after:	1 month

Index: kern/vfs_syscalls.c
===================================================================
--- kern/vfs_syscalls.c	(revision 195897)
+++ kern/vfs_syscalls.c	(working copy)
@@ -379,7 +379,7 @@ kern_fstatfs(struct thread *td, int fd, struct sta
 	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	vn_lock(vp, LK_SHARED | LK_RETRY);
 #ifdef AUDIT
-	AUDIT_ARG_VNODE(vp, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(vp);
 #endif
 	mp = vp->v_mount;
 	if (mp)
@@ -752,7 +752,7 @@ fchdir(td, uap)
 	fdrop(fp, td);
 	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	vn_lock(vp, LK_SHARED | LK_RETRY);
-	AUDIT_ARG_VNODE(vp, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(vp);
 	error = change_dir(vp, td);
 	while (!error && (mp = vp->v_mountedhere) != NULL) {
 		int tvfslocked;
@@ -2779,7 +2779,7 @@ fchflags(td, uap)
 	vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
 #ifdef AUDIT
 	vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
-	AUDIT_ARG_VNODE(fp->f_vnode, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(fp->f_vnode);
 	VOP_UNLOCK(fp->f_vnode, 0);
 #endif
 	error = setfflags(td, fp->f_vnode, uap->flags);
@@ -2940,7 +2940,7 @@ fchmod(td, uap)
 	vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
 #ifdef AUDIT
 	vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
-	AUDIT_ARG_VNODE(fp->f_vnode, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(fp->f_vnode);
 	VOP_UNLOCK(fp->f_vnode, 0);
 #endif
 	error = setfmode(td, fp->f_vnode, uap->mode);
@@ -3117,7 +3117,7 @@ fchown(td, uap)
 	vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
 #ifdef AUDIT
 	vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
-	AUDIT_ARG_VNODE(fp->f_vnode, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(fp->f_vnode);
 	VOP_UNLOCK(fp->f_vnode, 0);
 #endif
 	error = setfown(td, fp->f_vnode, uap->uid, uap->gid);
@@ -3353,7 +3353,7 @@ kern_futimes(struct thread *td, int fd, struct tim
 	vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
 #ifdef AUDIT
 	vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
-	AUDIT_ARG_VNODE(fp->f_vnode, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(fp->f_vnode);
 	VOP_UNLOCK(fp->f_vnode, 0);
 #endif
 	error = setutimes(td, fp->f_vnode, ts, 2, tptr == NULL);
@@ -3513,7 +3513,7 @@ fsync(td, uap)
 		lock_flags = LK_EXCLUSIVE;
 	}
 	vn_lock(vp, lock_flags | LK_RETRY);
-	AUDIT_ARG_VNODE(vp, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(vp);
 	if (vp->v_object != NULL) {
 		VM_OBJECT_LOCK(vp->v_object);
 		vm_object_page_clean(vp->v_object, 0, 0, 0);
@@ -4103,7 +4103,7 @@ unionread:
 	auio.uio_td = td;
 	auio.uio_resid = count;
 	vn_lock(vp, LK_SHARED | LK_RETRY);
-	AUDIT_ARG_VNODE(vp, ARG_VNODE1);
+	AUDIT_ARG_VNODE1(vp);
 	loff = auio.uio_offset = fp->f_offset;
 #ifdef MAC
 	error = mac_vnode_check_readdir(td->td_ucred, vp);
Index: kern/vfs_lookup.c
===================================================================
--- kern/vfs_lookup.c	(revision 195897)
+++ kern/vfs_lookup.c	(working copy)
@@ -203,8 +203,13 @@ namei(struct nameidata *ndp)
 		if (ndp->ni_startdir != NULL) {
 			dp = ndp->ni_startdir;
 			error = 0;
-		} else if (ndp->ni_dirfd != AT_FDCWD)
+		} else if (ndp->ni_dirfd != AT_FDCWD) {
+			if (cnp->cn_flags & AUDITVNODE1)
+				AUDIT_ARG_ATFD1(ndp->ni_dirfd);
+			if (cnp->cn_flags & AUDITVNODE2)
+				AUDIT_ARG_ATFD2(ndp->ni_dirfd);
 			error = fgetvp(td, ndp->ni_dirfd, &dp);
+		}
 		if (error != 0 || dp != NULL) {
 			FILEDESC_SUNLOCK(fdp);
 			if (error == 0 && dp->v_type != VDIR) {
@@ -569,9 +574,9 @@ dirloop:
 		ndp->ni_vp = dp;
 
 		if (cnp->cn_flags & AUDITVNODE1)
-			AUDIT_ARG_VNODE(dp, ARG_VNODE1);
+			AUDIT_ARG_VNODE1(dp);
 		else if (cnp->cn_flags & AUDITVNODE2)
-			AUDIT_ARG_VNODE(dp, ARG_VNODE2);
+			AUDIT_ARG_VNODE2(dp);
 
 		if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
 			VOP_UNLOCK(dp, 0);
@@ -854,9 +859,9 @@ nextname:
 		VOP_UNLOCK(ndp->ni_dvp, 0);
 
 	if (cnp->cn_flags & AUDITVNODE1)
-		AUDIT_ARG_VNODE(dp, ARG_VNODE1);
+		AUDIT_ARG_VNODE1(dp);
 	else if (cnp->cn_flags & AUDITVNODE2)
-		AUDIT_ARG_VNODE(dp, ARG_VNODE2);
+		AUDIT_ARG_VNODE2(dp);
 
 	if ((cnp->cn_flags & LOCKLEAF) == 0)
 		VOP_UNLOCK(dp, 0);
Index: kern/kern_exec.c
===================================================================
--- kern/kern_exec.c	(revision 195897)
+++ kern/kern_exec.c	(working copy)
@@ -419,7 +419,7 @@ interpret:
 			goto exec_fail;
 		vfslocked = VFS_LOCK_GIANT(binvp->v_mount);
 		vn_lock(binvp, LK_EXCLUSIVE | LK_RETRY);
-		AUDIT_ARG_VNODE(binvp, ARG_VNODE1);
+		AUDIT_ARG_VNODE1(binvp);
 		imgp->vp = binvp;
 	}
 
Index: security/audit/audit_arg.c
===================================================================
--- security/audit/audit_arg.c	(revision 195897)
+++ security/audit/audit_arg.c	(working copy)
@@ -101,6 +101,32 @@ audit_arg_len(int len)
 }
 
 void
+audit_arg_atfd1(int atfd)
+{
+	struct kaudit_record *ar;
+
+	ar = currecord();
+	if (ar == NULL)
+		return;
+
+	ar->k_ar.ar_arg_atfd1 = atfd;
+	ARG_SET_VALID(ar, ARG_ATFD1);
+}
+
+void
+audit_arg_atfd2(int atfd)
+{
+	struct kaudit_record *ar;
+
+	ar = currecord();
+	if (ar == NULL)
+		return;
+
+	ar->k_ar.ar_arg_atfd2 = atfd;
+	ARG_SET_VALID(ar, ARG_ATFD2);
+}
+
+void
 audit_arg_fd(int fd)
 {
 	struct kaudit_record *ar;
@@ -641,7 +667,7 @@ audit_arg_file(struct proc *p, struct file *fp)
 		vp = fp->f_vnode;
 		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 		vn_lock(vp, LK_SHARED | LK_RETRY);
-		audit_arg_vnode(vp, ARG_VNODE1);
+		audit_arg_vnode1(vp);
 		VOP_UNLOCK(vp, 0);
 		VFS_UNLOCK_GIANT(vfslocked);
 		break;
@@ -735,18 +761,12 @@ audit_arg_upath(struct thread *td, char *upath, u_
  *
  * XXXAUDIT: Possibly KASSERT the path pointer is NULL?
  */
-void
-audit_arg_vnode(struct vnode *vp, u_int64_t flags)
+static int
+audit_arg_vnode(struct vnode *vp, struct vnode_au_info *vnp)
 {
-	struct kaudit_record *ar;
 	struct vattr vattr;
 	int error;
-	struct vnode_au_info *vnp;
 
-	KASSERT(vp != NULL, ("audit_arg_vnode: vp == NULL"));
-	KASSERT((flags == ARG_VNODE1) || (flags == ARG_VNODE2),
-	    ("audit_arg_vnode: flags %jd", (intmax_t)flags));
-
 	/*
 	 * Assume that if the caller is calling audit_arg_vnode() on a
 	 * non-MPSAFE vnode, then it will have acquired Giant.
@@ -754,27 +774,10 @@ audit_arg_upath(struct thread *td, char *upath, u_
 	VFS_ASSERT_GIANT(vp->v_mount);
 	ASSERT_VOP_LOCKED(vp, "audit_arg_vnode");
 
-	ar = currecord();
-	if (ar == NULL)
-		return;
-
-	/*
-	 * XXXAUDIT: The below clears, and then resets the flags for valid
-	 * arguments.  Ideally, either the new vnode is used, or the old one
-	 * would be.
-	 */
-	if (flags & ARG_VNODE1) {
-		ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE1);
-		vnp = &ar->k_ar.ar_arg_vnode1;
-	} else {
-		ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE2);
-		vnp = &ar->k_ar.ar_arg_vnode2;
-	}
-
 	error = VOP_GETATTR(vp, &vattr, curthread->td_ucred);
 	if (error) {
 		/* XXX: How to handle this case? */
-		return;
+		return (error);
 	}
 
 	vnp->vn_mode = vattr.va_mode;
@@ -784,9 +787,38 @@ audit_arg_upath(struct thread *td, char *upath, u_
 	vnp->vn_fsid = vattr.va_fsid;
 	vnp->vn_fileid = vattr.va_fileid;
 	vnp->vn_gen = vattr.va_gen;
-	if (flags & ARG_VNODE1)
+	return (0);
+}
+
+void
+audit_arg_vnode1(struct vnode *vp)
+{
+	struct kaudit_record *ar;
+	int error;
+
+	ar = currecord();
+	if (ar == NULL)
+		return;
+
+	ARG_CLEAR_VALID(ar, ARG_VNODE1);
+	error = audit_arg_vnode(vp, &ar->k_ar.ar_arg_vnode1);
+	if (error == 0)
 		ARG_SET_VALID(ar, ARG_VNODE1);
-	else
+}
+
+void
+audit_arg_vnode2(struct vnode *vp)
+{
+	struct kaudit_record *ar;
+	int error;
+
+	ar = currecord();
+	if (ar == NULL)
+		return;
+
+	ARG_CLEAR_VALID(ar, ARG_VNODE2);
+	error = audit_arg_vnode(vp, &ar->k_ar.ar_arg_vnode2);
+	if (error == 0)
 		ARG_SET_VALID(ar, ARG_VNODE2);
 }
 
@@ -859,7 +891,7 @@ audit_sysclose(struct thread *td, int fd)
 	vp = fp->f_vnode;
 	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	vn_lock(vp, LK_SHARED | LK_RETRY);
-	audit_arg_vnode(vp, ARG_VNODE1);
+	audit_arg_vnode1(vp);
 	VOP_UNLOCK(vp, 0);
 	VFS_UNLOCK_GIANT(vfslocked);
 	fdrop(fp, td);
Index: security/audit/audit_private.h
===================================================================
--- security/audit/audit_private.h	(revision 195897)
+++ security/audit/audit_private.h	(working copy)
@@ -196,6 +196,8 @@ struct audit_record {
 	gid_t			ar_arg_gid;
 	struct groupset		ar_arg_groups;
 	int			ar_arg_fd;
+	int			ar_arg_atfd1;
+	int			ar_arg_atfd2;
 	int			ar_arg_fflags;
 	mode_t			ar_arg_mode;
 	int			ar_arg_dev;
@@ -238,6 +240,9 @@ struct audit_record {
 #define	ARG_SET_VALID(kar, arg) do {					\
 	(kar)->k_ar.ar_valid_arg |= (arg);				\
 } while (0)
+#define	ARG_CLEAR_VALID(kar, arg) do {					\
+	(kar)->k_ar.ar_valid_arg &= ~(arg);				\
+} while (0)
 
 /*
  * In-kernel version of audit record; the basic record plus queue meta-data.
@@ -323,6 +328,7 @@ void		 au_evclassmap_insert(au_event_t event, au_c
 au_class_t	 au_event_class(au_event_t event);
 au_event_t	 audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg);
 au_event_t	 audit_flags_and_error_to_openevent(int oflags, int error);
+au_event_t	 audit_flags_and_error_to_openatevent(int oflags, int error);
 au_event_t	 audit_msgctl_to_event(int cmd);
 au_event_t	 audit_semctl_to_event(int cmr);
 void		 audit_canon_path(struct thread *td, char *path, char *cpath);
Index: security/audit/audit.c
===================================================================
--- security/audit/audit.c	(revision 195897)
+++ security/audit/audit.c	(working copy)
@@ -409,17 +409,22 @@ audit_commit(struct kaudit_record *ar, int error,
 	else
 		sorf = AU_PRS_SUCCESS;
 
+	/*
+	 * syscalls.master sometimes contains a prototype event number, which
+	 * we will transform into a more specific event number now that we
+	 * have more complete information gathered during the system call.
+	 */
 	switch(ar->k_ar.ar_event) {
 	case AUE_OPEN_RWTC:
-		/*
-		 * The open syscall always writes a AUE_OPEN_RWTC event;
-		 * change it to the proper type of event based on the flags
-		 * and the error value.
-		 */
 		ar->k_ar.ar_event = audit_flags_and_error_to_openevent(
 		    ar->k_ar.ar_arg_fflags, error);
 		break;
 
+	case AUE_OPENAT_RWTC:
+		ar->k_ar.ar_event = audit_flags_and_error_to_openatevent(
+		    ar->k_ar.ar_arg_fflags, error);
+		break;
+
 	case AUE_SYSCTL:
 		ar->k_ar.ar_event = audit_ctlname_to_sysctlevent(
 		    ar->k_ar.ar_arg_ctlname, ar->k_ar.ar_valid_arg);
Index: security/audit/audit_bsm.c
===================================================================
--- security/audit/audit_bsm.c	(revision 195897)
+++ security/audit/audit_bsm.c	(working copy)
@@ -183,6 +183,20 @@ kau_free(struct au_record *rec)
  * XXXAUDIT: These macros assume that 'kar', 'ar', 'rec', and 'tok' in the
  * caller are OK with this.
  */
+#define	ATFD1_TOKENS(argnum) do {					\
+	if (ARG_IS_VALID(kar, ARG_ATFD1)) {				\
+		tok = au_to_arg32(argnum, "at fd 1", ar->ar_arg_atfd1);	\
+		kau_write(rec, tok);					\
+	}								\
+} while (0)
+
+#define	ATFD2_TOKENS(argnum) do {					\
+	if (ARG_IS_VALID(kar, ARG_ATFD2)) {				\
+		tok = au_to_arg32(argnum, "at fd 2", ar->ar_arg_atfd2);	\
+		kau_write(rec, tok);					\
+	}								\
+} while (0)
+
 #define	UPATH1_TOKENS do {						\
 	if (ARG_IS_VALID(kar, ARG_UPATH1)) {				\
 		tok = au_to_path(ar->ar_arg_upath1);			\
@@ -198,6 +212,10 @@ kau_free(struct au_record *rec)
 } while (0)
 
 #define	VNODE1_TOKENS do {						\
+	if (ARG_IS_VALID(kar, ARG_ATFD)) {				\
+		tok = au_to_arg32(1, "at fd", ar->ar_arg_atfd);		\
+		kau_write(rec, tok);					\
+	}								\
 	if (ARG_IS_VALID(kar, ARG_VNODE1)) {				\
 		tok = au_to_attr32(&ar->ar_arg_vnode1);			\
 		kau_write(rec, tok);					\
@@ -715,6 +733,8 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au
 
 	case AUE_CHDIR:
 	case AUE_CHROOT:
+	case AUE_FSTATAT:
+	case AUE_FUTIMESAT:
 	case AUE_GETATTRLIST:
 	case AUE_JAIL:
 	case AUE_LUTIMES:
@@ -733,7 +753,9 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au
 	case AUE_TRUNCATE:
 	case AUE_UNDELETE:
 	case AUE_UNLINK:
+	case AUE_UNLINKAT:
 	case AUE_UTIMES:
+		ATFD1_TOKENS(1);
 		UPATH1_VNODE1_TOKENS;
 		break;
 
@@ -771,6 +793,16 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au
 		UPATH1_VNODE1_TOKENS;
 		break;
 
+	case AUE_FCHMODAT:
+		ATFD1_TOKENS(1);
+		if (ARG_IS_VALID(kar, ARG_MODE)) {
+			tok = au_to_arg32(3, "new file mode",
+			    ar->ar_arg_mode);
+			kau_write(rec, tok);
+		}
+		UPATH1_VNODE1_TOKENS;
+		break;
+
 	case AUE_CHOWN:
 	case AUE_LCHOWN:
 		if (ARG_IS_VALID(kar, ARG_UID)) {
@@ -784,6 +816,19 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au
 		UPATH1_VNODE1_TOKENS;
 		break;
 
+	case AUE_FCHOWNAT:
+		ATFD1_TOKENS(1);
+		if (ARG_IS_VALID(kar, ARG_UID)) {
+			tok = au_to_arg32(3, "new file uid", ar->ar_arg_uid);
+			kau_write(rec, tok);
+		}
+		if (ARG_IS_VALID(kar, ARG_GID)) {
+			tok = au_to_arg32(4, "new file gid", ar->ar_arg_gid);
+			kau_write(rec, tok);
+		}
+		UPATH1_VNODE1_TOKENS;
+		break;
+
 	case AUE_EXCHANGEDATA:
 		UPATH1_VNODE1_TOKENS;
 		UPATH2_TOKENS;
@@ -991,8 +1036,12 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au
 		break;
 
 	case AUE_LINK:
+	case AUE_LINKAT:
 	case AUE_RENAME:
+	case AUE_RENAMEAT:
+		ATFD1_TOKENS(1);
 		UPATH1_VNODE1_TOKENS;
+		ATFD2_TOKENS(3);
 		UPATH2_TOKENS;
 		break;
 
@@ -1136,6 +1185,32 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au
 		UPATH1_VNODE1_TOKENS;
 		break;
 
+	case AUE_OPENAT_RC:
+	case AUE_OPENAT_RTC:
+	case AUE_OPENAT_RWC:
+	case AUE_OPENAT_RWTC:
+	case AUE_OPENAT_WC:
+	case AUE_OPENAT_WTC:
+		if (ARG_IS_VALID(kar, ARG_MODE)) {
+			tok = au_to_arg32(3, "mode", ar->ar_arg_mode);
+			kau_write(rec, tok);
+		}
+		/* FALLTHROUGH */
+
+	case AUE_OPENAT_R:
+	case AUE_OPENAT_RT:
+	case AUE_OPENAT_RW:
+	case AUE_OPENAT_RWT:
+	case AUE_OPENAT_W:
+	case AUE_OPENAT_WT:
+		if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
+			tok = au_to_arg32(2, "flags", ar->ar_arg_fflags);
+			kau_write(rec, tok);
+		}
+		ATFD1_TOKENS(1);
+		UPATH1_VNODE1_TOKENS;
+		break;
+
 	case AUE_PTRACE:
 		if (ARG_IS_VALID(kar, ARG_CMD)) {
 			tok = au_to_arg32(1, "request", ar->ar_arg_cmd);
Index: security/audit/audit_bsm_klib.c
===================================================================
--- security/audit/audit_bsm_klib.c	(revision 195897)
+++ security/audit/audit_bsm_klib.c	(working copy)
@@ -75,6 +75,43 @@ static struct evclass_list	evclass_hash[EVCLASSMAP
 #define	EVCLASS_WLOCK()		rw_wlock(&evclass_lock)
 #define	EVCLASS_WUNLOCK()	rw_wunlock(&evclass_lock)
 
+struct aue_open_event {
+	int		aoe_flags;
+	au_event_t	aoe_event;
+};
+
+static const struct aue_open_event aue_open[] = {
+	{ O_RDONLY,					AUE_OPEN_R },
+	{ (O_RDONLY | O_CREAT),				AUE_OPEN_RC },
+	{ (O_RDONLY | O_CREAT | O_TRUNC),		AUE_OPEN_RTC },
+	{ (O_RDONLY | O_TRUNC),				AUE_OPEN_RT },
+	{ O_RDWR,					AUE_OPEN_RW },
+	{ (O_RDWR | O_CREAT),				AUE_OPEN_RWC },
+	{ (O_RDWR | O_CREAT | O_TRUNC),			AUE_OPEN_RWTC },
+	{ (O_RDWR | O_TRUNC),				AUE_OPEN_RWT },
+	{ O_WRONLY,					AUE_OPEN_W },
+	{ (O_WRONLY | O_CREAT),				AUE_OPEN_WC },
+	{ (O_WRONLY | O_CREAT | O_TRUNC),		AUE_OPEN_WTC },
+	{ (O_WRONLY | O_TRUNC),				AUE_OPEN_WT },
+};
+static const int aue_open_count = sizeof(aue_open) / sizeof(aue_open[0]);
+
+static const struct aue_open_event aue_openat[] = {
+	{ O_RDONLY,					AUE_OPENAT_R },
+	{ (O_RDONLY | O_CREAT),				AUE_OPENAT_RC },
+	{ (O_RDONLY | O_CREAT | O_TRUNC),		AUE_OPENAT_RTC },
+	{ (O_RDONLY | O_TRUNC),				AUE_OPENAT_RT },
+	{ O_RDWR,					AUE_OPENAT_RW },
+	{ (O_RDWR | O_CREAT),				AUE_OPENAT_RWC },
+	{ (O_RDWR | O_CREAT | O_TRUNC),			AUE_OPENAT_RWTC },
+	{ (O_RDWR | O_TRUNC),				AUE_OPENAT_RWT },
+	{ O_WRONLY,					AUE_OPENAT_W },
+	{ (O_WRONLY | O_CREAT),				AUE_OPENAT_WC },
+	{ (O_WRONLY | O_CREAT | O_TRUNC),		AUE_OPENAT_WTC },
+	{ (O_WRONLY | O_TRUNC),				AUE_OPENAT_WT },
+};
+static const int aue_openat_count = sizeof(aue_openat) / sizeof(aue_openat[0]);
+
 /*
  * Look up the class for an audit event in the class mapping table.
  */
@@ -253,94 +290,33 @@ audit_ctlname_to_sysctlevent(int name[], uint64_t
 au_event_t
 audit_flags_and_error_to_openevent(int oflags, int error)
 {
-	au_event_t aevent;
+	int i;
 
 	/*
 	 * Need to check only those flags we care about.
 	 */
 	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
-
-	/*
-	 * These checks determine what flags are on with the condition that
-	 * ONLY that combination is on, and no other flags are on.
-	 */
-	switch (oflags) {
-	case O_RDONLY:
-		aevent = AUE_OPEN_R;
-		break;
-
-	case (O_RDONLY | O_CREAT):
-		aevent = AUE_OPEN_RC;
-		break;
-
-	case (O_RDONLY | O_CREAT | O_TRUNC):
-		aevent = AUE_OPEN_RTC;
-		break;
-
-	case (O_RDONLY | O_TRUNC):
-		aevent = AUE_OPEN_RT;
-		break;
-
-	case O_RDWR:
-		aevent = AUE_OPEN_RW;
-		break;
-
-	case (O_RDWR | O_CREAT):
-		aevent = AUE_OPEN_RWC;
-		break;
-
-	case (O_RDWR | O_CREAT | O_TRUNC):
-		aevent = AUE_OPEN_RWTC;
-		break;
-
-	case (O_RDWR | O_TRUNC):
-		aevent = AUE_OPEN_RWT;
-		break;
-
-	case O_WRONLY:
-		aevent = AUE_OPEN_W;
-		break;
-
-	case (O_WRONLY | O_CREAT):
-		aevent = AUE_OPEN_WC;
-		break;
-
-	case (O_WRONLY | O_CREAT | O_TRUNC):
-		aevent = AUE_OPEN_WTC;
-		break;
-
-	case (O_WRONLY | O_TRUNC):
-		aevent = AUE_OPEN_WT;
-		break;
-
-	default:
-		aevent = AUE_OPEN;
-		break;
+	for (i = 0; i < aue_open_count; i++) {
+		if (aue_open[i].aoe_flags == oflags)
+			return (aue_open[i].aoe_event);
 	}
+	return (AUE_OPEN);
+}
 
-#if 0
+au_event_t
+audit_flags_and_error_to_openatevent(int oflags, int error)
+{
+	int i;
+
 	/*
-	 * Convert chatty errors to better matching events.  Failures to
-	 * find a file are really just attribute events -- so recast them as
-	 * such.
-	 *
-	 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
-	 * is just a placeholder.  However, in Darwin we return that in
-	 * preference to other events.  For now, comment this out as we don't
-	 * have a BSM conversion routine for AUE_OPEN.
+	 * Need to check only those flags we care about.
 	 */
-	switch (aevent) {
-	case AUE_OPEN_R:
-	case AUE_OPEN_RT:
-	case AUE_OPEN_RW:
-	case AUE_OPEN_RWT:
-	case AUE_OPEN_W:
-	case AUE_OPEN_WT:
-		if (error == ENOENT)
-			aevent = AUE_OPEN;
+	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
+	for (i = 0; i < aue_openat_count; i++) {
+		if (aue_openat[i].aoe_flags == oflags)
+			return (aue_openat[i].aoe_event);
 	}
-#endif
-	return (aevent);
+	return (AUE_OPENAT);
 }
 
 /*
Index: security/audit/audit.h
===================================================================
--- security/audit/audit.h	(revision 195897)
+++ security/audit/audit.h	(working copy)
@@ -114,6 +114,8 @@ extern int	audit_suspended;
 #define	ARG_IOVECSTR		0x0000800000000000ULL
 #define	ARG_ARGV		0x0001000000000000ULL
 #define	ARG_ENVV		0x0002000000000000ULL
+#define	ARG_ATFD1		0x0004000000000000ULL
+#define	ARG_ATFD2		0x0008000000000000ULL
 #define	ARG_NONE		0x0000000000000000ULL
 #define	ARG_ALL			0xFFFFFFFFFFFFFFFFULL
 
@@ -132,6 +134,8 @@ union auditon_udata;
 void	 audit_arg_addr(void * addr);
 void	 audit_arg_exit(int status, int retval);
 void	 audit_arg_len(int len);
+void	 audit_arg_atfd1(int atfd);
+void	 audit_arg_atfd2(int atfd);
 void	 audit_arg_fd(int fd);
 void	 audit_arg_fflags(int fflags);
 void	 audit_arg_gid(gid_t gid);
@@ -159,7 +163,8 @@ void	 audit_arg_auid(uid_t auid);
 void	 audit_arg_auditinfo(struct auditinfo *au_info);
 void	 audit_arg_auditinfo_addr(struct auditinfo_addr *au_info);
 void	 audit_arg_upath(struct thread *td, char *upath, u_int64_t flags);
-void	 audit_arg_vnode(struct vnode *vp, u_int64_t flags);
+void	 audit_arg_vnode1(struct vnode *vp);
+void	 audit_arg_vnode2(struct vnode *vp);
 void	 audit_arg_text(char *text);
 void	 audit_arg_cmd(int cmd);
 void	 audit_arg_svipc_cmd(int cmd);
@@ -197,6 +202,16 @@ void	 audit_thread_free(struct thread *td);
 		audit_arg_argv((argv), (argc), (length));		\
 } while (0)
 
+#define	AUDIT_ARG_ATFD1(atfd) do {					\
+	if (AUDITING_TD(curthread))					\
+		audit_arg_atfd1((atfd));				\
+} while (0)
+
+#define	AUDIT_ARG_ATFD2(atfd) do {					\
+	if (AUDITING_TD(curthread))					\
+		audit_arg_atfd2((atfd));				\
+} while (0)
+
 #define	AUDIT_ARG_AUDITON(udata) do {					\
 	if (AUDITING_TD(curthread))					\
 		audit_arg_auditon((udata));				\
@@ -327,11 +342,16 @@ void	 audit_thread_free(struct thread *td);
 		audit_arg_value((value));				\
 } while (0)
 
-#define	AUDIT_ARG_VNODE(vp, flags) do {					\
+#define	AUDIT_ARG_VNODE1(vp) do {					\
 	if (AUDITING_TD(curthread))					\
-		audit_arg_vnode((vp), (flags));				\
+		audit_arg_vnode1((vp));					\
 } while (0)
 
+#define	AUDIT_ARG_VNODE2(vp) do {					\
+	if (AUDITING_TD(curthread))					\
+		audit_arg_vnode2((vp));					\
+} while (0)
+
 #define	AUDIT_SYSCALL_ENTER(code, td)	do {				\
 	if (audit_enabled) {						\
 		audit_syscall_enter(code, td);				\
@@ -360,6 +380,8 @@ void	 audit_thread_free(struct thread *td);
 
 #define	AUDIT_ARG_ADDR(addr)
 #define	AUDIT_ARG_ARGV(argv, argc, length)
+#define	AUDIT_ARG_ATFD1(atfd)
+#define	AUDIT_ARG_ATFD2(atfd)
 #define	AUDIT_ARG_AUDITON(udata)
 #define	AUDIT_ARG_CMD(cmd)
 #define	AUDIT_ARG_DEV(dev)
@@ -386,7 +408,8 @@ void	 audit_thread_free(struct thread *td);
 #define	AUDIT_ARG_UID(uid)
 #define	AUDIT_ARG_UPATH(td, upath, flags)
 #define	AUDIT_ARG_VALUE(value)
-#define	AUDIT_ARG_VNODE(vp, flags)
+#define	AUDIT_ARG_VNODE1(vp)
+#define	AUDIT_ARG_VNODE2(vp)
 
 #define	AUDIT_SYSCALL_ENTER(code, td)
 #define	AUDIT_SYSCALL_EXIT(error, td)
