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:
parent
d4dc7a5cef
commit
ae1078d657
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=161813
@ -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);
|
||||
|
@ -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 |
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user