Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Jul 2009 21:39:58 +0000 (UTC)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r195925 - in head/sys: kern security/audit
Message-ID:  <200907282139.n6SLdw3a044235@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rwatson
Date: Tue Jul 28 21:39:58 2009
New Revision: 195925
URL: http://svn.freebsd.org/changeset/base/195925

Log:
  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).
  
  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.
  
  Approved by:	re (kib)
  Reviewed by:	rdivacky (fooat(2) portions)
  Obtained from:	TrustedBSD Project
  MFC after:	1 month

Modified:
  head/sys/kern/vfs_lookup.c
  head/sys/security/audit/audit.c
  head/sys/security/audit/audit.h
  head/sys/security/audit/audit_arg.c
  head/sys/security/audit/audit_bsm.c
  head/sys/security/audit/audit_bsm_klib.c
  head/sys/security/audit/audit_private.h

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c	Tue Jul 28 21:18:26 2009	(r195924)
+++ head/sys/kern/vfs_lookup.c	Tue Jul 28 21:39:58 2009	(r195925)
@@ -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) {

Modified: head/sys/security/audit/audit.c
==============================================================================
--- head/sys/security/audit/audit.c	Tue Jul 28 21:18:26 2009	(r195924)
+++ head/sys/security/audit/audit.c	Tue Jul 28 21:39:58 2009	(r195925)
@@ -409,17 +409,22 @@ audit_commit(struct kaudit_record *ar, i
 	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);

Modified: head/sys/security/audit/audit.h
==============================================================================
--- head/sys/security/audit/audit.h	Tue Jul 28 21:18:26 2009	(r195924)
+++ head/sys/security/audit/audit.h	Tue Jul 28 21:39:58 2009	(r195925)
@@ -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);
@@ -197,6 +201,16 @@ void	 audit_thread_free(struct thread *t
 		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));				\
@@ -360,6 +374,8 @@ void	 audit_thread_free(struct thread *t
 
 #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)

Modified: head/sys/security/audit/audit_arg.c
==============================================================================
--- head/sys/security/audit/audit_arg.c	Tue Jul 28 21:18:26 2009	(r195924)
+++ head/sys/security/audit/audit_arg.c	Tue Jul 28 21:39:58 2009	(r195925)
@@ -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;

Modified: head/sys/security/audit/audit_bsm.c
==============================================================================
--- head/sys/security/audit/audit_bsm.c	Tue Jul 28 21:18:26 2009	(r195924)
+++ head/sys/security/audit/audit_bsm.c	Tue Jul 28 21:39:58 2009	(r195925)
@@ -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,
 
 	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,
 	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,
 		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,
 		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,
 		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,
 		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);

Modified: head/sys/security/audit/audit_bsm_klib.c
==============================================================================
--- head/sys/security/audit/audit_bsm_klib.c	Tue Jul 28 21:18:26 2009	(r195924)
+++ head/sys/security/audit/audit_bsm_klib.c	Tue Jul 28 21:39:58 2009	(r195925)
@@ -75,6 +75,43 @@ static struct evclass_list	evclass_hash[
 #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[],
 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);
+}
+
+au_event_t
+audit_flags_and_error_to_openatevent(int oflags, int error)
+{
+	int i;
 
-#if 0
 	/*
-	 * 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.
-	 */
-	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;
+	 * Need to check only those flags we care about.
+	 */
+	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);
 }
 
 /*

Modified: head/sys/security/audit/audit_private.h
==============================================================================
--- head/sys/security/audit/audit_private.h	Tue Jul 28 21:18:26 2009	(r195924)
+++ head/sys/security/audit/audit_private.h	Tue Jul 28 21:39:58 2009	(r195925)
@@ -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;
@@ -323,6 +325,7 @@ void		 au_evclassmap_insert(au_event_t e
 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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200907282139.n6SLdw3a044235>