Enabling coredumps

Han Holl (jeholl@euronet.nl)
Mon, 22 Sep 1997 21:10:05 +0200 (MET DST)


Hello,

The current Linux kernel refuses to dump core for several categories
of processes:
- processes that are direct descendants from init (daemons, cronjobs ...)
- processes that run setuid
- processes that manipulate their setuid status
- processes that don't have the appropropriate permissions to produce a
"core" file (directory not writeble, a core file from another process
exists, and so on).

Because there are situations that a core dump is very, very helpful
indeed, I created the following patches (against 2.0.31-pre9 or 2.0.29).

The first allows you to give a kernel option: init-rlimit-core=nnnnn
at boot time. Daemons and cron jobs will have a limit of nnnnn bytes
instead of 0.

The second introduces a global kernel variable, settable through
the sysctl mechanism: echo value >/proc/sys/kernel/coredump.
Initial value is 0, which implies current kernel behaviour.

Value is the sum of:
1 Log coredumps (and failures) via the KERN_INFO log facility
2 Allow setuid/setgid programs to dump core
4 Allow programs that manipulate their setuid settings (in kernel/sys.c)
8 Don't dump core in the current directory, but in /var/core/progname.pid
instead.

The last option deals with permission issues. If you make /var/core
write-only (333) I don't see too many security problems.

I hope sincerely that some facility like this will eventually make it
into the kernel, but in the meantime: the great thing about Linux is
that I don't have to persuade anyone to put it in. It _is_ in, on my
systems. That's freedom !

Han Holl

PS If someone spots a terrible mistake on my part, I'd appreciate
a correction.

Number 1:
--- ./init/main.c.orig Sun Sep 21 23:14:49 1997
+++ ./init/main.c Sat Sep 20 19:54:49 1997
@@ -671,6 +671,12 @@
execute_command = line;
continue;
}
+ if (!strncmp(line,"init-rlimit-core=",17)) {
+ line += 17;
+ init_task.rlim[RLIMIT_CORE].rlim_cur = simple_strtoul(line, NULL, 10);
+ continue;
+ }
+
if (checksetup(line))
continue;
/*
/* end-of-patch */
Number 2:
--- ./fs/exec.c.orig Sun Sep 21 23:14:49 1997
+++ ./fs/exec.c Sun Sep 21 21:56:02 1997
@@ -454,8 +454,8 @@

flush_thread();

- if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
- permission(bprm->inode,MAY_READ))
+ if (((bprm->e_uid != current->euid || bprm->e_gid != current->egid) &&
+ (cdmp_options & CDMP_OPT_INISETUID) == 0) || permission(bprm->inode,MAY_READ))
current->dumpable = 0;

flush_old_signals(current->sig);
--- ./fs/binfmt_elf.c.orig Sun Sep 21 23:14:49 1997
+++ ./fs/binfmt_elf.c Sun Sep 21 21:36:28 1997
@@ -977,7 +977,7 @@
struct file file;
struct inode *inode;
unsigned short fs;
- char corefile[6+sizeof(current->comm)];
+ char corefile[12+5+sizeof(current->comm)];
int segs;
int i;
size_t size;
@@ -991,8 +991,26 @@
elf_fpregset_t fpu; /* NT_PRFPREG */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */

- if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
+ if (cdmp_options & CDMP_OPT_VARCORE) {
+ sprintf(corefile, "/var/core/%s.%d", current->comm, current->pid);
+ } else {
+ memcpy(corefile,"core.",5);
+#if 0
+ memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+ corefile[4] = '\0';
+#endif
+ }
+ if (cdmp_options & CDMP_OPT_LOG)
+ printk(KERN_INFO "%s: Dumping core in %s\n",current->comm, corefile);
+ if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1) {
+ if (cdmp_options & CDMP_OPT_LOG)
+ printk(KERN_INFO "%s: No coredump, %s%s%s\n", current->comm,
+ ! current->dumpable ? "Not dumpable" : "",
+ limit < PAGE_SIZE ? "RLIMIT_CORE setting" : "",
+ current->mm->count != 1 ? "mm->count != 1" : "");
return 0;
+ }
current->dumpable = 0;

#ifndef CONFIG_BINFMT_ELF
@@ -1042,13 +1060,11 @@

fs = get_fs();
set_fs(KERNEL_DS);
- memcpy(corefile,"core.",5);
-#if 0
- memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
- corefile[4] = '\0';
-#endif
+
if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+ if (cdmp_options & CDMP_OPT_LOG)
+ printk(KERN_INFO "%s: Could not create %s\n", current->comm,
+ corefile);
inode = NULL;
goto end_coredump;
}
--- ./kernel/sched.c.orig Sun Sep 21 23:14:49 1997
+++ ./kernel/sched.c Sun Sep 21 21:22:28 1997
@@ -45,6 +45,7 @@
*/

