diff options
author | wsalamon <wsalamon@FreeBSD.org> | 2006-09-01 11:45:40 +0000 |
---|---|---|
committer | wsalamon <wsalamon@FreeBSD.org> | 2006-09-01 11:45:40 +0000 |
commit | c62317c442340f5e4627b6020679dc03d49a3918 (patch) | |
tree | 17f9a899743e9577c2e64080d7c7f0a957fbe0f4 | |
parent | e279989d710de9f19f0e36445d579caea48bf429 (diff) | |
download | FreeBSD-src-c62317c442340f5e4627b6020679dc03d49a3918.zip FreeBSD-src-c62317c442340f5e4627b6020679dc03d49a3918.tar.gz |
Audit the argv and env vectors passed in on exec:
Add the argument auditing functions for argv and env.
Add kernel-specific versions of the tokenizer functions for the
arg and env represented as a char array.
Implement the AUDIT_ARGV and AUDIT_ARGE audit policy commands to
enable/disable argv/env auditing.
Call the argument auditing from the exec system calls.
Obtained from: TrustedBSD Project
Approved by: rwatson (mentor)
-rw-r--r-- | sys/bsm/audit_record.h | 9 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 9 | ||||
-rw-r--r-- | sys/security/audit/audit.c | 8 | ||||
-rw-r--r-- | sys/security/audit/audit.h | 5 | ||||
-rw-r--r-- | sys/security/audit/audit_arg.c | 42 | ||||
-rw-r--r-- | sys/security/audit/audit_bsm.c | 15 | ||||
-rw-r--r-- | sys/security/audit/audit_bsm_token.c | 64 | ||||
-rw-r--r-- | sys/security/audit/audit_private.h | 6 | ||||
-rw-r--r-- | sys/security/audit/audit_syscalls.c | 9 |
9 files changed, 155 insertions, 12 deletions
diff --git a/sys/bsm/audit_record.h b/sys/bsm/audit_record.h index 18235e2..b1c975b 100644 --- a/sys/bsm/audit_record.h +++ b/sys/bsm/audit_record.h @@ -319,8 +319,13 @@ token_t *au_to_subject32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); token_t *au_to_subject64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid); -token_t *au_to_exec_args(const char **); -token_t *au_to_exec_env(const char **); +#if defined(_KERNEL) || defined(KERNEL) +token_t *au_to_exec_args(char *args, int argc); +token_t *au_to_exec_env(char *envs, int envc); +#else +token_t *au_to_exec_args(char **argv); +token_t *au_to_exec_env(char **envp); +#endif token_t *au_to_text(char *text); token_t *au_to_kevent(struct kevent *kev); token_t *au_to_trailer(int rec_size); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index d8f196b..9bd3104 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -79,6 +79,8 @@ __FBSDID("$FreeBSD$"); #include <machine/reg.h> +#include <security/audit/audit.h> + MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS); @@ -239,6 +241,10 @@ kern_execve(td, args, mac_p) struct proc *p = td->td_proc; int error; + AUDIT_ARG(argv, args->begin_argv, args->argc, + args->begin_envv - args->begin_argv); + AUDIT_ARG(envv, args->begin_envv, args->envc, + args->endp - args->begin_envv); if (p->p_flag & P_HADTHREADS) { PROC_LOCK(p); if (thread_single(SINGLE_BOUNDARY)) { @@ -351,6 +357,9 @@ do_execve(td, args, mac_p) /* * Translate the file name. namei() returns a vnode pointer * in ni_vp amoung other things. + * + * XXXAUDIT: It would be desirable to also audit the name of the + * interpreter if this is an interpreted binary. */ ndp = &nd; NDINIT(ndp, LOOKUP, ISOPEN | LOCKLEAF | FOLLOW | SAVENAME | MPSAFE | diff --git a/sys/security/audit/audit.c b/sys/security/audit/audit.c index 07cf3278..be0d481 100644 --- a/sys/security/audit/audit.c +++ b/sys/security/audit/audit.c @@ -92,6 +92,8 @@ int audit_suspended; */ int audit_panic_on_write_fail; int audit_fail_stop; +int audit_argv; +int audit_arge; /* * Are we currently "failing stop" due to out of disk space? @@ -204,6 +206,10 @@ audit_record_dtor(void *mem, int size, void *arg) free(ar->k_ar.ar_arg_text, M_AUDITTEXT); if (ar->k_udata != NULL) free(ar->k_udata, M_AUDITDATA); + if (ar->k_ar.ar_arg_argv != NULL) + free(ar->k_ar.ar_arg_argv, M_AUDITTEXT); + if (ar->k_ar.ar_arg_envv != NULL) + free(ar->k_ar.ar_arg_envv, M_AUDITTEXT); } /* @@ -221,6 +227,8 @@ audit_init(void) audit_panic_on_write_fail = 0; audit_fail_stop = 0; audit_in_failure = 0; + audit_argv = 0; + audit_arge = 0; audit_fstat.af_filesz = 0; /* '0' means unset, unbounded */ audit_fstat.af_currsz = 0; diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h index 6043236..574f6af 100644 --- a/sys/security/audit/audit.h +++ b/sys/security/audit/audit.h @@ -111,6 +111,9 @@ extern int audit_suspended; #define ARG_MACHPORT1 0x0000100000000000ULL #define ARG_MACHPORT2 0x0000200000000000ULL #define ARG_EXIT 0x0000400000000000ULL +#define ARG_IOVECSTR 0x0000800000000000ULL +#define ARG_ARGV 0x0001000000000000ULL +#define ARG_ENVV 0x0002000000000000ULL #define ARG_NONE 0x0000000000000000ULL #define ARG_ALL 0xFFFFFFFFFFFFFFFFULL @@ -165,6 +168,8 @@ void audit_arg_svipc_addr(void *addr); void audit_arg_posix_ipc_perm(uid_t uid, gid_t gid, mode_t mode); void audit_arg_auditon(union auditon_udata *udata); void audit_arg_file(struct proc *p, struct file *fp); +void audit_arg_argv(char *argv, int argc, int length); +void audit_arg_envv(char *envv, int envc, int length); void audit_sysclose(struct thread *td, int fd); void audit_proc_alloc(struct proc *p); void audit_proc_kproc0(struct proc *p); diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c index 5da377f..ea569f7 100644 --- a/sys/security/audit/audit_arg.c +++ b/sys/security/audit/audit_arg.c @@ -763,6 +763,48 @@ audit_arg_vnode(struct vnode *vp, u_int64_t flags) } /* + * Audit the argument strings passed to exec. + */ +void +audit_arg_argv(char *argv, int argc, int length) +{ + struct kaudit_record *ar; + + if (audit_argv == 0) + return; + + ar = currecord(); + if (ar == NULL) + return; + + ar->k_ar.ar_arg_argv = malloc(length, M_AUDITTEXT, M_WAITOK); + bcopy(argv, ar->k_ar.ar_arg_argv, length); + ar->k_ar.ar_arg_argc = argc; + ARG_SET_VALID(ar, ARG_ARGV); +} + +/* + * Audit the environment strings passed to exec. + */ +void +audit_arg_envv(char *envv, int envc, int length) +{ + struct kaudit_record *ar; + + if (audit_arge == 0) + return; + + ar = currecord(); + if (ar == NULL) + return; + + ar->k_ar.ar_arg_envv = malloc(length, M_AUDITTEXT, M_WAITOK); + bcopy(envv, ar->k_ar.ar_arg_envv, length); + ar->k_ar.ar_arg_envc = envc; + ARG_SET_VALID(ar, ARG_ENVV); +} + +/* * The close() system call uses it's own audit call to capture the path/vnode * information because those pieces are not easily obtained within the system * call itself. diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c index 9beb68e..2bfab8a 100644 --- a/sys/security/audit/audit_bsm.c +++ b/sys/security/audit/audit_bsm.c @@ -572,7 +572,6 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau) case AUE_CHDIR: case AUE_CHROOT: case AUE_EACCESS: - case AUE_EXECVE: case AUE_GETATTRLIST: case AUE_NFS_GETFH: case AUE_LSTAT: @@ -671,6 +670,20 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau) EXTATTR_TOKENS; break; + case AUE_EXECVE: + if (ARG_IS_VALID(kar, ARG_ARGV)) { + tok = au_to_exec_args(ar->ar_arg_argv, + ar->ar_arg_argc); + kau_write(rec, tok); + } + if (ARG_IS_VALID(kar, ARG_ENVV)) { + tok = au_to_exec_env(ar->ar_arg_envv, + ar->ar_arg_envc); + kau_write(rec, tok); + } + UPATH1_VNODE1_TOKENS; + break; + case AUE_FCHMOD: if (ARG_IS_VALID(kar, ARG_MODE)) { tok = au_to_arg32(2, "new file mode", diff --git a/sys/security/audit/audit_bsm_token.c b/sys/security/audit/audit_bsm_token.c index 7b9abe5..a5d404b 100644 --- a/sys/security/audit/audit_bsm_token.c +++ b/sys/security/audit/audit_bsm_token.c @@ -1014,13 +1014,60 @@ au_to_me(void) } #endif +#if defined(_KERNEL) || defined(KERNEL) +static token_t * +au_to_exec_strings(char *strs, int count, u_char type) +{ + token_t *t; + u_char *dptr = NULL; + u_int32_t totlen; + int ctr; + char *p; + + totlen = 0; + ctr = count; + p = strs; + while (ctr-- > 0) { + totlen += strlen(p) + 1; + p = strs + totlen; + } + GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen); + ADD_U_CHAR(dptr, type); + ADD_U_INT32(dptr, count); + ADD_STRING(dptr, strs, totlen); + + return (t); +} + +/* + * token ID 1 byte + * count 4 bytes + * text count null-terminated strings + */ +token_t * +au_to_exec_args(char *args, int argc) +{ + return (au_to_exec_strings(args, argc, AUT_EXEC_ARGS)); +} + /* * token ID 1 byte * count 4 bytes * text count null-terminated strings */ token_t * -au_to_exec_args(const char **args) +au_to_exec_env(char *envs, int envc) +{ + return (au_to_exec_strings(envs, envc, AUT_EXEC_ENV)); +} +#else +/* + * token ID 1 byte + * count 4 bytes + * text count null-terminated strings + */ +token_t * +au_to_exec_args(char **argv) { token_t *t; u_char *dptr = NULL; @@ -1028,7 +1075,7 @@ au_to_exec_args(const char **args) int i, count = 0; size_t totlen = 0; - nextarg = *args; + nextarg = *argv; while (nextarg != NULL) { int nextlen; @@ -1036,7 +1083,7 @@ au_to_exec_args(const char **args) nextlen = strlen(nextarg); totlen += nextlen + 1; count++; - nextarg = *(args + count); + nextarg = *(argv + count); } totlen += count * sizeof(char); /* nul terminations. */ @@ -1046,7 +1093,7 @@ au_to_exec_args(const char **args) ADD_U_INT32(dptr, count); for (i = 0; i < count; i++) { - nextarg = *(args + i); + nextarg = *(argv + i); ADD_MEM(dptr, nextarg, strlen(nextarg) + 1); } @@ -1059,7 +1106,7 @@ au_to_exec_args(const char **args) * text count null-terminated strings */ token_t * -au_to_exec_env(const char **env) +au_to_exec_env(char **envp) { token_t *t; u_char *dptr = NULL; @@ -1067,7 +1114,7 @@ au_to_exec_env(const char **env) size_t totlen = 0; const char *nextenv; - nextenv = *env; + nextenv = *envp; while (nextenv != NULL) { int nextlen; @@ -1075,7 +1122,7 @@ au_to_exec_env(const char **env) nextlen = strlen(nextenv); totlen += nextlen + 1; count++; - nextenv = *(env + count); + nextenv = *(envp + count); } totlen += sizeof(char) * count; @@ -1085,12 +1132,13 @@ au_to_exec_env(const char **env) ADD_U_INT32(dptr, count); for (i = 0; i < count; i++) { - nextenv = *(env + i); + nextenv = *(envp + i); ADD_MEM(dptr, nextenv, strlen(nextenv) + 1); } return (t); } +#endif /* * token ID 1 byte diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h index 2dc61ec..f6cd17a 100644 --- a/sys/security/audit/audit_private.h +++ b/sys/security/audit/audit_private.h @@ -74,6 +74,8 @@ extern struct audit_fstat audit_fstat; extern struct au_mask audit_nae_mask; extern int audit_panic_on_write_fail; extern int audit_fail_stop; +extern int audit_argv; +extern int audit_arge; /* * Success/failure conditions for the conversion of a kernel audit record to @@ -210,6 +212,10 @@ struct audit_record { void * ar_arg_svipc_addr; struct posix_ipc_perm ar_arg_pipc_perm; union auditon_udata ar_arg_auditon; + char *ar_arg_argv; + int ar_arg_argc; + char *ar_arg_envv; + int ar_arg_envc; int ar_arg_exitstatus; int ar_arg_exitretval; }; diff --git a/sys/security/audit/audit_syscalls.c b/sys/security/audit/audit_syscalls.c index 8bd6ccb..eb18c76 100644 --- a/sys/security/audit/audit_syscalls.c +++ b/sys/security/audit/audit_syscalls.c @@ -190,16 +190,23 @@ auditon(struct thread *td, struct auditon_args *uap) udata.au_policy |= AUDIT_CNT; if (audit_panic_on_write_fail) udata.au_policy |= AUDIT_AHLT; + if (audit_argv) + udata.au_policy |= AUDIT_ARGV; + if (audit_arge) + udata.au_policy |= AUDIT_ARGE; break; case A_SETPOLICY: - if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT)) + if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| + AUDIT_ARGE)) return (EINVAL); /* * XXX - Need to wake up waiters if the policy relaxes? */ audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); + audit_argv = (udata.au_policy & AUDIT_ARGV); + audit_arge = (udata.au_policy & AUDIT_ARGE); break; case A_GETKMASK: |