Implement AUE_CORE, which adds process core dump support into the kernel.

This change introduces audit_proc_coredump() which is called by coredump(9)
to create an audit record for the coredump event.  When a process
dumps a core, it could be security relevant.  It could be an indicator that
a stack within the process has been overflowed with an incorrectly constructed
malicious payload or a number of other events.

The record that is generated looks like this:

header,111,10,process dumped core,0,Thu Oct 25 19:36:29 2007, + 179 msec
argument,0,0xb,signal
path,/usr/home/csjp/test.core
subject,csjp,csjp,staff,csjp,staff,1101,1095,50457,10.37.129.2
return,success,1
trailer,111

- We allocate a completely new record to make sure we arent clobbering
  the audit data associated with the syscall that produced the core
  (assuming the core is being generated in response to SIGABRT  and not
  an invalid memory access).
- Shuffle around expand_name() so we can use the coredump name at the very
  beginning of the coredump call.  Make sure we free the storage referenced
  by "name" if we need to bail out early.
- Audit both successful and failed coredump creation efforts

Obtained from:	TrustedBSD Project
Reviewed by:	rwatson
MFC after:	1 month
This commit is contained in:
Christian S.J. Peron 2007-10-26 01:23:07 +00:00
parent ed0b604f1f
commit 57274c513c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=172995
4 changed files with 84 additions and 6 deletions

View file

@ -3058,8 +3058,19 @@ coredump(struct thread *td)
MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
_STOPEVENT(p, S_CORE, 0);
name = expand_name(p->p_comm, td->td_ucred->cr_uid, p->p_pid);
if (name == NULL) {
#ifdef AUDIT
audit_proc_coredump(td, NULL, EINVAL);
#endif
return (EINVAL);
}
if (((sugid_coredump == 0) && p->p_flag & P_SUGID) || do_coredump == 0) {
PROC_UNLOCK(p);
#ifdef AUDIT
audit_proc_coredump(td, name, EFAULT);
#endif
free(name, M_TEMP);
return (EFAULT);
}
@ -3073,19 +3084,25 @@ coredump(struct thread *td)
*/
limit = (off_t)lim_cur(p, RLIMIT_CORE);
PROC_UNLOCK(p);
if (limit == 0)
if (limit == 0) {
#ifdef AUDIT
audit_proc_coredump(td, name, EFBIG);
#endif
free(name, M_TEMP);
return (EFBIG);
}
restart:
name = expand_name(p->p_comm, td->td_ucred->cr_uid, p->p_pid);
if (name == NULL)
return (EINVAL);
NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, name, td);
flags = O_CREAT | FWRITE | O_NOFOLLOW;
error = vn_open(&nd, &flags, S_IRUSR | S_IWUSR, NULL);
free(name, M_TEMP);
if (error)
if (error) {
#ifdef AUDIT
audit_proc_coredump(td, name, error);
#endif
free(name, M_TEMP);
return (error);
}
vfslocked = NDHASGIANT(&nd);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
@ -3143,6 +3160,10 @@ coredump(struct thread *td)
if (error == 0)
error = error1;
out:
#ifdef AUDIT
audit_proc_coredump(td, name, error);
#endif
free(name, M_TEMP);
VFS_UNLOCK_GIANT(vfslocked);
return (error);
}

View file

@ -573,3 +573,51 @@ audit_thread_free(struct thread *td)
KASSERT(td->td_ar == NULL, ("audit_thread_free: td_ar != NULL"));
}
void
audit_proc_coredump(struct thread *td, char *path, int errcode)
{
struct kaudit_record *ar;
struct au_mask *aumask;
au_class_t class;
int ret, sorf;
char **pathp;
au_id_t auid;
/*
* Make sure we are using the correct preselection mask.
*/
auid = td->td_ucred->cr_audit.ai_auid;
if (auid == AU_DEFAUDITID)
aumask = &audit_nae_mask;
else
aumask = &td->td_ucred->cr_audit.ai_mask;
/*
* It's possible for coredump(9) generation to fail. Make sure that
* we handle this case correctly for preselection.
*/
if (errcode != 0)
sorf = AU_PRS_FAILURE;
else
sorf = AU_PRS_SUCCESS;
class = au_event_class(AUE_CORE);
if (au_preselect(AUE_CORE, class, aumask, sorf) == 0)
return;
/*
* If we are interested in seeing this audit record, allocate it.
* Where possible coredump records should contain a pathname and arg32
* (signal) tokens.
*/
ar = audit_new(AUE_CORE, td);
if (path != NULL) {
pathp = &ar->k_ar.ar_arg_upath1;
*pathp = malloc(MAXPATHLEN, M_AUDITPATH, M_WAITOK);
canon_path(td, path, *pathp);
ARG_SET_VALID(ar, ARG_UPATH1);
}
ar->k_ar.ar_arg_signum = td->td_proc->p_sig;
ARG_SET_VALID(ar, ARG_SIGNUM);
if (errcode != 0)
ret = 1;
audit_commit(ar, errcode, ret);
}

View file

@ -177,6 +177,7 @@ void audit_cred_destroy(struct ucred *cred);
void audit_cred_init(struct ucred *cred);
void audit_cred_kproc0(struct ucred *cred);
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);

View file

@ -715,6 +715,14 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau)
UPATH1_VNODE1_TOKENS;
break;
case AUE_CORE:
if (ARG_IS_VALID(kar, ARG_SIGNUM)) {
tok = au_to_arg32(0, "signal", ar->ar_arg_signum);
kau_write(rec, tok);
}
UPATH1_VNODE1_TOKENS;
break;
case AUE_EXTATTRCTL:
UPATH1_VNODE1_TOKENS;
if (ARG_IS_VALID(kar, ARG_CMD)) {