int securelevel = 0; /* system security level */
+int cdmp_options = 0; /* system security level */

long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */
volatile struct timeval xtime; /* The current time */
--- ./kernel/sys.c.orig Sun Sep 21 23:14:49 1997
+++ ./kernel/sys.c Sun Sep 21 21:53:14 1997
@@ -268,7 +268,7 @@
(egid != (gid_t) -1 && egid != old_rgid))
current->sgid = current->egid;
current->fsgid = current->egid;
- if (current->egid != old_egid)
+ if (current->egid != old_egid && (cdmp_options & CDMP_OPT_CHGSETUID) == 0)
current->dumpable = 0;
return 0;
}
@@ -286,7 +286,7 @@
current->egid = current->fsgid = gid;
else
return -EPERM;
- if (current->egid != old_egid)
+ if (current->egid != old_egid && (cdmp_options & CDMP_OPT_CHGSETUID) == 0)
current->dumpable = 0;
return 0;
}
@@ -477,7 +477,7 @@
(euid != (uid_t) -1 && euid != old_ruid))
current->suid = current->euid;
current->fsuid = current->euid;
- if (current->euid != old_euid)
+ if (current->euid != old_euid && (cdmp_options & CDMP_OPT_CHGSETUID) == 0)
current->dumpable = 0;
return 0;
}
@@ -503,7 +503,7 @@
current->fsuid = current->euid = uid;
else
return -EPERM;
- if (current->euid != old_euid)
+ if (current->euid != old_euid && (cdmp_options & CDMP_OPT_CHGSETUID) == 0)
current->dumpable = 0;
return(0);
}
@@ -521,7 +521,7 @@
if (uid == current->uid || uid == current->euid ||
uid == current->suid || uid == current->fsuid || suser())
current->fsuid = uid;
- if (current->fsuid != old_fsuid)
+ if (current->fsuid != old_fsuid && (cdmp_options & CDMP_OPT_CHGSETUID) == 0)
current->dumpable = 0;
return old_fsuid;
}
@@ -536,7 +536,7 @@
if (gid == current->gid || gid == current->egid ||
gid == current->sgid || gid == current->fsgid || suser())
current->fsgid = gid;
- if (current->fsgid != old_fsgid)
+ if (current->fsgid != old_fsgid && (cdmp_options & CDMP_OPT_CHGSETUID) == 0)
current->dumpable = 0;
return old_fsgid;
}
--- ./kernel/sysctl.c.orig Sun Sep 21 23:14:49 1997
+++ ./kernel/sysctl.c Sun Sep 21 21:44:14 1997
@@ -126,6 +126,8 @@
0644, NULL, &proc_dointvec},
{KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
0444, NULL, &proc_dointvec},
+ {KERN_COREDUMP_OPT, "coredump", &cdmp_options, sizeof(int),
+ 0644, NULL, &proc_dointvec},
{KERN_MAXFILE, "file-max", &max_files, sizeof(int),
0644, NULL, &proc_dointvec},
{KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
--- ./include/linux/sched.h.orig Sun Sep 21 23:14:49 1997
+++ ./include/linux/sched.h Sun Sep 21 21:47:11 1997
@@ -332,7 +332,12 @@
extern unsigned long prof_len;
extern unsigned long prof_shift;

-extern int securelevel; /* system security level */
+extern int securelevel; /* system security level */
+extern int cdmp_options; /* coredump options*/
+#define CDMP_OPT_LOG 1 /* log coredumps KERN_INFO */
+#define CDMP_OPT_INISETUID 2 /* allow setuid programs */
+#define CDMP_OPT_CHGSETUID 4 /* allow programs that change uid/gid */
+#define CDMP_OPT_VARCORE 8 /* dump core in /var/core */

#define CURRENT_TIME (xtime.tv_sec)

--- ./include/linux/sysctl.h.orig Sun Sep 21 23:14:49 1997
+++ ./include/linux/sysctl.h Sun Sep 21 23:22:04 1997
@@ -61,6 +61,7 @@
#define KERN_NFSRADDRS 18 /* NFS root addresses */
#define KERN_JAVA_INTERPRETER 19 /* path to Java(tm) interpreter */
#define KERN_JAVA_APPLETVIEWER 20 /* path to Java(tm) appletviewer */
+#define KERN_COREDUMP_OPT 21 /* several ways to facilitate coredumps */

/* CTL_VM names: */
#define VM_SWAPCTL 1 /* struct: Set vm swapping control */