summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2009-07-28 21:39:58 +0000
committerrwatson <rwatson@FreeBSD.org>2009-07-28 21:39:58 +0000
commit21e3bcee4378f043e902dc1bab9ac2915235f40a (patch)
tree441a5395402f45cf8439af427c181e056625d4f4
parentfa74d2c7e54f546f30ebc8df6467929fa74d72f6 (diff)
downloadFreeBSD-src-21e3bcee4378f043e902dc1bab9ac2915235f40a.zip
FreeBSD-src-21e3bcee4378f043e902dc1bab9ac2915235f40a.tar.gz
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
-rw-r--r--sys/kern/vfs_lookup.c7
-rw-r--r--sys/security/audit/audit.c15
-rw-r--r--sys/security/audit/audit.h16
-rw-r--r--sys/security/audit/audit_arg.c26
-rw-r--r--sys/security/audit/audit_bsm.c75
-rw-r--r--sys/security/audit/audit_bsm_klib.c132
-rw-r--r--sys/security/audit/audit_private.h3
7 files changed, 190 insertions, 84 deletions
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index e154c56..2f3b54e 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -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) {
diff --git a/sys/security/audit/audit.c b/sys/security/audit/audit.c
index 1967e05..40daaa9 100644
--- a/sys/security/audit/audit.c
+++ b/sys/security/audit/audit.c
@@ -409,17 +409,22 @@ audit_commit(struct kaudit_record *ar, int error, int retval)
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);
diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h
index 582cc24..e8b3550 100644
--- a/sys/security/audit/audit.h
+++ b/sys/security/audit/audit.h
@@ -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 *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)); \
@@ -360,6 +374,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)
diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c
index cf62421..bf4cb0a 100644
--- a/sys/security/audit/audit_arg.c
+++ b/sys/security/audit/audit_arg.c
@@ -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;
diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c
index e5c0d52..b1a9931 100644
--- a/sys/security/audit/audit_bsm.c
+++ b/sys/security/audit/audit_bsm.c
@@ -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_record **pau)
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_record **pau)
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_record **pau)
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_record **pau)
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_record **pau)
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_record **pau)
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);
diff --git a/sys/security/audit/audit_bsm_klib.c b/sys/security/audit/audit_bsm_klib.c
index 547e09a..c8d4035 100644
--- a/sys/security/audit/audit_bsm_klib.c
+++ b/sys/security/audit/audit_bsm_klib.c
@@ -75,6 +75,43 @@ static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
#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 valid_arg)
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.
+ * 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);
}
/*
diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h
index 0da2f2d..97433df 100644
--- a/sys/security/audit/audit_private.h
+++ b/sys/security/audit/audit_private.h
@@ -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 event, au_class_t class);
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);
OpenPOWER on IntegriCloud