aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2005-06-23 03:09:43 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:26 -0400
commitd6e711448137ca3301512cec41a2c2ce852b3d0a (patch)
treef0765ebd90fdbdf270c05fcd7f3d32b24ba56681 /fs/exec.c
parent8b0914ea7475615c7c8965c1ac8fe4069270f25c (diff)
[PATCH] setuid core dump
Add a new `suid_dumpable' sysctl: This value can be used to query and set the core dump mode for setuid or otherwise protected/tainted binaries. The modes are 0 - (default) - traditional behaviour. Any process which has changed privilege levels or is execute only will not be dumped 1 - (debug) - all processes dump core when possible. The core dump is owned by the current user and no security is applied. This is intended for system debugging situations only. Ptrace is unchecked. 2 - (suidsafe) - any binary which normally would not be dumped is dumped readable by root only. This allows the end user to remove such a dump but not access it directly. For security reasons core dumps in this mode will not overwrite one another or other files. This mode is appropriate when adminstrators are attempting to debug problems in a normal environment. (akpm: > > +EXPORT_SYMBOL(suid_dumpable); > > EXPORT_SYMBOL_GPL? No problem to me. > > if (current->euid == current->uid && current->egid == current->gid) > > current->mm->dumpable = 1; > > Should this be SUID_DUMP_USER? Actually the feedback I had from last time was that the SUID_ defines should go because its clearer to follow the numbers. They can go everywhere (and there are lots of places where dumpable is tested/used as a bool in untouched code) > Maybe this should be renamed to `dump_policy' or something. Doing that > would help us catch any code which isn't using the #defines, too. Fair comment. The patch was designed to be easy to maintain for Red Hat rather than for merging. Changing that field would create a gigantic diff because it is used all over the place. ) Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 3a4b35a14c0d..48871917d363 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -58,6 +58,9 @@
58 58
59int core_uses_pid; 59int core_uses_pid;
60char core_pattern[65] = "core"; 60char core_pattern[65] = "core";
61int suid_dumpable = 0;
62
63EXPORT_SYMBOL(suid_dumpable);
61/* The maximal length of core_pattern is also specified in sysctl.c */ 64/* The maximal length of core_pattern is also specified in sysctl.c */
62 65
63static struct linux_binfmt *formats; 66static struct linux_binfmt *formats;
@@ -864,6 +867,9 @@ int flush_old_exec(struct linux_binprm * bprm)
864 867
865 if (current->euid == current->uid && current->egid == current->gid) 868 if (current->euid == current->uid && current->egid == current->gid)
866 current->mm->dumpable = 1; 869 current->mm->dumpable = 1;
870 else
871 current->mm->dumpable = suid_dumpable;
872
867 name = bprm->filename; 873 name = bprm->filename;
868 874
869 /* Copies the binary name from after last slash */ 875 /* Copies the binary name from after last slash */
@@ -884,7 +890,7 @@ int flush_old_exec(struct linux_binprm * bprm)
884 permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) || 890 permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) ||
885 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { 891 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
886 suid_keys(current); 892 suid_keys(current);
887 current->mm->dumpable = 0; 893 current->mm->dumpable = suid_dumpable;
888 } 894 }
889 895
890 /* An exec changes our domain. We are no longer part of the thread 896 /* An exec changes our domain. We are no longer part of the thread
@@ -1432,6 +1438,8 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1432 struct inode * inode; 1438 struct inode * inode;
1433 struct file * file; 1439 struct file * file;
1434 int retval = 0; 1440 int retval = 0;
1441 int fsuid = current->fsuid;
1442 int flag = 0;
1435 1443
1436 binfmt = current->binfmt; 1444 binfmt = current->binfmt;
1437 if (!binfmt || !binfmt->core_dump) 1445 if (!binfmt || !binfmt->core_dump)
@@ -1441,6 +1449,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1441 up_write(&mm->mmap_sem); 1449 up_write(&mm->mmap_sem);
1442 goto fail; 1450 goto fail;
1443 } 1451 }
1452
1453 /*
1454 * We cannot trust fsuid as being the "true" uid of the
1455 * process nor do we know its entire history. We only know it
1456 * was tainted so we dump it as root in mode 2.
1457 */
1458 if (mm->dumpable == 2) { /* Setuid core dump mode */
1459 flag = O_EXCL; /* Stop rewrite attacks */
1460 current->fsuid = 0; /* Dump root private */
1461 }
1444 mm->dumpable = 0; 1462 mm->dumpable = 0;
1445 init_completion(&mm->core_done); 1463 init_completion(&mm->core_done);
1446 spin_lock_irq(&current->sighand->siglock); 1464 spin_lock_irq(&current->sighand->siglock);
@@ -1466,7 +1484,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1466 lock_kernel(); 1484 lock_kernel();
1467 format_corename(corename, core_pattern, signr); 1485 format_corename(corename, core_pattern, signr);
1468 unlock_kernel(); 1486 unlock_kernel();
1469 file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600); 1487 file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600);
1470 if (IS_ERR(file)) 1488 if (IS_ERR(file))
1471 goto fail_unlock; 1489 goto fail_unlock;
1472 inode = file->f_dentry->d_inode; 1490 inode = file->f_dentry->d_inode;
@@ -1491,6 +1509,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1491close_fail: 1509close_fail:
1492 filp_close(file, NULL); 1510 filp_close(file, NULL);
1493fail_unlock: 1511fail_unlock:
1512 current->fsuid = fsuid;
1494 complete_all(&mm->core_done); 1513 complete_all(&mm->core_done);
1495fail: 1514fail:
1496 return retval; 1515 return retval;