Core dumps, patch

Uwe Ohse (uwe@tirka.gun.de)
Thu, 29 Feb 1996 21:04:12 +0100 (MET)


This patch adds:
- alternative naming for core dumps ("core", "core.command",
"core.command.pid", "core.pid"). The later three will not overwrite
existing files (overwriting of "core" can be disabled, too).
- the possibility to restrict core dumps to uid 0.
- the possibility to en/disable the generation of core dumps on the fly.
- a sysctl interface (/proc/sys/kern/coredump).
- a compile time option to disable core dumps altogether.

usage: echo $value >/proc/sys/kern/coredump
"value" is a bitfield, with the bits defined in fs.h. Examples:
value: result
0 disable generation of core dumps. Any value with bit 0
cleared has that effect.
1 "core". This is the default.
3 "core.command"
7 "core.command.pid"
9 "core", but only processes with uid 0 may dump core
19 "core.command". If that exists "core" will be written
(overwritten if it exists).
33 "core", but that will nether be overwritten if it exists
(if "gdb prog core" crashed, "core" won't get destroyed).

I would like a better interface, possibly like this:
echo "+comm +pid -overwrite" >/proc/sys/kern/coredump
but that would be too much kernel bloat, i think.

Uwe

diff -ur linux-1.3.69/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-1.3.69/Documentation/Configure.help Wed Feb 28 10:42:57 1996
+++ linux/Documentation/Configure.help Thu Feb 29 18:04:33 1996
@@ -2188,6 +2188,11 @@
use it. Probably this is only useful for multi user systems. If
unsure, say N.

+Disable coredumps
+CONFIG_DISABLE_CORE
+ Say Y to completely disable generation of core dumps. This will save
+ about 4 KB memory. If in doubt, say N.
+
Standard (minix) fs support
CONFIG_MINIX_FS
Minix is a simple operating system used in many classes about
diff -ur linux-1.3.69/fs/Config.in linux/fs/Config.in
--- linux-1.3.69/fs/Config.in Tue Feb 20 20:11:27 1996
+++ linux/fs/Config.in Thu Feb 29 17:58:43 1996
@@ -4,7 +4,8 @@
mainmenu_option next_comment
comment 'Filesystems'

-bool 'Quota support' CONFIG_QUOTA
+bool 'Quota support' CONFIG_QUOTA
+bool 'Disable coredumps' CONFIG_DISABLE_CORE
tristate 'Standard (minix) fs support' CONFIG_MINIX_FS
tristate 'Extended fs support' CONFIG_EXT_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
diff -ur linux-1.3.69/include/linux/fs.h linux/include/linux/fs.h
--- linux-1.3.69/include/linux/fs.h Wed Feb 28 10:38:58 1996
+++ linux/include/linux/fs.h Thu Feb 29 18:29:25 1996
@@ -36,6 +36,7 @@
/* And dynamically-tunable limits and defaults: */
extern int max_inodes, nr_inodes;
extern int max_files, nr_files;
+extern int core_dump_scheme;
#define NR_INODE 2048 /* this should be bigger than NR_FILE */
#define NR_FILE 1024 /* this can well be larger on a larger system */

@@ -59,6 +60,24 @@
#define SEL_IN 1
#define SEL_OUT 2
#define SEL_EX 4
+
+#ifndef CONFIG_DISABLE_CORE
+ /* no coredumps are written if CORE_ENABLE is not set */
+#define CORE_ENABLE 1
+ /* the command name is appended to the core filename: core.bash */
+#define CORE_COMM 2
+ /* the process id is appended to the core filename: core.init.1 or core.1 */
+#define CORE_PID 4
+ /* core dumps are only written for uid 0 if CORE_ONLY_ROOT is set */
+#define CORE_ONLY_ROOT 8
+ /* dump to "core" if "core.[command][.pid]" already exist */
+#define CORE_FALLBACK 16
+ /* "core" will never be overwritten if CORE_NO_OVERWRITE is set.
+ * "core.xxx" is never overwritten even if CORE_NO_OVERWRITE is not set. */
+#define CORE_NO_OVERWRITE 32
+ /* default value "core" (old behaviour). Change it with sysctl()! */
+#define CORE_DEFAULT (CORE_ENABLE)
+#endif /* CONFIG_DISABLE_CORE */

/*
* These are the fs-independent mount-flags: up to 16 flags are supported
diff -ur linux-1.3.69/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux-1.3.69/include/linux/sysctl.h Wed Feb 28 10:39:34 1996
+++ linux/include/linux/sysctl.h Thu Feb 29 17:54:50 1996
@@ -55,6 +55,7 @@
#define KERN_MAXFILE 12
#define KERN_MAXID 13
#define KERN_SECURELVL 14 /* int: system security level */
+#define KERN_COREDUMP 15 /* int: core dump flags */

/* CTL_VM names: */
#define VM_SWAPCTL 1 /* struct: Set vm swapping control */
diff -ur linux-1.3.69/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-1.3.69/fs/binfmt_elf.c Tue Feb 20 20:03:51 1996
+++ linux/fs/binfmt_elf.c Thu Feb 29 19:05:04 1996
@@ -11,6 +11,8 @@

#include <linux/module.h>

+#include <linux/config.h>
+
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/sched.h>
@@ -31,7 +33,6 @@
#include <asm/segment.h>
#include <asm/pgtable.h>

-#include <linux/config.h>

#define DLINFO_ITEMS 12

@@ -39,9 +40,15 @@

static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_elf_library(int fd);
+#ifndef CONFIG_DISABLE_CORE
static int elf_core_dump(long signr, struct pt_regs * regs);
+#endif
extern int dump_fpu (elf_fpregset_t *);

+
+#ifdef CONFIG_DISABLE_CORE
+#define elf_core_dump NULL
+#endif
static struct linux_binfmt elf_format = {
#ifndef MODULE
NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
@@ -50,6 +57,7 @@
#endif
};

+#ifndef CONFIG_DISABLE_CORE
static void set_brk(unsigned long start, unsigned long end)
{
start = PAGE_ALIGN(start);
@@ -60,6 +68,7 @@
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, 0);
}
+#endif


