[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Ptrace patch for 2.4.x BREAKS kill() 2 interesting effects for .pid and dot locking? (was Re: Ptrace hole / Linux 2.2.25)



hi all

I have a similar problem after compiling a new kernel with
kernel-source-2.4.20_2.4.20-3woody.3_all.deb

The output of ps has change and doesn't output the full-path
of a prozess anymore.
like this:

sid 2.4.20 build with source from kernel.org
(ptrace bug unpatch) 
or any other woody 2.4.17-19 
(all build from kernel-source.deb)
I looked at :
---------------------------------------------
ps faux | grep apache
root     16960  0.0  0.9 141232 4812 ?       S    14:45   0:00 /usr/sbin/apache
www-data 16964  0.0  1.1 142156 5328 ?       S    14:45   0:00  \_ /usr/sbin/apache


woody 2.4.20 build with 
kernel-source-2.4.20_2.4.20-3woody.3_all.deb:
---------------------------------------------
ps faux | grep apache
root       695  0.0  1.3 71420 1784 ?        S    Mar21   0:02 /usr/sbin/apache
www-data 27165  0.0  1.5 71480 2016 ?        S    06:26   0:00  \_ [apache]

in my case "mailscanner" from woody is broken since it does a 
pid=`/bin/ps axww | /bin/grep /usr/sbin/mailscanner
but there are very likly others

Is this just me doing something wrong?


tks and greeting 

pascal


Am Thu, Mar 20, 2003 at 10:43:05AM +1200, Matthew Grant sagte:
> Hi There!
> 
> Sorry about making a racket, but I am posting this for the edification
> of all, as there is a work around without breaking your server for this
> one.
> 
> As you can read below, I have found that the patch on 2.4.x also BREAKS
> kill() 2 when executed for signal 0 on a process ID that the user is not
> the owner of, except for root of course.
> 
> This has all sorts of interesting effects for processing .pid files, and
> probably dot locking.....  Makes the patch as it stands unacceptable for
> 2.4.21, and vendor kernels I would say... (See below for effects on
> Debian netsaint...)
> 
> I have been just digging harder, and the vulnerability is only
> exploitable if you are using the kernel auto module loader, so compile
> your kernel with out auto module loader enabled, or echo some garbage
> into /proc/sys/kernel/modprobe after loading all your modules.  It has
> to be an invalid executable name in there as any executable file will
> open the bug to exploit.
> 
> Here are the effects on a netsaint box I look after:
> 
> bucket: -foo- [~] 
> $ ls -l /var/run/netsaint/netsaint.pid 
> -rw-r--r--    1 root     root            5 Mar 19 16:32 /var/run/netsaint/netsaint.pid
> 
> bucket: -foo- [~] 
> $ cat !$
> cat /var/run/netsaint/netsaint.pid
> 4276
> 
> bucket: -foo- [~] 
> $ kill -0 4276
> bash: kill: (4276) - Operation not permitted
> 
> and the netsaint Web front end can't find the process alive that it
> wants to talk to via a unix pipe so that it can start and stop
> notifications etc....
> 
> Could I please say this to the kernel developers, please fix it
> properly!
> 
> Thanks heaps, 
> 
> Matthew Grant
> 
> On Thu, 2003-03-20 at 09:34, Matthew Grant wrote:
>     Dear All,
>     
>     The patch also breaks kill(2) on a process with signal number 0 - This
>     is used by a lot of monitoring programs running as one user ID to make
>     sure a process with another user ID is running.
>     
>     This causes trouble with packages like nagios and netsaint, as well as
>     other stuff.
>     
>     Alan, don't want to bash you around, but isn't there another fix
>     possible that doesn't break this function call and UML skas mode?
>     
>     Cheers,
>     
>     Matthew Grantal
>     
>     On Thu, 2003-03-20 at 08:09, Matthew Grant wrote:
>         Mistyped linux-kernel address  %-< 
>         
>         -----Forwarded Message----- 
>         
>         From: Matthew Grant <grantma@anathoth.gen.nz>
>         To: Alan Cox <alan@lxorguk.ukuu.org.uk>
>         Cc: Jeff Dike <jdike@karaya.com>, liinux-kerel@vger.kernel.org
>         Subject: Re: Ptrace hole / Linux 2.2.25
>         Date: 20 Mar 2003 07:55:45 +1200
>         
>         Alan,
>         
>         This patch really breaks UML using the skas mode of thread tracing skas3
>         patch on quite a significant amount of machines out there. The skas mode
>         is a lot more secure than the traditional UML tt mode. I guess this is
>         related to the below...
>         
>         I am running a UML site that a lot of hospitals ad clinics in Bangldesh
>         depend on for there email.  It allows them to work around the corruption
>         and agrandidement of the ISPs over there.  The skas3 mode patch is
>         needed for the site to run securely.  Tracing thread mode does not cut
>         it.
>         
>         There are also a large number of other telehoused ISP virtual hosting 
>         machines that use this stuff, and it is actually proving to be quite
>         reliable.
>         
>         I have attached the skas3 patch that Jeff Dike is currently using, and
>         the patch that you have produced.  Could you please look into the clash
>         between them, and get it fixed.
>         
>         Thank you - there are lots out there who will appreciate this.
>         
>         Cheers,
>         
>         Matthew Grant
>         
>         On Mon, 2003-03-17 at 18:39, Ben Pfaff wrote:
>         > I am concerned about this change because it will break sandboxing
>         > software that I have written, which uses prctl() to turn
>         > dumpability back on so that it can open a file, setuid(), and
>         > then execve() through the open file via /proc/self/fd/#. Without
>         > calling prctl(), the ownership of /proc/self/fd/* becomes root,
>         > so the process cannot exec it after it drops privileges. It uses
>         > prctl() in other places to get the same effect in /proc, but
>         > that's one of the most critical.
>         
>         The dumpability is per mm, which means that you have to consider
>         all the cases of a thread being created in parallel to dumpability
>         being enabled.
>         
>         So consider a three threaded process. Thread one triggers kernel thread
>         creation, thread two turns dumpability back on, thread three ptraces
>         the new kernel thread.
>         
>         Proving that is safe is non trivial so the current patch chooses not
>         to attempt it. For 2.4.21 proper someone can sit down and do the needed
>         verification if they wish 
>         
>         -- 
>         ===============================================================================
>         Matthew Grant	     /\	 ^/\^	grantma@anathoth.gen.nz      /~~~~\
>         A Linux Network Guy /~~\^/~~\_/~~~~~\_______/~~~~~~~~~~\____/******\
>         ===GPG KeyID: 2EE20270  FingerPrint:
>         8C2535E1A11DF3EA5EA19125BA4E790E2EE20270==
>         
>         ________________________________________________________________________
>         
>         diff -Naur host/arch/i386/config.in host-ptrace/arch/i386/config.in
>         --- host/arch/i386/config.in	Fri Aug  9 15:57:14 2002
>         +++ host-ptrace/arch/i386/config.in	Sun Nov 10 18:40:09 2002
>         @@ -291,6 +291,8 @@
>             bool '    Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
>          fi
>          
>         +bool '/proc/mm' CONFIG_PROC_MM
>         +
>          endmenu
>          
>          source drivers/mtd/Config.in
>         diff -Naur host/arch/i386/kernel/ldt.c host-ptrace/arch/i386/kernel/ldt.c
>         --- host/arch/i386/kernel/ldt.c	Fri Oct 26 00:01:41 2001
>         +++ host-ptrace/arch/i386/kernel/ldt.c	Sun Nov  3 18:37:48 2002
>         @@ -24,11 +24,12 @@
>           * assured by user-space anyway. Writes are atomic, to protect
>           * the security checks done on new descriptors.
>           */
>         -static int read_ldt(void * ptr, unsigned long bytecount)
>         +static int read_ldt(struct task_struct *task, void * ptr, 
>         +		    unsigned long bytecount)
>          {
>          	int err;
>          	unsigned long size;
>         -	struct mm_struct * mm = current->mm;
>         +	struct mm_struct * mm = task->mm;
>          
>          	err = 0;
>          	if (!mm->context.segments)
>         @@ -64,9 +65,10 @@
>          	return err;
>          }
>          
>         -static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
>         +static int write_ldt(struct task_struct *task, void * ptr, 
>         +		     unsigned long bytecount, int oldmode)
>          {
>         -	struct mm_struct * mm = current->mm;
>         +	struct mm_struct * mm = task->mm;
>          	__u32 entry_1, entry_2, *lp;
>          	int error;
>          	struct modify_ldt_ldt_s ldt_info;
>         @@ -148,23 +150,29 @@
>          	return error;
>          }
>          
>         -asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
>         +int modify_ldt(struct task_struct *task, int func, void *ptr, 
>         +	       unsigned long bytecount)
>          {
>          	int ret = -ENOSYS;
>          
>          	switch (func) {
>          	case 0:
>         -		ret = read_ldt(ptr, bytecount);
>         +		ret = read_ldt(task, ptr, bytecount);
>          		break;
>          	case 1:
>         -		ret = write_ldt(ptr, bytecount, 1);
>         +		ret = write_ldt(task, ptr, bytecount, 1);
>          		break;
>          	case 2:
>          		ret = read_default_ldt(ptr, bytecount);
>          		break;
>          	case 0x11:
>         -		ret = write_ldt(ptr, bytecount, 0);
>         +		ret = write_ldt(task, ptr, bytecount, 0);
>          		break;
>          	}
>          	return ret;
>         +}
>         +
>         +asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
>         +{
>         +	return(modify_ldt(current, func, ptr, bytecount));
>          }
>         diff -Naur host/arch/i386/kernel/process.c host-ptrace/arch/i386/kernel/process.c
>         --- host/arch/i386/kernel/process.c	Fri Aug  9 15:57:14 2002
>         +++ host-ptrace/arch/i386/kernel/process.c	Wed Nov  6 22:12:45 2002
>         @@ -551,13 +551,11 @@
>           * we do not have to muck with descriptors here, that is
>           * done in switch_mm() as needed.
>           */
>         -void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
>         +void mm_copy_segments(struct mm_struct *old_mm, struct mm_struct *new_mm)
>          {
>         -	struct mm_struct * old_mm;
>          	void *old_ldt, *ldt;
>          
>          	ldt = NULL;
>         -	old_mm = current->mm;
>          	if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
>          		/*
>          		 * Completely new LDT, we initialize it from the parent:
>         @@ -570,6 +568,16 @@
>          	}
>          	new_mm->context.segments = ldt;
>          	new_mm->context.cpuvalid = ~0UL;	/* valid on all CPU's - they can't have stale data */
>         +}
>         +
>         +void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
>         +{
>         +	mm_copy_segments(current->mm, new_mm);
>         +}
>         +
>         +void copy_task_segments(struct task_struct *from, struct mm_struct *new_mm)
>         +{
>         +	mm_copy_segments(from->mm, new_mm);
>          }
>          
>          /*
>         diff -Naur host/arch/i386/kernel/ptrace.c host-ptrace/arch/i386/kernel/ptrace.c
>         --- host/arch/i386/kernel/ptrace.c	Fri Aug  9 15:57:14 2002
>         +++ host-ptrace/arch/i386/kernel/ptrace.c	Mon Nov 11 19:03:38 2002
>         @@ -147,6 +147,11 @@
>          	put_stack_long(child, EFL_OFFSET, tmp);
>          }
>          
>         +extern int modify_ldt(struct task_struct *task, int func, void *ptr, 
>         +		      unsigned long bytecount);
>         +
>         +extern struct mm_struct *proc_mm_get_mm(int fd);
>         +
>          asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
>          {
>          	struct task_struct *child;
>         @@ -415,6 +420,53 @@
>          			child->ptrace |= PT_TRACESYSGOOD;
>          		else
>          			child->ptrace &= ~PT_TRACESYSGOOD;
>         +		ret = 0;
>         +		break;
>         +	}
>         +
>         +	case PTRACE_FAULTINFO: {
>         +		struct ptrace_faultinfo fault;
>         +
>         +		fault = ((struct ptrace_faultinfo) 
>         +			{ .is_write	= child->thread.error_code,
>         +			  .addr		= child->thread.cr2 });
>         +		ret = copy_to_user((unsigned long *) data, &fault, 
>         +				   sizeof(fault));
>         +		if(ret)
>         +			break;
>         +		break;
>         +	}
>         +	case PTRACE_SIGPENDING:
>         +		ret = copy_to_user((unsigned long *) data, 
>         +				   &child->pending.signal,
>         +				   sizeof(child->pending.signal));
>         +		break;
>         +
>         +	case PTRACE_LDT: {
>         +		struct ptrace_ldt ldt;
>         +
>         +		if(copy_from_user(&ldt, (unsigned long *) data, 
>         +				  sizeof(ldt))){
>         +			ret = -EIO;
>         +			break;
>         +		}
>         +		ret = modify_ldt(child, ldt.func, ldt.ptr, ldt.bytecount);
>         +		break;
>         +	}
>         +
>         +	case PTRACE_SWITCH_MM: {
>         +		struct mm_struct *old = child->mm;
>         +		struct mm_struct *new = proc_mm_get_mm(data);
>         +
>         +		if(IS_ERR(new)){
>         +			ret = PTR_ERR(new);
>         +			break;
>         +		}
>         +
>         +		atomic_inc(&new->mm_users);
>         +		child->mm = new;
>         +		child->active_mm = new;
>         +		mmput(old);
>          		ret = 0;
>          		break;
>          	}
>         diff -Naur host/arch/i386/kernel/sys_i386.c host-ptrace/arch/i386/kernel/sys_i386.c
>         --- host/arch/i386/kernel/sys_i386.c	Mon Mar 19 15:35:09 2001
>         +++ host-ptrace/arch/i386/kernel/sys_i386.c	Mon Nov 11 17:23:25 2002
>         @@ -40,7 +40,7 @@
>          }
>          
>          /* common code for old and new mmaps */
>         -static inline long do_mmap2(
>         +long do_mmap2(struct mm_struct *mm,
>          	unsigned long addr, unsigned long len,
>          	unsigned long prot, unsigned long flags,
>          	unsigned long fd, unsigned long pgoff)
>         @@ -55,9 +55,9 @@
>          			goto out;
>          	}
>          
>         -	down_write(&current->mm->mmap_sem);
>         -	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
>         -	up_write(&current->mm->mmap_sem);
>         +	down_write(&mm->mmap_sem);
>         +	error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
>         +	up_write(&mm->mmap_sem);
>          
>          	if (file)
>          		fput(file);
>         @@ -69,7 +69,7 @@
>          	unsigned long prot, unsigned long flags,
>          	unsigned long fd, unsigned long pgoff)
>          {
>         -	return do_mmap2(addr, len, prot, flags, fd, pgoff);
>         +	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
>          }
>          
>          /*
>         @@ -100,7 +100,7 @@
>          	if (a.offset & ~PAGE_MASK)
>          		goto out;
>          
>         -	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
>         +	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
>          out:
>          	return err;
>          }
>         diff -Naur host/include/asm-i386/processor.h host-ptrace/include/asm-i386/processor.h
>         --- host/include/asm-i386/processor.h	Sun Nov 10 18:47:37 2002
>         +++ host-ptrace/include/asm-i386/processor.h	Mon Nov 11 17:33:30 2002
>         @@ -436,6 +436,8 @@
>          extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
>          
>          /* Copy and release all segment info associated with a VM */
>         +extern void mm_copy_segments(struct mm_struct *old_mm, 
>         +			     struct mm_struct *new_mm);
>          extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
>          extern void release_segments(struct mm_struct * mm);
>          
>         diff -Naur host/include/asm-i386/ptrace.h host-ptrace/include/asm-i386/ptrace.h
>         --- host/include/asm-i386/ptrace.h	Sun Sep 23 19:20:51 2001
>         +++ host-ptrace/include/asm-i386/ptrace.h	Sun Nov 10 18:36:22 2002
>         @@ -51,6 +51,22 @@
>          
>          #define PTRACE_SETOPTIONS         21
>          
>         +struct ptrace_faultinfo {
>         +	int is_write;
>         +	unsigned long addr;
>         +};
>         +
>         +struct ptrace_ldt {
>         +	int func;
>         +  	void *ptr;
>         +	unsigned long bytecount;
>         +};
>         +
>         +#define PTRACE_FAULTINFO 52
>         +#define PTRACE_SIGPENDING 53
>         +#define PTRACE_LDT 54
>         +#define PTRACE_SWITCH_MM 55
>         +
>          /* options set using PTRACE_SETOPTIONS */
>          #define PTRACE_O_TRACESYSGOOD     0x00000001
>          
>         diff -Naur host/include/linux/mm.h host-ptrace/include/linux/mm.h
>         --- host/include/linux/mm.h	Fri Aug 30 15:03:44 2002
>         +++ host-ptrace/include/linux/mm.h	Mon Nov 11 19:08:53 2002
>         @@ -492,6 +492,9 @@
>          int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
>          		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
>          
>         +extern long do_mprotect(struct mm_struct *mm, unsigned long start, 
>         +			size_t len, unsigned long prot);
>         +
>          /*
>           * On a two-level page table, this ends up being trivial. Thus the
>           * inlining and the symmetry break with pte_alloc() that does all
>         @@ -539,9 +542,10 @@
>          
>          extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
>          
>         -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
>         -	unsigned long len, unsigned long prot,
>         -	unsigned long flag, unsigned long pgoff);
>         +extern unsigned long do_mmap_pgoff(struct mm_struct *mm, 
>         +				   struct file *file, unsigned long addr,
>         +				   unsigned long len, unsigned long prot,
>         +				   unsigned long flag, unsigned long pgoff);
>          
>          static inline unsigned long do_mmap(struct file *file, unsigned long addr,
>          	unsigned long len, unsigned long prot,
>         @@ -551,7 +555,7 @@
>          	if ((offset + PAGE_ALIGN(len)) < offset)
>          		goto out;
>          	if (!(offset & ~PAGE_MASK))
>         -		ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
>         +		ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, offset >> PAGE_SHIFT);
>          out:
>          	return ret;
>          }
>         diff -Naur host/include/linux/proc_mm.h host-ptrace/include/linux/proc_mm.h
>         --- host/include/linux/proc_mm.h	Wed Dec 31 19:00:00 1969
>         +++ host-ptrace/include/linux/proc_mm.h	Mon Nov 11 17:41:09 2002
>         @@ -0,0 +1,44 @@
>         +/* 
>         + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
>         + * Licensed under the GPL
>         + */
>         +
>         +#ifndef __PROC_MM_H
>         +#define __PROC_MM_H
>         +
>         +#define MM_MMAP 54
>         +#define MM_MUNMAP 55
>         +#define MM_MPROTECT 56
>         +#define MM_COPY_SEGMENTS 57
>         +
>         +struct mm_mmap {
>         +	unsigned long addr;
>         +	unsigned long len;
>         +	unsigned long prot;
>         +	unsigned long flags;
>         +	unsigned long fd;
>         +	unsigned long offset;
>         +};
>         +
>         +struct mm_munmap {
>         +	unsigned long addr;
>         +	unsigned long len;	
>         +};
>         +
>         +struct mm_mprotect {
>         +	unsigned long addr;
>         +	unsigned long len;
>         +        unsigned int prot;
>         +};
>         +
>         +struct proc_mm_op {
>         +	int op;
>         +	union {
>         +		struct mm_mmap mmap;
>         +		struct mm_munmap munmap;
>         +	        struct mm_mprotect mprotect;
>         +		int copy_segments;
>         +	} u;
>         +};
>         +
>         +#endif
>         diff -Naur host/mm/Makefile host-ptrace/mm/Makefile
>         --- host/mm/Makefile	Fri Aug  9 15:57:31 2002
>         +++ host-ptrace/mm/Makefile	Sun Nov 10 18:37:33 2002
>         @@ -17,5 +17,6 @@
>          	    shmem.o
>          
>          obj-$(CONFIG_HIGHMEM) += highmem.o
>         +obj-$(CONFIG_PROC_MM) += proc_mm.o
>          
>          include $(TOPDIR)/Rules.make
>         diff -Naur host/mm/mmap.c host-ptrace/mm/mmap.c
>         --- host/mm/mmap.c	Fri Aug  9 15:57:31 2002
>         +++ host-ptrace/mm/mmap.c	Mon Nov 11 17:24:18 2002
>         @@ -390,10 +390,11 @@
>          	return 0;
>          }
>          
>         -unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
>         -	unsigned long prot, unsigned long flags, unsigned long pgoff)
>         +unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file, 
>         +			    unsigned long addr, unsigned long len,
>         +			    unsigned long prot, unsigned long flags, 
>         +			    unsigned long pgoff)
>          {
>         -	struct mm_struct * mm = current->mm;
>          	struct vm_area_struct * vma, * prev;
>          	unsigned int vm_flags;
>          	int correct_wcount = 0;
>         diff -Naur host/mm/mprotect.c host-ptrace/mm/mprotect.c
>         --- host/mm/mprotect.c	Fri Aug  9 15:57:31 2002
>         +++ host-ptrace/mm/mprotect.c	Mon Nov 11 17:47:58 2002
>         @@ -264,7 +264,8 @@
>          	return 0;
>          }
>          
>         -asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
>         +long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, 
>         +		 unsigned long prot)
>          {
>          	unsigned long nstart, end, tmp;
>          	struct vm_area_struct * vma, * next, * prev;
>         @@ -281,9 +282,9 @@
>          	if (end == start)
>          		return 0;
>          
>         -	down_write(&current->mm->mmap_sem);
>         +	down_write(&mm->mmap_sem);
>          
>         -	vma = find_vma_prev(current->mm, start, &prev);
>         +	vma = find_vma_prev(mm, start, &prev);
>          	error = -ENOMEM;
>          	if (!vma || vma->vm_start > start)
>          		goto out;
>         @@ -332,6 +333,11 @@
>          		prev->vm_mm->map_count--;
>          	}
>          out:
>         -	up_write(&current->mm->mmap_sem);
>         +	up_write(&mm->mmap_sem);
>          	return error;
>         +}
>         +
>         +asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
>         +{
>         +	return(do_mprotect(current->mm, start, len, prot));
>          }
>         diff -Naur host/mm/proc_mm.c host-ptrace/mm/proc_mm.c
>         --- host/mm/proc_mm.c	Wed Dec 31 19:00:00 1969
>         +++ host-ptrace/mm/proc_mm.c	Mon Nov 11 19:07:52 2002
>         @@ -0,0 +1,173 @@
>         +/* 
>         + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
>         + * Licensed under the GPL
>         + */
>         +
>         +#include "linux/proc_fs.h"
>         +#include "linux/proc_mm.h"
>         +#include "linux/file.h"
>         +#include "asm/uaccess.h"
>         +#include "asm/mmu_context.h"
>         +
>         +static struct file_operations proc_mm_fops;
>         +
>         +struct mm_struct *proc_mm_get_mm(int fd)
>         +{
>         +	struct mm_struct *ret = ERR_PTR(-EBADF);
>         +	struct file *file;
>         +
>         +	file = fget(fd);
>         +	if (!file)
>         +		goto out;
>         +
>         +	ret = ERR_PTR(-EINVAL);
>         +	if(file->f_op != &proc_mm_fops)
>         +		goto out_fput;
>         +
>         +	ret = file->private_data;
>         +
>         + out_fput:
>         +	fput(file);
>         + out:
>         +	return(ret);
>         +}
>         +
>         +extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
>         +		     unsigned long len, unsigned long prot, 
>         +		     unsigned long flags, unsigned long fd,
>         +		     unsigned long pgoff);
>         +
>         +static ssize_t write_proc_mm(struct file *file, const char *buffer,
>         +			     size_t count, loff_t *ppos)
>         +{
>         +	struct mm_struct *mm = file->private_data;
>         +	struct proc_mm_op req;
>         +	int n, ret;
>         +
>         +	if(count > sizeof(req))
>         +		return(-EINVAL);
>         +
>         +	n = copy_from_user(&req, buffer, count);
>         +	if(n != 0)
>         +		return(-EFAULT);
>         +
>         +	ret = count;
>         +	switch(req.op){
>         +	case MM_MMAP: {
>         +		struct mm_mmap *map = &req.u.mmap;
>         +
>         +		ret = do_mmap2(mm, map->addr, map->len, map->prot, 
>         +			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
>         +		if((ret & ~PAGE_MASK) == 0)
>         +			ret = count;
>         +	
>         +		break;
>         +	}
>         +	case MM_MUNMAP: {
>         +		struct mm_munmap *unmap = &req.u.munmap;
>         +
>         +		down_write(&mm->mmap_sem);
>         +		ret = do_munmap(mm, unmap->addr, unmap->len);
>         +		up_write(&mm->mmap_sem);
>         +
>         +		if(ret == 0)
>         +			ret = count;
>         +		break;
>         +	}
>         +	case MM_MPROTECT: {
>         +		struct mm_mprotect *protect = &req.u.mprotect;
>         +
>         +		ret = do_mprotect(mm, protect->addr, protect->len, 
>         +				  protect->prot);
>         +		if(ret == 0)
>         +			ret = count;
>         +		break;
>         +	}
>         +
>         +	case MM_COPY_SEGMENTS: {
>         +		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
>         +
>         +		if(IS_ERR(from)){
>         +			ret = PTR_ERR(from);
>         +			break;
>         +		}
>         +
>         +		mm_copy_segments(from, mm);
>         +		break;
>         +	}
>         +	default:
>         +		ret = -EINVAL;
>         +		break;
>         +	}
>         +
>         +	return(ret);
>         +}
>         +
>         +static int open_proc_mm(struct inode *inode, struct file *file)
>         +{
>         +	struct mm_struct *mm = mm_alloc();
>         +	int ret;
>         +
>         +	ret = -ENOMEM;
>         +	if(mm == NULL)
>         +		goto out_mem;
>         +
>         +	ret = init_new_context(current, mm);
>         +	if(ret)
>         +		goto out_free;
>         +
>         +	spin_lock(&mmlist_lock);
>         +	list_add(&mm->mmlist, &current->mm->mmlist);
>         +	mmlist_nr++;
>         +	spin_unlock(&mmlist_lock);
>         +
>         +	file->private_data = mm;
>         +
>         +	return(0);
>         +
>         + out_free:
>         +	mmput(mm);
>         + out_mem:
>         +	return(ret);
>         +}
>         +
>         +static int release_proc_mm(struct inode *inode, struct file *file)
>         +{
>         +	struct mm_struct *mm = file->private_data;
>         +
>         +	mmput(mm);
>         +	return(0);
>         +}
>         +
>         +static struct file_operations proc_mm_fops = {
>         +	.open		= open_proc_mm,
>         +	.release	= release_proc_mm,
>         +	.write		= write_proc_mm,
>         +};
>         +
>         +static int make_proc_mm(void)
>         +{
>         +	struct proc_dir_entry *ent;
>         +
>         +	ent = create_proc_entry("mm", 0222, &proc_root);
>         +	if(ent == NULL){
>         +		printk("make_proc_mm : Failed to register /proc/mm\n");
>         +		return(0);
>         +	}
>         +	ent->proc_fops = &proc_mm_fops;
>         +
>         +	return(0);
>         +}
>         +
>         +__initcall(make_proc_mm);
>         +
>         +/*
>         + * Overrides for Emacs so that we follow Linus's tabbing style.
>         + * Emacs will notice this stuff at the end of the file and automatically
>         + * adjust the settings for this buffer only.  This must remain at the end
>         + * of the file.
>         + * ---------------------------------------------------------------------------
>         + * Local variables:
>         + * c-file-style: "linux"
>         + * End:
>         + */
>         
>         ________________________________________________________________________
>         
>                                                                         LWN.net Logo 
>         
>         
>                                                                         Sponsored Link
>         
>            TrustCommerce
>         
>            E-Commerce & credit card processing - the Open Source way!
>              ___________________________________________________________________________________________________________________________________
>         
>            You are not logged in
>            Log in now
>            Create an account
>            Subscribe to LWN
>         
>            Recent Features
>         
>            LWN.net Weekly Edition for March 13, 2003
>         
>            A look at the SCO complaint
>         
>            LWN.net Weekly Edition for March 6, 2003
>         
>            LWN.net Weekly Edition for February 27, 2003
>         
>            LWN.net Weekly Edition for February 20, 2003
>         
>            Printable page
>         
>         
>                Home      Weekly edition     Archives    Security  Calendar
>            Distributions Penguin Gallery Kernel patches  Search   Old site
>             LWN.net FAQ   Subscriptions    Advertise    Headlines Privacy
>         
>         Ptrace vulnerability in 2.2 and 2.4 kernels
>         
>            From:   Alan Cox <alan@redhat.com>
>            To:   editor@lwn.net, scoop@freshmeat.net, kernel@linuxtoday.com, kernel@linuxfr.org, rob@linuxberg.com, chris@linuxdev.net,
>            kernel@linuxhq.com, kernel@linuxcare.com, marcelo@conectiva.com.br, ac-kernels@tonnikala.net
>            Subject:   Ptrace vulnerability in Linux 2.2/2.4
>            Date:   Mon, 17 Mar 2003 11:00:16 -0500 (EST)
>         
>         Vulnerability: CAN-2003-0127
>         
>         The Linux 2.2 and Linux 2.4 kernels have a flaw in ptrace. This hole allows
>         local users to obtain full privileges. Remote exploitation of this hole is
>         not possible. Linux 2.5 is not believed to be vulnerable.
>         
>         Linux 2.2.25 has been released to correct Linux 2.2. It contains no other
>         changes. The bug fixes that would have been in 2.2.5pre1 will now appear in
>         2.2.26pre1. The patch will apply directly to most older 2.2 releases.
>         
>         A patch for Linux 2.4.20/Linux 2.4.21pre is attached. The patch also
>         subtly changes the PR_SET_DUMPABLE prctl. We believe this is neccessary and
>         that it will not affect any software. The functionality change is specific
>         to unusual debugging situations.
>         
>         We would like to thank Andrzej Szombierski who found the problem, and
>         wrote an initial patch. Seth Arnold cleaned up the 2.2 change. Arjan van
>         de Ven and Ben LaHaise identified additional problems with the original
>         fix.
>         
>         Alan
>         
>         diff -purN linux.orig/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
>         --- linux.orig/arch/alpha/kernel/entry.S        Thu Mar 13 12:01:46 2003
>         +++ linux/arch/alpha/kernel/entry.S     Thu Mar 13 13:28:49 2003
>         @@ -231,12 +231,12 @@ kernel_clone:
>          .end   kernel_clone
>         
>          /*
>         - * kernel_thread(fn, arg, clone_flags)
>         + * arch_kernel_thread(fn, arg, clone_flags)
>           */
>          .align 3
>          .globl kernel_thread
>          .ent   kernel_thread
>         -kernel_thread:
>         +arch_kernel_thread:
>                 ldgp    $29,0($27)      /* we can be called from a module */
>                 .frame $30, 4*8, $26
>                 subq    $30,4*8,$30
>         diff -purN linux.orig/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
>         --- linux.orig/arch/arm/kernel/process.c        Thu Mar 13 12:01:29 2003
>         +++ linux/arch/arm/kernel/process.c     Thu Mar 13 13:25:56 2003
>         @@ -366,7 +366,7 @@ void dump_thread(struct pt_regs * regs,
>           * a system call from a "real" process, but the process memory space will
>           * not be free'd until both the parent and the child have exited.
>           */
>         -pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
>         +pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
>          {
>                 pid_t __ret;
>         
>         diff -purN linux.orig/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S
>         --- linux.orig/arch/cris/kernel/entry.S Thu Mar 13 12:01:29 2003
>         +++ linux/arch/cris/kernel/entry.S      Thu Mar 13 13:30:30 2003
>         @@ -736,12 +736,12 @@ hw_bp_trig_ptr:
>           * the grosser the code, at least with the gcc version in cris-dist-1.13.
>           */
>         
>         -/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
>         +/* int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
>          /*                   r10                r11         r12  */
>         
>                 .text
>         -       .global kernel_thread
>         -kernel_thread:
>         +       .global arch_kernel_thread
>         +arch_kernel_thread:
>         
>                 /* Save ARG for later.  */
>                 move.d $r11, $r13
>         diff -purN linux.orig/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
>         --- linux.orig/arch/i386/kernel/process.c       Thu Mar 13 12:01:57 2003
>         +++ linux/arch/i386/kernel/process.c    Thu Mar 13 13:26:08 2003
>         @@ -495,7 +495,7 @@ void release_segments(struct mm_struct *
>          /*
>           * 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)
>          {
>                 long retval, d0;
>         
>         @@ -518,6 +518,7 @@ int kernel_thread(int (*fn)(void *), voi
>                          "r" (arg), "r" (fn),
>                          "b" (flags | CLONE_VM)
>                         : "memory");
>         +
>                 return retval;
>          }
>         
>         diff -purN linux.orig/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c
>         --- linux.orig/arch/ia64/kernel/process.c       Thu Mar 13 12:01:29 2003
>         +++ linux/arch/ia64/kernel/process.c    Thu Mar 13 13:26:15 2003
>         @@ -220,7 +220,7 @@ ia64_load_extra (struct task_struct *tas
>           *     |                     | <-- sp (lowest addr)
>           *     +---------------------+
>           *
>         - * Note: if we get called through kernel_thread() then the memory
>         + * Note: if we get called through arch_kernel_thread() then the memory
>           * above "(highest addr)" is valid kernel stack memory that needs to
>           * be copied as well.
>           *
>         @@ -469,7 +469,7 @@ ia64_set_personality (struct elf64_hdr *
>          }
>         
>          pid_t
>         -kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
>         +arch_kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
>          {
>                 struct task_struct *parent = current;
>                 int result, tid;
>         diff -purN linux.orig/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
>         --- linux.orig/arch/m68k/kernel/process.c       Thu Mar 13 12:01:29 2003
>         +++ linux/arch/m68k/kernel/process.c    Thu Mar 13 13:26:18 2003
>         @@ -124,7 +124,7 @@ void show_regs(struct pt_regs * regs)
>          /*
>           * 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)
>          {
>                 int pid;
>                 mm_segment_t fs;
>         diff -purN linux.orig/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
>         --- linux.orig/arch/mips/kernel/process.c       Thu Mar 13 12:01:29 2003
>         +++ linux/arch/mips/kernel/process.c    Thu Mar 13 13:26:28 2003
>         @@ -155,7 +155,7 @@ void dump_thread(struct pt_regs *regs, s
>          /*
>           * 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)
>          {
>                 long retval;
>         
>         diff -purN linux.orig/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c
>         --- linux.orig/arch/mips64/kernel/process.c     Thu Mar 13 12:01:29 2003
>         +++ linux/arch/mips64/kernel/process.c  Thu Mar 13 13:26:23 2003
>         @@ -152,7 +152,7 @@ void dump_thread(struct pt_regs *regs, s
>          /*
>           * 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)
>          {
>                 int retval;
>         
>         diff -purN linux.orig/arch/parisc/kernel/process.c linux/arch/parisc/kernel/process.c
>         --- linux.orig/arch/parisc/kernel/process.c     Fri Feb  9 14:29:44 2001
>         +++ linux/arch/parisc/kernel/process.c  Thu Mar 13 13:26:36 2003
>         @@ -118,7 +118,7 @@ void machine_heartbeat(void)
>           */
>         
>          extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
>         -pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
>         +pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
>          {
>         
>                 /*
>         diff -purN linux.orig/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
>         --- linux.orig/arch/ppc/kernel/misc.S   Thu Mar 13 12:01:29 2003
>         +++ linux/arch/ppc/kernel/misc.S        Thu Mar 13 13:32:21 2003
>         @@ -899,9 +899,9 @@ _GLOBAL(cvt_df)
>         
>          /*
>           * Create a kernel thread
>         - *   kernel_thread(fn, arg, flags)
>         + *   arch_kernel_thread(fn, arg, flags)
>           */
>         -_GLOBAL(kernel_thread)
>         +_GLOBAL(arch_kernel_thread)
>                 mr      r6,r3           /* function */
>                 ori     r3,r5,CLONE_VM  /* flags */
>                 li      r0,__NR_clone
>         diff -purN linux.orig/arch/ppc64/kernel/misc.S linux/arch/ppc64/kernel/misc.S
>         --- linux.orig/arch/ppc64/kernel/misc.S Thu Mar 13 12:01:30 2003
>         +++ linux/arch/ppc64/kernel/misc.S      Thu Mar 13 13:29:42 2003
>         @@ -493,9 +493,9 @@ _GLOBAL(cvt_df)
>         
>          /*
>           * Create a kernel thread
>         - *   kernel_thread(fn, arg, flags)
>         + *   arch_kernel_thread(fn, arg, flags)
>           */
>         -_GLOBAL(kernel_thread)
>         +_GLOBAL(arch_kernel_thread)
>                 mr      r6,r3           /* function */
>                 ori     r3,r5,CLONE_VM  /* flags */
>                 li      r0,__NR_clone
>         diff -purN linux.orig/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
>         --- linux.orig/arch/s390/kernel/process.c       Thu Mar 13 12:01:30 2003
>         +++ linux/arch/s390/kernel/process.c    Thu Mar 13 13:26:43 2003
>         @@ -105,7 +105,7 @@ void show_regs(struct pt_regs *regs)
>                         show_trace((unsigned long *) regs->gprs[15]);
>          }
>         
>         -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>         +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>          {
>                  int clone_arg = flags | CLONE_VM;
>                  int retval;
>         diff -purN linux.orig/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
>         --- linux.orig/arch/s390x/kernel/process.c      Thu Mar 13 12:01:30 2003
>         +++ linux/arch/s390x/kernel/process.c   Thu Mar 13 13:26:46 2003
>         @@ -102,7 +102,7 @@ void show_regs(struct pt_regs *regs)
>                         show_trace((unsigned long *) regs->gprs[15]);
>          }
>         
>         -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>         +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>          {
>                  int clone_arg = flags | CLONE_VM;
>                  int retval;
>         diff -purN linux.orig/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
>         --- linux.orig/arch/sh/kernel/process.c Mon Oct 15 16:36:48 2001
>         +++ linux/arch/sh/kernel/process.c      Thu Mar 13 13:26:49 2003
>         @@ -118,7 +118,7 @@ void free_task_struct(struct task_struct
>           * This is the mechanism for creating a new 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)
>          {      /* Don't use this in BL=1(cli).  Or else, CPU resets! */
>                 register unsigned long __sc0 __asm__ ("r0");
>                 register unsigned long __sc3 __asm__ ("r3") = __NR_clone;
>         diff -purN linux.orig/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
>         --- linux.orig/arch/sparc/kernel/process.c      Thu Mar 13 12:01:30 2003
>         +++ linux/arch/sparc/kernel/process.c   Thu Mar 13 13:26:58 2003
>         @@ -676,7 +676,7 @@ out:
>           * a system call from a "real" process, but the process memory space will
>           * not be free'd until both the parent and the child have exited.
>           */
>         -pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>         +pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>          {
>                 long retval;
>         
>         diff -purN linux.orig/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
>         --- linux.orig/arch/sparc64/kernel/process.c    Thu Mar 13 12:01:30 2003
>         +++ linux/arch/sparc64/kernel/process.c Thu Mar 13 13:26:54 2003
>         @@ -658,7 +658,7 @@ int copy_thread(int nr, unsigned long cl
>           * a system call from a "real" process, but the process memory space will
>           * not be free'd until both the parent and the child have exited.
>           */
>         -pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>         +pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>          {
>                 long retval;
>         
>         diff -purN linux.orig/arch/um/kernel/process_kern.c linux/arch/um/kernel/process_kern.c
>         --- linux.orig/arch/um/kernel/process_kern.c    Thu Mar 13 12:01:48 2003
>         +++ linux/arch/um/kernel/process_kern.c Thu Mar 13 13:27:37 2003
>         @@ -171,14 +171,14 @@ static int new_thread_proc(void *stack)
>                 os_usr1_process(os_getpid());
>          }
>         
>         -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>         +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
>          {
>                 int pid;
>         
>                 current->thread.request.u.thread.proc = fn;
>                 current->thread.request.u.thread.arg = arg;
>                 pid = do_fork(CLONE_VM | flags, 0, NULL, 0);
>         -       if(pid < 0) panic("do_fork failed in kernel_thread");
>         +       if(pid < 0) panic("do_fork failed in arch_kernel_thread");
>                 return(pid);
>          }
>         
>         diff -purN linux.orig/fs/exec.c linux/fs/exec.c
>         --- linux.orig/fs/exec.c        Thu Mar 13 12:01:46 2003
>         +++ linux/fs/exec.c     Thu Mar 13 14:19:08 2003
>         @@ -559,8 +559,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 == '/')
>         @@ -952,7 +954,7 @@ int do_coredump(long signr, struct pt_re
>                 binfmt = current->binfmt;
>                 if (!binfmt || !binfmt->core_dump)
>                         goto fail;
>         -       if (!current->mm->dumpable)
>         +       if (!is_dumpable(current))
>                         goto fail;
>                 current->mm->dumpable = 0;
>                 if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
>         diff -purN linux.orig/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
>         --- linux.orig/include/asm-alpha/processor.h    Fri Oct  5 15:11:05 2001
>         +++ linux/include/asm-alpha/processor.h Thu Mar 13 13:35:18 2003
>         @@ -119,7 +119,7 @@ struct task_struct;
>          extern void release_thread(struct task_struct *);
>         
>          /* Create a kernel thread without removing it from tasklists.  */
>         -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
>         +extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
>         
>          #define copy_segments(tsk, mm)         do { } while (0)
>          #define release_segments(mm)           do { } while (0)
>         diff -purN linux.orig/include/asm-arm/processor.h linux/include/asm-arm/processor.h
>         --- linux.orig/include/asm-arm/processor.h      Thu Mar 13 12:01:35 2003
>         +++ linux/include/asm-arm/processor.h   Thu Mar 13 13:35:18 2003
>         @@ -117,7 +117,7 @@ extern void __free_task_struct(struct ta
>          /*
>           * Create a new kernel thread
>           */
>         -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);
>         
>          #endif
>         
>         diff -purN linux.orig/include/asm-cris/processor.h linux/include/asm-cris/processor.h
>         --- linux.orig/include/asm-cris/processor.h     Thu Mar 13 12:01:35 2003
>         +++ linux/include/asm-cris/processor.h  Thu Mar 13 13:35:18 2003
>         @@ -81,7 +81,7 @@ struct thread_struct {
>          #define INIT_THREAD  { \
>             0, 0, 0x20 }  /* ccr = int enable, nothing else */
>         
>         -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);
>         
>          /* give the thread a program location
>           * set user-mode (The 'U' flag (User mode flag) is CCR/DCCR bit 8)
>         diff -purN linux.orig/include/asm-i386/processor.h linux/include/asm-i386/processor.h
>         --- linux.orig/include/asm-i386/processor.h     Thu Mar 13 12:01:57 2003
>         +++ linux/include/asm-i386/processor.h  Thu Mar 13 13:51:02 2003
>         @@ -433,7 +433,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 */
>          extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
>         diff -purN linux.orig/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h
>         --- linux.orig/include/asm-ia64/processor.h     Thu Mar 13 12:01:35 2003
>         +++ linux/include/asm-ia64/processor.h  Thu Mar 13 13:35:18 2003
>         @@ -476,7 +476,7 @@ struct task_struct;
>           * do_basic_setup() and the timing is such that free_initmem() has
>           * been called already.
>           */
>         -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 */
>          #define copy_segments(tsk, mm)                 do { } while (0)
>         diff -purN linux.orig/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
>         --- linux.orig/include/asm-m68k/processor.h     Fri Oct  5 15:11:05 2001
>         +++ linux/include/asm-m68k/processor.h  Thu Mar 13 13:35:18 2003
>         @@ -105,7 +105,7 @@ static inline void release_thread(struct
>          {
>          }
>         
>         -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);
>         
>          #define copy_segments(tsk, mm)         do { } while (0)
>          #define release_segments(mm)           do { } while (0)
>         diff -purN linux.orig/include/asm-mips/processor.h linux/include/asm-mips/processor.h
>         --- linux.orig/include/asm-mips/processor.h     Thu Mar 13 12:01:36 2003
>         +++ linux/include/asm-mips/processor.h  Thu Mar 13 13:35:18 2003
>         @@ -186,7 +186,7 @@ struct thread_struct {
>          /* Free all resources held by a thread. */
>          #define release_thread(thread) do { } while(0)
>         
>         -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 */
>          #define copy_segments(p, mm) do { } while(0)
>         diff -purN linux.orig/include/asm-mips64/processor.h linux/include/asm-mips64/processor.h
>         --- linux.orig/include/asm-mips64/processor.h   Thu Mar 13 12:01:36 2003
>         +++ linux/include/asm-mips64/processor.h        Thu Mar 13 13:35:18 2003
>         @@ -245,7 +245,7 @@ struct thread_struct {
>          /* Free all resources held by a thread. */
>          #define release_thread(thread) do { } while(0)
>         
>         -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 */
>          #define copy_segments(p, mm) do { } while(0)
>         diff -purN linux.orig/include/asm-parisc/processor.h linux/include/asm-parisc/processor.h
>         --- linux.orig/include/asm-parisc/processor.h   Fri Oct  5 15:11:05 2001
>         +++ linux/include/asm-parisc/processor.h        Thu Mar 13 13:35:18 2003
>         @@ -305,7 +305,7 @@ struct task_struct;
>         
>          /* Free all resources held by a thread. */
>          extern void release_thread(struct task_struct *);
>         -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);
>         
>          #define copy_segments(tsk, mm) do { } while (0)
>          #define release_segments(mm)   do { } while (0)
>         diff -purN linux.orig/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
>         --- linux.orig/include/asm-ppc/processor.h      Thu Mar 13 12:01:36 2003
>         +++ linux/include/asm-ppc/processor.h   Thu Mar 13 13:35:18 2003
>         @@ -593,7 +593,7 @@ void release_thread(struct task_struct *
>          /*
>           * Create a new kernel thread.
>           */
>         -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
>         +extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
>         
>          /*
>           * Bus types
>         diff -purN linux.orig/include/asm-ppc64/processor.h linux/include/asm-ppc64/processor.h
>         --- linux.orig/include/asm-ppc64/processor.h    Thu Mar 13 12:01:36 2003
>         +++ linux/include/asm-ppc64/processor.h Thu Mar 13 13:35:18 2003
>         @@ -609,7 +609,7 @@ void release_thread(struct task_struct *
>          /*
>           * Create a new kernel thread.
>           */
>         -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
>         +extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
>         
>          /*
>           * Bus types
>         diff -purN linux.orig/include/asm-s390/processor.h linux/include/asm-s390/processor.h
>         --- linux.orig/include/asm-s390/processor.h     Thu Mar 13 12:01:36 2003
>         +++ linux/include/asm-s390/processor.h  Thu Mar 13 13:35:18 2003
>         @@ -113,7 +113,7 @@ struct mm_struct;
>         
>          /* Free all resources held by a thread. */
>          extern void release_thread(struct task_struct *);
>         -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 */
>          #define copy_segments(nr, mm)           do { } while (0)
>         diff -purN linux.orig/include/asm-s390x/processor.h linux/include/asm-s390x/processor.h
>         --- linux.orig/include/asm-s390x/processor.h    Thu Mar 13 12:01:36 2003
>         +++ linux/include/asm-s390x/processor.h Thu Mar 13 13:35:18 2003
>         @@ -127,7 +127,7 @@ struct mm_struct;
>         
>          /* Free all resources held by a thread. */
>          extern void release_thread(struct task_struct *);
>         -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 */
>          #define copy_segments(nr, mm)           do { } while (0)
>         diff -purN linux.orig/include/asm-sh/processor.h linux/include/asm-sh/processor.h
>         --- linux.orig/include/asm-sh/processor.h       Fri Oct  5 15:11:05 2001
>         +++ linux/include/asm-sh/processor.h    Thu Mar 13 13:35:18 2003
>         @@ -137,7 +137,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);
>         
>          /*
>           * Bus types
>         diff -purN linux.orig/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
>         --- linux.orig/include/asm-sparc/processor.h    Thu Oct 11 02:42:47 2001
>         +++ linux/include/asm-sparc/processor.h Thu Mar 13 13:35:18 2003
>         @@ -146,7 +146,7 @@ extern __inline__ void start_thread(stru
>         
>          /* Free all resources held by a thread. */
>          #define release_thread(tsk)            do { } while(0)
>         -extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
>         +extern pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
>         
>         
>          #define copy_segments(tsk, mm)         do { } while (0)
>         diff -purN linux.orig/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
>         --- linux.orig/include/asm-sparc64/processor.h  Thu Mar 13 12:01:36 2003
>         +++ linux/include/asm-sparc64/processor.h       Thu Mar 13 13:35:18 2003
>         @@ -270,7 +270,7 @@ do { \
>          /* Free all resources held by a thread. */
>          #define release_thread(tsk)            do { } while(0)
>         
>         -extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
>         +extern pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
>         
>          #define copy_segments(tsk, mm)         do { } while (0)
>          #define release_segments(mm)           do { } while (0)
>         diff -purN linux.orig/include/linux/sched.h linux/include/linux/sched.h
>         --- linux.orig/include/linux/sched.h    Thu Mar 13 12:01:57 2003
>         +++ linux/include/linux/sched.h Thu Mar 13 13:54:05 2003
>         @@ -362,6 +362,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;
>         @@ -485,6 +486,8 @@ struct task_struct {
>          #define PT_TRACESYSGOOD        0x00000008
>          #define PT_PTRACE_CAP  0x00000010      /* ptracer can follow suid-exec */
>         
>         +#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.
>         @@ -848,6 +851,8 @@ extern void FASTCALL(remove_wait_queue(w
>         
>          extern void wait_task_inactive(task_t * p);
>          extern void kick_if_running(task_t * p);
>         +extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
>         +
>         
>          #define __wait_event(wq, condition)                                    \
>          do {                                                                   \
>         diff -purN linux.orig/kernel/fork.c linux/kernel/fork.c
>         --- linux.orig/kernel/fork.c    Thu Mar 13 12:01:57 2003
>         +++ linux/kernel/fork.c Thu Mar 13 13:51:24 2003
>         @@ -28,6 +28,7 @@
>          #include <asm/pgalloc.h>
>          #include <asm/uaccess.h>
>          #include <asm/mmu_context.h>
>         +#include <asm/processor.h>
>         
>          /* The idle threads do not count.. */
>          int nr_threads;
>         @@ -575,6 +576,31 @@ static inline void copy_flags(unsigned l
>                 p->flags = new_flags;
>          }
>         
>         +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;
>         +}
>         +
>          /*
>           *  Ok, this is the main fork-routine. It copies the system process
>           * information (task[nr]) and sets up the necessary registers. It also
>         diff -purN linux.orig/kernel/ptrace.c linux/kernel/ptrace.c
>         --- linux.orig/kernel/ptrace.c  Thu Mar 13 12:01:46 2003
>         +++ linux/kernel/ptrace.c       Thu Mar 13 13:47:16 2003
>         @@ -21,6 +21,10 @@
>           */
>          int ptrace_check_attach(struct task_struct *child, int kill)
>          {
>         +       mb();
>         +       if (!is_dumpable(child))
>         +               return -EPERM;
>         +
>                 if (!(child->ptrace & PT_PTRACED))
>                         return -ESRCH;
>         
>         @@ -57,7 +61,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)
>         @@ -123,6 +127,8 @@ int access_process_vm(struct task_struct
>                 /* Worry about races with exit() */
>                 task_lock(tsk);
>                 mm = tsk->mm;
>         +       if (!is_dumpable(tsk) || (&init_mm == mm))
>         +               mm = NULL;
>                 if (mm)
>                         atomic_inc(&mm->mm_users);
>                 task_unlock(tsk);
>         diff -purN linux.orig/kernel/sys.c linux/kernel/sys.c
>         --- linux.orig/kernel/sys.c     Thu Mar 13 12:01:57 2003
>         +++ linux/kernel/sys.c  Thu Mar 13 13:41:25 2003
>         @@ -1286,7 +1286,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:
>         @@ -1294,7 +1294,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:
>          #ifdef SET_UNALIGN_CTL
>            _________________________________________________________________________________
>         
>            No comments have been posted. Log in to post comments.
>         
>                                                               Copyright (©) 2003, Eklektix, Inc.
>                                                     Linux (®) is a registered trademark of Linus Torvalds
>                                                             Web hosting provided by Rackspace.com.
>         -- 
>         ===============================================================================
>         Matthew Grant	     /\	 ^/\^	grantma@anathoth.gen.nz      /~~~~\
>         A Linux Network Guy /~~\^/~~\_/~~~~~\_______/~~~~~~~~~~\____/******\
>         ===GPG KeyID: 2EE20270  FingerPrint:
>         8C2535E1A11DF3EA5EA19125BA4E790E2EE20270==
>         
>         
>     
>     



Reply to: