diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/arch/i386/Kconfig linux-2.6.19.1/arch/i386/Kconfig --- linux-2.6.19.1-orig/arch/i386/Kconfig 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/arch/i386/Kconfig 2006-12-23 18:59:21.147582399 -0500 @@ -547,6 +547,10 @@ default y select RESOURCES_64BIT +config PROC_MM + bool "/proc/mm support" + default y + # Common NUMA Features config NUMA bool "Numa Memory Allocation and Scheduler Support" diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/arch/i386/kernel/ldt.c linux-2.6.19.1/arch/i386/kernel/ldt.c --- linux-2.6.19.1-orig/arch/i386/kernel/ldt.c 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/arch/i386/kernel/ldt.c 2006-12-23 19:02:30.346260763 -0500 @@ -28,11 +28,12 @@ } #endif -static int alloc_ldt(mm_context_t *pc, int mincount, int reload) +static int alloc_ldt(struct mm_struct *mm, int mincount, int reload) { void *oldldt; void *newldt; int oldsize; + mm_context_t * pc = &mm->context; if (mincount <= pc->size) return 0; @@ -59,13 +60,15 @@ #ifdef CONFIG_SMP cpumask_t mask; preempt_disable(); - load_LDT(pc); + if (¤t->active_mm->context == pc) + load_LDT(pc); mask = cpumask_of_cpu(smp_processor_id()); - if (!cpus_equal(current->mm->cpu_vm_mask, mask)) + if (!cpus_equal(mm->cpu_vm_mask, mask)) smp_call_function(flush_ldt, NULL, 1, 1); preempt_enable(); #else - load_LDT(pc); + if (¤t->active_mm->context == pc) + load_LDT(pc); #endif } if (oldsize) { @@ -77,12 +80,12 @@ return 0; } -static inline int copy_ldt(mm_context_t *new, mm_context_t *old) +static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old) { - int err = alloc_ldt(new, old->size, 0); + int err = alloc_ldt(new, old->context.size, 0); if (err < 0) return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE); return 0; } @@ -90,22 +93,24 @@ * we do not have to muck with descriptors here, that is * done in switch_mm() as needed. */ -int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +int copy_context(struct mm_struct *mm, struct mm_struct *old_mm) { - struct mm_struct * old_mm; int retval = 0; - init_MUTEX(&mm->context.sem); - mm->context.size = 0; - old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); - retval = copy_ldt(&mm->context, &old_mm->context); + retval = copy_ldt(mm, old_mm); up(&old_mm->context.sem); } return retval; } +int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + init_new_empty_context(mm); + return copy_context(mm, current->mm); +} + /* * No need to lock the MM as we are the last user */ @@ -122,11 +127,11 @@ } } -static int read_ldt(void __user * ptr, unsigned long bytecount) +static int read_ldt(struct mm_struct * mm, void __user * ptr, + unsigned long bytecount) { int err; unsigned long size; - struct mm_struct * mm = current->mm; if (!mm->context.size) return 0; @@ -175,9 +180,8 @@ return err; } -static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) +static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode) { - struct mm_struct * mm = current->mm; __u32 entry_1, entry_2; int error; struct user_desc ldt_info; @@ -201,7 +205,7 @@ down(&mm->context.sem); if (ldt_info.entry_number >= mm->context.size) { - error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); + error = alloc_ldt(mm, ldt_info.entry_number+1, 1); if (error < 0) goto out_unlock; } @@ -231,23 +235,33 @@ return error; } -asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, + unsigned long bytecount) { int ret = -ENOSYS; switch (func) { case 0: - ret = read_ldt(ptr, bytecount); + ret = read_ldt(mm, ptr, bytecount); break; case 1: - ret = write_ldt(ptr, bytecount, 1); + ret = write_ldt(mm, ptr, bytecount, 1); break; case 2: ret = read_default_ldt(ptr, bytecount); break; case 0x11: - ret = write_ldt(ptr, bytecount, 0); + ret = write_ldt(mm, ptr, bytecount, 0); break; } return ret; } + +asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +{ + int ret = __modify_ldt(current->mm, func, ptr, bytecount); + /* A tail call would reorder parameters on the stack and they would then + * be restored at the wrong places. */ + prevent_tail_call(ret); + return ret; +} diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/arch/i386/kernel/ptrace.c linux-2.6.19.1/arch/i386/kernel/ptrace.c --- linux-2.6.19.1-orig/arch/i386/kernel/ptrace.c 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/arch/i386/kernel/ptrace.c 2006-12-23 19:01:13.612236132 -0500 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -628,6 +629,58 @@ (struct user_desc __user *) data); break; +#ifdef CONFIG_PROC_MM + 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->mm, 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); + task_lock(child); + child->mm = new; + child->active_mm = new; + task_unlock(child); + mmput(old); + ret = 0; + break; + } +#endif + default: ret = ptrace_request(child, request, addr, data); break; diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/arch/i386/kernel/sys_i386.c linux-2.6.19.1/arch/i386/kernel/sys_i386.c --- linux-2.6.19.1-orig/arch/i386/kernel/sys_i386.c 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/arch/i386/kernel/sys_i386.c 2006-12-23 19:01:53.112982810 -0500 @@ -41,13 +41,12 @@ return error; } -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) +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) { int error = -EBADF; struct file *file = NULL; - struct mm_struct *mm = current->mm; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { @@ -57,7 +56,7 @@ } down_write(&mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff); up_write(&mm->mmap_sem); if (file) @@ -66,6 +65,18 @@ return error; } +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); + + /* A tail call would reorder parameters on the stack and they would then + * be restored at the wrong places. */ + prevent_tail_call(ret); + return ret; +} + /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux/i386 didn't use to be able to handle more than @@ -94,8 +105,11 @@ if (a.offset & ~PAGE_MASK) goto out; - err = sys_mmap2(a.addr, a.len, a.prot, a.flags, + err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + /* A tail call would reorder parameters on the stack and they would then + * be restored at the wrong places. */ + prevent_tail_call(err); out: return err; } diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/arch/um/include/skas_ptrace.h linux-2.6.19.1/arch/um/include/skas_ptrace.h --- linux-2.6.19.1-orig/arch/um/include/skas_ptrace.h 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/arch/um/include/skas_ptrace.h 2006-12-23 18:59:06.910917589 -0500 @@ -6,6 +6,8 @@ #ifndef __SKAS_PTRACE_H #define __SKAS_PTRACE_H +#ifndef PTRACE_FAULTINFO + #define PTRACE_FAULTINFO 52 #define PTRACE_SWITCH_MM 55 @@ -13,6 +15,8 @@ #endif +#endif + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/include/asm-i386/desc.h linux-2.6.19.1/include/asm-i386/desc.h --- linux-2.6.19.1-orig/include/asm-i386/desc.h 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/include/asm-i386/desc.h 2006-12-23 18:59:21.149581930 -0500 @@ -193,6 +193,9 @@ return base; } +extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, + unsigned long bytecount); + #endif /* !__ASSEMBLY__ */ #endif diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/include/asm-i386/mmu_context.h linux-2.6.19.1/include/asm-i386/mmu_context.h --- linux-2.6.19.1-orig/include/asm-i386/mmu_context.h 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/include/asm-i386/mmu_context.h 2006-12-23 18:59:37.211819087 -0500 @@ -5,13 +5,25 @@ #include #include #include +#include /* - * Used for LDT copy/destruction. + * Used for LDT initialization/destruction. You cannot copy an LDT with + * init_new_context, since it thinks you are passing it a new LDT and won't + * deallocate its old content. */ int init_new_context(struct task_struct *tsk, struct mm_struct *mm); void destroy_context(struct mm_struct *mm); +/* LDT initialization for a clean environment - needed for SKAS.*/ +static inline void init_new_empty_context(struct mm_struct *mm) +{ + init_MUTEX(&mm->context.sem); + mm->context.size = 0; +} + +/* LDT copy for SKAS - for the above problem.*/ +int copy_context(struct mm_struct *mm, struct mm_struct *old_mm); static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { @@ -28,6 +40,10 @@ { int cpu = smp_processor_id(); +#ifdef CONFIG_SMP + prev = per_cpu(cpu_tlbstate, cpu).active_mm; +#endif + if (likely(prev != next)) { /* stop flush ipis for the previous mm */ cpu_clear(cpu, prev->cpu_vm_mask); @@ -49,7 +65,6 @@ #ifdef CONFIG_SMP else { per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; - BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next); if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { /* We were in lazy tlb mode and leave_mm disabled diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/include/asm-i386/ptrace.h linux-2.6.19.1/include/asm-i386/ptrace.h --- linux-2.6.19.1-orig/include/asm-i386/ptrace.h 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/include/asm-i386/ptrace.h 2006-12-23 18:59:21.150581696 -0500 @@ -54,4 +54,26 @@ extern unsigned long profile_pc(struct pt_regs *regs); #endif /* __KERNEL__ */ +/*For SKAS3 support.*/ +#ifndef _LINUX_PTRACE_STRUCT_DEF +#define _LINUX_PTRACE_STRUCT_DEF + +#define PTRACE_FAULTINFO 52 +#define PTRACE_SIGPENDING 53 +#define PTRACE_LDT 54 +#define PTRACE_SWITCH_MM 55 + +struct ptrace_faultinfo { + int is_write; + unsigned long addr; +}; + +struct ptrace_ldt { + int func; + void *ptr; + unsigned long bytecount; +}; + +#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/ + #endif diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/include/linux/mm.h linux-2.6.19.1/include/linux/mm.h --- linux-2.6.19.1-orig/include/linux/mm.h 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/include/linux/mm.h 2006-12-23 18:59:06.907918292 -0500 @@ -996,9 +996,15 @@ 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, +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_pgoff(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flag, unsigned long pgoff); + unsigned long flag, unsigned long pgoff) { + return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff); +} static inline unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, @@ -1015,6 +1021,9 @@ extern int do_munmap(struct mm_struct *, unsigned long, size_t); +extern long do_mprotect(struct mm_struct *mm, unsigned long start, + size_t len, unsigned long prot); + extern unsigned long do_brk(unsigned long, unsigned long); /* filemap.c */ diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/include/linux/proc_mm.h linux-2.6.19.1/include/linux/proc_mm.h --- linux-2.6.19.1-orig/include/linux/proc_mm.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/include/linux/proc_mm.h 2006-12-23 18:59:06.908918057 -0500 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PROC_MM_H +#define __PROC_MM_H + +#include "linux/sched.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; +}; + +extern struct mm_struct *proc_mm_get_mm(int fd); + +#endif diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/localversion-skas linux-2.6.19.1/localversion-skas --- linux-2.6.19.1-orig/localversion-skas 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/localversion-skas 2006-12-23 19:02:36.297866584 -0500 @@ -0,0 +1 @@ +-skas3-v8.2 diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/mm/Makefile linux-2.6.19.1/mm/Makefile --- linux-2.6.19.1-orig/mm/Makefile 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/mm/Makefile 2006-12-23 18:59:06.908918057 -0500 @@ -29,3 +29,4 @@ obj-$(CONFIG_FS_XIP) += filemap_xip.o obj-$(CONFIG_MIGRATION) += migrate.o obj-$(CONFIG_SMP) += allocpercpu.o +obj-$(CONFIG_PROC_MM) += proc_mm.o diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/mm/mmap.c linux-2.6.19.1/mm/mmap.c --- linux-2.6.19.1-orig/mm/mmap.c 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/mm/mmap.c 2006-12-23 18:59:06.909917823 -0500 @@ -886,11 +886,11 @@ * The caller must hold down_write(current->mm->mmap_sem). */ -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; struct inode *inode; unsigned int vm_flags; @@ -1172,7 +1172,7 @@ return error; } -EXPORT_SYMBOL(do_mmap_pgoff); +EXPORT_SYMBOL(__do_mmap_pgoff); /* Get an address range which is currently unmapped. * For shmat() with addr=0. diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/mm/mprotect.c linux-2.6.19.1/mm/mprotect.c --- linux-2.6.19.1-orig/mm/mprotect.c 2006-11-29 16:57:37.000000000 -0500 +++ linux-2.6.19.1/mm/mprotect.c 2006-12-23 19:02:30.347260529 -0500 @@ -214,8 +214,9 @@ return error; } -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 vm_flags, nstart, end, tmp, reqprot; struct vm_area_struct *vma, *prev; @@ -245,9 +246,9 @@ vm_flags = calc_vm_prot_bits(prot); - down_write(¤t->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) goto out; @@ -309,6 +310,15 @@ } } out: - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); return error; } + +asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) +{ + long ret = do_mprotect(current->mm, start, len, prot); + /* A tail call would reorder parameters on the stack and they would then + * be restored at the wrong places. */ + prevent_tail_call(ret); + return ret; +} diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/mm/proc_mm.c linux-2.6.19.1/mm/proc_mm.c --- linux-2.6.19.1-orig/mm/proc_mm.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/mm/proc_mm.c 2006-12-23 19:00:10.463029512 -0500 @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "linux/init.h" +#include "linux/proc_fs.h" +#include "linux/proc_mm.h" +#include "linux/file.h" +#include "linux/mman.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; + + /* Nobody ever noticed it, but do_mmap_pgoff() calls + * get_unmapped_area() which checks current->mm, if + * MAP_FIXED is not set, so mmap() could replace + * an old mapping. + */ + if (! (map->flags & MAP_FIXED)) + return(-EINVAL); + + 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; + } + + ret = copy_context(mm, from); + if(ret == 0) + ret = count; + 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; + + init_new_empty_context(mm); + arch_pick_mmap_layout(mm); + + file->private_data = mm; + + return(0); + + 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: + */ diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/Add_generic_proc_mm_support.diff linux-2.6.19.1/skas/Add_generic_proc_mm_support.diff --- linux-2.6.19.1-orig/skas/Add_generic_proc_mm_support.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/Add_generic_proc_mm_support.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,396 @@ +Adds the arch-independent part of SKAS3 support. + +Fixes merged here: + +* Make SKAS and UML compile-time compatible +Avoid UML (and other archs, too) failing compilation when the SKAS+SYSEMU +patch is applied. + +* Avoid using current->mm while processing a /proc/mm request. +1) We have first a little fix for mprotect, which made it not work at all +and completely (which could explain why Java crashes Uml). +Actually, mprotect() worked onto the UML kernel address space. + +2) part of do_mmap_pgoff (actually arch_get_unmapped_area) has the same +bug, except if we call it with MAP_FIXED (as UML always does, see +arch/um/kernel/skas/mem_user.c:map()). So return -EINVAL otherwise +(actually, if we want to implement that later, we could return ENOSYS or +ENODEV, but for now the idea is that the interface only allows MAP_FIXED +mappings). Obviously, for SKAS4 it's a different matter, but in SKAS4 +it will work obviously. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/include/linux/mm.h +=================================================================== +--- linux-2.6.git.orig/include/linux/mm.h ++++ linux-2.6.git/include/linux/mm.h +@@ -1027,9 +1027,15 @@ extern int may_expand_vm(struct mm_struc + + 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, ++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_pgoff(struct file *file, unsigned long addr, + unsigned long len, unsigned long prot, +- unsigned long flag, unsigned long pgoff); ++ unsigned long flag, unsigned long pgoff) { ++ return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff); ++} + + static inline unsigned long do_mmap(struct file *file, unsigned long addr, + unsigned long len, unsigned long prot, +@@ -1046,6 +1052,9 @@ out: + + extern int do_munmap(struct mm_struct *, unsigned long, size_t); + ++extern long do_mprotect(struct mm_struct *mm, unsigned long start, ++ size_t len, unsigned long prot); ++ + extern unsigned long do_brk(unsigned long, unsigned long); + + /* filemap.c */ +Index: linux-2.6.git/include/linux/proc_mm.h +=================================================================== +--- /dev/null ++++ linux-2.6.git/include/linux/proc_mm.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __PROC_MM_H ++#define __PROC_MM_H ++ ++#include "linux/sched.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; ++}; ++ ++extern struct mm_struct *proc_mm_get_mm(int fd); ++ ++#endif +Index: linux-2.6.git/mm/Makefile +=================================================================== +--- linux-2.6.git.orig/mm/Makefile ++++ linux-2.6.git/mm/Makefile +@@ -29,3 +29,4 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_h + obj-$(CONFIG_FS_XIP) += filemap_xip.o + obj-$(CONFIG_MIGRATION) += migrate.o + obj-$(CONFIG_SMP) += allocpercpu.o ++obj-$(CONFIG_PROC_MM) += proc_mm.o +Index: linux-2.6.git/mm/mmap.c +=================================================================== +--- linux-2.6.git.orig/mm/mmap.c ++++ linux-2.6.git/mm/mmap.c +@@ -886,11 +886,11 @@ void vm_stat_account(struct mm_struct *m + * The caller must hold down_write(current->mm->mmap_sem). + */ + +-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; + struct inode *inode; + unsigned int vm_flags; +@@ -1172,7 +1172,7 @@ unacct_error: + return error; + } + +-EXPORT_SYMBOL(do_mmap_pgoff); ++EXPORT_SYMBOL(__do_mmap_pgoff); + + /* Get an address range which is currently unmapped. + * For shmat() with addr=0. +Index: linux-2.6.git/mm/mprotect.c +=================================================================== +--- linux-2.6.git.orig/mm/mprotect.c ++++ linux-2.6.git/mm/mprotect.c +@@ -214,8 +214,9 @@ fail: + return error; + } + +-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 vm_flags, nstart, end, tmp, reqprot; + struct vm_area_struct *vma, *prev; +@@ -245,9 +246,9 @@ sys_mprotect(unsigned long start, size_t + + vm_flags = calc_vm_prot_bits(prot); + +- down_write(¤t->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) + goto out; +@@ -316,6 +317,11 @@ sys_mprotect(unsigned long start, size_t + } + } + out: +- up_write(¤t->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)); ++} +Index: linux-2.6.git/mm/proc_mm.c +=================================================================== +--- /dev/null ++++ linux-2.6.git/mm/proc_mm.c +@@ -0,0 +1,183 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/mm.h" ++#include "linux/init.h" ++#include "linux/proc_fs.h" ++#include "linux/proc_mm.h" ++#include "linux/file.h" ++#include "linux/mman.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; ++ ++ /* Nobody ever noticed it, but do_mmap_pgoff() calls ++ * get_unmapped_area() which checks current->mm, if ++ * MAP_FIXED is not set, so mmap() could replace ++ * an old mapping. ++ */ ++ if (! (map->flags & MAP_FIXED)) ++ return(-EINVAL); ++ ++ 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; ++ } ++ ++ __init_new_context(mm, from); ++ 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, ¤t->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: ++ */ +Index: linux-2.6.git/arch/um/include/skas_ptrace.h +=================================================================== +--- linux-2.6.git.orig/arch/um/include/skas_ptrace.h ++++ linux-2.6.git/arch/um/include/skas_ptrace.h +@@ -6,6 +6,8 @@ + #ifndef __SKAS_PTRACE_H + #define __SKAS_PTRACE_H + ++#ifndef PTRACE_FAULTINFO ++ + #define PTRACE_FAULTINFO 52 + #define PTRACE_SWITCH_MM 55 + +@@ -13,6 +15,8 @@ + + #endif + ++#endif ++ + /* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/fix-dumpable-handling.diff linux-2.6.19.1/skas/fix-dumpable-handling.diff --- linux-2.6.19.1-orig/skas/fix-dumpable-handling.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/fix-dumpable-handling.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,252 @@ +SKAS3: fix mm->dumpable handling + +From: Paolo 'Blaisorblade' Giarrusso , Henrik Nordstrom , Michael Richardson + +When a child mm is created by opening /proc/mm, without this patch its +mm->dumpable flag is left set to 0, even when there is no reason to do so. + +This way, for instance, if is the pid of a userspace thread, +/proc/ is only readable by root (which was the original reason letting +this be diagnosed by Michael Richardson). + +Paolo and Henrik discussed about this in detail, finally Paolo wrote the patch +and sent it for comment. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/Kconfig +=================================================================== +--- linux-2.6.git.orig/arch/i386/Kconfig ++++ linux-2.6.git/arch/i386/Kconfig +@@ -551,6 +551,22 @@ config PROC_MM + bool "/proc/mm support" + default y + ++config PROC_MM_DUMPABLE ++ bool "Make UML childs /proc/ completely browsable" ++ default n ++ help ++ If in doubt, say N. ++ ++ This fiddles with some settings to make sure /proc/ is completely ++ browsable by who started UML, at the expense of some additional ++ locking (maybe this could slow down the runned UMLs of a few percents, ++ I've not tested this). ++ ++ Also, if there is a bug in this feature, there is some little ++ possibility to do privilege escalation if you have UML installed ++ setuid (which you shouldn't have done) or if UML changes uid on ++ startup (which will be a good thing, when enabled) ... ++ + # Common NUMA Features + config NUMA + bool "Numa Memory Allocation and Scheduler Support" +Index: linux-2.6.git/arch/i386/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ptrace.c ++++ linux-2.6.git/arch/i386/kernel/ptrace.c +@@ -671,10 +671,14 @@ long arch_ptrace(struct task_struct *chi + } + + atomic_inc(&new->mm_users); +- task_lock(child); ++ ++ lock_fix_dumpable_setting(child, new); ++ + child->mm = new; + child->active_mm = new; ++ + task_unlock(child); ++ + mmput(old); + ret = 0; + break; +Index: linux-2.6.git/arch/x86_64/ia32/ptrace32.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c ++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c +@@ -434,10 +434,14 @@ asmlinkage long sys32_ptrace(long reques + } + + atomic_inc(&new->mm_users); +- task_lock(child); ++ ++ lock_fix_dumpable_setting(child, new); ++ + child->mm = new; + child->active_mm = new; ++ + task_unlock(child); ++ + mmput(old); + ret = 0; + break; +Index: linux-2.6.git/arch/x86_64/Kconfig +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/Kconfig ++++ linux-2.6.git/arch/x86_64/Kconfig +@@ -463,6 +463,22 @@ config PROC_MM + bool "/proc/mm support" + default y + ++config PROC_MM_DUMPABLE ++ bool "Make UML childs /proc/ completely browsable" ++ default n ++ help ++ If in doubt, say N. ++ ++ This fiddles with some settings to make sure /proc/ is completely ++ browsable by who started UML, at the expense of some additional ++ locking (maybe this could slow down the runned UMLs of a few percents, ++ I've not tested this). ++ ++ Also, if there is a bug in this feature, there is some little ++ possibility to do privilege escalation if you have UML installed ++ setuid (which you shouldn't have done) or if UML changes uid on ++ startup (which will be a good thing, when enabled) ... ++ + config X86_MCE + bool "Machine check support" if EMBEDDED + default y +Index: linux-2.6.git/arch/x86_64/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ptrace.c ++++ linux-2.6.git/arch/x86_64/kernel/ptrace.c +@@ -610,10 +610,14 @@ long arch_ptrace(struct task_struct *chi + } + + atomic_inc(&new->mm_users); +- task_lock(child); ++ ++ lock_fix_dumpable_setting(child, new); ++ + child->mm = new; + child->active_mm = new; ++ + task_unlock(child); ++ + mmput(old); + ret = 0; + break; +Index: linux-2.6.git/include/linux/proc_mm.h +=================================================================== +--- linux-2.6.git.orig/include/linux/proc_mm.h ++++ linux-2.6.git/include/linux/proc_mm.h +@@ -8,6 +8,7 @@ + + #include + #include ++#include + + /* The differences between this one and do_mmap are that: + * - we must perform controls for userspace-supplied params (which are +@@ -90,4 +91,24 @@ struct proc_mm_op { + + extern struct mm_struct *proc_mm_get_mm(int fd); + ++/* Cope with older kernels */ ++#ifndef __acquires ++#define __acquires(x) ++#endif ++ ++#ifdef CONFIG_PROC_MM_DUMPABLE ++/* ++ * Since we take task_lock of child and it's needed also by the caller, we ++ * return with it locked. ++ */ ++extern void lock_fix_dumpable_setting(struct task_struct * child, ++ struct mm_struct* new) __acquires(child->alloc_lock); ++#else ++static inline void lock_fix_dumpable_setting(struct task_struct * child, ++ struct mm_struct* new) __acquires(child->alloc_lock) ++{ ++ task_lock(child); ++} ++#endif ++ + #endif +Index: linux-2.6.git/mm/proc_mm.c +=================================================================== +--- linux-2.6.git.orig/mm/proc_mm.c ++++ linux-2.6.git/mm/proc_mm.c +@@ -4,6 +4,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -13,6 +14,62 @@ + #include + #include + ++#ifdef CONFIG_PROC_MM_DUMPABLE ++/* Checks if a task must be considered dumpable ++ * ++ * XXX: copied from fs/proc/base.c, removed task_lock, added rmb(): this must be ++ * called with task_lock(task) held. */ ++static int task_dumpable(struct task_struct *task) ++{ ++ int dumpable = 0; ++ struct mm_struct *mm; ++ ++ mm = task->mm; ++ if (mm) { ++ rmb(); ++ dumpable = mm->dumpable; ++ } ++ return dumpable; ++} ++ ++/* ++ * This is to be used in PTRACE_SWITCH_MM handling. We are going to set ++ * child->mm to new, and we must first correctly set new->dumpable. ++ * Since we take task_lock of child and it's needed also by the caller, we ++ * return with it locked. ++ */ ++void lock_fix_dumpable_setting(struct task_struct* child, struct mm_struct* new) ++ __acquires(child->alloc_lock) ++{ ++ int dumpable = 1; ++ ++ /* We must be safe. ++ * If the child is ptraced from a non-dumpable process, ++ * let's not be dumpable. If the child is non-dumpable itself, ++ * copy this property across mm's. ++ * ++ * Don't try to be smart for the opposite case and turn ++ * child->mm->dumpable to 1: I've not made sure it is safe. ++ */ ++ ++ task_lock(current); ++ if (unlikely(!task_dumpable(current))) { ++ dumpable = 0; ++ } ++ task_unlock(current); ++ ++ task_lock(child); ++ if (likely(dumpable) && unlikely(!task_dumpable(child))) { ++ dumpable = 0; ++ } ++ ++ if (!dumpable) { ++ new->dumpable = 0; ++ wmb(); ++ } ++} ++#endif ++ + /* Naming conventions are a mess, so I note them down. + * + * Things ending in _mm can be for everything. It's only for +@@ -41,6 +98,10 @@ static int open_proc_mm(struct inode *in + + init_new_empty_context(mm); + arch_pick_mmap_layout(mm); ++#ifdef CONFIG_PROC_MM_DUMPABLE ++ mm->dumpable = current->mm->dumpable; ++ wmb(); ++#endif + + file->private_data = mm; + diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/handle-flexible-mmap-layout.diff linux-2.6.19.1/skas/handle-flexible-mmap-layout.diff --- linux-2.6.19.1-orig/skas/handle-flexible-mmap-layout.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/handle-flexible-mmap-layout.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,21 @@ +UML - SKAS: handle flexible mmap layout + +From: Paolo 'Blaisorblade' Giarrusso +When creating a new mm_struct by opening /proc/mm, call arch_pick_mmap_layout +as well, like is done in the rest of the kernel when creating a new mm_struct. +This is needed since 2.6.9 to support the flexible-mmap-layout patch by Ingo +Molnar. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/mm/proc_mm.c +=================================================================== +--- linux-2.6.git.orig/mm/proc_mm.c ++++ linux-2.6.git/mm/proc_mm.c +@@ -125,6 +125,7 @@ static int open_proc_mm(struct inode *in + goto out_mem; + + init_new_empty_context(mm); ++ arch_pick_mmap_layout(mm); + + spin_lock(&mmlist_lock); + list_add(&mm->mmlist, ¤t->mm->mmlist); diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/i386-specific.diff linux-2.6.19.1/skas/i386-specific.diff --- linux-2.6.19.1-orig/skas/i386-specific.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/i386-specific.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,355 @@ +i386-specific code. + +The main chunk of i386-specific code. Various fixes have not yet been merged +in this part. +Some have been, instead: + +* SKAS: rename modify_ldt to avoid conflicts + +SKAS adds a function modify_ldt (closely related to sys_modify_ldt) but the +declaration conflicts with some external code (ATI kernel modules). Since the +name is not important, rename the function to __modify_ldt. + +* Description of the SMP hack in include/asm-i386/mmu_context.h: + +From: Jeff Dike and me, Paolo Giarrusso +The removed panic can be triggered if it happens that: +1) a UML thread sleeps +2) a kernel-thread is scheduled on the same CPU and lazy-TLB switching is used +3) on any other CPU PTRACE_SWITCH_MM is called onto the sleeping thread +4) and the sleeping thread is rescheduled onto the same CPU; the same task is +going back BUT you need a context switch, since that task has changed its ->mm. + +By the way, the combination of 1), 3) and 4) is likely to occur (I think it +happens on every context switch inside the guest); the 2) part is the one not +always happening (when the CPU goes to sleep, indeed it runs with lazy-TLB the +idle thread, so 2) is happening). + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/Kconfig +=================================================================== +--- linux-2.6.git.orig/arch/i386/Kconfig ++++ linux-2.6.git/arch/i386/Kconfig +@@ -547,6 +547,10 @@ config X86_PAE + default y + select RESOURCES_64BIT + ++config PROC_MM ++ bool "/proc/mm support" ++ default y ++ + # Common NUMA Features + config NUMA + bool "Numa Memory Allocation and Scheduler Support" +Index: linux-2.6.git/arch/i386/kernel/ldt.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ldt.c ++++ linux-2.6.git/arch/i386/kernel/ldt.c +@@ -55,7 +55,7 @@ static int alloc_ldt(mm_context_t *pc, i + pc->size = mincount; + wmb(); + +- if (reload) { ++ if (reload && (¤t->active_mm->context == pc)) { + #ifdef CONFIG_SMP + cpumask_t mask; + preempt_disable(); +@@ -90,14 +90,12 @@ static inline int copy_ldt(mm_context_t + * we do not have to muck with descriptors here, that is + * done in switch_mm() as needed. + */ +-int init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm) + { +- struct mm_struct * old_mm; + int retval = 0; + + init_MUTEX(&mm->context.sem); + mm->context.size = 0; +- old_mm = current->mm; + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); + retval = copy_ldt(&mm->context, &old_mm->context); +@@ -106,6 +104,11 @@ int init_new_context(struct task_struct + return retval; + } + ++int init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ return __init_new_context(mm, current->mm); ++} ++ + /* + * No need to lock the MM as we are the last user + */ +@@ -122,11 +125,11 @@ void destroy_context(struct mm_struct *m + } + } + +-static int read_ldt(void __user * ptr, unsigned long bytecount) ++static int read_ldt(struct mm_struct * mm, void __user * ptr, ++ unsigned long bytecount) + { + int err; + unsigned long size; +- struct mm_struct * mm = current->mm; + + if (!mm->context.size) + return 0; +@@ -175,9 +178,8 @@ static int read_default_ldt(void __user + return err; + } + +-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) ++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode) + { +- struct mm_struct * mm = current->mm; + __u32 entry_1, entry_2; + int error; + struct user_desc ldt_info; +@@ -201,7 +203,7 @@ static int write_ldt(void __user * ptr, + + down(&mm->context.sem); + if (ldt_info.entry_number >= mm->context.size) { +- error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); ++ error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1); + if (error < 0) + goto out_unlock; + } +@@ -231,23 +233,29 @@ out: + return error; + } + +-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) ++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, ++ unsigned long bytecount) + { + int ret = -ENOSYS; + + switch (func) { + case 0: +- ret = read_ldt(ptr, bytecount); ++ ret = read_ldt(mm, ptr, bytecount); + break; + case 1: +- ret = write_ldt(ptr, bytecount, 1); ++ ret = write_ldt(mm, ptr, bytecount, 1); + break; + case 2: + ret = read_default_ldt(ptr, bytecount); + break; + case 0x11: +- ret = write_ldt(ptr, bytecount, 0); ++ ret = write_ldt(mm, ptr, bytecount, 0); + break; + } + return ret; + } ++ ++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) ++{ ++ return __modify_ldt(current->mm, func, ptr, bytecount); ++} +Index: linux-2.6.git/arch/i386/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ptrace.c ++++ linux-2.6.git/arch/i386/kernel/ptrace.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -628,6 +629,56 @@ long arch_ptrace(struct task_struct *chi + (struct user_desc __user *) data); + break; + ++#ifdef CONFIG_PROC_MM ++ 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->mm, 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; ++ } ++#endif ++ + default: + ret = ptrace_request(child, request, addr, data); + break; +Index: linux-2.6.git/arch/i386/kernel/sys_i386.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/sys_i386.c ++++ linux-2.6.git/arch/i386/kernel/sys_i386.c +@@ -41,13 +41,12 @@ asmlinkage int sys_pipe(unsigned long __ + return error; + } + +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) ++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) + { + int error = -EBADF; + struct file *file = NULL; +- struct mm_struct *mm = current->mm; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { +@@ -57,7 +56,7 @@ asmlinkage long sys_mmap2(unsigned long + } + + down_write(&mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); ++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff); + up_write(&mm->mmap_sem); + + if (file) +@@ -66,6 +65,13 @@ out: + return error; + } + ++asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long pgoff) ++{ ++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); ++} ++ + /* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/i386 didn't use to be able to handle more than +@@ -94,7 +100,7 @@ asmlinkage int old_mmap(struct mmap_arg_ + if (a.offset & ~PAGE_MASK) + goto out; + +- err = sys_mmap2(a.addr, a.len, a.prot, a.flags, ++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, + a.fd, a.offset >> PAGE_SHIFT); + out: + return err; +Index: linux-2.6.git/include/asm-i386/desc.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/desc.h ++++ linux-2.6.git/include/asm-i386/desc.h +@@ -193,6 +193,9 @@ static inline unsigned long get_desc_bas + return base; + } + ++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, ++ unsigned long bytecount); ++ + #endif /* !__ASSEMBLY__ */ + + #endif +Index: linux-2.6.git/include/asm-i386/processor.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/processor.h ++++ linux-2.6.git/include/asm-i386/processor.h +@@ -721,6 +721,8 @@ static inline void prefetchw(const void + + extern void select_idle_routine(const struct cpuinfo_x86 *c); + ++extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm); ++ + #define cache_line_size() (boot_cpu_data.x86_cache_alignment) + + extern unsigned long boot_option_idle_override; +Index: linux-2.6.git/include/asm-i386/ptrace.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/ptrace.h ++++ linux-2.6.git/include/asm-i386/ptrace.h +@@ -54,4 +54,26 @@ static inline int user_mode_vm(struct pt + extern unsigned long profile_pc(struct pt_regs *regs); + #endif /* __KERNEL__ */ + ++/*For SKAS3 support.*/ ++#ifndef _LINUX_PTRACE_STRUCT_DEF ++#define _LINUX_PTRACE_STRUCT_DEF ++ ++#define PTRACE_FAULTINFO 52 ++#define PTRACE_SIGPENDING 53 ++#define PTRACE_LDT 54 ++#define PTRACE_SWITCH_MM 55 ++ ++struct ptrace_faultinfo { ++ int is_write; ++ unsigned long addr; ++}; ++ ++struct ptrace_ldt { ++ int func; ++ void *ptr; ++ unsigned long bytecount; ++}; ++ ++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/ ++ + #endif +Index: linux-2.6.git/include/asm-i386/mmu_context.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/mmu_context.h ++++ linux-2.6.git/include/asm-i386/mmu_context.h +@@ -28,6 +28,10 @@ static inline void switch_mm(struct mm_s + { + int cpu = smp_processor_id(); + ++#ifdef CONFIG_SMP ++ prev = per_cpu(cpu_tlbstate, cpu).active_mm; ++#endif ++ + if (likely(prev != next)) { + /* stop flush ipis for the previous mm */ + cpu_clear(cpu, prev->cpu_vm_mask); +@@ -49,7 +53,6 @@ static inline void switch_mm(struct mm_s + #ifdef CONFIG_SMP + else { + per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; +- BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next); + + if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { + /* We were in lazy tlb mode and leave_mm disabled diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/include-proto.diff linux-2.6.19.1/skas/include-proto.diff --- linux-2.6.19.1-orig/skas/include-proto.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/include-proto.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,12 @@ +Index: linux-2.6.git/arch/i386/kernel/sys_i386.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/sys_i386.c ++++ linux-2.6.git/arch/i386/kernel/sys_i386.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + /* + * sys_pipe() is the normal C calling standard for creating diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/localversion-v9-pre9.diff linux-2.6.19.1/skas/localversion-v9-pre9.diff --- linux-2.6.19.1-orig/skas/localversion-v9-pre9.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/localversion-v9-pre9.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,7 @@ +Index: linux-2.6.git/localversion-skas +=================================================================== +--- linux-2.6.git.orig/localversion-skas ++++ linux-2.6.git/localversion-skas +@@ -1 +1 @@ +--skas3-v9-pre8 ++-skas3-v9-pre9 diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/ptrace_ldt-reload-smp-fix.diff linux-2.6.19.1/skas/ptrace_ldt-reload-smp-fix.diff --- linux-2.6.19.1-orig/skas/ptrace_ldt-reload-smp-fix.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/ptrace_ldt-reload-smp-fix.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,90 @@ +SKAS3: Bug for PTRACE_LDT on SMP host. + +From: Bodo Stroesser + +The SKAS3 host patch isn't smp-safe. + +The wrong part is the implementation of PTRACE_LDT. +If the ptraced child runs on an other processor than its parent, +and the child's mm still is the active_mm, the changed LDT +isn't flushed out. +The problem occurs in alloc_ldt, but to fix this, I had to +change the params of copy_ldt, too. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/kernel/ldt.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ldt.c ++++ linux-2.6.git/arch/i386/kernel/ldt.c +@@ -28,11 +28,12 @@ static void flush_ldt(void *null) + } + #endif + +-static int alloc_ldt(mm_context_t *pc, int mincount, int reload) ++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload) + { + void *oldldt; + void *newldt; + int oldsize; ++ mm_context_t * pc = &mm->context; + + if (mincount <= pc->size) + return 0; +@@ -55,17 +56,19 @@ static int alloc_ldt(mm_context_t *pc, i + pc->size = mincount; + wmb(); + +- if (reload && (¤t->active_mm->context == pc)) { ++ if (reload) { + #ifdef CONFIG_SMP + cpumask_t mask; + preempt_disable(); +- load_LDT(pc); ++ if (¤t->active_mm->context == pc) ++ load_LDT(pc); + mask = cpumask_of_cpu(smp_processor_id()); +- if (!cpus_equal(current->mm->cpu_vm_mask, mask)) ++ if (!cpus_equal(mm->cpu_vm_mask, mask)) + smp_call_function(flush_ldt, NULL, 1, 1); + preempt_enable(); + #else +- load_LDT(pc); ++ if (¤t->active_mm->context == pc) ++ load_LDT(pc); + #endif + } + if (oldsize) { +@@ -77,12 +80,12 @@ static int alloc_ldt(mm_context_t *pc, i + return 0; + } + +-static inline int copy_ldt(mm_context_t *new, mm_context_t *old) ++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old) + { +- int err = alloc_ldt(new, old->size, 0); ++ int err = alloc_ldt(new, old->context.size, 0); + if (err < 0) + return err; +- memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); ++ memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE); + return 0; + } + +@@ -96,7 +99,7 @@ int copy_context(struct mm_struct *mm, s + + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); +- retval = copy_ldt(&mm->context, &old_mm->context); ++ retval = copy_ldt(mm, old_mm); + up(&old_mm->context.sem); + } + return retval; +@@ -202,7 +205,7 @@ static int write_ldt(struct mm_struct * + + down(&mm->context.sem); + if (ldt_info.entry_number >= mm->context.size) { +- error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1); ++ error = alloc_ldt(mm, ldt_info.entry_number+1, 1); + if (error < 0) + goto out_unlock; + } diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/ptrace_ldt-reload-smp-fix-x86-64.diff linux-2.6.19.1/skas/ptrace_ldt-reload-smp-fix-x86-64.diff --- linux-2.6.19.1-orig/skas/ptrace_ldt-reload-smp-fix-x86-64.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/ptrace_ldt-reload-smp-fix-x86-64.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,91 @@ +SKAS3: Bug for PTRACE_LDT on SMP host. + +From: Bodo Stroesser + +The SKAS3 host patch isn't smp-safe. + +The wrong part is the implementation of PTRACE_LDT. +If the ptraced child runs on an other processor than its parent, +and the child's mm still is the active_mm, the changed LDT +isn't flushed out. +The problem occurs in alloc_ldt, but to fix this, I had to +change the params of copy_ldt, too. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/x86_64/kernel/ldt.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ldt.c ++++ linux-2.6.git/arch/x86_64/kernel/ldt.c +@@ -32,11 +32,12 @@ static void flush_ldt(void *null) + } + #endif + +-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload) ++static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload) + { + void *oldldt; + void *newldt; + unsigned oldsize; ++ mm_context_t * pc = &mm->context; + + if (mincount <= (unsigned)pc->size) + return 0; +@@ -59,18 +60,20 @@ static int alloc_ldt(mm_context_t *pc, u + wmb(); + pc->size = mincount; + wmb(); +- if (reload && (¤t->active_mm->context == pc)) { ++ if (reload) { + #ifdef CONFIG_SMP + cpumask_t mask; + + preempt_disable(); + mask = cpumask_of_cpu(smp_processor_id()); +- load_LDT(pc); +- if (!cpus_equal(current->mm->cpu_vm_mask, mask)) ++ if (¤t->active_mm->context == pc) ++ load_LDT(pc); ++ if (!cpus_equal(mm->cpu_vm_mask, mask)) + smp_call_function(flush_ldt, NULL, 1, 1); + preempt_enable(); + #else +- load_LDT(pc); ++ if (¤t->active_mm->context == pc) ++ load_LDT(pc); + #endif + } + if (oldsize) { +@@ -82,12 +85,12 @@ static int alloc_ldt(mm_context_t *pc, u + return 0; + } + +-static inline int copy_ldt(mm_context_t *new, mm_context_t *old) ++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old) + { +- int err = alloc_ldt(new, old->size, 0); ++ int err = alloc_ldt(new, old->context.size, 0); + if (err < 0) + return err; +- memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); ++ memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE); + return 0; + } + +@@ -101,7 +104,7 @@ int copy_context(struct mm_struct *mm, s + + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); +- retval = copy_ldt(&mm->context, &old_mm->context); ++ retval = copy_ldt(mm, old_mm); + up(&old_mm->context.sem); + } + return retval; +@@ -198,7 +201,7 @@ static int write_ldt(struct mm_struct * + + down(&mm->context.sem); + if (ldt_info.entry_number >= (unsigned)mm->context.size) { +- error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1); ++ error = alloc_ldt(mm, ldt_info.entry_number+1, 1); + if (error < 0) + goto out_unlock; + } diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/remove-donothing-statement.diff linux-2.6.19.1/skas/remove-donothing-statement.diff --- linux-2.6.19.1-orig/skas/remove-donothing-statement.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/remove-donothing-statement.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,44 @@ +Index: linux-2.6.git/arch/i386/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ptrace.c ++++ linux-2.6.git/arch/i386/kernel/ptrace.c +@@ -639,8 +639,6 @@ long arch_ptrace(struct task_struct *chi + .trap_no = child->thread.trap_no }); + ret = copy_to_user((unsigned long *) data, &fault, + sizeof(fault)); +- if(ret) +- break; + break; + } + +@@ -652,8 +650,6 @@ long arch_ptrace(struct task_struct *chi + .addr = child->thread.cr2 }); + ret = copy_to_user((unsigned long *) data, &fault, + sizeof(fault)); +- if(ret) +- break; + break; + } + +Index: linux-2.6.git/arch/x86_64/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ptrace.c ++++ linux-2.6.git/arch/x86_64/kernel/ptrace.c +@@ -578,8 +578,6 @@ long arch_ptrace(struct task_struct *chi + .trap_no = child->thread.trap_no }); + ret = copy_to_user((unsigned long *) data, &fault, + sizeof(fault)); +- if(ret) +- break; + break; + } + +@@ -596,8 +594,6 @@ long arch_ptrace(struct task_struct *chi + .addr = child->thread.cr2 }); + ret = copy_to_user((unsigned long *) data, &fault, + sizeof(fault)); +- if(ret) +- break; + break; + } + #endif diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-add-locking-for-mm-switch.diff linux-2.6.19.1/skas/skas-add-locking-for-mm-switch.diff --- linux-2.6.19.1-orig/skas/skas-add-locking-for-mm-switch.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-add-locking-for-mm-switch.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,39 @@ +SKAS3: add locking around ->mm for PTRACE_SWITCH_MM + +From: Paolo 'Blaisorblade' Giarrusso + +I just discovered that task_lock() and task_unlock() is used to protect +task_struct->mm... so this patch makes sure it is used for this purpose in +SKAS code. + +Seeing this comment: + +/* + * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm and + * synchronises with wait4(). + * + * Nests both inside and outside of read_lock(&tasklist_lock). + * It must not be nested with write_lock_irq(&tasklist_lock), + * neither inside nor outside. + */ +static inline void task_lock(struct task_struct *p) + +I've verified to some extent that it is called even without holding +tasklist_lock (for instance during execve). + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ptrace.c ++++ linux-2.6.git/arch/i386/kernel/ptrace.c +@@ -671,8 +671,10 @@ long arch_ptrace(struct task_struct *chi + } + + atomic_inc(&new->mm_users); ++ task_lock(child); + child->mm = new; + child->active_mm = new; ++ task_unlock(child); + mmput(old); + ret = 0; + break; diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-add-locking-for-mm-switch-x86-64.diff linux-2.6.19.1/skas/skas-add-locking-for-mm-switch-x86-64.diff --- linux-2.6.19.1-orig/skas/skas-add-locking-for-mm-switch-x86-64.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-add-locking-for-mm-switch-x86-64.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,56 @@ +SKAS3: add locking around ->mm for PTRACE_SWITCH_MM + +From: Paolo 'Blaisorblade' Giarrusso + +x86-64 port of skas-add-locking-for-mm-switch. Original changelog follows. + +I just discovered that task_lock() and task_unlock() is used to protect +task_struct->mm... so this patch makes sure it is used for this purpose in +SKAS code. + +Seeing this comment: + +/* + * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm and + * synchronises with wait4(). + * + * Nests both inside and outside of read_lock(&tasklist_lock). + * It must not be nested with write_lock_irq(&tasklist_lock), + * neither inside nor outside. + */ +static inline void task_lock(struct task_struct *p) + +I've verified to some extent that it is called even without holding +tasklist_lock (for instance during execve). + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/x86_64/ia32/ptrace32.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c ++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c +@@ -434,8 +434,10 @@ asmlinkage long sys32_ptrace(long reques + } + + atomic_inc(&new->mm_users); ++ task_lock(child); + child->mm = new; + child->active_mm = new; ++ task_unlock(child); + mmput(old); + ret = 0; + break; +Index: linux-2.6.git/arch/x86_64/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ptrace.c ++++ linux-2.6.git/arch/x86_64/kernel/ptrace.c +@@ -610,8 +610,10 @@ long arch_ptrace(struct task_struct *chi + } + + atomic_inc(&new->mm_users); ++ task_lock(child); + child->mm = new; + child->active_mm = new; ++ task_unlock(child); + mmput(old); + ret = 0; + break; diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-ex-faultinfo.diff linux-2.6.19.1/skas/skas-ex-faultinfo.diff --- linux-2.6.19.1-orig/skas/skas-ex-faultinfo.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-ex-faultinfo.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,156 @@ +skas-ex-faultinfo + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ptrace.c ++++ linux-2.6.git/arch/i386/kernel/ptrace.c +@@ -630,6 +630,20 @@ long arch_ptrace(struct task_struct *chi + break; + + #ifdef CONFIG_PROC_MM ++ case PTRACE_EX_FAULTINFO: { ++ struct ptrace_ex_faultinfo fault; ++ ++ fault = ((struct ptrace_ex_faultinfo) ++ { .is_write = child->thread.error_code, ++ .addr = child->thread.cr2, ++ .trap_no = child->thread.trap_no }); ++ ret = copy_to_user((unsigned long *) data, &fault, ++ sizeof(fault)); ++ if(ret) ++ break; ++ break; ++ } ++ + case PTRACE_FAULTINFO: { + struct ptrace_faultinfo fault; + +Index: linux-2.6.git/arch/x86_64/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ptrace.c ++++ linux-2.6.git/arch/x86_64/kernel/ptrace.c +@@ -566,6 +566,25 @@ long arch_ptrace(struct task_struct *chi + } + + #ifdef CONFIG_PROC_MM ++ case PTRACE_EX_FAULTINFO: { ++ struct ptrace_ex_faultinfo fault; ++ ++ /* I checked in thread_struct comments that error_code and cr2 ++ * are still part of the "fault info" section, so I guess that ++ * things are unchanged for now. Still to check manuals. BB*/ ++ fault = ((struct ptrace_ex_faultinfo) ++ { .is_write = child->thread.error_code, ++ .addr = child->thread.cr2, ++ .trap_no = child->thread.trap_no }); ++ ret = copy_to_user((unsigned long *) data, &fault, ++ sizeof(fault)); ++ if(ret) ++ break; ++ break; ++ } ++ ++ /*Don't extend this broken interface to x86-64*/ ++#if 0 + case PTRACE_FAULTINFO: { + struct ptrace_faultinfo fault; + +@@ -581,6 +600,7 @@ long arch_ptrace(struct task_struct *chi + break; + break; + } ++#endif + + case PTRACE_LDT: { + struct ptrace_ldt ldt; +Index: linux-2.6.git/include/asm-i386/ptrace.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/ptrace.h ++++ linux-2.6.git/include/asm-i386/ptrace.h +@@ -62,12 +62,19 @@ extern unsigned long profile_pc(struct p + /* 53 was used for PTRACE_SIGPENDING, don't reuse it. */ + #define PTRACE_LDT 54 + #define PTRACE_SWITCH_MM 55 ++#define PTRACE_EX_FAULTINFO 56 + + struct ptrace_faultinfo { + int is_write; + unsigned long addr; + }; + ++struct ptrace_ex_faultinfo { ++ int is_write; ++ unsigned long addr; ++ int trap_no; ++}; ++ + struct ptrace_ldt { + int func; + void *ptr; +Index: linux-2.6.git/include/asm-x86_64/ptrace.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/ptrace.h ++++ linux-2.6.git/include/asm-x86_64/ptrace.h +@@ -90,6 +90,12 @@ struct ptrace_faultinfo32 { + compat_ulong_t addr; + }; + ++struct ptrace_ex_faultinfo32 { ++ compat_int_t is_write; ++ compat_ulong_t addr; ++ compat_int_t trap_no; ++}; ++ + struct ptrace_ldt32 { + compat_int_t func; + compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/ +@@ -101,6 +107,12 @@ struct ptrace_faultinfo { + unsigned long addr; + }; + ++struct ptrace_ex_faultinfo { ++ int is_write; ++ unsigned long addr; ++ int trap_no; ++}; ++ + struct ptrace_ldt { + int func; + void *ptr; +Index: linux-2.6.git/include/asm-x86_64/ptrace-abi.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/ptrace-abi.h ++++ linux-2.6.git/include/asm-x86_64/ptrace-abi.h +@@ -46,6 +46,7 @@ + /* 53 was used for PTRACE_SIGPENDING, don't reuse it. */ + #define PTRACE_LDT 54 + #define PTRACE_SWITCH_MM 55 ++#define PTRACE_EX_FAULTINFO 56 + + /* only useful for access 32bit programs */ + #define PTRACE_GET_THREAD_AREA 25 +Index: linux-2.6.git/arch/x86_64/ia32/ptrace32.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c ++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c +@@ -395,6 +395,18 @@ asmlinkage long sys32_ptrace(long reques + break; + } + #ifdef CONFIG_PROC_MM ++ case PTRACE_EX_FAULTINFO: { ++ struct ptrace_ex_faultinfo32 fault; ++ ++ fault = ((struct ptrace_ex_faultinfo32) ++ { .is_write = (compat_int_t) child->thread.error_code, ++ .addr = (compat_uptr_t) child->thread.cr2, ++ .trap_no = (compat_int_t) child->thread.trap_no }); ++ ret = copy_to_user((unsigned long *) datap, &fault, ++ sizeof(fault)); ++ break; ++ } ++ + case PTRACE_FAULTINFO: { + struct ptrace_faultinfo32 fault; + diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-localversion-v8_1.diff linux-2.6.19.1/skas/skas-localversion-v8_1.diff --- linux-2.6.19.1-orig/skas/skas-localversion-v8_1.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-localversion-v8_1.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,11 @@ +skas-localversion-v8_5 + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/localversion-skas +=================================================================== +--- linux-2.6.git.orig/localversion-skas ++++ linux-2.6.git/localversion-skas +@@ -1 +1 @@ +--skas3-v8 ++-skas3-v8.1 diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-localversion-v8_2.diff linux-2.6.19.1/skas/skas-localversion-v8_2.diff --- linux-2.6.19.1-orig/skas/skas-localversion-v8_2.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-localversion-v8_2.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,11 @@ +skas-localversion-v8_2 + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/localversion-skas +=================================================================== +--- linux-2.6.git.orig/localversion-skas ++++ linux-2.6.git/localversion-skas +@@ -1 +1 @@ +--skas3-v8.1 ++-skas3-v8.2 diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-localversion-v8.diff linux-2.6.19.1/skas/skas-localversion-v8.diff --- linux-2.6.19.1-orig/skas/skas-localversion-v8.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-localversion-v8.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,10 @@ +skas-localversion-v8 + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/localversion-skas +=================================================================== +--- /dev/null ++++ linux-2.6.git/localversion-skas +@@ -0,0 +1 @@ ++-skas3-v8 diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-localversion-v9-pre7.diff linux-2.6.19.1/skas/skas-localversion-v9-pre7.diff --- linux-2.6.19.1-orig/skas/skas-localversion-v9-pre7.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-localversion-v9-pre7.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,11 @@ +skas-localversion-v9-pre7 + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/localversion-skas +=================================================================== +--- linux-2.6.git.orig/localversion-skas ++++ linux-2.6.git/localversion-skas +@@ -1 +1 @@ +--skas3-v8.2 ++-skas3-v9-pre7 diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-localversion-v9-pre8.diff linux-2.6.19.1/skas/skas-localversion-v9-pre8.diff --- linux-2.6.19.1-orig/skas/skas-localversion-v9-pre8.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-localversion-v9-pre8.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,7 @@ +Index: linux-2.6.git/localversion-skas +=================================================================== +--- linux-2.6.git.orig/localversion-skas ++++ linux-2.6.git/localversion-skas +@@ -1 +1 @@ +--skas3-v9-pre7 ++-skas3-v9-pre8 diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-mm-debug.diff linux-2.6.19.1/skas/skas-mm-debug.diff --- linux-2.6.19.1-orig/skas/skas-mm-debug.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-mm-debug.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,72 @@ +skas-mm-debug + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/mm/Makefile +=================================================================== +--- linux-2.6.git.orig/mm/Makefile ++++ linux-2.6.git/mm/Makefile +@@ -30,3 +30,7 @@ obj-$(CONFIG_FS_XIP) += filemap_xip.o + obj-$(CONFIG_MIGRATION) += migrate.o + obj-$(CONFIG_SMP) += allocpercpu.o + obj-$(CONFIG_PROC_MM) += proc_mm.o ++ ++ifeq ($(CONFIG_PROC_MM),y) ++obj-m += proc_mm-mod.o ++endif +Index: linux-2.6.git/mm/proc_mm-mod.c +=================================================================== +--- /dev/null ++++ linux-2.6.git/mm/proc_mm-mod.c +@@ -0,0 +1,51 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_64BIT ++#define PRINT_OFFSET(type, member) \ ++ printk(KERN_DEBUG "struct " #type "32->" #member " \t: %ld\n", (long) offsetof(struct type ## 32, member)) ++#else ++#define PRINT_OFFSET(type, member) \ ++ printk(KERN_DEBUG "struct " #type "->" #member " \t: %ld\n", (long) offsetof(struct type, member)) ++#endif ++ ++static int debug_printoffsets(void) ++{ ++ printk(KERN_DEBUG "Skas core structures layout BEGIN:\n"); ++ PRINT_OFFSET(mm_mmap, addr); ++ PRINT_OFFSET(mm_mmap, len); ++ PRINT_OFFSET(mm_mmap, prot); ++ PRINT_OFFSET(mm_mmap, flags); ++ PRINT_OFFSET(mm_mmap, fd); ++ PRINT_OFFSET(mm_mmap, offset); ++ ++ PRINT_OFFSET(mm_munmap, addr); ++ PRINT_OFFSET(mm_munmap, len); ++ ++ PRINT_OFFSET(mm_mprotect, addr); ++ PRINT_OFFSET(mm_mprotect, len); ++ PRINT_OFFSET(mm_mprotect, prot); ++ ++ PRINT_OFFSET(proc_mm_op, op); ++ PRINT_OFFSET(proc_mm_op, u); ++ PRINT_OFFSET(proc_mm_op, u.mmap); ++ PRINT_OFFSET(proc_mm_op, u.munmap); ++ PRINT_OFFSET(proc_mm_op, u.mprotect); ++ PRINT_OFFSET(proc_mm_op, u.copy_segments); ++ ++ PRINT_OFFSET(ptrace_faultinfo, is_write); ++ PRINT_OFFSET(ptrace_faultinfo, addr); ++ ++ PRINT_OFFSET(ptrace_ldt, func); ++ PRINT_OFFSET(ptrace_ldt, ptr); ++ PRINT_OFFSET(ptrace_ldt, bytecount); ++ printk(KERN_DEBUG "Skas core structures layout END.\n"); ++ ++ return 0; ++} ++#undef PRINT_OFFSET ++ ++module_init(debug_printoffsets); diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-new-leak-fix.diff linux-2.6.19.1/skas/skas-new-leak-fix.diff --- linux-2.6.19.1-orig/skas/skas-new-leak-fix.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-new-leak-fix.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,127 @@ +UML - SKAS: avoid leak of kernel memory by SKAS patch. + +Part 1: fix the kernel leak. +init_new_context was called, and then __init_new_context; they both clear +the LDT (by setting its size to 0) and alloc a new one; and since the LDT size +has been cleared, alloc_ldt does not free() the LDT. It it exposed only if actually +the UML process has an LDT to allocate, i.e. if the UML kernel thread had an LDT +on the host when forking the init process. + +Part 2: avoid allocating a useless LDT for the init inside UML. +Until now, when opening /proc/mm the SKAS patch copied the current LDT +like on fork(). +Since currently UML does not expect the userspace thread to inherit +its own LDT, we can avoid this and save 4k for each child (useful when hosting +lots of UML). And besides, that was waste memory. + +Actually UML never sets its one LDT, since it does not use +TLS; it can just inherits it from his fathers, but it's useless. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/kernel/ldt.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ldt.c ++++ linux-2.6.git/arch/i386/kernel/ldt.c +@@ -90,12 +90,10 @@ static inline int copy_ldt(mm_context_t + * we do not have to muck with descriptors here, that is + * done in switch_mm() as needed. + */ +-int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm) ++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm) + { + int retval = 0; + +- init_MUTEX(&mm->context.sem); +- mm->context.size = 0; + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); + retval = copy_ldt(&mm->context, &old_mm->context); +@@ -106,7 +104,8 @@ int __init_new_context(struct mm_struct + + int init_new_context(struct task_struct *tsk, struct mm_struct *mm) + { +- return __init_new_context(mm, current->mm); ++ init_new_empty_context(mm); ++ return copy_context(mm, current->mm); + } + + /* +Index: linux-2.6.git/include/asm-i386/mmu_context.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/mmu_context.h ++++ linux-2.6.git/include/asm-i386/mmu_context.h +@@ -5,13 +5,25 @@ + #include + #include + #include ++#include + + /* +- * Used for LDT copy/destruction. ++ * Used for LDT initialization/destruction. You cannot copy an LDT with ++ * init_new_context, since it thinks you are passing it a new LDT and won't ++ * deallocate its old content. + */ + int init_new_context(struct task_struct *tsk, struct mm_struct *mm); + void destroy_context(struct mm_struct *mm); + ++/* LDT initialization for a clean environment - needed for SKAS.*/ ++static inline void init_new_empty_context(struct mm_struct *mm) ++{ ++ init_MUTEX(&mm->context.sem); ++ mm->context.size = 0; ++} ++ ++/* LDT copy for SKAS - for the above problem.*/ ++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm); + + static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) + { +Index: linux-2.6.git/mm/proc_mm.c +=================================================================== +--- linux-2.6.git.orig/mm/proc_mm.c ++++ linux-2.6.git/mm/proc_mm.c +@@ -102,7 +102,9 @@ static ssize_t write_proc_mm(struct file + break; + } + +- __init_new_context(mm, from); ++ ret = copy_context(mm, from); ++ if(ret == 0) ++ ret = count; + break; + } + default: +@@ -122,9 +124,7 @@ static int open_proc_mm(struct inode *in + if(mm == NULL) + goto out_mem; + +- ret = init_new_context(current, mm); +- if(ret) +- goto out_free; ++ init_new_empty_context(mm); + + spin_lock(&mmlist_lock); + list_add(&mm->mmlist, ¤t->mm->mmlist); +@@ -135,8 +135,6 @@ static int open_proc_mm(struct inode *in + + return(0); + +- out_free: +- mmput(mm); + out_mem: + return(ret); + } +Index: linux-2.6.git/include/asm-i386/processor.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/processor.h ++++ linux-2.6.git/include/asm-i386/processor.h +@@ -721,8 +721,6 @@ static inline void prefetchw(const void + + extern void select_idle_routine(const struct cpuinfo_x86 *c); + +-extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm); +- + #define cache_line_size() (boot_cpu_data.x86_cache_alignment) + + extern unsigned long boot_option_idle_override; diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-prevent-tail-call-cont.diff linux-2.6.19.1/skas/skas-prevent-tail-call-cont.diff --- linux-2.6.19.1-orig/skas/skas-prevent-tail-call-cont.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-prevent-tail-call-cont.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,34 @@ +skas-prevent-tail-call-cont + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/kernel/ldt.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ldt.c ++++ linux-2.6.git/arch/i386/kernel/ldt.c +@@ -259,5 +259,9 @@ int __modify_ldt(struct mm_struct * mm, + + asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) + { +- return __modify_ldt(current->mm, func, ptr, bytecount); ++ int ret = __modify_ldt(current->mm, func, ptr, bytecount); ++ /* A tail call would reorder parameters on the stack and they would then ++ * be restored at the wrong places. */ ++ prevent_tail_call(ret); ++ return ret; + } +Index: linux-2.6.git/mm/mprotect.c +=================================================================== +--- linux-2.6.git.orig/mm/mprotect.c ++++ linux-2.6.git/mm/mprotect.c +@@ -323,5 +323,9 @@ out: + + asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) + { +- return(do_mprotect(current->mm, start, len, prot)); ++ long ret = do_mprotect(current->mm, start, len, prot); ++ /* A tail call would reorder parameters on the stack and they would then ++ * be restored at the wrong places. */ ++ prevent_tail_call(ret); ++ return ret; + } diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-prevent-tail-call.diff linux-2.6.19.1/skas/skas-prevent-tail-call.diff --- linux-2.6.19.1-orig/skas/skas-prevent-tail-call.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-prevent-tail-call.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,32 @@ +skas-prevent-tail-call + + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/kernel/sys_i386.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/sys_i386.c ++++ linux-2.6.git/arch/i386/kernel/sys_i386.c +@@ -69,7 +69,12 @@ asmlinkage long sys_mmap2(unsigned long + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) + { +- return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); ++ long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); ++ ++ /* A tail call would reorder parameters on the stack and they would then ++ * be restored at the wrong places. */ ++ prevent_tail_call(ret); ++ return ret; + } + + /* +@@ -102,6 +107,9 @@ asmlinkage int old_mmap(struct mmap_arg_ + + err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, + a.fd, a.offset >> PAGE_SHIFT); ++ /* A tail call would reorder parameters on the stack and they would then ++ * be restored at the wrong places. */ ++ prevent_tail_call(err); + out: + return err; + } diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-remove-sigpending.diff linux-2.6.19.1/skas/skas-remove-sigpending.diff --- linux-2.6.19.1-orig/skas/skas-remove-sigpending.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-remove-sigpending.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,90 @@ +skas: remove PTRACE_SIGPENDING + +Remove the longly unused and bad PTRACE_SIGPENDING extension from host-skas +patch. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/arch/i386/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/i386/kernel/ptrace.c ++++ linux-2.6.git/arch/i386/kernel/ptrace.c +@@ -643,12 +643,6 @@ long arch_ptrace(struct task_struct *chi + 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; + +Index: linux-2.6.git/arch/x86_64/ia32/ptrace32.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c ++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c +@@ -269,7 +269,6 @@ asmlinkage long sys32_ptrace(long reques + case PTRACE_GETEVENTMSG: + #ifdef CONFIG_PROC_MM + case PTRACE_FAULTINFO: +- case PTRACE_SIGPENDING: + case PTRACE_LDT: + case PTRACE_SWITCH_MM: + #endif +@@ -406,11 +405,6 @@ asmlinkage long sys32_ptrace(long reques + sizeof(fault)); + break; + } +- case PTRACE_SIGPENDING: +- ret = copy_to_user((unsigned long *) datap, +- &child->pending.signal, +- sizeof(child->pending.signal)); +- break; + + case PTRACE_LDT: { + struct ptrace_ldt32 ldt; +Index: linux-2.6.git/arch/x86_64/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ptrace.c ++++ linux-2.6.git/arch/x86_64/kernel/ptrace.c +@@ -582,12 +582,6 @@ long arch_ptrace(struct task_struct *chi + 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; + +Index: linux-2.6.git/include/asm-i386/ptrace.h +=================================================================== +--- linux-2.6.git.orig/include/asm-i386/ptrace.h ++++ linux-2.6.git/include/asm-i386/ptrace.h +@@ -59,7 +59,7 @@ extern unsigned long profile_pc(struct p + #define _LINUX_PTRACE_STRUCT_DEF + + #define PTRACE_FAULTINFO 52 +-#define PTRACE_SIGPENDING 53 ++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */ + #define PTRACE_LDT 54 + #define PTRACE_SWITCH_MM 55 + +Index: linux-2.6.git/include/asm-x86_64/ptrace-abi.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/ptrace-abi.h ++++ linux-2.6.git/include/asm-x86_64/ptrace-abi.h +@@ -43,7 +43,7 @@ + #define PTRACE_SETFPXREGS 19 + + #define PTRACE_FAULTINFO 52 +-#define PTRACE_SIGPENDING 53 ++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */ + #define PTRACE_LDT 54 + #define PTRACE_SWITCH_MM 55 + diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/skas-update-2.6.10.diff linux-2.6.19.1/skas/skas-update-2.6.10.diff --- linux-2.6.19.1-orig/skas/skas-update-2.6.10.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/skas-update-2.6.10.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,29 @@ +skas-v7: update the 2.6.9 version for 2.6.10-rc* + +This is simply a resync with this change: + +http://linux.bkbits.net:8080/linux-2.5/cset@4176817885Kn6zGc09K1fOrpbsJJQA + +Since we create an mm and added it to the list, the patch must be updated now, +otherwise it does not even build. + +Please, test the resulting kernel and post result with it (I've not yet done +this, in fact you cannot find it on my site). + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/mm/proc_mm.c +=================================================================== +--- linux-2.6.git.orig/mm/proc_mm.c ++++ linux-2.6.git/mm/proc_mm.c +@@ -127,11 +127,6 @@ static int open_proc_mm(struct inode *in + init_new_empty_context(mm); + arch_pick_mmap_layout(mm); + +- spin_lock(&mmlist_lock); +- list_add(&mm->mmlist, ¤t->mm->mmlist); +- mmlist_nr++; +- spin_unlock(&mmlist_lock); +- + file->private_data = mm; + + return(0); diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/x86-64-add-missing-proto.diff linux-2.6.19.1/skas/x86-64-add-missing-proto.diff --- linux-2.6.19.1-orig/skas/x86-64-add-missing-proto.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/x86-64-add-missing-proto.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,13 @@ +Index: linux-2.6.git/include/asm-x86_64/proc_mm.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/proc_mm.h ++++ linux-2.6.git/include/asm-x86_64/proc_mm.h +@@ -37,6 +37,8 @@ struct proc_mm_op32 { + extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer, + size_t count, loff_t *ppos); + ++extern struct mm_struct *proc_mm_get_mm64(int fd); ++ + extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off); + diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/x86-64-ex-faultinfo-fix.diff linux-2.6.19.1/skas/x86-64-ex-faultinfo-fix.diff --- linux-2.6.19.1-orig/skas/x86-64-ex-faultinfo-fix.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/x86-64-ex-faultinfo-fix.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,12 @@ +Index: linux-2.6.git/arch/x86_64/ia32/ptrace32.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c ++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c +@@ -268,6 +268,7 @@ asmlinkage long sys32_ptrace(long reques + case PTRACE_GETFPXREGS: + case PTRACE_GETEVENTMSG: + #ifdef CONFIG_PROC_MM ++ case PTRACE_EX_FAULTINFO: + case PTRACE_FAULTINFO: + case PTRACE_LDT: + case PTRACE_SWITCH_MM: diff -Naur -X ../diff-exclude linux-2.6.19.1-orig/skas/x86-64-specific-addition.diff linux-2.6.19.1/skas/x86-64-specific-addition.diff --- linux-2.6.19.1-orig/skas/x86-64-specific-addition.diff 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.19.1/skas/x86-64-specific-addition.diff 2006-11-22 19:24:56.000000000 -0500 @@ -0,0 +1,1002 @@ +x86-64-specific-addition + +Adds the x86-64 specific code part, while reworking the rest a whole lot. + +Signed-off-by: Paolo 'Blaisorblade' Giarrusso +Index: linux-2.6.git/mm/proc_mm.c +=================================================================== +--- linux-2.6.git.orig/mm/proc_mm.c ++++ linux-2.6.git/mm/proc_mm.c +@@ -3,43 +3,66 @@ + * Licensed under the GPL + */ + +-#include "linux/mm.h" +-#include "linux/init.h" +-#include "linux/proc_fs.h" +-#include "linux/proc_mm.h" +-#include "linux/file.h" +-#include "linux/mman.h" +-#include "asm/uaccess.h" +-#include "asm/mmu_context.h" +- +-static struct file_operations proc_mm_fops; ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Naming conventions are a mess, so I note them down. ++ * ++ * Things ending in _mm can be for everything. It's only for ++ * {open,release}_proc_mm. ++ * ++ * For the rest: ++ * ++ * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure ++ * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or ++ * /proc/mm64; for instance the /proc handling). ++ * ++ * While for what is conversion dependant, we use the suffix _native and _emul. ++ * In some cases, there is a mapping between these ones (defined by ++ * ). ++ */ + +-struct mm_struct *proc_mm_get_mm(int fd) ++/*These two are common to everything.*/ ++static int open_proc_mm(struct inode *inode, struct file *file) + { +- struct mm_struct *ret = ERR_PTR(-EBADF); +- struct file *file; ++ struct mm_struct *mm = mm_alloc(); ++ int ret; + +- file = fget(fd); +- if (!file) +- goto out; ++ ret = -ENOMEM; ++ if(mm == NULL) ++ goto out_mem; + +- ret = ERR_PTR(-EINVAL); +- if(file->f_op != &proc_mm_fops) +- goto out_fput; ++ init_new_empty_context(mm); ++ arch_pick_mmap_layout(mm); + +- ret = file->private_data; +- out_fput: +- fput(file); +- out: +- return(ret); ++ file->private_data = mm; ++ ++ return 0; ++ ++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; + } + +-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 struct file_operations proc_mm_fops; ++ ++struct mm_struct *proc_mm_get_mm_native(int fd); + +-static ssize_t write_proc_mm(struct file *file, const char *buffer, ++static ssize_t write_proc_mm_native(struct file *file, const char *buffer, + size_t count, loff_t *ppos) + { + struct mm_struct *mm = file->private_data; +@@ -66,8 +89,8 @@ static ssize_t write_proc_mm(struct file + if (! (map->flags & MAP_FIXED)) + return(-EINVAL); + +- ret = do_mmap2(mm, map->addr, map->len, map->prot, +- map->flags, map->fd, map->offset >> PAGE_SHIFT); ++ ret = __do_mmap(mm, map->addr, map->len, map->prot, ++ map->flags, map->fd, map->offset); + if((ret & ~PAGE_MASK) == 0) + ret = count; + +@@ -95,7 +118,7 @@ static ssize_t write_proc_mm(struct file + } + + case MM_COPY_SEGMENTS: { +- struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments); ++ struct mm_struct *from = proc_mm_get_mm_native(req.u.copy_segments); + + if(IS_ERR(from)){ + ret = PTR_ERR(from); +@@ -112,43 +135,37 @@ static ssize_t write_proc_mm(struct file + break; + } + +- return(ret); ++ return ret; + } + +-static int open_proc_mm(struct inode *inode, struct file *file) ++/*These three are all for /proc/mm.*/ ++struct mm_struct *proc_mm_get_mm(int fd) + { +- struct mm_struct *mm = mm_alloc(); +- int ret; +- +- ret = -ENOMEM; +- if(mm == NULL) +- goto out_mem; +- +- init_new_empty_context(mm); +- arch_pick_mmap_layout(mm); ++ struct mm_struct *ret = ERR_PTR(-EBADF); ++ struct file *file; + +- file->private_data = mm; ++ file = fget(fd); ++ if (!file) ++ goto out; + +- return(0); ++ ret = ERR_PTR(-EINVAL); ++ if(file->f_op != &proc_mm_fops) ++ goto out_fput; + +- out_mem: ++ ret = file->private_data; ++out_fput: ++ fput(file); ++out: + 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, + }; + ++/*Macro-ify it to avoid the duplication.*/ + static int make_proc_mm(void) + { + struct proc_dir_entry *ent; +@@ -160,11 +177,56 @@ static int make_proc_mm(void) + } + ent->proc_fops = &proc_mm_fops; + +- return(0); ++ return 0; + } + + __initcall(make_proc_mm); + ++/*XXX: change the option.*/ ++#ifdef CONFIG_64BIT ++static struct file_operations proc_mm64_fops = { ++ .open = open_proc_mm, ++ .release = release_proc_mm, ++ .write = write_proc_mm64, ++}; ++ ++static int make_proc_mm64(void) ++{ ++ struct proc_dir_entry *ent; ++ ++ ent = create_proc_entry("mm64", 0222, &proc_root); ++ if(ent == NULL){ ++ printk("make_proc_mm : Failed to register /proc/mm64\n"); ++ return(0); ++ } ++ ent->proc_fops = &proc_mm64_fops; ++ ++ return 0; ++} ++ ++__initcall(make_proc_mm64); ++ ++struct mm_struct *proc_mm_get_mm64(int fd) ++{ ++ struct mm_struct *ret = ERR_PTR(-EBADF); ++ struct file *file; ++ ++ file = fget(fd); ++ if (!file) ++ goto out; ++ ++ ret = ERR_PTR(-EINVAL); ++ /*This is the only change.*/ ++ if(file->f_op != &proc_mm64_fops) ++ goto out_fput; ++ ++ ret = file->private_data; ++out_fput: ++ fput(file); ++out: ++ return(ret); ++} ++#endif + /* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically +Index: linux-2.6.git/include/linux/proc_mm.h +=================================================================== +--- linux-2.6.git.orig/include/linux/proc_mm.h ++++ linux-2.6.git/include/linux/proc_mm.h +@@ -6,7 +6,52 @@ + #ifndef __PROC_MM_H + #define __PROC_MM_H + +-#include "linux/sched.h" ++#include ++#include ++ ++/* The differences between this one and do_mmap are that: ++ * - we must perform controls for userspace-supplied params (which are ++ * arch-specific currently). And also fget(fd) if needed and so on... ++ * - we must accept the struct mm_struct on which to act as first param, and the ++ * offset in byte rather than page units as last param. ++ */ ++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr, ++ unsigned long len, unsigned long prot, ++ unsigned long flags, unsigned long fd, ++ unsigned long off); ++ ++/* This header can be used only on archs defining CONFIG_PROC_MM in their ++ * configs, so asm/proc_mm.h can still exist only for the needed archs. ++ * Including it only in the x86-64 case does not make sense.*/ ++#include ++ ++/*XXX: this is defined on x86_64, but not on every 64-bit arch (not on sh64).*/ ++#ifdef CONFIG_64BIT ++ ++#define write_proc_mm write_proc_mm_emul ++#define write_proc_mm64 write_proc_mm_native ++ ++/* It would make more sense to do this mapping the reverse direction, to map the ++ * called name to the defined one and not the reverse. Like the 2nd example ++ */ ++/*#define proc_mm_get_mm proc_mm_get_mm_emul ++#define proc_mm_get_mm64 proc_mm_get_mm_native*/ ++ ++#define proc_mm_get_mm_emul proc_mm_get_mm ++#define proc_mm_get_mm_native proc_mm_get_mm64 ++ ++#else ++ ++#define write_proc_mm write_proc_mm_native ++#undef write_proc_mm64 ++ ++/*#define proc_mm_get_mm proc_mm_get_mm_native ++#undef proc_mm_get_mm64*/ ++ ++#define proc_mm_get_mm_native proc_mm_get_mm ++#undef proc_mm_get_mm_emul ++ ++#endif + + #define MM_MMAP 54 + #define MM_MUNMAP 55 +Index: linux-2.6.git/arch/x86_64/mm/proc_mm.c +=================================================================== +--- /dev/null ++++ linux-2.6.git/arch/x86_64/mm/proc_mm.c +@@ -0,0 +1,85 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ssize_t write_proc_mm_emul(struct file *file, const char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct mm_struct *mm = file->private_data; ++ struct proc_mm_op32 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_mmap32 *map = &req.u.mmap; ++ ++ /* Nobody ever noticed it, but do_mmap_pgoff() calls ++ * get_unmapped_area() which checks current->mm, if ++ * MAP_FIXED is not set, so mmap() could replace ++ * an old mapping. ++ */ ++ if (! (map->flags & MAP_FIXED)) ++ return(-EINVAL); ++ ++ ret = __do_mmap(mm, map->addr, map->len, map->prot, ++ map->flags, map->fd, map->offset); ++ if((ret & ~PAGE_MASK) == 0) ++ ret = count; ++ ++ break; ++ } ++ case MM_MUNMAP: { ++ struct mm_munmap32 *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_mprotect32 *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_emul(req.u.copy_segments); ++ ++ if(IS_ERR(from)){ ++ ret = PTR_ERR(from); ++ break; ++ } ++ ++ ret = copy_context(mm, from); ++ if(ret == 0) ++ ret = count; ++ break; ++ } ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ +Index: linux-2.6.git/include/asm-x86_64/proc_mm.h +=================================================================== +--- /dev/null ++++ linux-2.6.git/include/asm-x86_64/proc_mm.h +@@ -0,0 +1,56 @@ ++#ifndef __ASM_PROC_MM ++#define __ASM_PROC_MM ++#include ++ ++#include ++ ++struct mm_mmap32 { ++ compat_ulong_t addr; ++ compat_ulong_t len; ++ compat_ulong_t prot; ++ compat_ulong_t flags; ++ compat_ulong_t fd; ++ compat_ulong_t offset; ++}; ++ ++struct mm_munmap32 { ++ compat_ulong_t addr; ++ compat_ulong_t len; ++}; ++ ++struct mm_mprotect32 { ++ compat_ulong_t addr; ++ compat_ulong_t len; ++ compat_uint_t prot; ++}; ++ ++struct proc_mm_op32 { ++ compat_int_t op; ++ union { ++ struct mm_mmap32 mmap; ++ struct mm_munmap32 munmap; ++ struct mm_mprotect32 mprotect; ++ compat_int_t copy_segments; ++ } u; ++}; ++ ++extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer, ++ size_t count, loff_t *ppos); ++ ++extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long off); ++ ++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr, ++ unsigned long len, unsigned long prot, ++ unsigned long flags, unsigned long fd, ++ unsigned long off) ++{ ++ /* The latter one is stricter, since will actually check that off is page ++ * aligned. The first one skipped the check. */ ++ ++ /* return do32_mmap2(mm, addr, len, prot, flags, fd, off >> ++ * PAGE_SHIFT);*/ ++ return do64_mmap(mm, addr, len, prot, flags, fd, off); ++} ++ ++#endif /* __ASM_PROC_MM */ +Index: linux-2.6.git/arch/x86_64/Kconfig +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/Kconfig ++++ linux-2.6.git/arch/x86_64/Kconfig +@@ -459,6 +459,10 @@ config CALGARY_IOMMU + config SWIOTLB + bool + ++config PROC_MM ++ bool "/proc/mm support" ++ default y ++ + config X86_MCE + bool "Machine check support" if EMBEDDED + default y +Index: linux-2.6.git/arch/x86_64/ia32/ptrace32.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c ++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c +@@ -16,6 +16,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -26,6 +28,7 @@ + #include + #include + #include ++#include + + /* + * Determines which flags the user has access to [1 = access, 0 = no access]. +@@ -264,6 +267,12 @@ asmlinkage long sys32_ptrace(long reques + case PTRACE_SETFPXREGS: + case PTRACE_GETFPXREGS: + case PTRACE_GETEVENTMSG: ++#ifdef CONFIG_PROC_MM ++ case PTRACE_FAULTINFO: ++ case PTRACE_SIGPENDING: ++ case PTRACE_LDT: ++ case PTRACE_SWITCH_MM: ++#endif + break; + + case PTRACE_SETSIGINFO: +@@ -386,6 +395,52 @@ asmlinkage long sys32_ptrace(long reques + ret = 0; + break; + } ++#ifdef CONFIG_PROC_MM ++ case PTRACE_FAULTINFO: { ++ struct ptrace_faultinfo32 fault; ++ ++ fault = ((struct ptrace_faultinfo32) ++ { .is_write = (compat_int_t) child->thread.error_code, ++ .addr = (compat_uptr_t) child->thread.cr2 }); ++ ret = copy_to_user((unsigned long *) datap, &fault, ++ sizeof(fault)); ++ break; ++ } ++ case PTRACE_SIGPENDING: ++ ret = copy_to_user((unsigned long *) datap, ++ &child->pending.signal, ++ sizeof(child->pending.signal)); ++ break; ++ ++ case PTRACE_LDT: { ++ struct ptrace_ldt32 ldt; ++ ++ if(copy_from_user(&ldt, (unsigned long *) datap, ++ sizeof(ldt))){ ++ ret = -EIO; ++ break; ++ } ++ ret = __modify_ldt(child->mm, ldt.func, compat_ptr(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; ++ } ++#endif + + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data)); +Index: linux-2.6.git/include/asm-x86_64/mmu_context.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/mmu_context.h ++++ linux-2.6.git/include/asm-x86_64/mmu_context.h +@@ -7,13 +7,28 @@ + #include + #include + #include ++#include + + /* + * possibly do the LDT unload here? ++ * Used for LDT initialization/destruction. You cannot copy an LDT with ++ * init_new_context, since it thinks you are passing it a new LDT and won't ++ * deallocate its old content. + */ ++ + int init_new_context(struct task_struct *tsk, struct mm_struct *mm); + void destroy_context(struct mm_struct *mm); + ++/* LDT initialization for a clean environment - needed for SKAS.*/ ++static inline void init_new_empty_context(struct mm_struct *mm) ++{ ++ init_MUTEX(&mm->context.sem); ++ mm->context.size = 0; ++} ++ ++/* LDT copy for SKAS - for the above problem.*/ ++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm); ++ + static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) + { + #ifdef CONFIG_SMP +@@ -31,6 +46,9 @@ static inline void switch_mm(struct mm_s + struct task_struct *tsk) + { + unsigned cpu = smp_processor_id(); ++#ifdef CONFIG_SMP ++ prev = read_pda(active_mm); ++#endif + if (likely(prev != next)) { + /* stop flush ipis for the previous mm */ + cpu_clear(cpu, prev->cpu_vm_mask); +@@ -47,8 +65,6 @@ static inline void switch_mm(struct mm_s + #ifdef CONFIG_SMP + else { + write_pda(mmu_state, TLBSTATE_OK); +- if (read_pda(active_mm) != next) +- out_of_line_bug(); + if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { + /* We were in lazy tlb mode and leave_mm disabled + * tlb flush IPI delivery. We must reload CR3 +Index: linux-2.6.git/arch/x86_64/ia32/sys_ia32.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/ia32/sys_ia32.c ++++ linux-2.6.git/arch/x86_64/ia32/sys_ia32.c +@@ -759,11 +759,10 @@ sys32_sendfile(int out_fd, int in_fd, co + return ret; + } + +-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, ++long do32_mmap2(struct mm_struct *mm, unsigned long addr, ++ unsigned long len, unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) + { +- struct mm_struct *mm = current->mm; + unsigned long error; + struct file * file = NULL; + +@@ -775,7 +774,7 @@ asmlinkage long sys32_mmap2(unsigned lon + } + + down_write(&mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); ++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff); + up_write(&mm->mmap_sem); + + if (file) +@@ -783,6 +782,15 @@ asmlinkage long sys32_mmap2(unsigned lon + return error; + } + ++/* XXX: this wrapper can be probably removed, we can simply use the 64-bit ++ * version.*/ ++asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long pgoff) ++{ ++ return do32_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); ++} ++ + asmlinkage long sys32_olduname(struct oldold_utsname __user * name) + { + int err; +Index: linux-2.6.git/arch/x86_64/kernel/ldt.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ldt.c ++++ linux-2.6.git/arch/x86_64/kernel/ldt.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ + static void flush_ldt(void *null) +@@ -58,7 +59,7 @@ static int alloc_ldt(mm_context_t *pc, u + wmb(); + pc->size = mincount; + wmb(); +- if (reload) { ++ if (reload && (¤t->active_mm->context == pc)) { + #ifdef CONFIG_SMP + cpumask_t mask; + +@@ -94,14 +95,10 @@ static inline int copy_ldt(mm_context_t + * we do not have to muck with descriptors here, that is + * done in switch_mm() as needed. + */ +-int init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm) + { +- struct mm_struct * old_mm; + int retval = 0; + +- init_MUTEX(&mm->context.sem); +- mm->context.size = 0; +- old_mm = current->mm; + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); + retval = copy_ldt(&mm->context, &old_mm->context); +@@ -110,6 +107,12 @@ int init_new_context(struct task_struct + return retval; + } + ++int init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ init_new_empty_context(mm); ++ return copy_context(mm, current->mm); ++} ++ + /* + * + * Don't touch the LDT register - we're already in the next thread. +@@ -125,11 +128,10 @@ void destroy_context(struct mm_struct *m + } + } + +-static int read_ldt(void __user * ptr, unsigned long bytecount) ++static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount) + { + int err; + unsigned long size; +- struct mm_struct * mm = current->mm; + + if (!mm->context.size) + return 0; +@@ -170,10 +172,8 @@ static int read_default_ldt(void __user + return bytecount; + } + +-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) ++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode) + { +- struct task_struct *me = current; +- struct mm_struct * mm = me->mm; + __u32 entry_1, entry_2, *lp; + int error; + struct user_desc ldt_info; +@@ -198,7 +198,7 @@ static int write_ldt(void __user * ptr, + + down(&mm->context.sem); + if (ldt_info.entry_number >= (unsigned)mm->context.size) { +- error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); ++ error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1); + if (error < 0) + goto out_unlock; + } +@@ -231,23 +231,29 @@ out: + return error; + } + +-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) ++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, ++ unsigned long bytecount) + { + int ret = -ENOSYS; + + switch (func) { + case 0: +- ret = read_ldt(ptr, bytecount); ++ ret = read_ldt(mm, ptr, bytecount); + break; + case 1: +- ret = write_ldt(ptr, bytecount, 1); ++ ret = write_ldt(mm, ptr, bytecount, 1); + break; + case 2: + ret = read_default_ldt(ptr, bytecount); + break; + case 0x11: +- ret = write_ldt(ptr, bytecount, 0); ++ ret = write_ldt(mm, ptr, bytecount, 0); + break; + } + return ret; + } ++ ++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) ++{ ++ return __modify_ldt(current->mm, func, ptr, bytecount); ++} +Index: linux-2.6.git/include/asm-x86_64/desc.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/desc.h ++++ linux-2.6.git/include/asm-x86_64/desc.h +@@ -233,6 +233,9 @@ static inline void load_LDT(mm_context_t + + extern struct desc_ptr idt_descr; + ++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, ++ unsigned long bytecount); ++ + #endif /* !__ASSEMBLY__ */ + + #endif +Index: linux-2.6.git/include/asm-x86_64/ptrace.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/ptrace.h ++++ linux-2.6.git/include/asm-x86_64/ptrace.h +@@ -72,6 +72,47 @@ enum { + EF_ID = 0x00200000, /* id */ + }; + ++/* Stolen from ++#include ; we can't include it because ++there is a nasty ciclic include chain. ++*/ ++ ++#include ++ ++#define compat_int_t s32 ++#define compat_long_t s32 ++#define compat_uint_t u32 ++#define compat_ulong_t u32 ++#define compat_uptr_t u32 ++ ++struct ptrace_faultinfo32 { ++ compat_int_t is_write; ++ compat_ulong_t addr; ++}; ++ ++struct ptrace_ldt32 { ++ compat_int_t func; ++ compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/ ++ compat_ulong_t bytecount; ++}; ++ ++struct ptrace_faultinfo { ++ int is_write; ++ unsigned long addr; ++}; ++ ++struct ptrace_ldt { ++ int func; ++ void *ptr; ++ unsigned long bytecount; ++}; ++ ++#undef compat_int_t ++#undef compat_long_t ++#undef compat_uint_t ++#undef compat_ulong_t ++#undef compat_uptr_t ++ + #endif + + #endif +Index: linux-2.6.git/include/asm-x86_64/ptrace-abi.h +=================================================================== +--- linux-2.6.git.orig/include/asm-x86_64/ptrace-abi.h ++++ linux-2.6.git/include/asm-x86_64/ptrace-abi.h +@@ -42,6 +42,11 @@ + #define PTRACE_GETFPXREGS 18 + #define PTRACE_SETFPXREGS 19 + ++#define PTRACE_FAULTINFO 52 ++#define PTRACE_SIGPENDING 53 ++#define PTRACE_LDT 54 ++#define PTRACE_SWITCH_MM 55 ++ + /* only useful for access 32bit programs */ + #define PTRACE_GET_THREAD_AREA 25 + #define PTRACE_SET_THREAD_AREA 26 +Index: linux-2.6.git/arch/x86_64/mm/Makefile +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/mm/Makefile ++++ linux-2.6.git/arch/x86_64/mm/Makefile +@@ -7,5 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag + obj-$(CONFIG_NUMA) += numa.o + obj-$(CONFIG_K8_NUMA) += k8topology.o + obj-$(CONFIG_ACPI_NUMA) += srat.o ++obj-$(CONFIG_PROC_MM) += proc_mm.o + + hugetlbpage-y = ../../i386/mm/hugetlbpage.o +Index: linux-2.6.git/arch/x86_64/kernel/ptrace.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/ptrace.c ++++ linux-2.6.git/arch/x86_64/kernel/ptrace.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -564,6 +565,59 @@ long arch_ptrace(struct task_struct *chi + break; + } + ++#ifdef CONFIG_PROC_MM ++ case PTRACE_FAULTINFO: { ++ struct ptrace_faultinfo fault; ++ ++ /* I checked in thread_struct comments that error_code and cr2 ++ * are still part of the "fault info" section, so I guess that ++ * things are unchanged for now. Still to check manuals. BB*/ ++ 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->mm, ldt.func, ldt.ptr, ldt.bytecount); ++ break; ++ } ++ ++ case PTRACE_SWITCH_MM: { ++ struct mm_struct *old = child->mm; ++ struct mm_struct *new = proc_mm_get_mm64(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; ++ } ++#endif ++ + default: + ret = ptrace_request(child, request, addr, data); + break; +Index: linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c +=================================================================== +--- linux-2.6.git.orig/arch/x86_64/kernel/sys_x86_64.c ++++ linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c +@@ -19,6 +19,7 @@ + + #include + #include ++#include + + /* + * sys_pipe() is the normal C calling standard for creating +@@ -37,7 +38,7 @@ asmlinkage long sys_pipe(int __user *fil + return error; + } + +-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, ++long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off) + { + long error; +@@ -55,9 +56,9 @@ asmlinkage long sys_mmap(unsigned long a + if (!file) + goto out; + } +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT); +- up_write(¤t->mm->mmap_sem); ++ down_write(&mm->mmap_sem); ++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, off >> PAGE_SHIFT); ++ up_write(&mm->mmap_sem); + + if (file) + fput(file); +@@ -65,6 +66,12 @@ out: + return error; + } + ++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long off) ++{ ++ return do64_mmap(current->mm, addr, len, prot, flags, fd, off); ++} ++ + static void find_start_end(unsigned long flags, unsigned long *begin, + unsigned long *end) + { +Index: linux-2.6.git/include/asm-i386/proc_mm.h +=================================================================== +--- /dev/null ++++ linux-2.6.git/include/asm-i386/proc_mm.h +@@ -0,0 +1,18 @@ ++#ifndef __ASM_PROC_MM ++#define __ASM_PROC_MM ++ ++#include ++ ++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 inline long __do_mmap(struct mm_struct *mm, unsigned long addr, ++ unsigned long len, unsigned long prot, ++ unsigned long flags, unsigned long fd, ++ unsigned long off) ++{ ++ return do_mmap2(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT); ++} ++ ++#endif /* __ASM_PROC_MM */