/* We need to explicitly zero any fractional pages
@@ -939,13 +948,15 @@
* and then they are actually written out. If we run out of core limit
* we just truncate.
*/
+#ifndef CONFIG_DISABLE_CORE
static int elf_core_dump(long signr, struct pt_regs * regs)
{
int has_dumped = 0;
struct file file;
struct inode *inode;
unsigned short fs;
- char corefile[6+sizeof(current->comm)];
+ /* core. + \0 + pid(8) + 2 dots */
+ char corefile[16+sizeof(current->comm)];
int segs;
int i;
size_t size;
@@ -958,7 +969,14 @@
struct elf_prstatus prstatus; /* NT_PRSTATUS */
elf_fpregset_t fpu; /* NT_PRFPREG */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
-
+ int corenamelen;
+ int exclusive;
+
+ /* core dumps totally disabled? */
+ if (!(core_dump_scheme & CORE_ENABLE))
+ return 0;
+ if (core_dump_scheme & CORE_ONLY_ROOT && current->uid!=0)
+ return 0;
if (!current->dumpable || limit < PAGE_SIZE)
return 0;
current->dumpable = 0;
@@ -1009,15 +1027,43 @@

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)) {
- inode = NULL;
- goto end_coredump;
+ memcpy(corefile,"core",5);
+ corenamelen=4;
+ if (core_dump_scheme & CORE_COMM) {
+ size_t len=strlen(current->comm);
+ corefile[corenamelen]='.';
+ memcpy(corefile+corenamelen+1,current->comm,len+1);
+ corenamelen+=len+1;
+ }
+ if (core_dump_scheme & CORE_PID) {
+ sprintf(corefile+corenamelen,".%ld",(long) current->pid);
+ }
+ if (corenamelen>4 || (core_dump_scheme & CORE_NO_OVERWRITE))
+ {
+ /* we must not under any circumstances overwrite a file.
+ * consider what happens if "core.compare" is truncated
+ * on MS-loss-filesystems.
+ */
+ exclusive=O_EXCL;
+ }
+ else
+ exclusive=0;
+ if (open_namei(corefile,O_CREAT | exclusive | 2 | O_TRUNC,0600,
+ &inode,NULL)) {
+ if (!(core_dump_scheme & CORE_FALLBACK)) {
+ inode = NULL;
+ goto end_coredump;
+ }
+ if (core_dump_scheme & CORE_NO_OVERWRITE)
+ exclusive=O_EXCL;
+ else
+ exclusive=0;
+ memcpy(corefile,"core",5);
+ if (open_namei(corefile,O_CREAT | exclusive | 2 | O_TRUNC,0600,
+ &inode,NULL)) {
+ inode = NULL;
+ goto end_coredump;
+ }
}
if (!S_ISREG(inode->i_mode))
goto end_coredump;
@@ -1220,6 +1266,7 @@
#endif
return has_dumped;
}
+#endif /* CONFIG_DISABLE_CORE */

