Index: audit.c =================================================================== RCS file: /usr/ncvs/src/sys/security/audit/audit.c,v retrieving revision 1.17 diff -u -r1.17 audit.c --- audit.c 8 Jun 2006 21:58:04 -0000 1.17 +++ audit.c 26 Aug 2006 16:11:38 -0000 @@ -389,8 +389,8 @@ if (audit_pipe_preselect(auid, event, class, sorf, ar->k_ar_commit & AR_PRESELECT_TRAIL) != 0) ar->k_ar_commit |= AR_PRESELECT_PIPE; - if ((ar->k_ar_commit & (AR_PRESELECT_TRAIL | AR_PRESELECT_PIPE)) == - 0) { + if ((ar->k_ar_commit & (AR_PRESELECT_TRAIL | AR_PRESELECT_PIPE | + AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE)) == 0) { mtx_lock(&audit_mtx); audit_pre_q_len--; mtx_unlock(&audit_mtx); Index: audit_bsm.c =================================================================== RCS file: /usr/ncvs/src/sys/security/audit/audit_bsm.c,v retrieving revision 1.9 diff -u -r1.9 audit_bsm.c --- audit_bsm.c 26 Aug 2006 08:17:58 -0000 1.9 +++ audit_bsm.c 31 Aug 2006 21:21:18 -0000 @@ -1324,19 +1324,51 @@ * record is good, 0 otherwise. */ int -bsm_rec_verify(void *rec) +bsm_rec_verify(struct kaudit_record *ar) { - char c = *(char *)rec; + int rettok, trailer, subject; + u_char *tok_type, *this_tok; + size_t tok_len; + char c; /* * Check the token ID of the first token; it has to be a header * token. - * - * XXXAUDIT There needs to be a token structure to map a token. - * XXXAUDIT 'Shouldn't be simply looking at the first char. */ + KASSERT(ar->k_udata != NULL, ("NULL BSM record")); + c = *(char *)ar->k_udata; + KASSERT(ar->k_ulen > 0, ("zero length bsm record")); if ((c != AUT_HEADER32) && (c != AUT_HEADER32_EX) && (c != AUT_HEADER64) && (c != AUT_HEADER64_EX)) - return (0); - return (1); + return (EINVAL); + ar->k_uevent = bsm_get_event_type(ar->k_udata); + ar->k_uclass = au_event_class(ar->k_uevent); + this_tok = ar->k_udata; + rettok = trailer = subject = 0; + while (this_tok < ((u_char *)ar->k_udata + ar->k_ulen)) { + tok_type = (u_char *)this_tok; + switch (*tok_type) { + case AUT_RETURN32: + case AUT_RETURN64: + if (!bsm_get_return_status(ar->k_udata, ar->k_ulen)) + ar->k_usorf = AU_PRS_SUCCESS; + else + ar->k_usorf = AU_PRS_FAILURE; + rettok++; + break; + case AUT_TRAILER: + trailer++; + break; + case AUT_SUBJECT32: + case AUT_SUBJECT32_EX: + ar->k_uauid = bsm_get_auid(ar->k_udata, ar->k_ulen); + subject++; + break; + } + tok_len = bsm_token_size(this_tok); + this_tok += tok_len; + } + if (!rettok || !trailer || !subject) + return (EINVAL); + return (0); } Index: audit_bsm_klib.c =================================================================== RCS file: /usr/ncvs/src/sys/security/audit/audit_bsm_klib.c,v retrieving revision 1.4 diff -u -r1.4 audit_bsm_klib.c --- audit_bsm_klib.c 5 Jun 2006 14:48:17 -0000 1.4 +++ audit_bsm_klib.c 26 Aug 2006 15:51:19 -0000 @@ -31,6 +31,7 @@ */ #include +#include #include #include #include @@ -43,8 +44,13 @@ #include #include +#include +#include +#include + #include #include +#include #include #include @@ -543,3 +549,243 @@ strlcpy(cpath, bufp, MAXPATHLEN); } } + +size_t +bsm_token_size(u_char *token) +{ + struct vnode_au_info vni; /* CSJPXXX yuck */ + u_char *val8, *tokidp; + size_t mval, len; + u_int16_t *val16; + u_int32_t *val32; + char *str; + int i; + + len = mval = 0; + tokidp = (u_char *)token; + switch (*tokidp) { + case AUT_ARG32: + len = sizeof(u_char) + sizeof(u_char) + sizeof(u_int32_t) + + sizeof(u_int16_t); + val16 = (u_int16_t *)(token + len - sizeof(u_int16_t)); + len += be16toh(*val16); + break; + case AUT_ARG64: + len = sizeof(u_char) + sizeof(u_char) + sizeof(u_int64_t) + + sizeof(u_int16_t); + val16 = (u_int16_t *)(token + len - sizeof(u_int16_t)); + len += be16toh(*val16); + break; + case AUT_ATTR32: + len = sizeof(u_char) + sizeof(u_int16_t) + sizeof(u_int16_t) + + sizeof(u_int32_t) + sizeof(u_int32_t) + sizeof(u_int32_t); + if (sizeof(vni.vn_fileid) == sizeof(uint32_t)) { + len += 2 * sizeof(u_int32_t); + } else if (sizeof(vni.vn_fileid) == sizeof(uint64_t)) + len += sizeof(u_int64_t); + else + len += sizeof(u_int64_t); + len += sizeof(u_int32_t); + break; + case AUT_DATA: + val8 = (u_char *)(token + 2 * sizeof(u_char)); + switch (*val8) { + case AUR_BYTE: + mval = AUR_BYTE_SIZE; + break; + case AUR_SHORT: + mval = AUR_SHORT_SIZE; + break; + case AUR_INT32: + mval = AUR_INT32_SIZE; + break; + case AUR_INT64: + mval = AUR_INT64_SIZE; + break; + } + val8 = (u_char *)(token + 3 * sizeof(u_char)); + len = 4 * sizeof(u_char) + mval * *val8; + break; + case AUT_EXIT: + len = sizeof(u_char) + 2 * sizeof(u_int32_t); + break; + case AUT_NEWGROUPS: + val16 = (u_int16_t *)(token + sizeof(u_char)); + len = sizeof(u_char) + sizeof(u_int16_t) + + be16toh(*val16) * sizeof(u_int32_t); + break; + case AUT_IN_ADDR: + len = sizeof(u_char) + sizeof(uint32_t); + break; + case AUT_IN_ADDR_EX: + len = sizeof(u_char) + 5 * sizeof(uint32_t); + break; + case AUT_IP: + len = sizeof(u_char) + sizeof(struct ip); + break; + case AUT_IPC: + len = 2 * sizeof(u_char) + sizeof(u_int32_t); + break; + case AUT_IPC_PERM: + len = 12 * sizeof(u_int16_t) + sizeof(u_int32_t); + break; + case AUT_IPORT: + len = sizeof(u_char) + sizeof(u_int16_t); + break; + case AUT_OPAQUE: + val16 = (u_int16_t *)(token + sizeof(u_char)); + len = sizeof(u_char) + sizeof(u_int16_t) + be16toh(*val16); + break; + case AUT_OTHER_FILE32: + val16 = (u_int16_t *)(token + sizeof(u_char) + 2 * sizeof(u_int32_t)); + len = sizeof(u_char) + 2 * sizeof(u_int32_t) + + sizeof(u_int16_t) + be16toh(*val16); + break; + case AUT_TEXT: + val16 = (u_int16_t *)(token + sizeof(u_char)); + len = sizeof(u_char) + sizeof(u_int16_t) + be16toh(*val16); + break; + case AUT_PATH: + val16 = (u_int16_t *)(token + sizeof(u_char)); + len = sizeof(u_char) + sizeof(u_int16_t) + be16toh(*val16); + break; + case AUT_PROCESS32: + len = sizeof(u_char) + 9 * sizeof(u_int32_t); + break; + case AUT_PROCESS32_EX: + val32 = (u_int32_t *)(token + sizeof(u_char) + 8 + * sizeof(u_int32_t)); + if (be32toh(*val32) == AU_IPv4) + len = sizeof(u_char) + 10 * sizeof(u_int32_t); + else if (be32toh(*val32) == AU_IPv6) + len = sizeof(u_char) + 13 * sizeof(u_int32_t); + break; + case AUT_RETURN32: + len = 2 * sizeof(u_char) + sizeof(u_int32_t); + break; + case AUT_RETURN64: + len = 2 * sizeof(u_char) + sizeof(u_int64_t); + break; + case AUT_SEQ: + len = sizeof(u_char) + sizeof(u_int32_t); + break; + case AU_SOCK_UNIX_TOKEN: + str = (char *)(token + 3 * sizeof(u_char)); + len = 3 * sizeof(u_char) + strlen(str) + 1; + break; + case AUT_SOCKINET32: + len = sizeof(u_char) + 2 * sizeof(uint16_t) + sizeof(uint32_t); + break; + case AUT_SOCKINET128: + len = 3 * sizeof(u_char) + sizeof(u_int16_t) + + 4 * sizeof(u_int32_t); + break; + case AUT_SUBJECT32: + len = sizeof(u_char) + 9 * sizeof(u_int32_t); + break; + case AUT_SUBJECT32_EX: + val32 = (u_int32_t *)(token + sizeof(u_char) + 8 + * sizeof(u_int32_t)); + if (be32toh(*val32) == AU_IPv4) + len = sizeof(u_char) + 10 * sizeof(u_int32_t); + else if (be32toh(*val32) == AU_IPv6) + len = sizeof(u_char) + 13 * sizeof(u_int32_t); + break; + /* XXX AUT_SUBJECT64 ? */ + case AUT_EXEC_ARGS: + val32 = (u_int32_t *)(token + sizeof(u_char)); + str = (char *)(token + sizeof(u_char) + sizeof(u_int32_t)); + for (i = 0; i < be32toh(*val32); i++) { + mval += strlen(str) + 1; + str += mval; + } + len = sizeof(u_char) + sizeof(u_int32_t) + mval; + break; + case AUT_EXEC_ENV: + val32 = (u_int32_t *)(token + sizeof(u_char)); + str = (char *)(token + sizeof(u_char) + sizeof(u_int32_t)); + for (i = 0; i < be32toh(*val32); i++) { + mval += strlen(str) + 1; + str += mval; + } + len = sizeof(u_char) + sizeof(u_int32_t) + mval; + break; + case AUT_HEADER32: + len = sizeof(u_char) + sizeof(u_int32_t) + sizeof(u_char) + + 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t); + break; + case AUT_TRAILER: + len = sizeof(u_char) + sizeof(u_int16_t) + sizeof(u_int32_t); + break; + } + return (len); +} + +au_event_t +bsm_get_event_type(u_char *bsm_record) +{ + u_int16_t *e_type; + u_char *tokenid; + + tokenid = (u_char *)bsm_record; + KASSERT(*tokenid == AUT_HEADER32, ("Header not AUT_HEADER32")); + e_type = (u_int16_t *)(bsm_record + sizeof(u_char) + sizeof(u_int32_t) + + sizeof(u_char)); + return (be16toh(*e_type)); +} + +u_int64_t +bsm_get_return_status(u_char *bsm_record, size_t bsm_reclen) +{ + u_char *tok_type, *this_tok; + u_int64_t *return64; + u_int32_t *return32; + size_t tok_len; + + this_tok = bsm_record; + while (this_tok < (bsm_record + bsm_reclen)) { + tok_type = (u_char *)this_tok; + if (*tok_type == AUT_RETURN32) { + return32 = (u_int32_t *)(this_tok + 2 * + sizeof(u_char)); + return ((u_int64_t)be32toh(*return32)); + } else if (*tok_type == AUT_RETURN64) { + return64 = (u_int64_t *)(this_tok + 2 * + sizeof(u_char)); + return (be64toh(*return64)); + } + tok_len = bsm_token_size(this_tok); + this_tok += tok_len; + } + /* XXXCSJP should we be allowing audit records with no + * return status? + */ + printf("bsm_get_return_status: supplied BSM record " + "has no return status\n"); + return (0); +} + +au_id_t +bsm_get_auid(u_char *bsm_record, size_t bsm_reclen) +{ + u_char *tok_type, *this_tok; + au_id_t *auidp; + size_t tok_len; + + this_tok = bsm_record; + while (this_tok < (bsm_record + bsm_reclen)) { + tok_type = (u_char *)this_tok; + switch (*tok_type) { + case AUT_SUBJECT32: + case AUT_SUBJECT64: + case AUT_SUBJECT32_EX: + case AUT_SUBJECT64_EX: + auidp = (au_id_t *)(this_tok + 1); + return (be32toh(*auidp)); + } + tok_len = bsm_token_size(this_tok); + this_tok += tok_len; + } + printf("bsm_get_auid: no subject token\n"); + return (0); +} Index: audit_pipe.c =================================================================== RCS file: /usr/ncvs/src/sys/security/audit/audit_pipe.c,v retrieving revision 1.9 diff -u -r1.9 audit_pipe.c --- audit_pipe.c 26 Aug 2006 17:59:31 -0000 1.9 +++ audit_pipe.c 31 Aug 2006 21:21:18 -0000 @@ -478,10 +478,14 @@ * should parse that information and return it. */ void -audit_pipe_submit_user(void *record, u_int record_len) +audit_pipe_submit_user(struct kaudit_record *ar, int trail_select) { struct audit_pipe *ap; + void *record; + u_int record_len; + record = ar->k_udata; + record_len = ar->k_ulen; /* * Lockless read to avoid mutex overhead if pipes are not in use. */ @@ -489,8 +493,12 @@ return; mtx_lock(&audit_pipe_mtx); - TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) - audit_pipe_append(ap, record, record_len); + TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) { + if (audit_pipe_preselect_check(ap, ar->k_uauid, ar->k_uevent, + ar->k_uclass, ar->k_usorf, trail_select)) { + audit_pipe_append(ap, record, record_len); + } + } audit_pipe_records++; mtx_unlock(&audit_pipe_mtx); cv_signal(&audit_pipe_cv); Index: audit_private.h =================================================================== RCS file: /usr/ncvs/src/sys/security/audit/audit_private.h,v retrieving revision 1.9 diff -u -r1.9 audit_private.h --- audit_private.h 5 Jun 2006 14:48:17 -0000 1.9 +++ audit_private.h 26 Aug 2006 16:09:04 -0000 @@ -94,6 +94,9 @@ #define AR_PRESELECT_TRAIL 0x00001000U #define AR_PRESELECT_PIPE 0x00002000U +#define AR_PRESELECT_USER_TRAIL 0x00004000U +#define AR_PRESELECT_USER_PIPE 0x00008000U + /* * Audit data is generated as a stream of struct audit_record structures, * linked by struct kaudit_record, and contain storage for possible audit so @@ -235,6 +238,12 @@ void *k_udata; /* User data. */ u_int k_ulen; /* User data length. */ struct uthread *k_uthread; /* Audited thread. */ + + /* Properties associated with the user supplied BSM record */ + au_event_t k_uevent; + au_class_t k_uclass; + int k_usorf; + au_id_t k_uauid; TAILQ_ENTRY(kaudit_record) k_q; }; TAILQ_HEAD(kaudit_queue, kaudit_record); @@ -254,7 +263,7 @@ */ struct au_record; int kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau); -int bsm_rec_verify(void *rec); +int bsm_rec_verify(struct kaudit_record *ar); /* * Kernel versions of the libbsm audit record functions. @@ -337,6 +346,14 @@ au_class_t class, int sorf, int trail_select); void audit_pipe_submit(au_id_t auid, au_event_t event, au_class_t class, int sorf, int trail_select, void *record, u_int record_len); -void audit_pipe_submit_user(void *record, u_int record_len); +void audit_pipe_submit_user(struct kaudit_record *ar, int trail_select); + +/* + * BSM kernel parsing functions + */ +size_t bsm_token_size(u_char *); +au_event_t bsm_get_event_type(u_char *); +u_int64_t bsm_get_return_status(u_char *, size_t); +au_id_t bsm_get_auid(u_char *, size_t); #endif /* ! _SECURITY_AUDIT_PRIVATE_H_ */ Index: audit_syscalls.c =================================================================== RCS file: /usr/ncvs/src/sys/security/audit/audit_syscalls.c,v retrieving revision 1.4 diff -u -r1.4 audit_syscalls.c --- audit_syscalls.c 5 Jun 2006 22:36:12 -0000 1.4 +++ audit_syscalls.c 31 Aug 2006 22:04:43 -0000 @@ -62,6 +62,7 @@ int error; void * rec; struct kaudit_record *ar; + struct au_mask *aumask; error = suser(td); if (error) @@ -102,10 +103,11 @@ goto free_out; /* Verify the record. */ - if (bsm_rec_verify(rec) == 0) { - error = EINVAL; + ar->k_ulen = uap->length; + ar->k_udata = rec; + error = bsm_rec_verify(ar); + if (error) goto free_out; - } /* * Attach the user audit record to the kernel audit record. Because @@ -115,9 +117,33 @@ * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, * k_ar_commit & AR_COMMIT_USER? */ - ar->k_udata = rec; - ar->k_ulen = uap->length; ar->k_ar_commit |= AR_COMMIT_USER; + if (ar->k_ar.ar_subj_auid == AU_DEFAUDITID) + aumask = &audit_nae_mask; + else + aumask = &ar->k_ar.ar_subj_amask; + /* + * Now that we have the necessary information to preselect this user + * supplied record, let's do it. + */ + if (au_preselect(ar->k_uevent, ar->k_uclass, aumask, + ar->k_usorf) != 0) { + ar->k_ar_commit |= AR_PRESELECT_USER_TRAIL; + } + + if (audit_pipe_preselect(ar->k_uauid, ar->k_uevent, ar->k_uclass, + ar->k_usorf, ar->k_ar_commit & AR_PRESELECT_USER_TRAIL) != 0) { + ar->k_ar_commit |= AR_PRESELECT_USER_PIPE; + } + + if ((ar->k_ar_commit & (AR_PRESELECT_USER_PIPE | + AR_PRESELECT_USER_TRAIL)) == 0) { + ar->k_ar_commit &= ~AR_COMMIT_USER; + free(ar->k_udata, M_AUDITDATA); + ar->k_udata = NULL; + ar->k_ulen = 0; + } + return (0); free_out: Index: audit_worker.c =================================================================== RCS file: /usr/ncvs/src/sys/security/audit/audit_worker.c,v retrieving revision 1.9 diff -u -r1.9 audit_worker.c --- audit_worker.c 6 Jun 2006 08:43:27 -0000 1.9 +++ audit_worker.c 31 Aug 2006 22:04:09 -0000 @@ -322,8 +322,8 @@ au_id_t auid; int sorf; - if ((ar->k_ar_commit & AR_COMMIT_USER) && - (ar->k_ar_commit & AR_PRESELECT_TRAIL)) { + if ((ar->k_ar_commit & AR_COMMIT_USER) != 0 && + (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) { error = audit_record_write(audit_vp, audit_cred, audit_td, ar->k_udata, ar->k_ulen); if (error && audit_panic_on_write_fail) @@ -331,11 +331,15 @@ else if (error) printf("audit_worker: write error %d\n", error); } - if ((ar->k_ar_commit & AR_COMMIT_USER) && - (ar->k_ar_commit & AR_PRESELECT_PIPE)) - audit_pipe_submit_user(ar->k_udata, ar->k_ulen); + if ((ar->k_ar_commit & AR_COMMIT_USER) != 0 && + (ar->k_ar_commit & AR_PRESELECT_USER_PIPE)) { + audit_pipe_submit_user(ar, ar->k_ar_commit & + AR_PRESELECT_USER_TRAIL); + } - if (!(ar->k_ar_commit & AR_COMMIT_KERNEL)) + if (!(ar->k_ar_commit & AR_COMMIT_KERNEL) || + ((ar->k_ar_commit & AR_PRESELECT_PIPE) == 0 && + (ar->k_ar_commit & AR_PRESELECT_TRAIL) == 0)) return; auid = ar->k_ar.ar_subj_auid;