summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-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);