int init_elf_binfmt(void) {
return register_binfmt(&elf_format);
diff -ur linux-1.3.69/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- linux-1.3.69/fs/binfmt_aout.c Wed Feb 28 10:38:21 1996
+++ linux/fs/binfmt_aout.c Thu Feb 29 19:05:27 1996
@@ -6,6 +6,8 @@

#include <linux/module.h>

+#include <linux/config.h>
+
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -29,10 +31,16 @@

static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(int fd);
+
+#ifndef CONFIG_DISABLE_CORE
static int aout_core_dump(long signr, struct pt_regs * regs);
+#endif

extern void dump_thread(struct pt_regs *, struct user *);

+#ifdef CONFIG_DISABLE_CORE
+#define aout_core_dump NULL
+#endif
static struct linux_binfmt aout_format = {
#ifndef MODULE
NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump
@@ -41,6 +49,7 @@
#endif
};

+#ifndef CONFIG_DISABLE_CORE
static void set_brk(unsigned long start, unsigned long end)
{
start = PAGE_ALIGN(start);
@@ -82,15 +91,22 @@
struct file file;
unsigned short fs;
int has_dumped = 0;
- char corefile[6+sizeof(current->comm)];
+ char corefile[16+sizeof(current->comm)];
unsigned long dump_start, dump_size;
struct user dump;
+ int corenamelen;
+ int exclusive;
#ifdef __alpha__
# define START_DATA(u) (u.start_data)
#else
# define START_DATA(u) (u.u_tsize << PAGE_SHIFT)
#endif

+ /* core dumps totally disabled? */
+ if (!(core_dump_scheme & CORE_ENABLE))
+ return 0;
+ if (core_dump_scheme & CORE_ONLY_ROOT && current->uid!=0)
+ return 0;
if (!current->dumpable)
return 0;
current->dumpable = 0;
@@ -100,16 +116,39 @@
return 0;
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)) {
- inode = NULL;
- goto end_coredump;
- }
+
+ memcpy(corefile,"core",5);
+ corenamelen=4;
+ if (core_dump_scheme & CORE_COMM) {
+ size_t len=strlen(current->comm);
+ corefile[corenamelen]='.';
+ memcpy(corefile+corenamelen+1,current->comm,len+1);
+ corenamelen+=1+len;
+ }
+ if (core_dump_scheme & CORE_PID) {
+ sprintf(corefile+corenamelen,".%ld",(long) current->pid);
+ }
+ if (corenamelen>4 || (core_dump_scheme & CORE_NO_OVERWRITE))
+ exclusive=O_EXCL;
+ else
+ exclusive=0;
+ if (open_namei(corefile,O_CREAT | exclusive | 2 | O_TRUNC,0600,
+ &inode,NULL)) {
+ if (!(core_dump_scheme & CORE_FALLBACK)) {
+ inode = NULL;
+ goto end_coredump;
+ }
+ if (core_dump_scheme & CORE_NO_OVERWRITE)
+ exclusive=O_EXCL;
+ else
+ exclusive=0;
+ memcpy(corefile,"core",5);
+ if (open_namei(corefile,O_CREAT | exclusive | 2 | O_TRUNC,0600,
+ &inode,NULL)) {
+ inode = NULL;
+ goto end_coredump;
+ }
+ }
if (!S_ISREG(inode->i_mode))
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
@@ -195,6 +234,7 @@
MOD_DEC_USE_COUNT;
return retval;
}
+#endif /* CONFIG_DISABLE_CORE */

/*
* These are the functions used to load a.out style executables and shared
diff -ur linux-1.3.69/fs/exec.c linux/fs/exec.c
--- linux-1.3.69/fs/exec.c Wed Feb 28 10:30:45 1996
+++ linux/fs/exec.c Thu Feb 29 18:01:27 1996
@@ -22,6 +22,7 @@
* formats.
*/

+#include <linux/config.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -43,9 +44,12 @@
#include <asm/segment.h>
#include <asm/pgtable.h>

-#include <linux/config.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
+#endif
+
+#ifndef CONFIG_DISABLE_CORE
+int core_dump_scheme=CORE_DEFAULT;
#endif

asmlinkage int sys_exit(int exit_code);
diff -ur linux-1.3.69/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-1.3.69/kernel/sysctl.c Wed Feb 28 10:38:52 1996
+++ linux/kernel/sysctl.c Thu Feb 29 18:51:19 1996
@@ -116,6 +116,11 @@
0644, NULL, &proc_dointvec},
{KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
+#ifndef CONFIG_DISABLE_CORE
+ /* no strategy and no min/max provided */
+ {KERN_COREDUMP, "coredump", &core_dump_scheme, sizeof(int),
+ 0644, NULL, &proc_dointvec},
+#endif
{0}
};