diff --git a/sys/bsm/audit_internal.h b/sys/bsm/audit_internal.h index 2c7a1ef65f0a..19bec4591874 100644 --- a/sys/bsm/audit_internal.h +++ b/sys/bsm/audit_internal.h @@ -72,7 +72,9 @@ typedef struct au_record au_record_t; * token structures may contain pointers of whose contents we do not know the * size (e.g text tokens). */ +#define AUDIT_HEADER_EX_SIZE(a) ((a)->ai_termid.at_type+18+sizeof(u_int32_t)) #define AUDIT_HEADER_SIZE 18 +#define MAX_AUDIT_HEADER_SIZE (5*sizeof(u_int32_t)+18) #define AUDIT_TRAILER_SIZE 7 /* diff --git a/sys/bsm/audit_record.h b/sys/bsm/audit_record.h index dd3ea299c4f1..4e269ea2f538 100644 --- a/sys/bsm/audit_record.h +++ b/sys/bsm/audit_record.h @@ -244,10 +244,13 @@ token_t *au_to_file(char *file, struct timeval tm); token_t *au_to_header32_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, struct timeval tm); +token_t *au_to_header32_ex_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, + struct timeval tm, struct auditinfo_addr *aia); token_t *au_to_header64_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, struct timeval tm); #if !defined(KERNEL) && !defined(_KERNEL) token_t *au_to_header(int rec_size, au_event_t e_type, au_emod_t e_mod); +token_t *au_to_header_ex(int rec_size, au_event_t e_type, au_emod_t e_mod); token_t *au_to_header32(int rec_size, au_event_t e_type, au_emod_t e_mod); token_t *au_to_header64(int rec_size, au_event_t e_type, au_emod_t e_mod); #endif diff --git a/sys/security/audit/audit.c b/sys/security/audit/audit.c index 737c693a30fb..8680ad3a4018 100644 --- a/sys/security/audit/audit.c +++ b/sys/security/audit/audit.c @@ -157,6 +157,45 @@ struct cv audit_watermark_cv; */ static struct cv audit_fail_cv; +/* + * Kernel audit information. This will store the current audit address + * or host information that the kernel will use when it's generating + * audit records. This data is modified by the A_GET{SET}KAUDIT auditon(2) + * command. + */ +static struct auditinfo_addr audit_kinfo; +static struct rwlock audit_kinfo_lock; + +#define KINFO_LOCK_INIT() rw_init(&audit_kinfo_lock, "kernel audit info lock") +#define KINFO_RLOCK() rw_rlock(&audit_kinfo_lock) +#define KINFO_WLOCK() rw_wlock(&audit_kinfo_lock) +#define KINFO_RUNLOCK() rw_runlock(&audit_kinfo_lock) +#define KINFO_WUNLOCK() rw_wunlock(&audit_kinfo_lock) + +void +audit_set_kinfo(struct auditinfo_addr *ak) +{ + + KASSERT(ak->ai_termid.at_type == AU_IPv4 || + ak->ai_termid.at_type == AU_IPv6, + ("audit_set_kinfo: invalid address type")); + KINFO_WLOCK(); + audit_kinfo = *ak; + KINFO_WUNLOCK(); +} + +void +audit_get_kinfo(struct auditinfo_addr *ak) +{ + + KASSERT(audit_kinfo.ai_termid.at_type == AU_IPv4 || + audit_kinfo.ai_termid.at_type == AU_IPv6, + ("audit_set_kinfo: invalid address type")); + KINFO_RLOCK(); + *ak = audit_kinfo; + KINFO_RUNLOCK(); +} + /* * Construct an audit record for the passed thread. */ @@ -241,7 +280,11 @@ audit_init(void) audit_qctrl.aq_bufsz = AQ_BUFSZ; audit_qctrl.aq_minfree = AU_FS_MINFREE; + audit_kinfo.ai_termid.at_type = AU_IPv4; + audit_kinfo.ai_termid.at_addr[0] = INADDR_ANY; + mtx_init(&audit_mtx, "audit_mtx", NULL, MTX_DEF); + KINFO_LOCK_INIT(); cv_init(&audit_worker_cv, "audit_worker_cv"); cv_init(&audit_watermark_cv, "audit_watermark_cv"); cv_init(&audit_fail_cv, "audit_fail_cv"); diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h index 14dbcfd0ced2..9481c14328c8 100644 --- a/sys/security/audit/audit.h +++ b/sys/security/audit/audit.h @@ -180,6 +180,8 @@ void audit_cred_proc1(struct ucred *cred); void audit_proc_coredump(struct thread *td, char *path, int errcode); void audit_thread_alloc(struct thread *td); void audit_thread_free(struct thread *td); +void audit_set_kinfo(struct auditinfo_addr *); +void audit_get_kinfo(struct auditinfo_addr *); /* * Define a macro to wrap the audit_arg_* calls by checking the global diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c index e06072705248..a62f35b0c604 100644 --- a/sys/security/audit/audit_bsm.c +++ b/sys/security/audit/audit_bsm.c @@ -113,13 +113,34 @@ kau_close(struct au_record *rec, struct timespec *ctime, short event) size_t tot_rec_size; token_t *cur, *hdr, *trail; struct timeval tm; + size_t hdrsize; + struct auditinfo_addr ak; + struct in6_addr *ap; - tot_rec_size = rec->len + AUDIT_HEADER_SIZE + AUDIT_TRAILER_SIZE; + audit_get_kinfo(&ak); + hdrsize = 0; + switch (ak.ai_termid.at_type) { + case AU_IPv4: + hdrsize = (ak.ai_termid.at_addr[0] == INADDR_ANY) ? + AUDIT_HEADER_SIZE : AUDIT_HEADER_EX_SIZE(&ak); + break; + case AU_IPv6: + ap = (struct in6_addr *)&ak.ai_termid.at_addr[0]; + hdrsize = (IN6_IS_ADDR_UNSPECIFIED(ap)) ? AUDIT_HEADER_SIZE : + AUDIT_HEADER_EX_SIZE(&ak); + break; + default: + panic("kau_close: invalid address family"); + } + tot_rec_size = rec->len + hdrsize + AUDIT_TRAILER_SIZE; rec->data = malloc(tot_rec_size, M_AUDITBSM, M_WAITOK | M_ZERO); tm.tv_usec = ctime->tv_nsec / 1000; tm.tv_sec = ctime->tv_sec; - hdr = au_to_header32_tm(tot_rec_size, event, 0, tm); + if (hdrsize != AUDIT_HEADER_SIZE) + hdr = au_to_header32_ex_tm(tot_rec_size, event, 0, tm, &ak); + else + hdr = au_to_header32_tm(tot_rec_size, event, 0, tm); TAILQ_INSERT_HEAD(&rec->token_q, hdr, tokens); trail = au_to_trailer(tot_rec_size); diff --git a/sys/security/audit/audit_bsm_token.c b/sys/security/audit/audit_bsm_token.c index b60a6887f811..ad9ffcc5902d 100644 --- a/sys/security/audit/audit_bsm_token.c +++ b/sys/security/audit/audit_bsm_token.c @@ -1289,6 +1289,51 @@ au_to_exec_env(char **envp) } #endif +/* + * token ID 1 byte + * record byte count 4 bytes + * version # 1 byte + * event type 2 bytes + * event modifier 2 bytes + * address type/length 4 bytes + * machine address 4 bytes/16 bytes (IPv4/IPv6 address) + * seconds of time 4 bytes/8 bytes (32/64-bits) + * milliseconds of time 4 bytes/8 bytes (32/64-bits) + */ +token_t * +au_to_header32_ex_tm(int rec_size, au_event_t e_type, au_emod_t e_mod, + struct timeval tm, struct auditinfo_addr *aia) +{ + token_t *t; + u_char *dptr = NULL; + u_int32_t timems; + struct au_tid_addr *tid; + + tid = &aia->ai_termid; + KASSERT(tid->at_type == AU_IPv4 || tid->at_type == AU_IPv6, + ("au_to_header32_ex_tm: invalid address family")); + + GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + + sizeof(u_char) + 2 * sizeof(u_int16_t) + 3 * sizeof(u_int32_t) + + tid->at_type); + + ADD_U_CHAR(dptr, AUT_HEADER32_EX); + ADD_U_INT32(dptr, rec_size); + ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM); + ADD_U_INT16(dptr, e_type); + ADD_U_INT16(dptr, e_mod); + ADD_U_INT32(dptr, tid->at_type); + if (tid->at_type == AU_IPv6) + ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t)); + else + ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t)); + timems = tm.tv_usec / 1000; + /* Add the timestamp */ + ADD_U_INT32(dptr, tm.tv_sec); + ADD_U_INT32(dptr, timems); /* We need time in ms. */ + return (t); +} + /* * token ID 1 byte * record byte count 4 bytes diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h index d0cfe941c8bf..395d8c0c2d8c 100644 --- a/sys/security/audit/audit_private.h +++ b/sys/security/audit/audit_private.h @@ -132,6 +132,7 @@ union auditon_udata { au_qctrl_t au_qctrl; au_stat_t au_stat; au_fstat_t au_fstat; + auditinfo_addr_t au_kau_info; }; struct posix_ipc_perm { diff --git a/sys/security/audit/audit_syscalls.c b/sys/security/audit/audit_syscalls.c index 7b7cb0efcfa2..cf88c93420fe 100644 --- a/sys/security/audit/audit_syscalls.c +++ b/sys/security/audit/audit_syscalls.c @@ -395,11 +395,14 @@ auditon(struct thread *td, struct auditon_args *uap) break; case A_GETKAUDIT: - return (ENOSYS); + audit_get_kinfo(&udata.au_kau_info); break; case A_SETKAUDIT: - return (ENOSYS); + if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && + udata.au_kau_info.ai_termid.at_type != AU_IPv6) + return (EINVAL); + audit_set_kinfo(&udata.au_kau_info); break; case A_SENDTRIGGER: