summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcsjp <csjp@FreeBSD.org>2007-10-26 01:23:07 +0000
committercsjp <csjp@FreeBSD.org>2007-10-26 01:23:07 +0000
commita16bb8381db4aec49650ac2d3da3ea686ba74d42 (patch)
tree7d368f5fbf689769a57d382da467cdf9405088ad
parentbf5c2ef02d1494f1190fcdba11368c04b9a89442 (diff)
downloadFreeBSD-src-a16bb8381db4aec49650ac2d3da3ea686ba74d42.zip
FreeBSD-src-a16bb8381db4aec49650ac2d3da3ea686ba74d42.tar.gz
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
-rw-r--r--sys/kern/kern_sig.c33
-rw-r--r--sys/security/audit/audit.c48
-rw-r--r--sys/security/audit/audit.h1
-rw-r--r--sys/security/audit/audit_bsm.c8
4 files changed, 84 insertions, 6 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 694d145..3b213a6 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -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 @@ close:
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);
}
diff --git a/sys/security/audit/audit.c b/sys/security/audit/audit.c
index 1caf18f..1b4ac87 100644
--- a/sys/security/audit/audit.c
+++ b/sys/security/audit/audit.c
@@ -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);
+}
diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h
index 9442a1d..08bebcd 100644
--- a/sys/security/audit/audit.h
+++ b/sys/security/audit/audit.h
@@ -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);
diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c
index 59f1b86..6ccf66d 100644
--- a/sys/security/audit/audit_bsm.c
+++ b/sys/security/audit/audit_bsm.c
@@ -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)) {
OpenPOWER on IntegriCloud