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)
This commit is contained in:
Wayne Salamon 2006-09-01 11:45:40 +00:00
parent d4dc7a5cef
commit ae1078d657
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=161813
9 changed files with 155 additions and 12 deletions

View File

@ -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);

View File

@ -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 |

View File

@ -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;

View File

@ -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);

View File

@ -762,6 +762,48 @@ audit_arg_vnode(struct vnode *vp, u_int64_t flags)
ARG_SET_VALID(ar, ARG_VNODE2);
}
/*
* 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

View File

@ -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",

View File

@ -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(const char **args)
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_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

View File

@ -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;
};

View File

@ -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: