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
This commit is contained in:
parent
3d1001cb11
commit
e4b4bbb665
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195925
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -100,6 +100,32 @@ audit_arg_len(int len)
|
||||
ARG_SET_VALID(ar, ARG_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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
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;
|
||||
|
||||
/*
|
||||
* These checks determine what flags are on with the condition that
|
||||
* ONLY that combination is on, and no other flags are on.
|
||||
* Need to check only those flags we care about.
|
||||
*/
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
return (aevent);
|
||||
return (AUE_OPENAT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user