summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2014-05-04 03:53:39 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2014-05-04 03:53:39 +0000
commite75387b5443d933b7afda70735259944f64e39d2 (patch)
tree0c6b680083886ff3f4f14bca34b69526bfd71b28 /sys
parent078ffdecc4d697879a48c141229ab44dcb1af514 (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.c54
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);