diff -purN linux-2.4.20/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- linux-2.4.20/arch/i386/kernel/process.c 2003-03-13 20:57:06.000000000 +0100 +++ linux/arch/i386/kernel/process.c 2003-03-13 20:57:57.000000000 +0100 @@ -503,7 +503,7 @@ __asm__(".align 4\n" /* * Create a kernel thread */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct task_struct *p; struct pt_regs regs; diff -purN linux-2.4.20/fs/exec.c linux/fs/exec.c --- linux-2.4.20/fs/exec.c 2003-03-13 20:57:03.000000000 +0100 +++ linux/fs/exec.c 2003-03-13 20:59:12.000000000 +0100 @@ -712,8 +712,10 @@ int flush_old_exec(struct linux_binprm * current->sas_ss_sp = current->sas_ss_size = 0; - if (current->euid == current->uid && current->egid == current->gid) + if (current->euid == current->uid && current->egid == current->gid) { current->mm->dumpable = 1; + current->task_dumpable = 1; + } name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -1254,6 +1256,8 @@ int do_coredump(long signr, int exit_cod up_write(&mm->mmap_sem); goto fail; } + if (!is_dumpable(current)) + goto fail; mm->dumpable = 0; init_completion(&mm->core_done); current->signal->group_exit = 1; diff -purN linux-2.4.20/include/asm-i386/processor.h linux/include/asm-i386/processor.h --- linux-2.4.20/include/asm-i386/processor.h 2003-03-13 20:57:04.000000000 +0100 +++ linux/include/asm-i386/processor.h 2003-03-13 20:57:59.000000000 +0100 @@ -447,7 +447,7 @@ extern void release_thread(struct task_s /* * create a kernel thread without removing it from tasklists */ -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* Copy and release all segment info associated with a VM * Unusable due to lack of error handling, use {init_new,destroy}_context diff -purN linux-2.4.20/include/linux/sched.h linux/include/linux/sched.h --- linux-2.4.20/include/linux/sched.h 2003-03-13 20:57:04.000000000 +0100 +++ linux/include/linux/sched.h 2003-03-13 21:03:58.000000000 +0100 @@ -426,6 +426,7 @@ struct task_struct { /* ??? */ unsigned long personality; int did_exec:1; + unsigned task_dumpable:1; pid_t pid; pid_t pgrp; pid_t tty_old_pgrp; @@ -557,6 +558,8 @@ struct task_struct { #define PT_TRACE_EXIT 0x00000200 #define PT_DTRACE 0x00000400 /* delayed trace (used on m68k, i386) */ +#define is_dumpable(tsk) ((tsk)->task_dumpable && (tsk)->mm->dumpable) + /* * Limit the stack by to some sane default: root can always * increase this limit if needed.. 8MB seems reasonable. @@ -901,6 +904,8 @@ extern void kick_if_running(task_t * p); #define wait_task_inactive(p) do {} while (0) #define kick_if_running(p) do {} while (0) #endif +extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + #define __wait_event(wq, condition) \ do { \ diff -purN linux-2.4.20/kernel/fork.c linux/kernel/fork.c --- linux-2.4.20/kernel/fork.c 2003-03-13 20:57:03.000000000 +0100 +++ linux/kernel/fork.c 2003-03-13 20:57:59.000000000 +0100 @@ -32,6 +32,7 @@ #include #include #include +#include static kmem_cache_t *task_struct_cachep; @@ -649,6 +650,31 @@ asmlinkage int sys_set_tid_address(int * return current->pid; } +long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + struct task_struct *task = current; + unsigned old_task_dumpable; + long ret; + + /* lock out any potential ptracer */ + task_lock(task); + if (task->ptrace) { + task_unlock(task); + return -EPERM; + } + + old_task_dumpable = task->task_dumpable; + task->task_dumpable = 0; + task_unlock(task); + + ret = arch_kernel_thread(fn, arg, flags); + + /* never reached in child process, only in parent */ + current->task_dumpable = old_task_dumpable; + + return ret; +} + /* * This creates a new process as a copy of the old one, * but does not actually start it yet. diff -purN linux-2.4.20/kernel/ptrace.c linux/kernel/ptrace.c --- linux-2.4.20/kernel/ptrace.c 2003-03-13 20:57:03.000000000 +0100 +++ linux/kernel/ptrace.c 2003-03-13 21:02:41.000000000 +0100 @@ -60,6 +60,10 @@ void __ptrace_unlink(task_t *child) */ int ptrace_check_attach(struct task_struct *child, int kill) { + mb(); + if (!is_dumpable(child)) + return -EPERM; + if (!(child->ptrace & PT_PTRACED)) return -ESRCH; @@ -95,7 +99,7 @@ int ptrace_attach(struct task_struct *ta (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto bad; rmb(); - if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) + if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE)) goto bad; /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) @@ -149,12 +153,14 @@ int ptrace_detach(struct task_struct *ch int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) { - struct mm_struct *mm; + struct mm_struct *mm = NULL; struct vm_area_struct *vma; struct page *page; void *old_buf = buf; - mm = get_task_mm(tsk); + if (is_dumpable(tsk) && (&init_mm != mm)) + mm = get_task_mm(tsk); + if (!mm) return 0; diff -purN linux-2.4.20/kernel/sys.c linux/kernel/sys.c --- linux-2.4.20/kernel/sys.c 2003-03-13 20:57:03.000000000 +0100 +++ linux/kernel/sys.c 2003-03-13 20:57:59.000000000 +0100 @@ -1319,7 +1319,7 @@ asmlinkage long sys_prctl(int option, un error = put_user(current->pdeath_signal, (int *)arg2); break; case PR_GET_DUMPABLE: - if (current->mm->dumpable) + if (is_dumpable(current)) error = 1; break; case PR_SET_DUMPABLE: @@ -1327,7 +1327,8 @@ asmlinkage long sys_prctl(int option, un error = -EINVAL; break; } - current->mm->dumpable = arg2; + if (is_dumpable(current)) + current->mm->dumpable = arg2; break; case PR_SET_UNALIGN: