lkml.org 
[lkml]   [1999]   [Jul]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [RFC] new kernel syscall
On Tue, 20 Jul 1999, Pavel Machek wrote:

> > The syscall essentially exposes current->dumpable to userland. NAMES
> > FOR THE SYSCALL ON A POSTCARD PLEASE.
> >
> > Why would you want do do this?
> >
> > Well, in userland, we are having to do a lot of second guessing of
> > current->dumpable. If dumpable is FALSE, we need to restrict several
> > things in the dynamic linker, and libc, for security reasons.
>
> Yes, please. This was one of major reasons elfcap patch became a bit
> ugly. We'll need that few months before we can put capabilities into
> mainstream use.

Attached is a patch which does a little more than what
was suggested. It:
* splits dumpable into three flags which separately protect against
signals and ptrace and restrict core dumps.
* exposes this to userspace via prctl(2) - a process can query its
protection level, and also increase it.

This has potentially serious security implications, and there could
well be cases that I've missed, or reasons why this is just a dangerous
idea.

Comments?

Matthew.
diff -ru linux-2.3.10-clean/arch/alpha/kernel/ptrace.c linux-2.3.10/arch/alpha/kernel/ptrace.c
--- linux-2.3.10-clean/arch/alpha/kernel/ptrace.c Sun Jul 4 21:41:08 1999
+++ linux-2.3.10/arch/alpha/kernel/ptrace.c Tue Jul 20 20:04:21 1999
@@ -256,7 +256,7 @@
ret = -EPERM;
if (child == current)
goto out;
- if ((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
(current->uid != child->uid) ||
diff -ru linux-2.3.10-clean/arch/arm/kernel/ptrace.c linux-2.3.10/arch/arm/kernel/ptrace.c
--- linux-2.3.10-clean/arch/arm/kernel/ptrace.c Thu Jun 17 09:11:35 1999
+++ linux-2.3.10/arch/arm/kernel/ptrace.c Tue Jul 20 20:08:03 1999
@@ -560,7 +560,7 @@
if (request == PTRACE_ATTACH) {
if (child == current)
goto out;
- if ((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
(current->uid != child->uid) ||
diff -ru linux-2.3.10-clean/arch/i386/kernel/ptrace.c linux-2.3.10/arch/i386/kernel/ptrace.c
--- linux-2.3.10-clean/arch/i386/kernel/ptrace.c Sun Jul 4 21:41:08 1999
+++ linux-2.3.10/arch/i386/kernel/ptrace.c Tue Jul 20 20:03:59 1999
@@ -162,7 +162,7 @@
if (request == PTRACE_ATTACH) {
if (child == current)
goto out;
- if ((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
(current->uid != child->uid) ||
diff -ru linux-2.3.10-clean/arch/m68k/kernel/ptrace.c linux-2.3.10/arch/m68k/kernel/ptrace.c
--- linux-2.3.10-clean/arch/m68k/kernel/ptrace.c Mon Jun 7 19:15:33 1999
+++ linux-2.3.10/arch/m68k/kernel/ptrace.c Tue Jul 20 20:07:23 1999
@@ -319,7 +319,7 @@
if (request == PTRACE_ATTACH) {
if (child == current)
goto out;
- if ((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
(current->uid != child->uid) ||
diff -ru linux-2.3.10-clean/arch/mips/kernel/irixelf.c linux-2.3.10/arch/mips/kernel/irixelf.c
--- linux-2.3.10-clean/arch/mips/kernel/irixelf.c Sun Jun 27 02:03:31 1999
+++ linux-2.3.10/arch/mips/kernel/irixelf.c Tue Jul 20 20:11:33 1999
@@ -1136,9 +1136,9 @@
elf_fpregset_t fpu; /* NT_PRFPREG */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */

- if (!current->dumpable || limit < PAGE_SIZE)
+ if ((current->protflags & PR_FLAG_CORE) || limit < PAGE_SIZE)
return 0;
- current->dumpable = 0;
+ current->protflags |= PR_FLAG_CORE;

#ifndef CONFIG_BINFMT_IRIX
MOD_INC_USE_COUNT;
diff -ru linux-2.3.10-clean/arch/mips/kernel/ptrace.c linux-2.3.10/arch/mips/kernel/ptrace.c
--- linux-2.3.10-clean/arch/mips/kernel/ptrace.c Tue Jul 6 03:44:57 1999
+++ linux-2.3.10/arch/mips/kernel/ptrace.c Tue Jul 20 20:05:57 1999
@@ -61,7 +61,7 @@
res = -EPERM;
goto out;
}
- if ((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
(current->uid != child->uid) ||
diff -ru linux-2.3.10-clean/arch/ppc/kernel/ptrace.c linux-2.3.10/arch/ppc/kernel/ptrace.c
--- linux-2.3.10-clean/arch/ppc/kernel/ptrace.c Mon Jun 7 19:15:33 1999
+++ linux-2.3.10/arch/ppc/kernel/ptrace.c Tue Jul 20 20:07:13 1999
@@ -308,7 +308,7 @@
if (request == PTRACE_ATTACH) {
if (child == current)
goto out;
- if ((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->uid) ||
(current->uid != child->suid) ||
diff -ru linux-2.3.10-clean/arch/sparc/kernel/ptrace.c linux-2.3.10/arch/sparc/kernel/ptrace.c
--- linux-2.3.10-clean/arch/sparc/kernel/ptrace.c Mon Jul 5 19:30:11 1999
+++ linux-2.3.10/arch/sparc/kernel/ptrace.c Tue Jul 20 20:04:37 1999
@@ -321,7 +321,7 @@
pt_error_return(regs, EPERM);
goto out;
}
- if((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->uid) ||
(current->uid != child->suid) ||
diff -ru linux-2.3.10-clean/arch/sparc64/kernel/binfmt_aout32.c linux-2.3.10/arch/sparc64/kernel/binfmt_aout32.c
--- linux-2.3.10-clean/arch/sparc64/kernel/binfmt_aout32.c Fri Jul 2 01:33:12 1999
+++ linux-2.3.10/arch/sparc64/kernel/binfmt_aout32.c Tue Jul 20 20:09:36 1999
@@ -76,7 +76,8 @@
* Currently only a stub-function.
*
* Note that setuid/setgid files won't make a core-dump if the uid/gid
- * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
+ * changed due to the set[u|g]id. It's enforced by
+ * current->protflags & PR_FLAGS_CORE
* field, which also makes sure the core-dumps won't be recursive if the
* dumping of the process results in another error..
*/
@@ -95,9 +96,10 @@
# define START_DATA(u) (u.u_tsize)
# define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))

- if (!current->dumpable || atomic_read(&current->mm->count) != 1)
+ if ((current->protflags & PR_FLAGS_CORE)
+ || atomic_read(&current->mm->count) != 1)
return 0;
- current->dumpable = 0;
+ current->protflags |= PR_FLAGS_CORE;

/* See if we have enough room to write the upage. */
if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
diff -ru linux-2.3.10-clean/arch/sparc64/kernel/ptrace.c linux-2.3.10/arch/sparc64/kernel/ptrace.c
--- linux-2.3.10-clean/arch/sparc64/kernel/ptrace.c Mon Jul 5 19:30:11 1999
+++ linux-2.3.10/arch/sparc64/kernel/ptrace.c Tue Jul 20 20:07:37 1999
@@ -175,7 +175,7 @@
pt_error_return(regs, EPERM);
goto out;
}
- if((!child->dumpable ||
+ if (((child->protflags & PR_FLAGS_PTRACE) ||
(current->uid != child->euid) ||
(current->uid != child->uid) ||
(current->uid != child->suid) ||
diff -ru linux-2.3.10-clean/fs/binfmt_aout.c linux-2.3.10/fs/binfmt_aout.c
--- linux-2.3.10-clean/fs/binfmt_aout.c Thu Jul 1 18:45:57 1999
+++ linux-2.3.10/fs/binfmt_aout.c Tue Jul 20 19:54:43 1999
@@ -77,7 +77,8 @@
* Currently only a stub-function.
*
* Note that setuid/setgid files won't make a core-dump if the uid/gid
- * changed due to the set[u|g]id. It's enforced by the "current->dumpable"
+ * changed due to the set[u|g]id. It's enforced by
+ * current->protflags & PR_FLAGS_CORE
* field, which also makes sure the core-dumps won't be recursive if the
* dumping of the process results in another error..
*/
@@ -106,9 +107,10 @@
# define START_STACK(u) (u.start_stack)
#endif

- if (!current->dumpable || atomic_read(&current->mm->count) != 1)
+ if ((current->protflags & PR_FLAGS_CORE)
+ || atomic_read(&current->mm->count) != 1)
return 0;
- current->dumpable = 0;
+ current->protflags |= PR_FLAGS_CORE;

/* See if we have enough room to write the upage. */
if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
diff -ru linux-2.3.10-clean/fs/binfmt_elf.c linux-2.3.10/fs/binfmt_elf.c
--- linux-2.3.10-clean/fs/binfmt_elf.c Tue Jul 6 03:59:55 1999
+++ linux-2.3.10/fs/binfmt_elf.c Tue Jul 20 19:55:41 1999
@@ -1058,11 +1058,11 @@
elf_fpregset_t fpu; /* NT_PRFPREG */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */

- if (!current->dumpable ||
+ if ((current->protflags & PR_FLAGS_CORE) ||
limit < ELF_EXEC_PAGESIZE ||
atomic_read(&current->mm->count) != 1)
return 0;
- current->dumpable = 0;
+ current->protflags |= PR_FLAGS_CORE;

#ifndef CONFIG_BINFMT_ELF
MOD_INC_USE_COUNT;
diff -ru linux-2.3.10-clean/fs/exec.c linux-2.3.10/fs/exec.c
--- linux-2.3.10-clean/fs/exec.c Tue Jul 6 04:34:31 1999
+++ linux-2.3.10/fs/exec.c Tue Jul 20 19:58:34 1999
@@ -502,7 +502,7 @@
release_old_signals(oldsig);

if (current->euid == current->uid && current->egid == current->gid)
- current->dumpable = 1;
+ current->protflags = 0;
name = bprm->filename;
for (i=0; (ch = *(name++)) != '\0';) {
if (ch == '/')
@@ -515,9 +515,11 @@

flush_thread();

- if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
- permission(bprm->dentry->d_inode,MAY_READ))
- current->dumpable = 0;
+ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid)
+ current->protflags = PR_FLAGS_ALL;
+
+ if (permission(bprm->dentry->d_inode,MAY_READ))
+ current->protflags |= (PR_FLAGS_CORE | PR_FLAGS_PTRACE);

flush_signal_handlers(current);
flush_old_files(current->files);
@@ -684,7 +686,7 @@
current->sgid = current->egid = current->fsgid = bprm->e_gid;
if (current->euid != current->uid || current->egid != current->gid ||
!cap_issubset(new_permitted, current->cap_permitted))
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;
}


diff -ru linux-2.3.10-clean/fs/proc/array.c linux-2.3.10/fs/proc/array.c
--- linux-2.3.10-clean/fs/proc/array.c Sat Jul 3 20:04:12 1999
+++ linux-2.3.10/fs/proc/array.c Tue Jul 20 20:16:18 1999
@@ -1375,7 +1386,7 @@
p = find_task_by_pid(pid);
if (p) {
euid=p->euid;
- ok = p->dumpable;
+ ok = !p->protflags;
if(!cap_issubset(p->cap_permitted, current->cap_permitted))
ok=0;
if(!p->mm) /* Scooby scooby doo where are you ? */
diff -ru linux-2.3.10-clean/fs/proc/base.c linux-2.3.10/fs/proc/base.c
--- linux-2.3.10-clean/fs/proc/base.c Sat Jun 26 20:04:39 1999
+++ linux-2.3.10/fs/proc/base.c Tue Jul 20 20:01:56 1999
@@ -69,7 +69,7 @@
if (fill && (p = find_task_by_pid(pid)) != NULL) {
uid_t uid = 0;
gid_t gid = 0;
- if (p->dumpable || ino == PROC_PID_INO) {
+ if ((!p->protflags) || ino == PROC_PID_INO) {
uid = p->euid;
gid = p->egid;
}
diff -ru linux-2.3.10-clean/fs/proc/inode.c linux-2.3.10/fs/proc/inode.c
--- linux-2.3.10-clean/fs/proc/inode.c Sun Jul 4 18:18:52 1999
+++ linux-2.3.10/fs/proc/inode.c Tue Jul 20 20:02:16 1999
@@ -393,7 +393,7 @@
goto out_unlock;

ino &= 0x0000ffff;
- if (ino == PROC_PID_INO || p->dumpable) {
+ if (ino == PROC_PID_INO || (!p->protflags)) {
inode->i_uid = p->euid;
inode->i_gid = p->egid;
}
diff -ru linux-2.3.10-clean/include/linux/prctl.h linux-2.3.10/include/linux/prctl.h
--- linux-2.3.10-clean/include/linux/prctl.h Mon Sep 22 22:55:59 1997
+++ linux-2.3.10/include/linux/prctl.h Tue Jul 20 19:36:54 1999
@@ -4,6 +4,7 @@
/* Values to pass as first argument to prctl() */

#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */
+#define PR_SET_PROTFLAGS 2 /* Second arg is |ed with current->protflags */


#endif /* _LINUX_PRCTL_H */
diff -ru linux-2.3.10-clean/include/linux/sched.h linux-2.3.10/include/linux/sched.h
--- linux-2.3.10-clean/include/linux/sched.h Wed Jul 7 17:20:45 1999
+++ linux-2.3.10/include/linux/sched.h Tue Jul 20 20:55:54 1999
@@ -251,7 +251,7 @@
int pdeath_signal; /* The signal sent when the parent dies */
/* ??? */
unsigned long personality;
- int dumpable:1;
+ unsigned long protflags; /* per-process protection (flags defined below) */
int did_exec:1;
pid_t pid;
pid_t pgrp;
@@ -338,6 +338,17 @@

#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */
#define PF_DTRACE 0x00200000 /* delayed trace (used on m68k, i386) */
+
+/*
+ * Process self-defence flags. Processes can protect themselves from
+ * ptrace(), kill(), &c
+ */
+#define PR_FLAGS_PTRACE 0x00000001 /* Can't ptrace() me */
+#define PR_FLAGS_SIGNAL 0x00000002 /* Can't kill me */
+#define PR_FLAGS_CORE 0x00000004 /* Can I dump core? */
+#define PR_FLAGS_MASK 0x00000007
+#define PR_FLAGS_ALL PR_FLAGS_MASK
+

/*
* Limit the stack by to some sane default: root can always
diff -ru linux-2.3.10-clean/kernel/signal.c linux-2.3.10/kernel/signal.c
--- linux-2.3.10-clean/kernel/signal.c Tue Jul 6 04:02:10 1999
+++ linux-2.3.10/kernel/signal.c Tue Jul 20 20:34:08 1999
@@ -269,6 +269,9 @@
&& !capable(CAP_KILL))
goto out_nolock;

+ if((t->protflags & PR_FLAGS_SIGNAL) && !capable(CAP_KILL))
+ goto out_nolock;
+
/* The null signal is a permissions and process existance probe.
No signal is actually delivered. Same goes for zombies. */
ret = 0;
diff -ru linux-2.3.10-clean/kernel/sys.c linux-2.3.10/kernel/sys.c
--- linux-2.3.10-clean/kernel/sys.c Sat Jul 3 20:04:12 1999
+++ linux-2.3.10/kernel/sys.c Tue Jul 20 19:46:31 1999
@@ -281,7 +281,7 @@
current->sgid = current->egid;
current->fsgid = current->egid;
if (current->egid != old_egid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;
return 0;
}

@@ -302,7 +302,7 @@
return -EPERM;

if (current->egid != old_egid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;
return 0;
}

@@ -385,7 +385,7 @@
current->suid = current->euid;
current->fsuid = current->euid;
if (current->euid != old_euid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;

if(new_ruid != old_ruid) {
/* What if a process setreuid()'s and this brings the
@@ -433,7 +433,7 @@
return -EPERM;

if (current->euid != old_euid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;

if (new_ruid != old_ruid) {
/* See comment above about NPROC rlimit issues... */
@@ -479,7 +479,7 @@
}
if (euid != (uid_t) -1) {
if (euid != current->euid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;
current->euid = euid;
current->fsuid = euid;
}
@@ -524,7 +524,7 @@
current->gid = rgid;
if (egid != (gid_t) -1) {
if (egid != current->egid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;
current->egid = egid;
current->fsgid = egid;
}
@@ -561,7 +561,7 @@
capable(CAP_SETUID))
current->fsuid = uid;
if (current->fsuid != old_fsuid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;

/* We emulate fsuid by essentially doing a scaled-down version
* of what we did in setresuid and friends. However, we only
@@ -598,7 +598,7 @@
capable(CAP_SETGID))
current->fsgid = gid;
if (current->fsgid != old_fsgid)
- current->dumpable = 0;
+ current->protflags = PR_FLAGS_ALL;

return old_fsgid;
}
@@ -986,22 +986,25 @@
asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
- int error = 0;
+ int res = 0;
int sig;

switch (option) {
case PR_SET_PDEATHSIG:
sig = arg2;
if (sig > _NSIG) {
- error = -EINVAL;
+ res = -EINVAL;
break;
}
current->pdeath_signal = sig;
break;
+ case PR_SET_PROTFLAGS:
+ res = (current->protflags |= (arg2 & PR_FLAGS_MASK));
+ break;
default:
- error = -EINVAL;
+ res = -EINVAL;
break;
}
- return error;
+ return res;
}
\
 
 \ /
  Last update: 2005-03-22 13:53    [W:0.053 / U:0.568 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site