diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2014-05-04 03:53:39 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2014-05-04 03:53:39 +0000 |
commit | e75387b5443d933b7afda70735259944f64e39d2 (patch) | |
tree | 0c6b680083886ff3f4f14bca34b69526bfd71b28 /sys | |
parent | 078ffdecc4d697879a48c141229ab44dcb1af514 (diff) |
When kern.nosuidcoredump=3, act like =2 but try to dump cores into
the /var/crash/programname/ directory, as root. For instance,
# mkdir /var/crash/bgpd/
# chmod 700 /var/crash/bgpd/ # If you skip this step, you are a moron
# sysctl kern.nosuidcoredump=3
# bgpd
# pkill -ABRT bgpd
# ls /var/crash/bgpd/
14764.core 23207.core 6423.core
Of course, in real life the idea is that you don't kill the daemon but it
crashes and you collect parallel cores. Careful you don't fill your /var.
Further tuneables are being considered.
Sorry to be picking on bgpd for this example. I've watched the "too
difficult to debug privsep code" angst for far too long.
ok guenther
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_sig.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 5356365dc7b..dd42647a2e6 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.164 2014/04/18 11:51:17 guenther Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.165 2014/05/04 03:53:37 deraadt Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -51,6 +51,7 @@ #include <sys/buf.h> #include <sys/acct.h> #include <sys/file.h> +#include <sys/filedesc.h> #include <sys/kernel.h> #include <sys/wait.h> #include <sys/ktrace.h> @@ -1446,21 +1447,20 @@ coredump(struct proc *p) struct nameidata nd; struct vattr vattr; struct coredump_iostate io; - int error, len; - char name[sizeof("/var/crash/") + MAXCOMLEN + sizeof(".core")]; - char *dir = ""; + int error, len, incrash = 0; + char name[MAXPATHLEN]; + const char *dir = "/var/crash"; pr->ps_flags |= PS_COREDUMP; /* - * Don't dump if not root and the process has used set user or - * group privileges, unless the nosuidcoredump sysctl is set to 2, - * in which case dumps are put into /var/crash/. + * If the process has inconsistant uids, nosuidcoredump + * determines coredump placement policy. */ if (((pr->ps_flags & PS_SUGID) && (error = suser(p, 0))) || ((pr->ps_flags & PS_SUGID) && nosuidcoredump)) { - if (nosuidcoredump == 2) - dir = "/var/crash/"; + if (nosuidcoredump == 3 || nosuidcoredump == 2) + incrash = 1; else return (EPERM); } @@ -1470,16 +1470,42 @@ coredump(struct proc *p) p->p_rlimit[RLIMIT_CORE].rlim_cur) return (EFBIG); - len = snprintf(name, sizeof(name), "%s%s.core", dir, p->p_comm); + if (nosuidcoredump == 3) { + /* + * If the program directory does not exist, dumps of + * that core will silently fail. + */ + len = snprintf(name, sizeof(name), "%s/%s/%u.core", + dir, p->p_comm, p->p_pid); + } else if (nosuidcoredump == 2) + len = snprintf(name, sizeof(name), "%s/%s.core", + dir, p->p_comm); + else + len = snprintf(name, sizeof(name), "%s.core", p->p_comm); if (len >= sizeof(name)) return (EACCES); /* - * ... but actually write it as UID + * Control the UID used to write out. The normal case uses + * the real UID. If the sugid case is going to write into the + * controlled directory, we do so as root. */ - cred = crdup(cred); - cred->cr_uid = cred->cr_ruid; - cred->cr_gid = cred->cr_rgid; + if (incrash == 0) { + cred = crdup(cred); + cred->cr_uid = cred->cr_ruid; + cred->cr_gid = cred->cr_rgid; + } else { + if (p->p_fd->fd_rdir) { + vrele(p->p_fd->fd_rdir); + p->p_fd->fd_rdir = NULL; + } + p->p_ucred = crdup(p->p_ucred); + crfree(cred); + cred = p->p_ucred; + crhold(cred); + cred->cr_uid = 0; + cred->cr_gid = 0; + } NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, p); |