[Pkg-uml-commit] r160 - in trunk/src/kernel-patch-skas: . debian
Mattia Dongili
malattia at costa.debian.org
Sat Aug 26 11:26:04 UTC 2006
Author: malattia
Date: 2006-08-26 11:25:57 +0000 (Sat, 26 Aug 2006)
New Revision: 160
Added:
trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch
trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch
trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch
trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch
trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch
trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch
trunk/src/kernel-patch-skas/host-skas3.patch
trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch
trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch
trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch
trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch
trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch
trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch
trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch
trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch
Modified:
trunk/src/kernel-patch-skas/debian/changelog
Log:
add upstream patches
Modified: trunk/src/kernel-patch-skas/debian/changelog
===================================================================
--- trunk/src/kernel-patch-skas/debian/changelog 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/debian/changelog 2006-08-26 11:25:57 UTC (rev 160)
@@ -8,7 +8,7 @@
* filled the gap until 2.6.16 with patches from Paolo Giarrusso..
* updated debhelper compatibility version.
- -- Mattia Dongili <malattia at debian.org> Sun, 14 May 2006 18:20:02 +0200
+ -- Mattia Dongili <malattia at debian.org> Sat, 27 May 2006 16:52:53 +0200
kernel-patch-skas (3-9.3) unstable; urgency=low
Added: trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,801 @@
+--- linux-2.4.25-paolo/arch/i386/kernel/ldt.c 2004-09-11 19:25:37.632440992 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/ldt.c 2004-08-29 17:21:52.276721288 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *mm)
+@@ -53,7 +54,7 @@
+ wmb();
+ pc->ldt = newldt;
+ pc->size = mincount;
+- if (reload) {
++ if (reload && (¤t->active_mm->context == pc)) {
+ load_LDT(pc);
+ #ifdef CONFIG_SMP
+ if (current->mm->cpu_vm_mask != (1<<smp_processor_id()))
+@@ -86,6 +87,12 @@
+ * we do not have to muck with descriptors here, that is
+ * done in switch_mm() as needed.
+ */
++void init_new_empty_context(struct mm_struct *mm)
++{
++ init_MUTEX(&mm->context.sem);
++ mm->context.size = 0;
++}
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+ {
+ struct mm_struct * old_mm;
+@@ -102,6 +109,26 @@
+ return retval;
+ }
+
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
++{
++ int err = 0;
++ mm_context_t *new, *old;
++ new = &mm->context;
++ old = &old_mm->context;
++ if (old_mm && old_mm->context.size > 0) {
++ down(&old_mm->context.sem);
++ err = alloc_ldt(new, old->size, 0);
++ if (err < 0) {
++ up(&old_mm->context.sem);
++ goto out;
++ }
++ memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++ up(&old_mm->context.sem);
++ }
++out:
++ return err;
++}
++
+ /*
+ * No need to lock the MM as we are the last user
+ * Do not touch the ldt register, we are already
+@@ -118,11 +145,10 @@
+ }
+ }
+
+-static int read_ldt(void * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void * ptr, unsigned long bytecount)
+ {
+ int err;
+ unsigned long size;
+- struct mm_struct * mm = current->mm;
+
+ if (!mm->context.size)
+ return 0;
+@@ -166,9 +192,8 @@
+ return err;
+ }
+
+-static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void * ptr, unsigned long bytecount, int oldmode)
+ {
+- struct mm_struct * mm = current->mm;
+ __u32 entry_1, entry_2, *lp;
+ int error;
+ struct modify_ldt_ldt_s ldt_info;
+@@ -192,7 +217,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->context, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -243,20 +268,24 @@
+-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++int modify_ldt(struct mm_struct * mm, int func, void *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 *ptr, unsigned long bytecount) {
++ return modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- linux-2.4.25-paolo/arch/i386/kernel/ptrace.c 2004-08-29 17:21:51.920775400 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/ptrace.c 2004-08-29 17:21:52.616669608 +0200
+@@ -147,6 +147,11 @@
+ put_stack_long(child, EFL_OFFSET, tmp);
+ }
+
++extern int modify_ldt(struct mm_struct *mm, int func, void *ptr,
++ unsigned long bytecount);
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
+ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+ {
+ struct task_struct *child;
+@@ -270,6 +275,7 @@
+ }
+ break;
+
++ case PTRACE_SYSEMU: /* continue and replace next syscall */
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ long tmp;
+@@ -277,6 +283,10 @@
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
++ if (request == PTRACE_SYSEMU)
++ child->ptrace |= PT_SYSEMU;
++ else
++ child->ptrace &= ~PT_SYSEMU;
+ if (request == PTRACE_SYSCALL)
+ child->ptrace |= PT_TRACESYS;
+ else
+@@ -315,7 +325,7 @@
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+- child->ptrace &= ~PT_TRACESYS;
++ child->ptrace &= ~(PT_TRACESYS|PT_SYSEMU);
+ if ((child->ptrace & PT_DTRACE) == 0) {
+ /* Spurious delayed TF traps may occur */
+ child->ptrace |= PT_DTRACE;
+@@ -419,6 +429,53 @@
+ break;
+ }
+
++ case PTRACE_FAULTINFO: {
++ struct ptrace_faultinfo fault;
++
++ fault = ((struct ptrace_faultinfo)
++ { .is_write = child->thread.error_code,
++ .addr = child->thread.cr2 });
++ ret = copy_to_user((unsigned long *) data, &fault,
++ sizeof(fault));
++ 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;
++ }
++
++#if 1 /* CONFIG_PROC_MM*/
++ 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 = -EIO;
+ break;
+@@ -430,6 +487,29 @@
+ return ret;
+ }
+
++asmlinkage void syscall_emulate(void)
++{
++ if ((current->ptrace & (PT_PTRACED|PT_SYSEMU)) !=
++ (PT_PTRACED|PT_SYSEMU))
++ return;
++ /* the 0x80 provides a way for the tracing parent to distinguish
++ between a syscall stop and SIGTRAP delivery */
++ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
++ ? 0x80 : 0);
++ current->state = TASK_STOPPED;
++ notify_parent(current, SIGCHLD);
++ schedule();
++ /*
++ * this isn't the same as continuing with a signal, but it will do
++ * for normal use. strace only continues with a signal if the
++ * stopping signal is not SIGTRAP. -brl
++ */
++ if (current->exit_code) {
++ send_sig(current->exit_code, current, 1);
++ current->exit_code = 0;
++ }
++}
++
+ asmlinkage void syscall_trace(void)
+ {
+ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
+--- linux-2.4.25/arch/i386/kernel/sys_i386.c~host-skas3-2.4.25-no_CONFIG 2004-08-29 17:21:51.100900040 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/sys_i386.c 2004-08-29 17:21:51.111898368 +0200
+@@ -40,7 +40,7 @@ asmlinkage int sys_pipe(unsigned long *
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -55,9 +55,9 @@ static inline long do_mmap2(
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -69,7 +69,7 @@ asmlinkage long sys_mmap2(unsigned long
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -100,7 +100,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+--- linux-2.4.25/include/asm-i386/processor.h~host-skas3-2.4.25-no_CONFIG 2004-08-29 17:21:51.101899888 +0200
++++ linux-2.4.25-paolo/include/asm-i386/processor.h 2004-08-29 17:21:51.111898368 +0200
+@@ -433,6 +433,8 @@ extern int arch_kernel_thread(int (*fn)(
+ static inline void copy_segments(struct task_struct *p, struct mm_struct * mm) { }
+ static inline void release_segments(struct mm_struct * mm) { }
+
++extern int __init_new_context(struct mm_struct *old_mm, struct mm_struct *mm);
++
+ /*
+ * Return saved PC of a blocked thread.
+ */
+--- linux-2.4.25/include/asm-i386/ptrace.h~host-skas3-2.4.25-no_CONFIG 2004-08-29 17:21:51.102899736 +0200
++++ linux-2.4.25-paolo/include/asm-i386/ptrace.h 2004-08-29 17:21:51.111898368 +0200
+@@ -51,6 +51,22 @@ struct pt_regs {
+
+ #define PTRACE_SETOPTIONS 21
+
++struct ptrace_faultinfo {
++ int is_write;
++ unsigned long addr;
++};
++
++struct ptrace_ldt {
++ int func;
++ void *ptr;
++ unsigned long bytecount;
++};
++
++#define PTRACE_FAULTINFO 52
++#define PTRACE_SIGPENDING 53
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++
+ /* options set using PTRACE_SETOPTIONS */
+ #define PTRACE_O_TRACESYSGOOD 0x00000001
+
+--- linux-2.4.25/include/linux/mm.h~host-skas3-2.4.25-no_CONFIG 2004-08-29 17:21:51.103899584 +0200
++++ linux-2.4.25-paolo/include/linux/mm.h 2004-08-29 17:21:51.112898216 +0200
+@@ -505,6 +505,9 @@ extern int ptrace_check_attach(struct ta
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+ int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc() that does all
+@@ -552,9 +555,10 @@ extern void exit_mmap(struct mm_struct *
+
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+- unsigned long len, unsigned long prot,
+- unsigned long flag, unsigned long pgoff);
++extern unsigned long do_mmap_pgoff(struct mm_struct *mm,
++ struct file *file, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flag, unsigned long pgoff);
+
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long prot,
+@@ -564,7 +568,7 @@ static inline unsigned long do_mmap(stru
+ if ((offset + PAGE_ALIGN(len)) < offset)
+ goto out;
+ if (!(offset & ~PAGE_MASK))
+- ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
++ ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, offset >> PAGE_SHIFT);
+ out:
+ return ret;
+ }
+--- /dev/null 2004-06-25 17:47:25.000000000 +0200
++++ linux-2.4.25-paolo/include/linux/proc_mm.h 2004-08-29 17:21:51.112898216 +0200
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++ unsigned long addr;
++ unsigned long len;
++ unsigned long prot;
++ unsigned long flags;
++ unsigned long fd;
++ unsigned long offset;
++};
++
++struct mm_munmap {
++ unsigned long addr;
++ unsigned long len;
++};
++
++struct mm_mprotect {
++ unsigned long addr;
++ unsigned long len;
++ unsigned int prot;
++};
++
++struct proc_mm_op {
++ int op;
++ union {
++ struct mm_mmap mmap;
++ struct mm_munmap munmap;
++ struct mm_mprotect mprotect;
++ int copy_segments;
++ } u;
++};
++
++#endif
+--- linux-2.4.25/mm/Makefile~host-skas3-2.4.25-no_CONFIG 2004-08-29 17:21:51.105899280 +0200
++++ linux-2.4.25-paolo/mm/Makefile 2004-08-29 17:21:51.112898216 +0200
+@@ -17,5 +17,6 @@ obj-y := memory.o mmap.o filemap.o mpro
+ shmem.o
+
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-y += proc_mm.o
+
+ include $(TOPDIR)/Rules.make
+--- linux-2.4.25/mm/mmap.c~host-skas3-2.4.25-no_CONFIG 2004-08-29 17:21:51.106899128 +0200
++++ linux-2.4.25-paolo/mm/mmap.c 2004-08-29 17:21:51.112898216 +0200
+@@ -391,10 +391,11 @@ static int vma_merge(struct mm_struct *
+ return 0;
+ }
+
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags, unsigned long pgoff)
++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++ unsigned long addr, unsigned long len,
++ unsigned long prot, unsigned long flags,
++ unsigned long pgoff)
+ {
+- struct mm_struct * mm = current->mm;
+ struct vm_area_struct * vma, * prev;
+ unsigned int vm_flags;
+ int correct_wcount = 0;
+--- linux-2.4.25-paolo/mm/mprotect.c 2004-08-29 17:21:51.113898064 +0200
++++ linux-2.4.25-paolo/mm/mprotect.c 2004-08-29 17:21:52.974615192 +0200
+@@ -71,23 +71,24 @@
+ } while (address && (address < end));
+ }
+
+-static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
++static void change_protection(struct mm_struct *mm,
++ unsigned long start, unsigned long end, pgprot_t newprot)
+ {
+ pgd_t *dir;
+ unsigned long beg = start;
+
+- dir = pgd_offset(current->mm, start);
+- flush_cache_range(current->mm, beg, end);
++ dir = pgd_offset(mm, start);
++ flush_cache_range(mm, beg, end);
+ if (start >= end)
+ BUG();
+- spin_lock(¤t->mm->page_table_lock);
++ spin_lock(&mm->page_table_lock);
+ do {
+ change_pmd_range(dir, start, end - start, newprot);
+ start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (start && (start < end));
+- spin_unlock(¤t->mm->page_table_lock);
+- flush_tlb_range(current->mm, beg, end);
++ spin_unlock(&mm->page_table_lock);
++ flush_tlb_range(mm, beg, end);
+ return;
+ }
+
+@@ -125,6 +126,7 @@
+ int newflags, pgprot_t prot)
+ {
+ struct vm_area_struct * n, * prev = *pprev;
++ struct mm_struct * mm = vma->vm_mm;
+
+ *pprev = vma;
+
+@@ -153,7 +155,7 @@
+ lock_vma_mappings(vma);
+ spin_lock(&vma->vm_mm->page_table_lock);
+ vma->vm_start = end;
+- __insert_vm_struct(current->mm, n);
++ __insert_vm_struct(mm, n);
+ spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
+
+@@ -165,6 +167,7 @@
+ int newflags, pgprot_t prot)
+ {
+ struct vm_area_struct * n;
++ struct mm_struct * mm = vma->vm_mm;
+
+ n = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
+ if (!n)
+@@ -182,7 +185,7 @@
+ lock_vma_mappings(vma);
+ spin_lock(&vma->vm_mm->page_table_lock);
+ vma->vm_end = start;
+- __insert_vm_struct(current->mm, n);
++ __insert_vm_struct(mm, n);
+ spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
+
+@@ -196,6 +199,7 @@
+ int newflags, pgprot_t prot)
+ {
+ struct vm_area_struct * left, * right;
++ struct mm_struct * mm = vma->vm_mm;
+
+ left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+ if (!left)
+@@ -226,8 +230,8 @@
+ vma->vm_start = start;
+ vma->vm_end = end;
+ vma->vm_flags = newflags;
+- __insert_vm_struct(current->mm, left);
+- __insert_vm_struct(current->mm, right);
++ __insert_vm_struct(mm, left);
++ __insert_vm_struct(mm, right);
+ spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
+
+@@ -241,6 +245,7 @@
+ {
+ pgprot_t newprot;
+ int error;
++ struct mm_struct * mm = vma->vm_mm;
+
+ if (newflags == vma->vm_flags) {
+ *pprev = vma;
+@@ -260,11 +265,12 @@
+ if (error)
+ return error;
+
+- change_protection(start, end, newprot);
++ change_protection(mm, start, end, newprot);
+ return 0;
+ }
+
+-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++ unsigned long prot)
+ {
+ unsigned long nstart, end, tmp;
+ struct vm_area_struct * vma, * next, * prev;
+@@ -281,9 +287,9 @@
+ if (end == start)
+ return 0;
+
+- 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 || vma->vm_start > start)
+ goto out;
+@@ -335,3 +341,8 @@
+- 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));
++}
+--- linux-2.4.25-paolo/mm/proc_mm.c 2004-08-29 17:21:52.277721136 +0200
++++ linux-2.4.25-paolo/mm/proc_mm.c 2004-08-29 17:21:52.974615192 +0200
+@@ -0,0 +1,181 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#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;
++ }
++
++ /*mm_copy_segments(from, mm);*/
++ 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);
++
++ spin_lock(&mmlist_lock);
++ list_add(&mm->mmlist, ¤t->mm->mmlist);
++ mmlist_nr++;
++ spin_unlock(&mmlist_lock);
++
++ 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:
++ */
+--- linux-2.4.25-paolo/arch/i386/kernel/entry.S 2004-08-29 17:21:51.920775400 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/entry.S 2004-08-29 17:21:52.616669608 +0200
+@@ -203,6 +203,8 @@
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_CURRENT(%ebx)
++ testb $0x20,tsk_ptrace(%ebx) # PT_SYSEMU
++ jne emulatesys
+ testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
+ jne tracesys
+ cmpl $(NR_syscalls),%eax
+@@ -237,6 +239,10 @@
+ jmp restore_all
+
+ ALIGN
++emulatesys:
++ call SYMBOL_NAME(syscall_emulate)
++ jmp ret_from_sys_call
++ ALIGN
+ tracesys:
+ movl $-ENOSYS,EAX(%esp)
+ call SYMBOL_NAME(syscall_trace)
+--- linux-2.4.25-paolo/include/linux/ptrace.h 2004-08-29 17:21:51.920775400 +0200
++++ linux-2.4.25-paolo/include/linux/ptrace.h 2004-08-29 17:21:52.616669608 +0200
+@@ -20,6 +20,7 @@
+ #define PTRACE_DETACH 0x11
+
+ #define PTRACE_SYSCALL 24
++#define PTRACE_SYSEMU 31
+
+ #include <asm/ptrace.h>
+
+--- linux-2.4.25-paolo/include/linux/sched.h 2004-08-29 17:21:51.921775248 +0200
++++ linux-2.4.25-paolo/include/linux/sched.h 2004-08-29 17:21:52.617669456 +0200
+@@ -445,6 +445,7 @@
+ #define PT_DTRACE 0x00000004 /* delayed trace (used on m68k, i386) */
+ #define PT_TRACESYSGOOD 0x00000008
+ #define PT_PTRACE_CAP 0x00000010 /* ptracer can follow suid-exec */
++#define PT_SYSEMU 0x00000020 /* syscall emulation for UML */
+
+ #define is_dumpable(tsk) ((tsk)->task_dumpable && (tsk)->mm && (tsk)->mm->dumpable)
+
+--- linux-2.4.25/include/asm-i386/mmu_context.h~skas-avoid-ldt 2004-08-29 17:21:52.273721744 +0200
++++ linux-2.4.25-paolo/include/asm-i386/mmu_context.h 2004-08-29 17:21:52.276721288 +0200
+@@ -13,6 +13,8 @@
+ */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++void init_new_empty_context(struct mm_struct *mm);
+
+ #ifdef CONFIG_SMP
+
Added: trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,631 @@
+--- linux-2.6.0/include/linux/mm.h.Skas_add 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/mm.h 2003-12-31 17:13:57.000000000 +0100
+@@ -507,6 +507,9 @@
+ return __set_page_dirty_buffers(page);
+ }
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -537,9 +540,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,
+--- linux-2.6.0/include/linux/proc_mm.h.Skas_add 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/proc_mm.h 2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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
+--- linux-2.6.0/mm/mmap.c.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mmap.c 2003-12-31 17:13:57.000000000 +0100
+@@ -460,11 +460,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;
+@@ -712,7 +712,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.
+--- linux-2.6.0/mm/mprotect.c.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mprotect.c 2003-12-31 17:13:57.000000000 +0100
+@@ -221,8 +221,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;
+ struct vm_area_struct * vma, * next, * 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;
+@@ -326,6 +327,11 @@
+ prev->vm_mm->map_count--;
+ }
+ 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));
++}
+--- linux-2.6.0/mm/proc_mm.c.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/proc_mm.c 2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,174 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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 "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++ struct mm_struct *ret = ERR_PTR(-EBADF);
++ struct file *file;
++
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ ret = ERR_PTR(-EINVAL);
++ if(file->f_op != &proc_mm_fops)
++ goto out_fput;
++
++ ret = file->private_data;
++ out_fput:
++ fput(file);
++ out:
++ return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flags, unsigned long fd,
++ unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct mm_struct *mm = file->private_data;
++ struct proc_mm_op req;
++ int n, ret;
++
++ if(count > sizeof(req))
++ return(-EINVAL);
++
++ n = copy_from_user(&req, buffer, count);
++ if(n != 0)
++ return(-EFAULT);
++
++ ret = count;
++ switch(req.op){
++ case MM_MMAP: {
++ struct mm_mmap *map = &req.u.mmap;
++
++ ret = do_mmap2(mm, map->addr, map->len, map->prot,
++ map->flags, map->fd, map->offset >> PAGE_SHIFT);
++ if((ret & ~PAGE_MASK) == 0)
++ ret = count;
++
++ break;
++ }
++ case MM_MUNMAP: {
++ struct mm_munmap *unmap = &req.u.munmap;
++
++ down_write(&mm->mmap_sem);
++ ret = do_munmap(mm, unmap->addr, unmap->len);
++ up_write(&mm->mmap_sem);
++
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++ case MM_MPROTECT: {
++ struct mm_mprotect *protect = &req.u.mprotect;
++
++ ret = do_mprotect(mm, protect->addr, protect->len,
++ protect->prot);
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++
++ case MM_COPY_SEGMENTS: {
++ struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++ if(IS_ERR(from)){
++ ret = PTR_ERR(from);
++ break;
++ }
++
++ __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:
++ */
+--- linux-2.6.0/mm/Makefile.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/Makefile 2003-12-31 17:13:57.000000000 +0100
+@@ -12,3 +12,5 @@
+ slab.o swap.o truncate.o vmscan.o $(mmu-y)
+
+ obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
+--- linux-2.6.0/arch/i386/kernel/sys_i386.c.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/sys_i386.c 2003-12-31 16:57:39.000000000 +0100
+@@ -40,7 +40,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -55,9 +55,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -69,7 +69,7 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -100,7 +100,7 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+--- linux-2.6.0/arch/i386/kernel/ptrace.c.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ptrace.c 2003-12-31 16:57:39.000000000 +0100
+@@ -14,6 +14,7 @@
+ #include <linux/ptrace.h>
+ #include <linux/user.h>
+ #include <linux/security.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -507,6 +508,56 @@
+ addr, (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;
+--- linux-2.6.0/arch/i386/kernel/ldt.c.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ldt.c 2003-12-31 16:57:40.000000000 +0100
+@@ -54,7 +54,7 @@
+ pc->size = mincount;
+ wmb();
+
+- if (reload) {
++ if (reload && (¤t->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ cpumask_t mask;
+ preempt_disable();
+@@ -89,14 +89,12 @@
+ * 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);
+@@ -105,6 +103,11 @@
+ 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
+ */
+@@ -121,11 +124,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;
+@@ -169,9 +172,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -195,7 +197,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->context, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -228,23 +230,29 @@
+ 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);
++}
+--- linux-2.6.0/arch/i386/Kconfig.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/Kconfig 2003-12-31 16:57:40.000000000 +0100
+@@ -698,6 +698,9 @@
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++
+ # Common NUMA Features
+ config NUMA
+ bool "Numa Memory Allocation Support"
+--- linux-2.6.0/include/asm-i386/desc.h.i386_Skas 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/desc.h 2003-12-31 16:57:40.000000000 +0100
+@@ -123,6 +123,9 @@
+ put_cpu();
+ }
+
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++ unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif
+--- ./include/asm-i386/processor.h.fix 2004-01-09 21:27:46.000000000 +0100
++++ ./include/asm-i386/processor.h 2004-02-11 19:13:22.000000000 +0100
+@@ -630,4 +630,6 @@
+
+ extern void select_idle_routine(const struct cpuinfo_x86 *c);
+
++extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #endif /* __ASM_I386_PROCESSOR_H */
+--- linux-2.6.0/include/asm-i386/ptrace.h.i386_Skas 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/ptrace.h 2003-12-31 16:57:54.000000000 +0100
+@@ -59,4 +59,26 @@
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+
++/*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
+--- ./include/asm-i386/mmu_context.h.fix 2003-12-25 19:24:24.000000000 +0100
++++ ./include/asm-i386/mmu_context.h 2004-02-29 16:16:54.000000000 +0100
+@@ -29,6 +29,10 @@
+ {
+ int cpu = smp_processor_id();
+
++#ifdef CONFIG_SMP
++ prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ if (likely(prev != next)) {
+ /* stop flush ipis for the previous mm */
+ cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +54,6 @@
+ #ifdef CONFIG_SMP
+ else {
+ cpu_tlbstate[cpu].state = TLBSTATE_OK;
+- BUG_ON(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
Added: trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,631 @@
+--- linux-2.6.0/include/linux/mm.h.Skas_add 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/mm.h 2003-12-31 17:13:57.000000000 +0100
+@@ -515,6 +515,9 @@
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -548,9 +551,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,
+--- linux-2.6.0/include/linux/proc_mm.h.Skas_add 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/proc_mm.h 2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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
+--- linux-2.6.0/mm/mmap.c.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mmap.c 2003-12-31 17:13:57.000000000 +0100
+@@ -480,11 +480,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;
+@@ -737,7 +737,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.
+--- linux-2.6.0/mm/mprotect.c.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mprotect.c 2003-12-31 17:13:57.000000000 +0100
+@@ -223,8 +223,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;
+ struct vm_area_struct * vma, * next, * prev;
+@@ -247,9 +248,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;
+@@ -328,6 +329,11 @@
+ prev->vm_mm->map_count--;
+ }
+ 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));
++}
+--- linux-2.6.0/mm/proc_mm.c.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/proc_mm.c 2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,174 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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 "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++ struct mm_struct *ret = ERR_PTR(-EBADF);
++ struct file *file;
++
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ ret = ERR_PTR(-EINVAL);
++ if(file->f_op != &proc_mm_fops)
++ goto out_fput;
++
++ ret = file->private_data;
++ out_fput:
++ fput(file);
++ out:
++ return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flags, unsigned long fd,
++ unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct mm_struct *mm = file->private_data;
++ struct proc_mm_op req;
++ int n, ret;
++
++ if(count > sizeof(req))
++ return(-EINVAL);
++
++ n = copy_from_user(&req, buffer, count);
++ if(n != 0)
++ return(-EFAULT);
++
++ ret = count;
++ switch(req.op){
++ case MM_MMAP: {
++ struct mm_mmap *map = &req.u.mmap;
++
++ ret = do_mmap2(mm, map->addr, map->len, map->prot,
++ map->flags, map->fd, map->offset >> PAGE_SHIFT);
++ if((ret & ~PAGE_MASK) == 0)
++ ret = count;
++
++ break;
++ }
++ case MM_MUNMAP: {
++ struct mm_munmap *unmap = &req.u.munmap;
++
++ down_write(&mm->mmap_sem);
++ ret = do_munmap(mm, unmap->addr, unmap->len);
++ up_write(&mm->mmap_sem);
++
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++ case MM_MPROTECT: {
++ struct mm_mprotect *protect = &req.u.mprotect;
++
++ ret = do_mprotect(mm, protect->addr, protect->len,
++ protect->prot);
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++
++ case MM_COPY_SEGMENTS: {
++ struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++ if(IS_ERR(from)){
++ ret = PTR_ERR(from);
++ break;
++ }
++
++ __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:
++ */
+--- linux-2.6.0/mm/Makefile.Skas_add 2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/Makefile 2003-12-31 17:13:57.000000000 +0100
+@@ -13,3 +13,5 @@
+
+ obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o
+ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
+--- linux-2.6.0/arch/i386/kernel/sys_i386.c.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/sys_i386.c 2003-12-31 16:57:39.000000000 +0100
+@@ -41,7 +41,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,7 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -101,7 +101,7 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+--- linux-2.6.0/arch/i386/kernel/ptrace.c.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ptrace.c 2003-12-31 16:57:39.000000000 +0100
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -508,6 +509,56 @@
+ addr, (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;
+--- linux-2.6.0/arch/i386/kernel/ldt.c.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ldt.c 2003-12-31 16:57:40.000000000 +0100
+@@ -54,7 +54,7 @@
+ pc->size = mincount;
+ wmb();
+
+- if (reload) {
++ if (reload && (¤t->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ cpumask_t mask;
+ preempt_disable();
+@@ -89,14 +89,12 @@
+ * 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);
+@@ -105,6 +103,11 @@
+ 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
+ */
+@@ -121,11 +124,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;
+@@ -169,9 +172,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -195,7 +197,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->context, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -228,23 +230,29 @@
+ 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);
++}
+--- linux-2.6.0/arch/i386/Kconfig.i386_Skas 2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/Kconfig 2003-12-31 16:57:40.000000000 +0100
+@@ -707,6 +707,9 @@
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++
+ # Common NUMA Features
+ config NUMA
+ bool "Numa Memory Allocation Support"
+--- linux-2.6.0/include/asm-i386/desc.h.i386_Skas 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/desc.h 2003-12-31 16:57:40.000000000 +0100
+@@ -123,6 +123,9 @@
+ put_cpu();
+ }
+
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++ unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif
+--- ./include/asm-i386/processor.h.fix 2004-01-09 21:27:46.000000000 +0100
++++ ./include/asm-i386/processor.h 2004-02-11 19:13:22.000000000 +0100
+@@ -648,4 +648,6 @@
+
+ extern void select_idle_routine(const struct cpuinfo_x86 *c);
+
++extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #endif /* __ASM_I386_PROCESSOR_H */
+--- linux-2.6.0/include/asm-i386/ptrace.h.i386_Skas 2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/ptrace.h 2003-12-31 16:57:54.000000000 +0100
+@@ -59,4 +59,26 @@
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+
++/*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
+--- ./include/asm-i386/mmu_context.h.fix 2003-12-25 19:24:24.000000000 +0100
++++ ./include/asm-i386/mmu_context.h 2004-02-29 16:16:54.000000000 +0100
+@@ -29,6 +29,10 @@
+ {
+ int cpu = smp_processor_id();
+
++#ifdef CONFIG_SMP
++ prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ if (likely(prev != next)) {
+ /* stop flush ipis for the previous mm */
+ cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +54,6 @@
+ #ifdef CONFIG_SMP
+ else {
+ cpu_tlbstate[cpu].state = TLBSTATE_OK;
+- BUG_ON(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
Added: trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,633 @@
+--- ./arch/i386/kernel/sys_i386.c.skas 2004-03-13 17:55:23.000000000 +0100
++++ ./arch/i386/kernel/sys_i386.c 2004-06-17 16:24:30.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,7 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -101,7 +101,7 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+--- ./arch/i386/kernel/ptrace.c.skas 2004-06-16 22:25:18.000000000 +0200
++++ ./arch/i386/kernel/ptrace.c 2004-06-17 16:24:30.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -509,6 +510,56 @@
+ (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;
+--- ./arch/i386/kernel/ldt.c.skas 2003-12-25 19:23:56.000000000 +0100
++++ ./arch/i386/kernel/ldt.c 2004-06-17 16:24:30.000000000 +0200
+@@ -54,7 +54,7 @@
+ pc->size = mincount;
+ wmb();
+
+- if (reload) {
++ if (reload && (¤t->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ cpumask_t mask;
+ preempt_disable();
+@@ -89,14 +89,12 @@
+ * 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);
+@@ -105,6 +103,11 @@
+ 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
+ */
+@@ -121,11 +124,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;
+@@ -169,9 +172,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -195,7 +197,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->context, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -228,23 +230,29 @@
+ 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);
++}
+--- ./arch/i386/Kconfig.skas 2004-06-16 22:25:18.000000000 +0200
++++ ./arch/i386/Kconfig 2004-06-17 16:24:30.000000000 +0200
+@@ -720,6 +720,10 @@
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
+ # Common NUMA Features
+ config NUMA
+ bool "Numa Memory Allocation and Scheduler Support"
+--- ./include/linux/mm.h.skas 2004-06-16 22:27:11.000000000 +0200
++++ ./include/linux/mm.h 2004-06-17 16:24:30.000000000 +0200
+@@ -574,6 +574,9 @@
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -632,9 +635,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,
+--- ./include/linux/proc_mm.h.skas 2004-06-17 16:24:30.000000000 +0200
++++ ./include/linux/proc_mm.h 2004-06-17 16:24:30.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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
+--- ./include/asm-i386/desc.h.skas 2003-12-20 17:44:08.000000000 +0100
++++ ./include/asm-i386/desc.h 2004-06-17 16:24:30.000000000 +0200
+@@ -123,6 +123,9 @@
+ put_cpu();
+ }
+
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++ unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif
+--- ./include/asm-i386/processor.h.skas 2004-06-16 22:27:00.000000000 +0200
++++ ./include/asm-i386/processor.h 2004-06-17 16:24:30.000000000 +0200
+@@ -649,6 +649,8 @@
+
+ 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)
+
+ #ifdef CONFIG_SCHED_SMT
+--- ./include/asm-i386/ptrace.h.skas 2003-12-20 17:21:33.000000000 +0100
++++ ./include/asm-i386/ptrace.h 2004-06-17 16:24:30.000000000 +0200
+@@ -59,4 +59,26 @@
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+
++/*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
+--- ./include/asm-i386/mmu_context.h.skas 2003-12-25 19:24:24.000000000 +0100
++++ ./include/asm-i386/mmu_context.h 2004-06-17 16:24:30.000000000 +0200
+@@ -29,6 +29,10 @@
+ {
+ int cpu = smp_processor_id();
+
++#ifdef CONFIG_SMP
++ prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ if (likely(prev != next)) {
+ /* stop flush ipis for the previous mm */
+ cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +54,6 @@
+ #ifdef CONFIG_SMP
+ else {
+ cpu_tlbstate[cpu].state = TLBSTATE_OK;
+- BUG_ON(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
+--- ./mm/mmap.c.skas 2004-06-16 22:27:18.000000000 +0200
++++ ./mm/mmap.c 2004-06-17 16:24:30.000000000 +0200
+@@ -725,11 +725,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;
+@@ -988,7 +988,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.
+--- ./mm/mprotect.c.skas 2004-06-16 22:27:18.000000000 +0200
++++ ./mm/mprotect.c 2004-06-17 16:24:30.000000000 +0200
+@@ -185,8 +185,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;
+ struct vm_area_struct *vma, *prev;
+@@ -209,9 +210,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;
+@@ -277,6 +278,11 @@
+ }
+ }
+ 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));
++}
+--- ./mm/proc_mm.c.skas 2004-06-17 16:24:30.000000000 +0200
++++ ./mm/proc_mm.c 2004-06-17 16:24:30.000000000 +0200
+@@ -0,0 +1,174 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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 "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++ struct mm_struct *ret = ERR_PTR(-EBADF);
++ struct file *file;
++
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ ret = ERR_PTR(-EINVAL);
++ if(file->f_op != &proc_mm_fops)
++ goto out_fput;
++
++ ret = file->private_data;
++ out_fput:
++ fput(file);
++ out:
++ return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flags, unsigned long fd,
++ unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct mm_struct *mm = file->private_data;
++ struct proc_mm_op req;
++ int n, ret;
++
++ if(count > sizeof(req))
++ return(-EINVAL);
++
++ n = copy_from_user(&req, buffer, count);
++ if(n != 0)
++ return(-EFAULT);
++
++ ret = count;
++ switch(req.op){
++ case MM_MMAP: {
++ struct mm_mmap *map = &req.u.mmap;
++
++ ret = do_mmap2(mm, map->addr, map->len, map->prot,
++ map->flags, map->fd, map->offset >> PAGE_SHIFT);
++ if((ret & ~PAGE_MASK) == 0)
++ ret = count;
++
++ break;
++ }
++ case MM_MUNMAP: {
++ struct mm_munmap *unmap = &req.u.munmap;
++
++ down_write(&mm->mmap_sem);
++ ret = do_munmap(mm, unmap->addr, unmap->len);
++ up_write(&mm->mmap_sem);
++
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++ case MM_MPROTECT: {
++ struct mm_mprotect *protect = &req.u.mprotect;
++
++ ret = do_mprotect(mm, protect->addr, protect->len,
++ protect->prot);
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++
++ case MM_COPY_SEGMENTS: {
++ struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++ if(IS_ERR(from)){
++ ret = PTR_ERR(from);
++ break;
++ }
++
++ __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:
++ */
+--- ./mm/Makefile.skas 2004-06-16 22:27:15.000000000 +0200
++++ ./mm/Makefile 2004-06-17 16:24:30.000000000 +0200
+@@ -15,3 +15,4 @@
+ obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o
+ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
+ obj-$(CONFIG_NUMA) += mempolicy.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
Added: trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,872 @@
+
+
+Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade_spam at yahoo.it>
+---
+
+ vanilla-linux-2.6.8.1-paolo/Makefile | 2
+ vanilla-linux-2.6.8.1-paolo/arch/i386/Kconfig | 4
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/entry.S | 9
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ldt.c | 38 +-
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ptrace.c | 71 ++++-
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/sys_i386.c | 12
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/desc.h | 3
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/mmu_context.h | 19 +
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/ptrace.h | 22 +
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/thread_info.h | 4
+ vanilla-linux-2.6.8.1-paolo/include/linux/mm.h | 13
+ vanilla-linux-2.6.8.1-paolo/include/linux/proc_mm.h | 48 +++
+ vanilla-linux-2.6.8.1-paolo/include/linux/ptrace.h | 1
+ vanilla-linux-2.6.8.1-paolo/kernel/fork.c | 1
+ vanilla-linux-2.6.8.1-paolo/mm/Makefile | 1
+ vanilla-linux-2.6.8.1-paolo/mm/mmap.c | 10
+ vanilla-linux-2.6.8.1-paolo/mm/mprotect.c | 23 +
+ vanilla-linux-2.6.8.1-paolo/mm/proc_mm.c | 181 +++++++++++++
+ 18 files changed, 415 insertions(+), 47 deletions(-)
+
+diff -puN arch/i386/Kconfig~host-skas3-2.6.8.1-v6 arch/i386/Kconfig
+--- vanilla-linux-2.6.8.1/arch/i386/Kconfig~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.166827168 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/Kconfig 2004-10-18 19:02:18.301806648 +0200
+@@ -721,6 +721,10 @@ config X86_PAE
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
+ # Common NUMA Features
+ config NUMA
+ bool "Numa Memory Allocation and Scheduler Support"
+diff -puN arch/i386/kernel/entry.S~host-skas3-2.6.8.1-v6 arch/i386/kernel/entry.S
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/entry.S~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.202821696 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/entry.S 2004-10-18 19:02:18.335801480 +0200
+@@ -258,7 +258,7 @@ sysenter_past_esp:
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ call *sys_call_table(,%eax,4)
+ movl %eax,EAX(%esp)
+@@ -280,8 +280,8 @@ ENTRY(system_call)
+ GET_THREAD_INFO(%ebp)
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+- # system call tracing in operation
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ # system call tracing in operation / emulation
++ testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ syscall_call:
+ call *sys_call_table(,%eax,4)
+@@ -340,6 +340,9 @@ syscall_trace_entry:
+ movl %esp, %eax
+ xorl %edx,%edx
+ call do_syscall_trace
++ cmpl $0, %eax
++ jne syscall_exit # ret != 0 -> running under PTRACE_SYSEMU,
++ # so must skip actual syscall
+ movl ORIG_EAX(%esp), %eax
+ cmpl $(nr_syscalls), %eax
+ jnae syscall_call
+diff -puN arch/i386/kernel/ldt.c~host-skas3-2.6.8.1-v6 arch/i386/kernel/ldt.c
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/ldt.c~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.203821544 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ldt.c 2004-10-18 19:02:18.319803912 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -54,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();
+@@ -89,14 +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 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);
+@@ -105,6 +102,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);
++}
++
+ /*
+ * No need to lock the MM as we are the last user
+ */
+@@ -121,11 +124,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;
+@@ -169,9 +172,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -195,7 +197,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;
+ }
+@@ -228,23 +230,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);
++}
+diff -puN arch/i386/kernel/ptrace.c~host-skas3-2.6.8.1-v6 arch/i386/kernel/ptrace.c
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/ptrace.c~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.204821392 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ptrace.c 2004-10-18 19:02:18.319803912 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -357,6 +358,7 @@ asmlinkage int sys_ptrace(long request,
+ }
+ break;
+
++ case PTRACE_SYSEMU: /* continue and replace next syscall */
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ long tmp;
+@@ -364,6 +366,12 @@ asmlinkage int sys_ptrace(long request,
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
++ if (request == PTRACE_SYSEMU) {
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ }
++ else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ }
+ if (request == PTRACE_SYSCALL) {
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ }
+@@ -404,6 +412,7 @@ asmlinkage int sys_ptrace(long request,
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ if ((child->ptrace & PT_DTRACE) == 0) {
+ /* Spurious delayed TF traps may occur */
+@@ -509,6 +518,56 @@ asmlinkage int sys_ptrace(long request,
+ (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;
+@@ -524,8 +583,9 @@ out:
+ * - triggered by current->work.syscall_trace
+ */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++ int is_sysemu;
+ if (unlikely(current->audit_context)) {
+ if (!entryexit)
+ audit_syscall_entry(current, regs->orig_eax,
+@@ -534,11 +594,12 @@ void do_syscall_trace(struct pt_regs *re
+ else
+ audit_syscall_exit(current, regs->eax);
+ }
++ is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
+
+- if (!test_thread_flag(TIF_SYSCALL_TRACE))
+- return;
++ if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
++ return 0;
+ if (!(current->ptrace & PT_PTRACED))
+- return;
++ return 0;
+ /* the 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+@@ -553,4 +614,6 @@ void do_syscall_trace(struct pt_regs *re
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
++ /* != 0 if nullifying the syscall, 0 if running it normally */
++ return is_sysemu;
+ }
+diff -puN arch/i386/kernel/sys_i386.c~host-skas3-2.6.8.1-v6 arch/i386/kernel/sys_i386.c
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/sys_i386.c~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.205821240 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/sys_i386.c 2004-10-18 19:02:18.320803760 +0200
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,7 @@ asmlinkage long sys_mmap2(unsigned long
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -101,7 +101,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+diff -puN include/asm-i386/desc.h~host-skas3-2.6.8.1-v6 include/asm-i386/desc.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/desc.h~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.214819872 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/desc.h 2004-10-18 19:02:18.320803760 +0200
+@@ -124,6 +124,9 @@ static inline void load_LDT(mm_context_t
+ put_cpu();
+ }
+
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++ unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif
+diff -puN include/asm-i386/mmu_context.h~host-skas3-2.6.8.1-v6 include/asm-i386/mmu_context.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/mmu_context.h~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.215819720 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/mmu_context.h 2004-10-18 19:02:18.335801480 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,10 @@ static inline void switch_mm(struct mm_s
+ {
+ int cpu = smp_processor_id();
+
++#ifdef CONFIG_SMP
++ prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ if (likely(prev != next)) {
+ /* stop flush ipis for the previous mm */
+ cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ else {
+ cpu_tlbstate[cpu].state = TLBSTATE_OK;
+- BUG_ON(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 -puN include/asm-i386/ptrace.h~host-skas3-2.6.8.1-v6 include/asm-i386/ptrace.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/ptrace.h~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.216819568 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/ptrace.h 2004-10-18 19:02:18.335801480 +0200
+@@ -59,4 +59,26 @@ struct pt_regs {
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+
++/*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 -puN include/asm-i386/thread_info.h~host-skas3-2.6.8.1-v6 include/asm-i386/thread_info.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/thread_info.h~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.217819416 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/thread_info.h 2004-10-18 19:02:18.336801328 +0200
+@@ -143,6 +143,7 @@ static inline unsigned long current_stac
+ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
+ #define TIF_IRET 5 /* return with iret */
++#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+
+@@ -152,12 +153,13 @@ static inline unsigned long current_stac
+ #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+ #define _TIF_IRET (1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+- (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
++ (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
+
+ /*
+diff -puN include/linux/mm.h~host-skas3-2.6.8.1-v6 include/linux/mm.h
+--- vanilla-linux-2.6.8.1/include/linux/mm.h~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.237816376 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/linux/mm.h 2004-10-18 19:02:18.248814704 +0200
+@@ -575,6 +575,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -633,9 +636,15 @@ extern void exit_mmap(struct mm_struct *
+
+ 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,
+diff -puN include/linux/proc_mm.h~host-skas3-2.6.8.1-v6 include/linux/proc_mm.h
+--- vanilla-linux-2.6.8.1/include/linux/proc_mm.h~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.238816224 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/linux/proc_mm.h 2004-10-18 19:02:18.275810600 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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 -puN include/linux/ptrace.h~host-skas3-2.6.8.1-v6 include/linux/ptrace.h
+--- vanilla-linux-2.6.8.1/include/linux/ptrace.h~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.239816072 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/linux/ptrace.h 2004-10-18 19:02:18.336801328 +0200
+@@ -20,6 +20,7 @@
+ #define PTRACE_DETACH 0x11
+
+ #define PTRACE_SYSCALL 24
++#define PTRACE_SYSEMU 31
+
+ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
+ #define PTRACE_SETOPTIONS 0x4200
+diff -puN kernel/fork.c~host-skas3-2.6.8.1-v6 kernel/fork.c
+--- vanilla-linux-2.6.8.1/kernel/fork.c~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.240815920 +0200
++++ vanilla-linux-2.6.8.1-paolo/kernel/fork.c 2004-10-18 19:02:18.337801176 +0200
+@@ -1008,6 +1008,7 @@ struct task_struct *copy_process(unsigne
+ * of CLONE_PTRACE.
+ */
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++ clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+diff -puN mm/Makefile~host-skas3-2.6.8.1-v6 mm/Makefile
+--- vanilla-linux-2.6.8.1/mm/Makefile~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.242815616 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/Makefile 2004-10-18 19:02:18.275810600 +0200
+@@ -15,3 +15,4 @@ obj-y := bootmem.o filemap.o mempool.o
+ obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o
+ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
+ obj-$(CONFIG_NUMA) += mempolicy.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+diff -puN mm/mmap.c~host-skas3-2.6.8.1-v6 mm/mmap.c
+--- vanilla-linux-2.6.8.1/mm/mmap.c~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.243815464 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/mmap.c 2004-10-18 19:02:18.276810448 +0200
+@@ -736,11 +736,11 @@ none:
+ * 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;
+@@ -1006,7 +1006,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.
+diff -puN mm/mprotect.c~host-skas3-2.6.8.1-v6 mm/mprotect.c
+--- vanilla-linux-2.6.8.1/mm/mprotect.c~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.244815312 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/mprotect.c 2004-10-18 19:02:18.284809232 +0200
+@@ -92,19 +92,20 @@ change_protection(struct vm_area_struct
+ {
+ pgd_t *dir;
+ unsigned long beg = start;
++ struct mm_struct * mm = vma->vm_mm;
+
+- dir = pgd_offset(current->mm, start);
++ dir = pgd_offset(mm, start);
+ flush_cache_range(vma, beg, end);
+ if (start >= end)
+ BUG();
+- spin_lock(¤t->mm->page_table_lock);
++ spin_lock(&mm->page_table_lock);
+ do {
+ change_pmd_range(dir, start, end - start, newprot);
+ start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (start && (start < end));
+ flush_tlb_range(vma, beg, end);
+- spin_unlock(¤t->mm->page_table_lock);
++ spin_unlock(&mm->page_table_lock);
+ return;
+ }
+
+@@ -185,8 +186,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;
+ struct vm_area_struct *vma, *prev;
+@@ -215,9 +217,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;
+@@ -283,6 +285,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));
++}
+diff -puN mm/proc_mm.c~host-skas3-2.6.8.1-v6 mm/proc_mm.c
+--- vanilla-linux-2.6.8.1/mm/proc_mm.c~host-skas3-2.6.8.1-v6 2004-10-18 19:02:18.245815160 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/proc_mm.c 2004-10-18 19:02:18.301806648 +0200
+@@ -0,0 +1,181 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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);
++
++ spin_lock(&mmlist_lock);
++ list_add(&mm->mmlist, ¤t->mm->mmlist);
++ mmlist_nr++;
++ spin_unlock(&mmlist_lock);
++
++ 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:
++ */
+_
Added: trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,871 @@
+--- vanilla-linux-2.6.9-paolo/arch/i386/kernel/entry.S 2004-10-26 02:24:42.196918400 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/kernel/entry.S 2004-10-26 02:24:46.219306904 +0200
+@@ -256,7 +256,7 @@
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -278,8 +278,8 @@
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+- # system call tracing in operation
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ # system call tracing in operation / emulation
++ testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -340,6 +340,9 @@
+ movl %esp, %eax
+ xorl %edx,%edx
+ call do_syscall_trace
++ cmpl $0, %eax
++ jne syscall_exit # ret != 0 -> running under PTRACE_SYSEMU,
++ # so must skip actual syscall
+ movl ORIG_EAX(%esp), %eax
+ cmpl $(nr_syscalls), %eax
+ jnae syscall_call
+--- vanilla-linux-2.6.9-paolo/arch/i386/kernel/ptrace.c 2004-10-29 00:52:30.744281064 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/kernel/ptrace.c 2004-10-29 00:52:34.737673976 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -358,6 +359,7 @@
+ }
+ break;
+
++ case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ long tmp;
+@@ -365,10 +367,21 @@
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
++ /* If we came here with PTRACE_SYSEMU and now continue with
++ * PTRACE_SYSCALL, entry.S used to intercept the syscall return.
++ * But it shouldn't!
++ * So we don't clear TIF_SYSCALL_EMU, which is always unused in
++ * this special case, to remember, we came from SYSEMU. That
++ * flag will be cleared by do_syscall_trace().
++ */
++ if (request == PTRACE_SYSEMU) {
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ } else if (request == PTRACE_CONT) {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ }
+ if (request == PTRACE_SYSCALL) {
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+- }
+- else {
++ } else {
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ }
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+@@ -407,6 +420,8 @@
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
++ /*See do_syscall_trace to know why we don't clear
++ * TIF_SYSCALL_EMU.*/
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ if ((child->ptrace & PT_DTRACE) == 0) {
+ /* Spurious delayed TF traps may occur */
+@@ -513,6 +528,56 @@
+ (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;
+@@ -528,8 +593,9 @@
+ * - triggered by current->work.syscall_trace
+ */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++ int is_sysemu, is_systrace, is_singlestep;
+ if (unlikely(current->audit_context)) {
+ if (!entryexit)
+ audit_syscall_entry(current, regs->orig_eax,
+@@ -538,16 +604,27 @@
+ else
+ audit_syscall_exit(current, regs->eax);
+ }
++ is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
++ is_systrace = test_thread_flag(TIF_SYSCALL_TRACE);
++ is_singlestep = test_thread_flag(TIF_SINGLESTEP);
+
+- if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+- !test_thread_flag(TIF_SINGLESTEP))
+- return;
++ if (!is_systrace && !is_singlestep && !is_sysemu)
++ return 0;
++ /* We can detect the case of coming from PTRACE_SYSEMU and now running
++ * with PTRACE_SYSCALL or PTRACE_SINGLESTEP, by TIF_SYSCALL_EMU being
++ * set additionally.
++ * If so let's reset the flag and return without action.
++ */
++ if (is_sysemu && (is_systrace || is_singlestep)) {
++ clear_thread_flag(TIF_SYSCALL_EMU);
++ return 0;
++ }
+ if (!(current->ptrace & PT_PTRACED))
+- return;
++ return 0;
+ /* the 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
+- !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
++ !is_singlestep ? 0x80 : 0));
+
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+@@ -560,2 +637,4 @@
+ }
++ /* != 0 if nullifying the syscall, 0 if running it normally */
++ return is_sysemu;
+ }
+--- vanilla-linux-2.6.9/include/asm-i386/thread_info.h~host-sysemu-2.6.7-4 2004-10-26 02:24:42.191919160 +0200
++++ vanilla-linux-2.6.9-paolo/include/asm-i386/thread_info.h 2004-10-26 02:24:42.197918248 +0200
+@@ -143,6 +143,7 @@ static inline unsigned long current_stac
+ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
+ #define TIF_IRET 5 /* return with iret */
++#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+
+@@ -152,12 +153,14 @@ static inline unsigned long current_stac
+ #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+ #define _TIF_IRET (1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+- (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
++ (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++ _TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
+
+ /*
+--- vanilla-linux-2.6.9-paolo/include/linux/ptrace.h 2004-10-26 02:24:42.197918248 +0200
++++ vanilla-linux-2.6.9-paolo/include/linux/ptrace.h 2004-10-26 02:24:46.218307056 +0200
+@@ -20,6 +20,7 @@
+ #define PTRACE_DETACH 0x11
+
+ #define PTRACE_SYSCALL 24
++#define PTRACE_SYSEMU 31
+
+ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
+ #define PTRACE_SETOPTIONS 0x4200
+--- vanilla-linux-2.6.9-paolo/kernel/fork.c 2004-10-26 02:24:42.197918248 +0200
++++ vanilla-linux-2.6.9-paolo/kernel/fork.c 2004-10-26 01:59:51.388555720 +0200
+@@ -1040,6 +1040,9 @@
+ * of CLONE_PTRACE.
+ */
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++ clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+--- vanilla-linux-2.6.9/include/linux/mm.h~Add_generic_proc_mm_support 2004-10-26 00:46:35.058899416 +0200
++++ vanilla-linux-2.6.9-paolo/include/linux/mm.h 2004-10-26 00:46:35.090894552 +0200
+@@ -623,6 +623,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -682,9 +685,15 @@ extern void exit_mmap(struct mm_struct *
+
+ 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,
+--- vanilla-linux-2.6.9/include/linux/proc_mm.h~Add_generic_proc_mm_support 2004-10-26 00:46:35.059899264 +0200
++++ vanilla-linux-2.6.9-paolo/include/linux/proc_mm.h 2004-10-26 00:46:35.090894552 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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
+--- vanilla-linux-2.6.9/mm/Makefile~Add_generic_proc_mm_support 2004-10-26 00:46:35.060899112 +0200
++++ vanilla-linux-2.6.9-paolo/mm/Makefile 2004-10-26 00:46:35.091894400 +0200
+@@ -18,3 +18,4 @@ obj-$(CONFIG_NUMA) += mempolicy.o
+ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+--- vanilla-linux-2.6.9/mm/mmap.c~Add_generic_proc_mm_support 2004-10-26 00:46:35.061898960 +0200
++++ vanilla-linux-2.6.9-paolo/mm/mmap.c 2004-10-26 00:46:35.091894400 +0200
+@@ -759,11 +759,11 @@ void __vm_stat_account(struct mm_struct
+ * 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;
+@@ -1034,7 +1034,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.
+--- vanilla-linux-2.6.9-paolo/mm/mprotect.c 2004-10-26 00:46:35.092894248 +0200
++++ linux-2.6.9-current-paolo/mm/mprotect.c 2004-10-14 18:35:43.018815232 +0200
+@@ -92,19 +92,20 @@
+ {
+ pgd_t *dir;
+ unsigned long beg = start;
++ struct mm_struct * mm = vma->vm_mm;
+
+- dir = pgd_offset(current->mm, start);
++ dir = pgd_offset(mm, start);
+ flush_cache_range(vma, beg, end);
+ if (start >= end)
+ BUG();
+- spin_lock(¤t->mm->page_table_lock);
++ spin_lock(&mm->page_table_lock);
+ do {
+ change_pmd_range(dir, start, end - start, newprot);
+ start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (start && (start < end));
+ flush_tlb_range(vma, beg, end);
+- spin_unlock(¤t->mm->page_table_lock);
++ spin_unlock(&mm->page_table_lock);
+ return;
+ }
+
+@@ -187,8 +188,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;
+ struct vm_area_struct *vma, *prev;
+@@ -217,9 +219,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;
+@@ -288,3 +290,8 @@
+- 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));
++}
+--- linux-2.6.9-current-paolo/mm/proc_mm.c 2004-10-14 18:35:43.019815080 +0200
++++ linux-2.6.9-current-paolo/mm/proc_mm.c 2004-10-14 18:42:05.146722960 +0200
+@@ -0,0 +1,182 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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);
++
++ spin_lock(&mmlist_lock);
++ list_add(&mm->mmlist, ¤t->mm->mmlist);
++ mmlist_nr++;
++ spin_unlock(&mmlist_lock);
++
++ 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:
++ */
+--- vanilla-linux-2.6.9/arch/i386/Kconfig~i386-specific 2004-10-29 00:52:34.701679448 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/Kconfig 2004-10-29 00:52:34.709678232 +0200
+@@ -724,6 +724,10 @@ config X86_PAE
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
+ # Common NUMA Features
+ config NUMA
+ bool "Numa Memory Allocation and Scheduler Support"
+--- vanilla-linux-2.6.9-paolo/arch/i386/kernel/ldt.c 2004-10-29 00:52:34.737673976 +0200
++++ linux-2.6.9-current-paolo/arch/i386/kernel/ldt.c 2004-10-14 18:27:44.384578696 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -54,7 +55,7 @@
+ pc->size = mincount;
+ wmb();
+
+- if (reload) {
++ if (reload && (¤t->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ cpumask_t mask;
+ preempt_disable();
+@@ -89,14 +90,10 @@
+ * 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);
+@@ -105,6 +102,12 @@
+ 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
+ */
+@@ -121,11 +124,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;
+@@ -174,9 +177,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -200,7 +202,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->context, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -236,20 +238,26 @@
+-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);
++}
+--- vanilla-linux-2.6.9/arch/i386/kernel/sys_i386.c~i386-specific 2004-10-29 00:52:34.704678992 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/kernel/sys_i386.c 2004-10-29 00:52:34.738673824 +0200
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,7 @@ asmlinkage long sys_mmap2(unsigned long
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -101,7 +101,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+--- vanilla-linux-2.6.9/include/asm-i386/desc.h~i386-specific 2004-10-29 00:52:34.705678840 +0200
++++ vanilla-linux-2.6.9-paolo/include/asm-i386/desc.h 2004-10-29 00:52:34.738673824 +0200
+@@ -126,6 +126,9 @@ static inline void load_LDT(mm_context_t
+ put_cpu();
+ }
+
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++ unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif
+--- vanilla-linux-2.6.9/include/asm-i386/ptrace.h~i386-specific 2004-10-29 00:52:34.707678536 +0200
++++ vanilla-linux-2.6.9-paolo/include/asm-i386/ptrace.h 2004-10-29 00:52:34.738673824 +0200
+@@ -64,4 +64,26 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif
+
++/*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
+--- linux-2.6.9-current-paolo/include/asm-i386/mmu_context.h 2004-10-14 18:27:17.059732704 +0200
++++ linux-2.6.9-current-paolo/include/asm-i386/mmu_context.h 2004-10-14 18:27:44.384578696 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+--- vanilla-linux-2.6.9/arch/um/include/skas_ptrace.h~make-skas-uml-compatible 2004-10-26 01:59:51.352561192 +0200
++++ vanilla-linux-2.6.9-paolo/arch/um/include/skas_ptrace.h 2004-10-26 01:59:51.388555720 +0200
+@@ -6,6 +6,7 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+
++#ifndef PTRACE_FAULTINFO
+ struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+@@ -21,6 +22,7 @@ struct ptrace_ldt {
+ #define PTRACE_SIGPENDING 53
+ #define PTRACE_LDT 54
+ #define PTRACE_SWITCH_MM 55
++#endif
+
+ #endif
Added: trunk/src/kernel-patch-skas/host-skas3.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,589 @@
+diff -Naur host/arch/i386/config.in host-ptrace/arch/i386/config.in
+--- host/arch/i386/config.in Fri Aug 9 15:57:14 2002
++++ host-ptrace/arch/i386/config.in Sun Nov 10 18:40:09 2002
+@@ -291,6 +291,8 @@
+ bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
+ fi
+
++bool '/proc/mm' CONFIG_PROC_MM
++
+ endmenu
+
+ source drivers/mtd/Config.in
+diff -Naur host/arch/i386/kernel/ldt.c host-ptrace/arch/i386/kernel/ldt.c
+--- host/arch/i386/kernel/ldt.c Fri Oct 26 00:01:41 2001
++++ host-ptrace/arch/i386/kernel/ldt.c Sun Nov 3 18:37:48 2002
+@@ -24,11 +24,12 @@
+ * assured by user-space anyway. Writes are atomic, to protect
+ * the security checks done on new descriptors.
+ */
+-static int read_ldt(void * ptr, unsigned long bytecount)
++static int read_ldt(struct task_struct *task, void * ptr,
++ unsigned long bytecount)
+ {
+ int err;
+ unsigned long size;
+- struct mm_struct * mm = current->mm;
++ struct mm_struct * mm = task->mm;
+
+ err = 0;
+ if (!mm->context.segments)
+@@ -64,9 +65,10 @@
+ return err;
+ }
+
+-static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct task_struct *task, void * ptr,
++ unsigned long bytecount, int oldmode)
+ {
+- struct mm_struct * mm = current->mm;
++ struct mm_struct * mm = task->mm;
+ __u32 entry_1, entry_2, *lp;
+ int error;
+ struct modify_ldt_ldt_s ldt_info;
+@@ -148,23 +150,29 @@
+ return error;
+ }
+
+-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++int modify_ldt(struct task_struct *task, int func, void *ptr,
++ unsigned long bytecount)
+ {
+ int ret = -ENOSYS;
+
+ switch (func) {
+ case 0:
+- ret = read_ldt(ptr, bytecount);
++ ret = read_ldt(task, ptr, bytecount);
+ break;
+ case 1:
+- ret = write_ldt(ptr, bytecount, 1);
++ ret = write_ldt(task, ptr, bytecount, 1);
+ break;
+ case 2:
+ ret = read_default_ldt(ptr, bytecount);
+ break;
+ case 0x11:
+- ret = write_ldt(ptr, bytecount, 0);
++ ret = write_ldt(task, ptr, bytecount, 0);
+ break;
+ }
+ return ret;
++}
++
++asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++{
++ return(modify_ldt(current, func, ptr, bytecount));
+ }
+diff -Naur host/arch/i386/kernel/process.c host-ptrace/arch/i386/kernel/process.c
+--- host/arch/i386/kernel/process.c Fri Aug 9 15:57:14 2002
++++ host-ptrace/arch/i386/kernel/process.c Wed Nov 6 22:12:45 2002
+@@ -551,13 +551,11 @@
+ * we do not have to muck with descriptors here, that is
+ * done in switch_mm() as needed.
+ */
+-void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
++void mm_copy_segments(struct mm_struct *old_mm, struct mm_struct *new_mm)
+ {
+- struct mm_struct * old_mm;
+ void *old_ldt, *ldt;
+
+ ldt = NULL;
+- old_mm = current->mm;
+ if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
+ /*
+ * Completely new LDT, we initialize it from the parent:
+@@ -570,6 +568,16 @@
+ }
+ new_mm->context.segments = ldt;
+ new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */
++}
++
++void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
++{
++ mm_copy_segments(current->mm, new_mm);
++}
++
++void copy_task_segments(struct task_struct *from, struct mm_struct *new_mm)
++{
++ mm_copy_segments(from->mm, new_mm);
+ }
+
+ /*
+diff -Naur host/arch/i386/kernel/ptrace.c host-ptrace/arch/i386/kernel/ptrace.c
+--- host/arch/i386/kernel/ptrace.c Fri Aug 9 15:57:14 2002
++++ host-ptrace/arch/i386/kernel/ptrace.c Mon Nov 11 19:03:38 2002
+@@ -147,6 +147,11 @@
+ put_stack_long(child, EFL_OFFSET, tmp);
+ }
+
++extern int modify_ldt(struct task_struct *task, int func, void *ptr,
++ unsigned long bytecount);
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
+ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+ {
+ struct task_struct *child;
+@@ -415,6 +420,53 @@
+ child->ptrace |= PT_TRACESYSGOOD;
+ else
+ child->ptrace &= ~PT_TRACESYSGOOD;
++ ret = 0;
++ break;
++ }
++
++ case PTRACE_FAULTINFO: {
++ struct ptrace_faultinfo fault;
++
++ fault = ((struct ptrace_faultinfo)
++ { .is_write = child->thread.error_code,
++ .addr = child->thread.cr2 });
++ ret = copy_to_user((unsigned long *) data, &fault,
++ sizeof(fault));
++ if(ret)
++ break;
++ break;
++ }
++ case PTRACE_SIGPENDING:
++ ret = copy_to_user((unsigned long *) data,
++ &child->pending.signal,
++ sizeof(child->pending.signal));
++ break;
++
++ case PTRACE_LDT: {
++ struct ptrace_ldt ldt;
++
++ if(copy_from_user(&ldt, (unsigned long *) data,
++ sizeof(ldt))){
++ ret = -EIO;
++ break;
++ }
++ ret = modify_ldt(child, ldt.func, ldt.ptr, ldt.bytecount);
++ break;
++ }
++
++ case PTRACE_SWITCH_MM: {
++ struct mm_struct *old = child->mm;
++ struct mm_struct *new = proc_mm_get_mm(data);
++
++ if(IS_ERR(new)){
++ ret = PTR_ERR(new);
++ break;
++ }
++
++ atomic_inc(&new->mm_users);
++ child->mm = new;
++ child->active_mm = new;
++ mmput(old);
+ ret = 0;
+ break;
+ }
+diff -Naur host/arch/i386/kernel/sys_i386.c host-ptrace/arch/i386/kernel/sys_i386.c
+--- host/arch/i386/kernel/sys_i386.c Mon Mar 19 15:35:09 2001
++++ host-ptrace/arch/i386/kernel/sys_i386.c Mon Nov 11 17:23:25 2002
+@@ -40,7 +40,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -55,9 +55,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -69,7 +69,7 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -100,7 +100,7 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+diff -Naur host/include/asm-i386/processor.h host-ptrace/include/asm-i386/processor.h
+--- host/include/asm-i386/processor.h Sun Nov 10 18:47:37 2002
++++ host-ptrace/include/asm-i386/processor.h Mon Nov 11 17:33:30 2002
+@@ -436,6 +436,8 @@
+ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+ /* Copy and release all segment info associated with a VM */
++extern void mm_copy_segments(struct mm_struct *old_mm,
++ struct mm_struct *new_mm);
+ extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
+ extern void release_segments(struct mm_struct * mm);
+
+diff -Naur host/include/asm-i386/ptrace.h host-ptrace/include/asm-i386/ptrace.h
+--- host/include/asm-i386/ptrace.h Sun Sep 23 19:20:51 2001
++++ host-ptrace/include/asm-i386/ptrace.h Sun Nov 10 18:36:22 2002
+@@ -51,6 +51,22 @@
+
+ #define PTRACE_SETOPTIONS 21
+
++struct ptrace_faultinfo {
++ int is_write;
++ unsigned long addr;
++};
++
++struct ptrace_ldt {
++ int func;
++ void *ptr;
++ unsigned long bytecount;
++};
++
++#define PTRACE_FAULTINFO 52
++#define PTRACE_SIGPENDING 53
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++
+ /* options set using PTRACE_SETOPTIONS */
+ #define PTRACE_O_TRACESYSGOOD 0x00000001
+
+diff -Naur host/include/linux/mm.h host-ptrace/include/linux/mm.h
+--- host/include/linux/mm.h Fri Aug 30 15:03:44 2002
++++ host-ptrace/include/linux/mm.h Mon Nov 11 19:08:53 2002
+@@ -492,6 +492,9 @@
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+ int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc() that does all
+@@ -539,9 +542,10 @@
+
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+- unsigned long len, unsigned long prot,
+- unsigned long flag, unsigned long pgoff);
++extern unsigned long do_mmap_pgoff(struct mm_struct *mm,
++ struct file *file, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flag, unsigned long pgoff);
+
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long prot,
+@@ -551,7 +555,7 @@
+ if ((offset + PAGE_ALIGN(len)) < offset)
+ goto out;
+ if (!(offset & ~PAGE_MASK))
+- ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
++ ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, offset >> PAGE_SHIFT);
+ out:
+ return ret;
+ }
+diff -Naur host/include/linux/proc_mm.h host-ptrace/include/linux/proc_mm.h
+--- host/include/linux/proc_mm.h Wed Dec 31 19:00:00 1969
++++ host-ptrace/include/linux/proc_mm.h Mon Nov 11 17:41:09 2002
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++ unsigned long addr;
++ unsigned long len;
++ unsigned long prot;
++ unsigned long flags;
++ unsigned long fd;
++ unsigned long offset;
++};
++
++struct mm_munmap {
++ unsigned long addr;
++ unsigned long len;
++};
++
++struct mm_mprotect {
++ unsigned long addr;
++ unsigned long len;
++ unsigned int prot;
++};
++
++struct proc_mm_op {
++ int op;
++ union {
++ struct mm_mmap mmap;
++ struct mm_munmap munmap;
++ struct mm_mprotect mprotect;
++ int copy_segments;
++ } u;
++};
++
++#endif
+diff -Naur host/mm/Makefile host-ptrace/mm/Makefile
+--- host/mm/Makefile Fri Aug 9 15:57:31 2002
++++ host-ptrace/mm/Makefile Sun Nov 10 18:37:33 2002
+@@ -17,5 +17,6 @@
+ shmem.o
+
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+
+ include $(TOPDIR)/Rules.make
+diff -Naur host/mm/mmap.c host-ptrace/mm/mmap.c
+--- host/mm/mmap.c Fri Aug 9 15:57:31 2002
++++ host-ptrace/mm/mmap.c Mon Nov 11 17:24:18 2002
+@@ -390,10 +390,11 @@
+ return 0;
+ }
+
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
+- unsigned long prot, unsigned long flags, unsigned long pgoff)
++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++ unsigned long addr, unsigned long len,
++ unsigned long prot, unsigned long flags,
++ unsigned long pgoff)
+ {
+- struct mm_struct * mm = current->mm;
+ struct vm_area_struct * vma, * prev;
+ unsigned int vm_flags;
+ int correct_wcount = 0;
+diff -Naur host/mm/mprotect.c host-ptrace/mm/mprotect.c
+--- host/mm/mprotect.c Fri Aug 9 15:57:31 2002
++++ host-ptrace/mm/mprotect.c Mon Nov 11 17:47:58 2002
+@@ -264,7 +264,8 @@
+ return 0;
+ }
+
+-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++ unsigned long prot)
+ {
+ unsigned long nstart, end, tmp;
+ struct vm_area_struct * vma, * next, * prev;
+@@ -281,9 +282,9 @@
+ if (end == start)
+ return 0;
+
+- down_write(¤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 || vma->vm_start > start)
+ goto out;
+@@ -332,6 +333,11 @@
+ prev->vm_mm->map_count--;
+ }
+ 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));
+ }
+diff -Naur host/mm/proc_mm.c host-ptrace/mm/proc_mm.c
+--- host/mm/proc_mm.c Wed Dec 31 19:00:00 1969
++++ host-ptrace/mm/proc_mm.c Mon Nov 11 19:07:52 2002
+@@ -0,0 +1,173 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++ struct mm_struct *ret = ERR_PTR(-EBADF);
++ struct file *file;
++
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ ret = ERR_PTR(-EINVAL);
++ if(file->f_op != &proc_mm_fops)
++ goto out_fput;
++
++ ret = file->private_data;
++
++ out_fput:
++ fput(file);
++ out:
++ return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++ unsigned long len, unsigned long prot,
++ unsigned long flags, unsigned long fd,
++ unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++ size_t count, loff_t *ppos)
++{
++ struct mm_struct *mm = file->private_data;
++ struct proc_mm_op req;
++ int n, ret;
++
++ if(count > sizeof(req))
++ return(-EINVAL);
++
++ n = copy_from_user(&req, buffer, count);
++ if(n != 0)
++ return(-EFAULT);
++
++ ret = count;
++ switch(req.op){
++ case MM_MMAP: {
++ struct mm_mmap *map = &req.u.mmap;
++
++ ret = do_mmap2(mm, map->addr, map->len, map->prot,
++ map->flags, map->fd, map->offset >> PAGE_SHIFT);
++ if((ret & ~PAGE_MASK) == 0)
++ ret = count;
++
++ break;
++ }
++ case MM_MUNMAP: {
++ struct mm_munmap *unmap = &req.u.munmap;
++
++ down_write(&mm->mmap_sem);
++ ret = do_munmap(mm, unmap->addr, unmap->len);
++ up_write(&mm->mmap_sem);
++
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++ case MM_MPROTECT: {
++ struct mm_mprotect *protect = &req.u.mprotect;
++
++ ret = do_mprotect(mm, protect->addr, protect->len,
++ protect->prot);
++ if(ret == 0)
++ ret = count;
++ break;
++ }
++
++ case MM_COPY_SEGMENTS: {
++ struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++ if(IS_ERR(from)){
++ ret = PTR_ERR(from);
++ break;
++ }
++
++ mm_copy_segments(from, mm);
++ break;
++ }
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++ struct mm_struct *mm = mm_alloc();
++ int ret;
++
++ ret = -ENOMEM;
++ if(mm == NULL)
++ goto out_mem;
++
++ ret = init_new_context(current, mm);
++ if(ret)
++ goto out_free;
++
++ spin_lock(&mmlist_lock);
++ list_add(&mm->mmlist, ¤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:
++ */
Added: trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,953 @@
+--- vanilla-linux-2.6.10-paolo/arch/i386/kernel/entry.S 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/entry.S 2005-03-10 18:16:15.000000000 +0100
+@@ -222,7 +222,7 @@
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -245,8 +245,8 @@
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+- # system call tracing in operation
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ # system call tracing in operation / emulation
++ testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -307,10 +307,19 @@
+ movl %esp, %eax
+ xorl %edx,%edx
+ call do_syscall_trace
++ cmpl $0, %eax
++ jne syscall_skip # ret != 0 -> running under PTRACE_SYSEMU,
++ # so must skip actual syscall
+ movl ORIG_EAX(%esp), %eax
+ cmpl $(nr_syscalls), %eax
+ jnae syscall_call
+ jmp syscall_exit
++syscall_skip:
++ cli # make sure we don't miss an interrupt
++ # setting need_resched or sigpending
++ # between sampling and the iret
++ movl TI_flags(%ebp), %ecx
++ jmp work_pending
+
+ # perform syscall exit tracing
+ ALIGN
+--- vanilla-linux-2.6.10-paolo/arch/i386/kernel/ptrace.c 2005-03-10 18:16:15.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/ptrace.c 2005-03-10 18:16:16.000000000 +0100
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -168,6 +169,8 @@
+ void ptrace_disable(struct task_struct *child)
+ {
+ clear_singlestep(child);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+
+ /*
+@@ -406,15 +409,20 @@
+ }
+ break;
+
++ case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: /* restart after signal. */
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+- if (request == PTRACE_SYSCALL) {
++ if (request == PTRACE_SYSEMU) {
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ } else if (request == PTRACE_SYSCALL) {
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+- }
+- else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ } else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ }
+ child->exit_code = data;
+@@ -439,10 +447,17 @@
+ wake_up_process(child);
+ break;
+
++ case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
++
++ if (request == PTRACE_SYSEMU_SINGLESTEP)
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ else
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ set_singlestep(child);
+ child->exit_code = data;
+@@ -542,6 +557,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;
+@@ -557,26 +624,45 @@
+ * - triggered by current->work.syscall_trace
+ */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++ int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
++ /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP */
++ int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ if (unlikely(current->audit_context)) {
+- if (!entryexit)
++ if (!entryexit) {
+ audit_syscall_entry(current, regs->orig_eax,
+ regs->ebx, regs->ecx,
+ regs->edx, regs->esi);
++ /* With TIF_SYSCALL_AUDIT | TIF_SINGLESTEP &&
++ * !TIF_SYSCALL_EMU we come in here, but must not
++ * continue with ptrace_notify().
++ * In the SINGLESTEP && ! _AUDIT case (i.e. normal one),
++ * entry.S will call us only on syscall exit and not on
++ * the syscall entry path, so let's be consistent.
++ */
++ if (is_singlestep)
++ return 0;
++ }
+ else
+ audit_syscall_exit(current, regs->eax);
+ }
++ /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++ * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++ * here. We have to check this and return */
++ if (is_sysemu && entryexit)
++ return 0;
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+- !test_thread_flag(TIF_SINGLESTEP))
+- return;
++ !is_singlestep && !is_sysemu)
++ return 0;
+ if (!(current->ptrace & PT_PTRACED))
+- return;
++ return 0;
+ /* the 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
+- !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
++ !is_singlestep ? 0x80 : 0));
+
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+@@ -589,2 +675,10 @@
+ }
++ /* != 0 if nullifying the syscall, 0 if running it normally */
++ if ( !is_sysemu )
++ return 0;
++
++ regs->orig_eax = -1; /* force skip of syscall restarting */
++ if (unlikely(current->audit_context))
++ audit_syscall_exit(current, regs->eax);
++ return 1;
+ }
+--- vanilla-linux-2.6.10/include/asm-i386/thread_info.h~host-sysemu-2.6.7-4 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/thread_info.h 2005-03-10 18:16:11.000000000 +0100
+@@ -139,6 +139,7 @@ register unsigned long current_stack_poi
+ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
+ #define TIF_IRET 5 /* return with iret */
++#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+
+@@ -148,12 +149,14 @@ register unsigned long current_stack_poi
+ #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+ #define _TIF_IRET (1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+- (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
++ (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++ _TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
+
+ /*
+--- vanilla-linux-2.6.10-paolo/include/linux/ptrace.h 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/linux/ptrace.h 2005-03-10 18:16:15.000000000 +0100
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH 0x11
+
+ #define PTRACE_SYSCALL 24
++#define PTRACE_SYSEMU 31
++#define PTRACE_SYSEMU_SINGLESTEP 32
+
+ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
+ #define PTRACE_SETOPTIONS 0x4200
+--- vanilla-linux-2.6.10/kernel/fork.c~host-sysemu-2.6.7-4 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/kernel/fork.c 2005-03-10 18:16:11.000000000 +0100
+@@ -926,6 +926,9 @@ static task_t *copy_process(unsigned lon
+ * of CLONE_PTRACE.
+ */
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++ clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+--- vanilla-linux-2.6.10/include/linux/mm.h~Add_generic_proc_mm_support 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/linux/mm.h 2005-03-10 18:16:11.000000000 +0100
+@@ -625,6 +625,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -684,9 +687,15 @@ extern void exit_mmap(struct mm_struct *
+
+ 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,
+--- vanilla-linux-2.6.10/include/linux/proc_mm.h~Add_generic_proc_mm_support 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/linux/proc_mm.h 2005-03-10 18:16:11.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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
+--- vanilla-linux-2.6.10/mm/Makefile~Add_generic_proc_mm_support 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/Makefile 2005-03-10 18:16:11.000000000 +0100
+@@ -18,3 +18,4 @@ obj-$(CONFIG_NUMA) += mempolicy.o
+ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+--- vanilla-linux-2.6.10/mm/mmap.c~Add_generic_proc_mm_support 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/mmap.c 2005-03-10 18:16:11.000000000 +0100
+@@ -759,11 +759,11 @@ void __vm_stat_account(struct mm_struct
+ * 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;
+@@ -1037,7 +1037,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.
+--- vanilla-linux-2.6.10/mm/mprotect.c~Add_generic_proc_mm_support 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/mprotect.c 2005-03-10 18:16:11.000000000 +0100
+@@ -93,19 +93,20 @@ change_protection(struct vm_area_struct
+ {
+ pgd_t *dir;
+ unsigned long beg = start;
++ struct mm_struct * mm = vma->vm_mm;
+
+- dir = pgd_offset(current->mm, start);
++ dir = pgd_offset(mm, start);
+ flush_cache_range(vma, beg, end);
+ if (start >= end)
+ BUG();
+- spin_lock(¤t->mm->page_table_lock);
++ spin_lock(&mm->page_table_lock);
+ do {
+ change_pmd_range(dir, start, end - start, newprot);
+ start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (start && (start < end));
+ flush_tlb_range(vma, beg, end);
+- spin_unlock(¤t->mm->page_table_lock);
++ spin_unlock(&mm->page_table_lock);
+ return;
+ }
+
+@@ -190,8 +191,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;
+ struct vm_area_struct *vma, *prev;
+@@ -220,9 +222,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;
+@@ -288,6 +290,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));
++}
+--- vanilla-linux-2.6.10-paolo/mm/proc_mm.c 2005-03-10 18:16:13.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/proc_mm.c 2005-03-10 18:16:13.000000000 +0100
+@@ -0,0 +1,177 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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:
++ */
+--- vanilla-linux-2.6.10/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support 2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/um/include/skas_ptrace.h 2005-03-10 18:16:11.000000000 +0100
+@@ -6,6 +6,7 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+
++#ifndef PTRACE_FAULTINFO
+ struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+@@ -21,6 +22,7 @@ struct ptrace_ldt {
+ #define PTRACE_SIGPENDING 53
+ #define PTRACE_LDT 54
+ #define PTRACE_SWITCH_MM 55
++#endif
+
+ #endif
+
+--- vanilla-linux-2.6.10/arch/i386/Kconfig~i386-specific 2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/Kconfig 2005-03-10 18:16:12.000000000 +0100
+@@ -730,6 +730,10 @@ config X86_PAE
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
+ # Common NUMA Features
+ config NUMA
+ bool "Numa Memory Allocation and Scheduler Support"
+--- vanilla-linux-2.6.10-paolo/arch/i386/kernel/ldt.c 2005-03-10 18:16:14.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/ldt.c 2005-03-10 18:16:14.000000000 +0100
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,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;
+@@ -58,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) {
+@@ -76,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;
+ }
+
+@@ -89,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
+ */
+@@ -121,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;
+@@ -174,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -200,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;
+ }
+@@ -236,20 +241,26 @@
+-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);
++}
+--- vanilla-linux-2.6.10/arch/i386/kernel/sys_i386.c~i386-specific 2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/sys_i386.c 2005-03-10 18:16:12.000000000 +0100
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,7 @@ asmlinkage long sys_mmap2(unsigned long
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(addr, len, prot, flags, fd, pgoff);
++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+
+ /*
+@@ -101,7 +101,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ return err;
+ }
+--- vanilla-linux-2.6.10-paolo/include/asm-i386/desc.h 2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/desc.h 2005-03-10 18:16:14.000000000 +0100
+@@ -126,6 +126,9 @@
+ put_cpu();
+ }
+
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++ unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+
+ #endif
+--- vanilla-linux-2.6.10/include/asm-i386/ptrace.h~i386-specific 2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/ptrace.h 2005-03-10 18:16:12.000000000 +0100
+@@ -64,4 +64,26 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif
+
++/*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
+--- vanilla-linux-2.6.10-paolo/include/asm-i386/mmu_context.h 2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/mmu_context.h 2005-03-10 18:16:12.000000000 +0100
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+--- /dev/null 2005-03-26 18:29:00.701330288 +0100
++++ clean-linux-2.6.10-paolo/localversion-skas 2005-03-29 16:00:28.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v8
Added: trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,946 @@
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/entry.S 2005-07-10 16:56:19.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/entry.S 2005-05-03 09:08:14.000000000 +0200
+@@ -219,7 +219,7 @@
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -242,8 +242,8 @@
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+- # system call tracing in operation
+- testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++ # system call tracing in operation / emulation
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -304,6 +304,9 @@
+ movl %esp, %eax
+ xorl %edx,%edx
+ call do_syscall_trace
++ cmpl $0, %eax
++ jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU,
++ # so must skip actual syscall
+ movl ORIG_EAX(%esp), %eax
+ cmpl $(nr_syscalls), %eax
+ jnae syscall_call
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/ptrace.c 2005-07-10 16:57:36.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/ptrace.c 2005-07-10 16:55:40.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -269,6 +270,8 @@
+ void ptrace_disable(struct task_struct *child)
+ {
+ clear_singlestep(child);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+
+ /*
+@@ -507,15 +510,20 @@
+ }
+ break;
+
++ case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: /* restart after signal. */
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+- if (request == PTRACE_SYSCALL) {
++ if (request == PTRACE_SYSEMU) {
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ } else if (request == PTRACE_SYSCALL) {
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+- }
+- else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ } else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ }
+ child->exit_code = data;
+@@ -540,10 +548,17 @@
+ wake_up_process(child);
+ break;
+
++ case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
++
++ if (request == PTRACE_SYSEMU_SINGLESTEP)
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ else
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ set_singlestep(child);
+ child->exit_code = data;
+@@ -643,6 +658,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;
+@@ -676,29 +743,49 @@
+ * - triggered by current->work.syscall_trace
+ */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++ int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
++ /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP */
++ int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ if (unlikely(current->audit_context)) {
+- if (!entryexit)
++ if (!entryexit) {
+ audit_syscall_entry(current, regs->orig_eax,
+ regs->ebx, regs->ecx,
+ regs->edx, regs->esi);
++ /* With TIF_SYSCALL_AUDIT | TIF_SINGLESTEP &&
++ * !TIF_SYSCALL_EMU we come in here, but must not
++ * continue with ptrace_notify().
++ * In the SINGLESTEP && ! _AUDIT case (i.e. normal one),
++ * entry.S will call us only on syscall exit and not on
++ * the syscall entry path, so let's be consistent.
++ */
++ if (is_singlestep)
++ return 0;
++ }
+ else
+ audit_syscall_exit(current, regs->eax);
+ }
+-
+ if (!(current->ptrace & PT_PTRACED))
+- return;
++ return 0;
++
++ /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++ * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++ * here. We have to check this and return */
++ if (is_sysemu && entryexit)
++ return 0;
+
+ /* Fake a debug trap */
+- if (test_thread_flag(TIF_SINGLESTEP))
++ if (is_singlestep)
+ send_sigtrap(current, regs, 0);
+
+- if (!test_thread_flag(TIF_SYSCALL_TRACE))
+- return;
++ if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
++ return 0;
+
+ /* the 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
++ /* Note that the debugger could change the result of test_thread_flag!*/
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+
+ /*
+@@ -712,2 +799,10 @@
+ }
++ /* != 0 if nullifying the syscall, 0 if running it normally */
++ if ( !is_sysemu )
++ return 0;
++
++ regs->orig_eax = -1; /* force skip of syscall restarting */
++ if (unlikely(current->audit_context))
++ audit_syscall_exit(current, regs->eax);
++ return 1;
+ }
+--- clean-linux-2.6.11-paolo/include/asm-i386/thread_info.h 2005-07-10 16:55:19.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/thread_info.h 2005-05-03 09:08:14.000000000 +0200
+@@ -140,6 +140,7 @@
+ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
+ #define TIF_IRET 5 /* return with iret */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
++#define TIF_SYSCALL_EMU 9 /* syscall emulation active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE 17
+
+@@ -149,12 +150,14 @@
+ #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+ #define _TIF_IRET (1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+- (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
++ (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++ _TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
+
+ /*
+--- clean-linux-2.6.11-paolo/include/linux/ptrace.h 2005-07-10 16:57:37.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/linux/ptrace.h 2005-07-10 16:55:38.000000000 +0200
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH 0x11
+
+ #define PTRACE_SYSCALL 24
++#define PTRACE_SYSEMU 31
++#define PTRACE_SYSEMU_SINGLESTEP 32
+
+ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
+ #define PTRACE_SETOPTIONS 0x4200
+--- clean-linux-2.6.11/kernel/fork.c~host-sysemu-2.6.7-4 2005-07-10 16:55:19.000000000 +0200
++++ clean-linux-2.6.11-paolo/kernel/fork.c 2005-07-10 16:55:19.000000000 +0200
+@@ -938,6 +938,9 @@ static task_t *copy_process(unsigned lon
+ * of CLONE_PTRACE.
+ */
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++ clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+--- clean-linux-2.6.11/include/linux/mm.h~Add_generic_proc_mm_support 2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/linux/mm.h 2005-07-10 16:55:31.000000000 +0200
+@@ -655,6 +655,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level or three-level page table, this ends up being trivial. Thus
+ * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -730,9 +733,15 @@ extern void exit_mmap(struct mm_struct *
+
+ 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,
+--- clean-linux-2.6.11/include/linux/proc_mm.h~Add_generic_proc_mm_support 2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/linux/proc_mm.h 2005-07-10 16:55:31.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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
+--- clean-linux-2.6.11/mm/Makefile~Add_generic_proc_mm_support 2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/Makefile 2005-07-10 16:55:31.000000000 +0200
+@@ -18,3 +18,4 @@ obj-$(CONFIG_NUMA) += mempolicy.o
+ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+--- clean-linux-2.6.11/mm/mmap.c~Add_generic_proc_mm_support 2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/mmap.c 2005-07-10 16:55:31.000000000 +0200
+@@ -861,11 +861,11 @@ void __vm_stat_account(struct mm_struct
+ * 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;
+@@ -1141,7 +1141,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.
+--- clean-linux-2.6.11-paolo/mm/mprotect.c 2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/mprotect.c 2005-07-11 11:35:56.000000000 +0200
+@@ -117,7 +117,7 @@
+ change_protection(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, pgprot_t newprot)
+ {
+- struct mm_struct *mm = current->mm;
++ struct mm_struct *mm = vma->vm_mm;
+ pgd_t *pgd;
+ unsigned long beg = start, next;
+ int i;
+@@ -219,8 +219,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;
+ struct vm_area_struct *vma, *prev;
+@@ -249,9 +250,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;
+@@ -320,3 +321,12 @@
+- 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;
++}
+--- clean-linux-2.6.11-paolo/mm/proc_mm.c 2005-07-10 16:57:39.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/proc_mm.c 2005-07-10 16:55:34.000000000 +0200
+@@ -0,0 +1,177 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at 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:
++ */
+--- clean-linux-2.6.11/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support 2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/um/include/skas_ptrace.h 2005-07-10 16:55:31.000000000 +0200
+@@ -6,6 +6,7 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+
++#ifndef PTRACE_FAULTINFO
+ struct ptrace_faultinfo {
+ int is_write;
+ unsigned long addr;
+@@ -21,6 +22,7 @@ struct ptrace_ldt {
+ #define PTRACE_SIGPENDING 53
+ #define PTRACE_LDT 54
+ #define PTRACE_SWITCH_MM 55
++#endif
+
+ #endif
+
+--- clean-linux-2.6.11/arch/i386/Kconfig~i386-specific 2005-07-10 16:55:32.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/Kconfig 2005-07-10 16:55:32.000000000 +0200
+@@ -745,6 +745,10 @@ config X86_PAE
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
+ # Common NUMA Features
+ config NUMA
+ bool "Numa Memory Allocation and Scheduler Support"
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/ldt.c 2005-07-10 16:55:35.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/ldt.c 2005-07-11 11:35:56.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,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;
+@@ -58,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) {
+@@ -76,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;
+ }
+
+@@ -89,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
+ */
+@@ -121,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;
+@@ -174,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -200,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;
+ }
+@@ -236,20 +241,30 @@
+-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;
++}
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/sys_i386.c 2005-07-10 16:57:34.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/sys_i386.c 2005-07-10 16:56:25.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,12 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(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;
+ }
+
+ /*
+@@ -101,7 +106,10 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ /* 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;
+ }
+--- clean-linux-2.6.11/include/asm-i386/desc.h~i386-specific 2005-07-10 16:55:32.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/desc.h 2005-07-10 16:55:32.000000000 +0200
+@@ -135,6 +135,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
+--- clean-linux-2.6.11/include/asm-i386/ptrace.h~i386-specific 2005-07-10 16:55:32.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/ptrace.h 2005-07-10 16:55:32.000000000 +0200
+@@ -66,4 +66,26 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif
+
++/*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
+--- clean-linux-2.6.11-paolo/include/asm-i386/mmu_context.h 2005-07-10 16:57:40.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/mmu_context.h 2005-07-10 16:55:33.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+--- clean-linux-2.6.11-paolo/localversion-skas 2005-07-10 16:56:52.000000000 +0200
++++ clean-linux-2.6.11-paolo/localversion-skas 2005-07-11 11:36:04.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v8.2
Added: trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1989 @@
+--- linux-2.6.12-paolo/arch/i386/kernel/entry.S 2005-05-08 19:52:15.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/arch/i386/kernel/entry.S 2005-07-08 12:26:20.000000000 +0200
+@@ -203,7 +203,7 @@
+ GET_THREAD_INFO(%ebp)
+
+ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+- testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -226,9 +226,9 @@
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+- # system call tracing in operation
++ # system call tracing in operation / emulation
+ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+- testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -338,6 +338,9 @@
+ movl %esp, %eax
+ xorl %edx,%edx
+ call do_syscall_trace
++ cmpl $0, %eax
++ jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU,
++ # so must skip actual syscall
+ movl ORIG_EAX(%esp), %eax
+ cmpl $(nr_syscalls), %eax
+ jnae syscall_call
+--- linux-2.6.git-paolo/arch/i386/kernel/ptrace.c 2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/kernel/ptrace.c 2005-05-21 18:00:55.000000000 +0200
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -271,6 +272,8 @@
+ void ptrace_disable(struct task_struct *child)
+ {
+ clear_singlestep(child);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+
+ /*
+@@ -509,15 +512,20 @@
+ }
+ break;
+
++ case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: /* restart after signal. */
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
+- if (request == PTRACE_SYSCALL) {
++ if (request == PTRACE_SYSEMU) {
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ } else if (request == PTRACE_SYSCALL) {
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+- }
+- else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ } else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ }
+ child->exit_code = data;
+@@ -542,10 +550,17 @@
+ wake_up_process(child);
+ break;
+
++ case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
++
++ if (request == PTRACE_SYSEMU_SINGLESTEP)
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ else
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ set_singlestep(child);
+ child->exit_code = data;
+@@ -645,6 +660,70 @@
+ (struct user_desc __user *) data);
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+@@ -678,26 +757,48 @@
+ * - triggered by current->work.syscall_trace
+ */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++ int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0;
++ /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP */
++ int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ /* do the secure computing check first */
+ secure_computing(regs->orig_eax);
+
+- if (unlikely(current->audit_context) && entryexit)
+- audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++ if (unlikely(current->audit_context)) {
++ if (entryexit)
++ audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++ /* With TIF_SYSCALL_AUDIT | TIF_SINGLESTEP &&
++ * !TIF_SYSCALL_EMU we come in here, but must not
++ * continue with ptrace_notify().
++ * In the SINGLESTEP && ! _AUDIT case (i.e. normal one),
++ * entry.S will call us only on syscall exit and not on
++ * the syscall entry path, so let's be consistent.
++ */
++ else if (is_singlestep)
++ goto out;
++ }
+
+ if (!(current->ptrace & PT_PTRACED))
+ goto out;
+
++ /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++ * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++ * here. We have to check this and return */
++ if (is_sysemu && entryexit)
++ return 0;
++
+ /* Fake a debug trap */
+- if (test_thread_flag(TIF_SINGLESTEP))
++ if (is_singlestep)
+ send_sigtrap(current, regs, 0);
+
+- if (!test_thread_flag(TIF_SYSCALL_TRACE))
++ if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
+ goto out;
+
+ /* the 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
++ /* Note that the debugger could change the result of test_thread_flag!*/
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+
+ /*
+@@ -711,7 +812,14 @@
+ }
++ ret = is_sysemu;
+ out:
+ if (unlikely(current->audit_context) && !entryexit)
+ audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
+ regs->ebx, regs->ecx, regs->edx, regs->esi);
++ if (ret == 0)
++ return 0;
+
++ regs->orig_eax = -1; /* force skip of syscall restarting */
++ if (unlikely(current->audit_context))
++ audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++ return 1;
+ }
+--- linux-2.6.12-paolo/include/asm-i386/thread_info.h 2005-05-08 19:16:10.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/thread_info.h 2005-05-06 16:26:26.000000000 +0200
+@@ -141,6 +141,7 @@
+ #define TIF_IRET 5 /* return with iret */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_SECCOMP 8 /* secure computing */
++#define TIF_SYSCALL_EMU 9 /* syscall emulation active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE 17
+
+@@ -150,13 +151,15 @@
+ #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+ #define _TIF_IRET (1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP (1<<TIF_SECCOMP)
+ #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+- (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
++ (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++ _TIF_SECCOMP|_TIF_SYSCALL_EMU))
+ /* work to do on any return to u-space */
+ #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
+
+--- linux-2.6.12-paolo/include/linux/ptrace.h 2005-05-08 19:16:10.000000000 +0200
++++ linux-2.6.12-paolo/include/linux/ptrace.h 2005-05-08 19:57:03.000000000 +0200
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH 0x11
+
+ #define PTRACE_SYSCALL 24
++#define PTRACE_SYSEMU 31
++#define PTRACE_SYSEMU_SINGLESTEP 32
+
+ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
+ #define PTRACE_SETOPTIONS 0x4200
+--- linux-2.6.12/kernel/fork.c~host-sysemu-2.6.7-4 2005-05-08 19:16:10.000000000 +0200
++++ linux-2.6.12-paolo/kernel/fork.c 2005-05-08 19:16:10.000000000 +0200
+@@ -989,6 +989,9 @@ static task_t *copy_process(unsigned lon
+ * of CLONE_PTRACE.
+ */
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++ clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+--- linux-2.6.git/include/linux/mm.h~Add_generic_proc_mm_support 2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/mm.h 2005-05-19 15:40:16.000000000 +0200
+@@ -654,6 +654,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level or three-level page table, this ends up being trivial. Thus
+ * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -730,9 +733,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,
+--- linux-2.6.git-paolo/include/linux/proc_mm.h 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/proc_mm.h 2005-06-02 05:02:46.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* 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 <asm/proc_mm.h>
++
++/*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
++#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);
++
++/* 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
+--- linux-2.6.git-paolo/mm/Makefile 2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/mm/Makefile 2005-05-21 18:00:57.000000000 +0200
+@@ -20,0 +21,5 @@
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m += proc_mm-mod.o
++endif
+--- linux-2.6.git/mm/mmap.c~Add_generic_proc_mm_support 2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/mm/mmap.c 2005-05-19 15:40:16.000000000 +0200
+@@ -864,11 +864,11 @@ void __vm_stat_account(struct mm_struct
+ * 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;
+@@ -1143,7 +1143,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.
+--- linux-2.6.git-paolo/mm/mprotect.c 2005-05-19 15:40:16.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/mm/mprotect.c 2005-07-10 20:08:24.000000000 +0200
+@@ -177,8 +177,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;
+@@ -209,9 +210,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;
+@@ -280,3 +281,12 @@
+- 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;
++}
+--- linux-2.6.git-paolo/mm/proc_mm.c 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/mm/proc_mm.c 2005-06-02 05:02:46.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#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>
++
++#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
++ * {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
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++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);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++ mm->dumpable = current->mm->dumpable;
++ wmb();
++#endif
++
++ 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;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++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;
++ 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_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_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_native(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;
++}
++
++/*These three are all for /proc/mm.*/
++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);
++}
++
++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;
++
++ 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);
++
++/*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
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.git/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support 2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/arch/um/include/skas_ptrace.h 2005-05-19 15:40:16.000000000 +0200
+@@ -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
+--- linux-2.6.12-paolo/arch/i386/Kconfig 2005-05-08 19:47:37.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/Kconfig 2005-06-02 05:02:46.000000000 +0200
+@@ -769,6 +769,26 @@
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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"
+--- linux-2.6.11-paolo/arch/i386/kernel/ldt.c 2005-02-10 13:25:39.841170200 +0100
++++ vanilla-linux-2.6.12-paolo/arch/i386/kernel/ldt.c 2005-07-10 20:08:06.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,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;
+@@ -58,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) {
+@@ -76,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;
+ }
+
+@@ -89,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
+ */
+@@ -121,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;
+@@ -174,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -200,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;
+ }
+@@ -236,20 +241,30 @@
+-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;
++}
+--- linux-2.6.12-paolo/arch/i386/kernel/sys_i386.c 2005-05-08 19:47:37.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/arch/i386/kernel/sys_i386.c 2005-07-10 16:06:02.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,12 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(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;
+ }
+
+ /*
+@@ -101,7 +106,10 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ /* 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;
+ }
+--- linux-2.6.12/include/asm-i386/desc.h~i386-specific 2005-05-08 19:47:37.000000000 +0200
++++ linux-2.6.12-paolo/include/asm-i386/desc.h 2005-05-08 19:47:37.000000000 +0200
+@@ -139,6 +139,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
+--- linux-2.6.git-paolo/include/asm-i386/ptrace.h 2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/ptrace.h 2005-05-21 18:00:55.000000000 +0200
+@@ -68,2 +68,31 @@
+
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO 52
++/* 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;
++ unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- linux-2.6.12-paolo/include/asm-i386/mmu_context.h 2005-05-08 19:48:07.000000000 +0200
++++ linux-2.6.12-paolo/include/asm-i386/mmu_context.h 2005-05-08 19:35:02.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+--- vanilla-linux-2.6.12-paolo/localversion-skas 2005-07-10 11:36:59.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/localversion-skas 2005-07-11 11:51:53.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v9-pre7
+--- linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c 2005-05-15 18:32:11.000000000 +0200
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++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;
++}
++
+--- /dev/null 2005-05-28 23:34:14.051125088 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/proc_mm.h 2005-06-02 05:03:04.000000000 +0200
+@@ -0,0 +1,56 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++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 */
+--- linux-2.6.git-paolo/arch/x86_64/Kconfig 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/Kconfig 2005-06-02 05:02:46.000000000 +0200
+@@ -347,6 +347,26 @@
+ of memory and any 32-bit devices. Don't turn on unless you know what you
+ are doing.
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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
+--- linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c 2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c 2005-05-21 18:00:55.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@
+ case PTRACE_SETFPXREGS:
+ case PTRACE_GETFPXREGS:
+ case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++ case PTRACE_FAULTINFO:
++ case PTRACE_LDT:
++ case PTRACE_SWITCH_MM:
++#endif
+ break;
+ }
+
+@@ -363,6 +371,65 @@
+ ret = 0;
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ child->mm = new;
++ child->active_mm = new;
++
++ task_unlock(child);
++
++ mmput(old);
++ ret = 0;
++ break;
++ }
++#endif
+
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+--- linux-2.6.git/include/asm-x86_64/mmu_context.h~x86-64-specific-addition 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/mmu_context.h 2005-06-02 05:03:04.000000000 +0200
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+ * 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);
++
+ #ifdef CONFIG_SMP
+
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,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 */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,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(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ /* We were in lazy tlb mode and leave_mm disabled
+ * tlb flush IPI delivery. We must reload CR3
+--- linux-2.6.git/arch/x86_64/ia32/sys_ia32.c~x86-64-specific-addition 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/sys_ia32.c 2005-06-02 05:03:04.000000000 +0200
+@@ -832,11 +832,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 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;
+
+@@ -848,7 +847,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)
+@@ -856,6 +855,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 error;
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ldt.c 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.11-paolo/arch/x86_64/kernel/ldt.c 2005-03-05 19:49:55.120753864 +0100
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@
+ }
+ #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;
+@@ -64,12 +66,14 @@
+
+ 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) {
+@@ -81,12 +85,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;
+ }
+
+@@ -94,22 +98,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);
++}
++
+ /*
+ *
+ * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@
+ }
+ }
+
+-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 +175,8 @@
+ 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 +201,7 @@
+
+ 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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -234,20 +237,26 @@
+-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);
++}
+--- linux-2.6.git/include/asm-x86_64/desc.h~x86-64-specific-addition 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/desc.h 2005-06-02 05:03:04.000000000 +0200
+@@ -212,6 +212,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
+--- linux-2.6.git-paolo/include/asm-x86_64/ptrace.h 2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/ptrace.h 2005-05-21 18:00:55.000000000 +0200
+@@ -64,6 +64,59 @@
+ /* top of stack page */
+ };
+
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#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_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.*/
++ compat_ulong_t bytecount;
++};
++
++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;
++ unsigned long bytecount;
++};
++
++#undef compat_int_t
++#undef compat_long_t
++#undef compat_uint_t
++#undef compat_ulong_t
++#undef compat_uptr_t
++
+ #endif
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@
+ #define PTRACE_GETFPXREGS 18
+ #define PTRACE_SETFPXREGS 19
+
++#define PTRACE_FAULTINFO 52
++/* 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
+ #define PTRACE_SET_THREAD_AREA 26
+--- linux-2.6.git/arch/x86_64/mm/Makefile~x86-64-specific-addition 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/Makefile 2005-06-02 05:03:04.000000000 +0200
+@@ -7,5 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag
+ obj-$(CONFIG_DISCONTIGMEM) += 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
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c 2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c 2005-05-21 18:00:55.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -601,6 +602,79 @@
+ break;
+ }
+
++#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;
++
++ /* 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;
++ }
++#endif
++
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+--- linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c~x86-64-specific-addition 2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/sys_x86_64.c 2005-06-02 05:03:04.000000000 +0200
+@@ -19,6 +19,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+
+ /*
+ * 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)
+ {
+--- /dev/null 2005-05-28 23:34:14.051125088 +0200
++++ linux-2.6.git-paolo/include/asm-i386/proc_mm.h 2005-06-02 05:03:04.000000000 +0200
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++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 */
+--- /dev/null 2005-05-20 16:07:16.788013064 +0200
++++ linux-2.6.git-paolo/mm/proc_mm-mod.c 2005-05-21 18:00:57.000000000 +0200
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#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);
Added: trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1994 @@
+--- linux-2.6.git-paolo/arch/i386/kernel/ptrace.c 2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/kernel/ptrace.c 2005-07-28 19:40:18.000000000 +0200
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -271,6 +272,8 @@
+ void ptrace_disable(struct task_struct *child)
+ {
+ clear_singlestep(child);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+
+ /*
+@@ -509,15 +512,20 @@
+ }
+ break;
+
++ case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: /* restart after signal. */
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
+- if (request == PTRACE_SYSCALL) {
++ if (request == PTRACE_SYSEMU) {
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++ } else if (request == PTRACE_SYSCALL) {
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+- }
+- else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ } else {
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ }
+ child->exit_code = data;
+@@ -542,10 +550,17 @@
+ wake_up_process(child);
+ break;
+
++ case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
++
++ if (request == PTRACE_SYSEMU_SINGLESTEP)
++ set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++ else
++ clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ set_singlestep(child);
+ child->exit_code = data;
+@@ -645,6 +660,70 @@
+ (struct user_desc __user *) data);
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+@@ -678,26 +757,52 @@
+ * - triggered by current->work.syscall_trace
+ */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++ int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0;
++ /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
++ * interception. */
++ int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ /* do the secure computing check first */
+ secure_computing(regs->orig_eax);
+
+- if (unlikely(current->audit_context) && entryexit)
+- audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++ if (unlikely(current->audit_context)) {
++ if (entryexit)
++ audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++ /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
++ * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
++ * not used, entry.S will call us only on syscall exit, not
++ * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
++ * calling send_sigtrap() on syscall entry.
++ *
++ * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
++ * is_singlestep is false, despite his name, so we will still do
++ * the correct thing.
++ */
++ else if (is_singlestep)
++ goto out;
++ }
+
+ if (!(current->ptrace & PT_PTRACED))
+ goto out;
+
++ /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++ * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++ * here. We have to check this and return */
++ if (is_sysemu && entryexit)
++ return 0;
++
+ /* Fake a debug trap */
+- if (test_thread_flag(TIF_SINGLESTEP))
++ if (is_singlestep)
+ send_sigtrap(current, regs, 0);
+
+- if (!test_thread_flag(TIF_SYSCALL_TRACE))
++ if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
+ goto out;
+
+ /* the 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
++ /* Note that the debugger could change the result of test_thread_flag!*/
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+
+ /*
+@@ -711,7 +816,14 @@
+ }
++ ret = is_sysemu;
+ out:
+ if (unlikely(current->audit_context) && !entryexit)
+ audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
+ regs->ebx, regs->ecx, regs->edx, regs->esi);
++ if (ret == 0)
++ return 0;
+
++ regs->orig_eax = -1; /* force skip of syscall restarting */
++ if (unlikely(current->audit_context))
++ audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++ return 1;
+ }
+--- linux-2.6.git-paolo/arch/i386/kernel/entry.S 2005-08-26 20:59:11.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/kernel/entry.S 2005-07-31 20:03:19.000000000 +0200
+@@ -203,7 +203,7 @@
+ GET_THREAD_INFO(%ebp)
+
+ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+- testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -226,9 +226,9 @@
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ GET_THREAD_INFO(%ebp)
+- # system call tracing in operation
++ # system call tracing in operation / emulation
+ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+- testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ jnz syscall_trace_entry
+ cmpl $(nr_syscalls), %eax
+ jae syscall_badsys
+@@ -338,6 +338,9 @@
+ movl %esp, %eax
+ xorl %edx,%edx
+ call do_syscall_trace
++ cmpl $0, %eax
++ jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU,
++ # so must skip actual syscall
+ movl ORIG_EAX(%esp), %eax
+ cmpl $(nr_syscalls), %eax
+ jnae syscall_call
+--- linux-2.6.git-paolo/include/asm-i386/thread_info.h 2005-07-26 20:24:57.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/thread_info.h 2005-05-06 16:26:26.000000000 +0200
+@@ -141,6 +141,7 @@
+ #define TIF_IRET 5 /* return with iret */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_SECCOMP 8 /* secure computing */
++#define TIF_SYSCALL_EMU 9 /* syscall emulation active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE 17
+
+@@ -150,13 +151,15 @@
+ #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+ #define _TIF_IRET (1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU (1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP (1<<TIF_SECCOMP)
+ #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+- (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
++ (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++ _TIF_SECCOMP|_TIF_SYSCALL_EMU))
+ /* work to do on any return to u-space */
+ #define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
+
+--- linux-2.6.git-paolo/include/linux/ptrace.h 2005-07-26 20:39:57.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/ptrace.h 2005-07-26 20:27:45.000000000 +0200
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH 0x11
+
+ #define PTRACE_SYSCALL 24
++#define PTRACE_SYSEMU 31
++#define PTRACE_SYSEMU_SINGLESTEP 32
+
+ /* 0x4200-0x4300 are reserved for architecture-independent additions. */
+ #define PTRACE_SETOPTIONS 0x4200
+--- linux-2.6.git/kernel/fork.c~host-sysemu 2005-07-26 20:24:57.000000000 +0200
++++ linux-2.6.git-paolo/kernel/fork.c 2005-07-26 20:24:57.000000000 +0200
+@@ -994,6 +994,9 @@ static task_t *copy_process(unsigned lon
+ * of CLONE_PTRACE.
+ */
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++ clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+
+ /* Our parent execution domain becomes current domain
+ These must match for thread signalling to apply */
+--- linux-2.6.git/include/linux/mm.h~Add_generic_proc_mm_support 2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/mm.h 2005-08-21 21:43:06.000000000 +0200
+@@ -759,6 +759,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level or three-level page table, this ends up being trivial. Thus
+ * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -841,9 +844,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,
+--- linux-2.6.git-paolo/include/linux/proc_mm.h 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/proc_mm.h 2005-08-21 21:44:05.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* 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 <asm/proc_mm.h>
++
++/*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
++#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);
++
++/* 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
+--- linux-2.6.git-paolo/mm/Makefile 2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/mm/Makefile 2005-07-04 18:50:00.000000000 +0200
+@@ -22,0 +23,6 @@
++
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m += proc_mm-mod.o
++endif
+--- linux-2.6.git/mm/mmap.c~Add_generic_proc_mm_support 2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/mm/mmap.c 2005-08-21 21:43:06.000000000 +0200
+@@ -868,11 +868,11 @@ void __vm_stat_account(struct mm_struct
+ * 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;
+@@ -1147,7 +1147,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.
+--- linux-2.6.git-paolo/mm/mprotect.c 2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-broken-paolo/mm/mprotect.c 2005-07-13 19:28:33.000000000 +0200
+@@ -177,8 +177,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;
+@@ -209,9 +210,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;
+@@ -280,3 +281,12 @@
+- 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;
++}
+--- linux-2.6.git-paolo/mm/proc_mm.c 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/mm/proc_mm.c 2005-08-21 21:44:05.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#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>
++
++#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
++ * {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
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++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);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++ mm->dumpable = current->mm->dumpable;
++ wmb();
++#endif
++
++ 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;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++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;
++ 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_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_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_native(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;
++}
++
++/*These three are all for /proc/mm.*/
++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);
++}
++
++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;
++
++ 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);
++
++/*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
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.git/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support 2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/arch/um/include/skas_ptrace.h 2005-08-21 21:43:06.000000000 +0200
+@@ -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
+--- linux-2.6.git-paolo/arch/i386/Kconfig 2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/Kconfig 2005-08-21 21:44:05.000000000 +0200
+@@ -748,6 +748,26 @@
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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"
+--- linux-2.6.git-paolo/arch/i386/kernel/ldt.c 2005-07-04 18:48:33.000000000 +0200
++++ linux-2.6.git-broken-paolo/arch/i386/kernel/ldt.c 2005-07-13 19:28:33.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,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;
+@@ -58,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) {
+@@ -76,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;
+ }
+
+@@ -89,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
+ */
+@@ -121,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;
+@@ -174,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, *lp;
+ int error;
+ struct user_desc ldt_info;
+@@ -200,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;
+ }
+@@ -236,20 +241,30 @@
+-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;
++}
+--- linux-2.6.git-paolo/arch/i386/kernel/sys_i386.c 2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-broken-paolo/arch/i386/kernel/sys_i386.c 2005-07-13 19:28:18.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,12 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(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;
+ }
+
+ /*
+@@ -101,7 +106,10 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ /* 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;
+ }
+--- linux-2.6.git/include/asm-i386/desc.h~i386-specific 2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/desc.h 2005-08-21 21:43:37.000000000 +0200
+@@ -139,6 +139,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
+--- linux-2.6.git-paolo/include/asm-i386/ptrace.h 2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/ptrace.h 2005-07-28 19:40:18.000000000 +0200
+@@ -79,2 +79,31 @@
+
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO 52
++/* 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;
++ unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- linux-2.6.git-paolo/include/asm-i386/mmu_context.h 2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/mmu_context.h 2005-07-04 18:48:25.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+--- linux-2.6.git-broken-paolo/localversion-skas 2005-07-13 19:30:11.000000000 +0200
++++ linux-2.6.git-broken-paolo/localversion-skas 2005-07-13 19:30:14.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v9-pre7
+--- linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c 2005-05-15 18:32:11.000000000 +0200
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++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;
++}
++
+--- /dev/null 2005-07-20 02:59:33.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/proc_mm.h 2005-07-31 18:56:20.000000000 +0200
+@@ -0,0 +1,56 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++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 */
+--- linux-2.6.git-paolo/arch/x86_64/Kconfig 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/Kconfig 2005-08-21 21:44:05.000000000 +0200
+@@ -355,6 +355,26 @@
+ of memory and any 32-bit devices. Don't turn on unless you know what you
+ are doing.
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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
+--- linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c 2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c 2005-07-28 19:40:18.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@
+ case PTRACE_SETFPXREGS:
+ case PTRACE_GETFPXREGS:
+ case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++ case PTRACE_FAULTINFO:
++ case PTRACE_LDT:
++ case PTRACE_SWITCH_MM:
++#endif
+ break;
+ }
+
+@@ -363,6 +371,65 @@
+ ret = 0;
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ child->mm = new;
++ child->active_mm = new;
++
++ task_unlock(child);
++
++ mmput(old);
++ ret = 0;
++ break;
++ }
++#endif
+
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+--- linux-2.6.git/include/asm-x86_64/mmu_context.h~x86-64-specific-addition 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/mmu_context.h 2005-07-31 18:56:20.000000000 +0200
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+ * 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);
++
+ #ifdef CONFIG_SMP
+
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,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 */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,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(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ /* We were in lazy tlb mode and leave_mm disabled
+ * tlb flush IPI delivery. We must reload CR3
+--- linux-2.6.git/arch/x86_64/ia32/sys_ia32.c~x86-64-specific-addition 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/sys_ia32.c 2005-07-31 18:56:20.000000000 +0200
+@@ -833,11 +833,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 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;
+
+@@ -849,7 +848,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)
+@@ -857,6 +856,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 error;
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ldt.c 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.11-paolo/arch/x86_64/kernel/ldt.c 2005-03-05 19:49:55.120753864 +0100
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@
+ }
+ #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;
+@@ -64,12 +66,14 @@
+
+ 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) {
+@@ -81,12 +85,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;
+ }
+
+@@ -94,22 +98,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);
++}
++
+ /*
+ *
+ * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@
+ }
+ }
+
+-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 +175,8 @@
+ 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 +201,7 @@
+
+ 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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -234,20 +237,26 @@
+-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);
++}
+--- linux-2.6.git/include/asm-x86_64/desc.h~x86-64-specific-addition 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/desc.h 2005-07-31 18:56:20.000000000 +0200
+@@ -213,6 +213,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
+--- linux-2.6.git-paolo/include/asm-x86_64/ptrace.h 2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/ptrace.h 2005-07-28 19:40:18.000000000 +0200
+@@ -64,6 +64,59 @@
+ /* top of stack page */
+ };
+
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#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_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.*/
++ compat_ulong_t bytecount;
++};
++
++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;
++ unsigned long bytecount;
++};
++
++#undef compat_int_t
++#undef compat_long_t
++#undef compat_uint_t
++#undef compat_ulong_t
++#undef compat_uptr_t
++
+ #endif
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@
+ #define PTRACE_GETFPXREGS 18
+ #define PTRACE_SETFPXREGS 19
+
++#define PTRACE_FAULTINFO 52
++/* 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
+ #define PTRACE_SET_THREAD_AREA 26
+--- linux-2.6.git/arch/x86_64/mm/Makefile~x86-64-specific-addition 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/Makefile 2005-07-31 18:56:20.000000000 +0200
+@@ -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
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c 2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c 2005-07-28 19:40:18.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -604,6 +605,79 @@
+ break;
+ }
+
++#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;
++
++ /* 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;
++ }
++#endif
++
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+--- linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c~x86-64-specific-addition 2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/sys_x86_64.c 2005-07-31 18:56:20.000000000 +0200
+@@ -19,6 +19,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+
+ /*
+ * 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)
+ {
+--- /dev/null 2005-07-20 02:59:33.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/proc_mm.h 2005-07-31 18:56:20.000000000 +0200
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++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 */
+--- /dev/null 2005-06-27 20:00:42.865153360 +0200
++++ linux-2.6.git-paolo/mm/proc_mm-mod.c 2005-07-04 18:50:00.000000000 +0200
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#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);
Added: trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1874 @@
+Index: linux-2.6.14/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.14.orig/arch/i386/Kconfig 2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/Kconfig 2005-10-29 05:50:33.000000000 +0200
+@@ -756,6 +756,26 @@
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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.14/arch/i386/kernel/ldt.c
+===================================================================
+--- linux-2.6.14.orig/arch/i386/kernel/ldt.c 2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/kernel/ldt.c 2005-10-29 05:50:30.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,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;
+@@ -58,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) {
+@@ -76,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;
+ }
+
+@@ -89,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
+ */
+@@ -121,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;
+@@ -174,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;
+@@ -200,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;
+ }
+@@ -230,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;
++}
+Index: linux-2.6.14/arch/i386/kernel/ptrace.c
+===================================================================
+--- linux-2.6.14.orig/arch/i386/kernel/ptrace.c 2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/kernel/ptrace.c 2005-10-29 05:50:34.000000000 +0200
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -659,6 +660,70 @@
+ (struct user_desc __user *) data);
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+Index: linux-2.6.14/arch/i386/kernel/sys_i386.c
+===================================================================
+--- linux-2.6.14.orig/arch/i386/kernel/sys_i386.c 2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/kernel/sys_i386.c 2005-10-29 05:50:28.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,12 @@
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(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;
+ }
+
+ /*
+@@ -101,7 +106,10 @@
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ /* 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;
+ }
+Index: linux-2.6.14/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.6.14.orig/arch/um/include/skas_ptrace.h 2005-10-29 05:49:33.000000000 +0200
++++ linux-2.6.14/arch/um/include/skas_ptrace.h 2005-10-29 05:50:00.000000000 +0200
+@@ -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
+Index: linux-2.6.14/arch/x86_64/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/ia32/ptrace32.c 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/ia32/ptrace32.c 2005-10-29 05:50:34.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@
+ case PTRACE_SETFPXREGS:
+ case PTRACE_GETFPXREGS:
+ case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++ case PTRACE_FAULTINFO:
++ case PTRACE_LDT:
++ case PTRACE_SWITCH_MM:
++#endif
+ break;
+ }
+
+@@ -363,6 +371,65 @@
+ ret = 0;
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ child->mm = new;
++ child->active_mm = new;
++
++ task_unlock(child);
++
++ 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.14/arch/x86_64/ia32/sys_ia32.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/ia32/sys_ia32.c 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/ia32/sys_ia32.c 2005-10-29 05:50:31.000000000 +0200
+@@ -833,11 +833,10 @@
+ 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;
+
+@@ -849,7 +848,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)
+@@ -857,6 +856,15 @@
+ 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 error;
+Index: linux-2.6.14/arch/x86_64/Kconfig
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/Kconfig 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/Kconfig 2005-10-29 05:50:33.000000000 +0200
+@@ -357,6 +357,26 @@
+ of memory and any 32-bit devices. Don't turn on unless you know what you
+ are doing.
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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.14/arch/x86_64/kernel/ldt.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/kernel/ldt.c 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/kernel/ldt.c 2005-10-29 05:50:33.000000000 +0200
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@
+ }
+ #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;
+@@ -64,12 +66,14 @@
+
+ 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) {
+@@ -81,12 +85,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;
+ }
+
+@@ -94,22 +98,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);
++}
++
+ /*
+ *
+ * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@
+ }
+ }
+
+-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 +175,8 @@
+ 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 +201,7 @@
+
+ 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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -231,23 +234,29 @@
+ 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.14/arch/x86_64/kernel/ptrace.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/kernel/ptrace.c 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/kernel/ptrace.c 2005-10-29 05:50:34.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -604,6 +605,79 @@
+ break;
+ }
+
++#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;
++
++ /* 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;
++ }
++#endif
++
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+Index: linux-2.6.14/arch/x86_64/kernel/sys_x86_64.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/kernel/sys_x86_64.c 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/kernel/sys_x86_64.c 2005-10-29 05:50:31.000000000 +0200
+@@ -19,6 +19,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+
+ /*
+ * sys_pipe() is the normal C calling standard for creating
+@@ -37,7 +38,7 @@
+ 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 @@
+ 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 @@
+ 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.14/arch/x86_64/mm/Makefile
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/mm/Makefile 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/mm/Makefile 2005-10-29 05:50:31.000000000 +0200
+@@ -7,5 +7,6 @@
+ 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.14/arch/x86_64/mm/proc_mm.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/arch/x86_64/mm/proc_mm.c 2005-10-29 05:50:31.000000000 +0200
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++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.14/include/asm-i386/desc.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/desc.h 2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/include/asm-i386/desc.h 2005-10-29 05:50:06.000000000 +0200
+@@ -156,6 +156,9 @@
+ 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.14/include/asm-i386/mmu_context.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/mmu_context.h 2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/include/asm-i386/mmu_context.h 2005-10-29 05:50:11.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+Index: linux-2.6.14/include/asm-i386/proc_mm.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/include/asm-i386/proc_mm.h 2005-10-29 05:50:31.000000000 +0200
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++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 */
+Index: linux-2.6.14/include/asm-i386/ptrace.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/ptrace.h 2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/include/asm-i386/ptrace.h 2005-10-29 05:50:34.000000000 +0200
+@@ -84,4 +84,33 @@
+ #endif
+ #endif /* __KERNEL__ */
+
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO 52
++/* 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;
++ unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+Index: linux-2.6.14/include/asm-i386/thread_info.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/thread_info.h 2005-10-29 05:49:28.000000000 +0200
++++ linux-2.6.14/include/asm-i386/thread_info.h 2005-10-29 05:50:29.000000000 +0200
+@@ -139,9 +139,9 @@
+ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
+ #define TIF_IRET 5 /* return with iret */
+-#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_SECCOMP 8 /* secure computing */
++#define TIF_SYSCALL_EMU 9 /* syscall emulation active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE 17
+
+Index: linux-2.6.14/include/asm-x86_64/desc.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-x86_64/desc.h 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/include/asm-x86_64/desc.h 2005-10-29 05:50:31.000000000 +0200
+@@ -215,6 +215,9 @@
+
+ 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.14/include/asm-x86_64/mmu_context.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-x86_64/mmu_context.h 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/include/asm-x86_64/mmu_context.h 2005-10-29 05:50:31.000000000 +0200
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+ * 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);
++
+ #ifdef CONFIG_SMP
+
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,9 @@
+ 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 */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,6 @@
+ #ifdef CONFIG_SMP
+ else {
+ write_pda(mmu_state, TLBSTATE_OK);
+- if (read_pda(active_mm) != next)
+- out_of_line_bug();
+ if(!test_and_set_bit(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.14/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/include/asm-x86_64/proc_mm.h 2005-10-29 05:50:31.000000000 +0200
+@@ -0,0 +1,56 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++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.14/include/asm-x86_64/ptrace.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-x86_64/ptrace.h 2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/include/asm-x86_64/ptrace.h 2005-10-29 05:50:34.000000000 +0200
+@@ -64,6 +64,59 @@
+ /* top of stack page */
+ };
+
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#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_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.*/
++ compat_ulong_t bytecount;
++};
++
++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;
++ unsigned long bytecount;
++};
++
++#undef compat_int_t
++#undef compat_long_t
++#undef compat_uint_t
++#undef compat_ulong_t
++#undef compat_uptr_t
++
+ #endif
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@
+ #define PTRACE_GETFPXREGS 18
+ #define PTRACE_SETFPXREGS 19
+
++#define PTRACE_FAULTINFO 52
++/* 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
+ #define PTRACE_SET_THREAD_AREA 26
+Index: linux-2.6.14/include/linux/mm.h
+===================================================================
+--- linux-2.6.14.orig/include/linux/mm.h 2005-10-29 05:49:33.000000000 +0200
++++ linux-2.6.14/include/linux/mm.h 2005-10-29 05:50:00.000000000 +0200
+@@ -759,6 +759,9 @@
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * On a two-level or three-level page table, this ends up being trivial. Thus
+ * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -841,9 +844,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,
+Index: linux-2.6.14/include/linux/proc_mm.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/include/linux/proc_mm.h 2005-10-29 05:50:33.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* 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 <asm/proc_mm.h>
++
++/*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
++#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);
++
++/* 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.14/localversion-skas
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/localversion-skas 2005-10-29 05:50:35.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v9-pre7
+Index: linux-2.6.14/mm/Makefile
+===================================================================
+--- linux-2.6.14.orig/mm/Makefile 2005-10-29 05:49:32.000000000 +0200
++++ linux-2.6.14/mm/Makefile 2005-10-29 05:50:34.000000000 +0200
+@@ -20,3 +20,9 @@
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
++
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m += proc_mm-mod.o
++endif
+Index: linux-2.6.14/mm/mmap.c
+===================================================================
+--- linux-2.6.14.orig/mm/mmap.c 2005-10-29 05:49:32.000000000 +0200
++++ linux-2.6.14/mm/mmap.c 2005-10-29 05:50:00.000000000 +0200
+@@ -861,11 +861,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;
+@@ -1140,7 +1140,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.
+Index: linux-2.6.14/mm/mprotect.c
+===================================================================
+--- linux-2.6.14.orig/mm/mprotect.c 2005-10-29 05:49:32.000000000 +0200
++++ linux-2.6.14/mm/mprotect.c 2005-10-29 05:50:30.000000000 +0200
+@@ -177,8 +177,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;
+@@ -209,9 +210,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;
+@@ -278,6 +279,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;
++}
+Index: linux-2.6.14/mm/proc_mm.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/mm/proc_mm.c 2005-10-29 05:50:33.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#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>
++
++#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
++ * {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
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++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);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++ mm->dumpable = current->mm->dumpable;
++ wmb();
++#endif
++
++ 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;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++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;
++ 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_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_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_native(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;
++}
++
++/*These three are all for /proc/mm.*/
++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);
++}
++
++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;
++
++ 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);
++
++/*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
++ * 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.14/mm/proc_mm-mod.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/mm/proc_mm-mod.c 2005-10-29 05:50:34.000000000 +0200
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#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);
Added: trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1860 @@
+Index: linux-2.6.15/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.15.orig/arch/i386/Kconfig
++++ linux-2.6.15/arch/i386/Kconfig
+@@ -458,6 +458,26 @@ config X86_PAE
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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.15/arch/i386/kernel/ldt.c
+===================================================================
+--- linux-2.6.15.orig/arch/i386/kernel/ldt.c
++++ linux-2.6.15/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;
+@@ -59,13 +60,15 @@ static int alloc_ldt(mm_context_t *pc, i
+ #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;
+ }
+
+@@ -90,22 +93,24 @@ 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);
++ 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 @@ 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 +180,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 +205,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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -231,23 +235,33 @@ 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)
++{
++ 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.15/arch/i386/kernel/ptrace.c
+===================================================================
+--- linux-2.6.15.orig/arch/i386/kernel/ptrace.c
++++ linux-2.6.15/arch/i386/kernel/ptrace.c
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -622,6 +623,66 @@ long arch_ptrace(struct task_struct *chi
+ (struct user_desc __user *) data);
+ 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));
++ break;
++ }
++
++ case PTRACE_FAULTINFO: {
++ struct ptrace_faultinfo fault;
++
++ fault = ((struct ptrace_faultinfo)
++ { .is_write = child->thread.error_code,
++ .addr = child->thread.cr2 });
++ ret = copy_to_user((unsigned long *) data, &fault,
++ sizeof(fault));
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+Index: linux-2.6.15/arch/i386/kernel/sys_i386.c
+===================================================================
+--- linux-2.6.15.orig/arch/i386/kernel/sys_i386.c
++++ linux-2.6.15/arch/i386/kernel/sys_i386.c
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,12 @@ asmlinkage long sys_mmap2(unsigned long
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(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;
+ }
+
+ /*
+@@ -101,7 +106,10 @@ asmlinkage int old_mmap(struct mmap_arg_
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ /* 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;
+ }
+Index: linux-2.6.15/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.6.15.orig/arch/um/include/skas_ptrace.h
++++ linux-2.6.15/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
+Index: linux-2.6.15/arch/x86_64/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/ia32/ptrace32.c
++++ linux-2.6.15/arch/x86_64/ia32/ptrace32.c
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@ asmlinkage long sys32_ptrace(long reques
+ case PTRACE_SETFPXREGS:
+ case PTRACE_GETFPXREGS:
+ case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++ case PTRACE_FAULTINFO:
++ case PTRACE_LDT:
++ case PTRACE_SWITCH_MM:
++#endif
+ break;
+ }
+
+@@ -363,6 +371,65 @@ asmlinkage long sys32_ptrace(long reques
+ ret = 0;
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ child->mm = new;
++ child->active_mm = new;
++
++ task_unlock(child);
++
++ 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.15/arch/x86_64/ia32/sys_ia32.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/ia32/sys_ia32.c
++++ linux-2.6.15/arch/x86_64/ia32/sys_ia32.c
+@@ -833,11 +833,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 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;
+
+@@ -849,7 +848,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)
+@@ -857,6 +856,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 error;
+Index: linux-2.6.15/arch/x86_64/Kconfig
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/Kconfig
++++ linux-2.6.15/arch/x86_64/Kconfig
+@@ -374,6 +374,26 @@ config DUMMY_IOMMU
+ of memory and any 32-bit devices. Don't turn on unless you know what you
+ are doing.
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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.15/arch/x86_64/kernel/ldt.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/kernel/ldt.c
++++ linux-2.6.15/arch/x86_64/kernel/ldt.c
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,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;
+@@ -64,12 +66,14 @@ static int alloc_ldt(mm_context_t *pc, u
+
+ 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) {
+@@ -81,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;
+ }
+
+@@ -94,22 +98,24 @@ 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);
++ 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);
++}
++
+ /*
+ *
+ * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,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 +175,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 +201,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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -231,23 +234,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.15/arch/x86_64/kernel/ptrace.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/kernel/ptrace.c
++++ linux-2.6.15/arch/x86_64/kernel/ptrace.c
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -567,6 +568,75 @@ long arch_ptrace(struct task_struct *chi
+ break;
+ }
+
++#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));
++ break;
++ }
++
++ /*Don't extend this broken interface to x86-64*/
++#if 0
++ 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));
++ break;
++ }
++#endif
++
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+Index: linux-2.6.15/arch/x86_64/kernel/sys_x86_64.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/kernel/sys_x86_64.c
++++ linux-2.6.15/arch/x86_64/kernel/sys_x86_64.c
+@@ -19,6 +19,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+
+ /*
+ * 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.15/arch/x86_64/mm/Makefile
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/mm/Makefile
++++ linux-2.6.15/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.15/arch/x86_64/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.15/arch/x86_64/mm/proc_mm.c
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++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.15/include/asm-i386/desc.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/desc.h
++++ linux-2.6.15/include/asm-i386/desc.h
+@@ -158,6 +158,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.15/include/asm-i386/mmu_context.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/mmu_context.h
++++ linux-2.6.15/include/asm-i386/mmu_context.h
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+Index: linux-2.6.15/include/asm-i386/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.15/include/asm-i386/proc_mm.h
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++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 */
+Index: linux-2.6.15/include/asm-i386/ptrace.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/ptrace.h
++++ linux-2.6.15/include/asm-i386/ptrace.h
+@@ -84,4 +84,33 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif /* __KERNEL__ */
+
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO 52
++/* 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;
++ unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+Index: linux-2.6.15/include/asm-i386/thread_info.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/thread_info.h
++++ linux-2.6.15/include/asm-i386/thread_info.h
+@@ -139,9 +139,9 @@ register unsigned long current_stack_poi
+ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
+ #define TIF_IRET 5 /* return with iret */
+-#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+ #define TIF_SECCOMP 8 /* secure computing */
++#define TIF_SYSCALL_EMU 9 /* syscall emulation active */
+ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE 17
+
+Index: linux-2.6.15/include/asm-x86_64/desc.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-x86_64/desc.h
++++ linux-2.6.15/include/asm-x86_64/desc.h
+@@ -225,6 +225,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.15/include/asm-x86_64/mmu_context.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-x86_64/mmu_context.h
++++ linux-2.6.15/include/asm-x86_64/mmu_context.h
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+ * 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);
++
+ #ifdef CONFIG_SMP
+
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,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 */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,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(!test_and_set_bit(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.15/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.15/include/asm-x86_64/proc_mm.h
+@@ -0,0 +1,58 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++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 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);
++
++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.15/include/asm-x86_64/ptrace.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-x86_64/ptrace.h
++++ linux-2.6.15/include/asm-x86_64/ptrace.h
+@@ -64,6 +64,59 @@ struct pt_regs {
+ /* top of stack page */
+ };
+
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#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_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.*/
++ compat_ulong_t bytecount;
++};
++
++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;
++ unsigned long bytecount;
++};
++
++#undef compat_int_t
++#undef compat_long_t
++#undef compat_uint_t
++#undef compat_ulong_t
++#undef compat_uptr_t
++
+ #endif
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@ struct pt_regs {
+ #define PTRACE_GETFPXREGS 18
+ #define PTRACE_SETFPXREGS 19
+
++#define PTRACE_FAULTINFO 52
++/* 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
+ #define PTRACE_SET_THREAD_AREA 26
+Index: linux-2.6.15/include/linux/mm.h
+===================================================================
+--- linux-2.6.15.orig/include/linux/mm.h
++++ linux-2.6.15/include/linux/mm.h
+@@ -719,6 +719,9 @@ extern unsigned long do_mremap(unsigned
+ unsigned long old_len, unsigned long new_len,
+ unsigned long flags, unsigned long new_addr);
+
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++ size_t len, unsigned long prot);
++
+ /*
+ * Prototype to add a shrinker callback for ageable caches.
+ *
+@@ -872,9 +875,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,
+Index: linux-2.6.15/include/linux/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.15/include/linux/proc_mm.h
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* 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 <asm/proc_mm.h>
++
++/*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
++#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);
++
++/* 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.15/localversion-skas
+===================================================================
+--- /dev/null
++++ linux-2.6.15/localversion-skas
+@@ -0,0 +1 @@
++-skas3-v9-pre8
+Index: linux-2.6.15/mm/Makefile
+===================================================================
+--- linux-2.6.15.orig/mm/Makefile
++++ linux-2.6.15/mm/Makefile
+@@ -20,3 +20,9 @@ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
++
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m += proc_mm-mod.o
++endif
+Index: linux-2.6.15/mm/mmap.c
+===================================================================
+--- linux-2.6.15.orig/mm/mmap.c
++++ linux-2.6.15/mm/mmap.c
+@@ -867,11 +867,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;
+@@ -1146,7 +1146,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.15/mm/mprotect.c
+===================================================================
+--- linux-2.6.15.orig/mm/mprotect.c
++++ linux-2.6.15/mm/mprotect.c
+@@ -176,8 +176,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;
+@@ -208,9 +209,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;
+@@ -277,6 +278,15 @@ 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)
++{
++ 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;
++}
+Index: linux-2.6.15/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.15/mm/proc_mm.c
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#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>
++
++#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
++ * {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
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++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);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++ mm->dumpable = current->mm->dumpable;
++ wmb();
++#endif
++
++ 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;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++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;
++ 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_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_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_native(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;
++}
++
++/*These three are all for /proc/mm.*/
++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);
++}
++
++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;
++
++ 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);
++
++/*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
++ * 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.15/mm/proc_mm-mod.c
+===================================================================
+--- /dev/null
++++ linux-2.6.15/mm/proc_mm-mod.c
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#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);
Added: trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1846 @@
+Index: linux-2.6.16/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.16.orig/arch/i386/Kconfig
++++ linux-2.6.16/arch/i386/Kconfig
+@@ -496,6 +496,26 @@ config X86_PAE
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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.16/arch/i386/kernel/ldt.c
+===================================================================
+--- linux-2.6.16.orig/arch/i386/kernel/ldt.c
++++ linux-2.6.16/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;
+@@ -59,13 +60,15 @@ static int alloc_ldt(mm_context_t *pc, i
+ #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;
+ }
+
+@@ -90,22 +93,24 @@ 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);
++ 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 @@ 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 +180,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 +205,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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -231,23 +235,33 @@ 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)
++{
++ 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.16/arch/i386/kernel/ptrace.c
+===================================================================
+--- linux-2.6.16.orig/arch/i386/kernel/ptrace.c
++++ linux-2.6.16/arch/i386/kernel/ptrace.c
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -625,6 +626,66 @@ long arch_ptrace(struct task_struct *chi
+ (struct user_desc __user *) data);
+ 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));
++ break;
++ }
++
++ case PTRACE_FAULTINFO: {
++ struct ptrace_faultinfo fault;
++
++ fault = ((struct ptrace_faultinfo)
++ { .is_write = child->thread.error_code,
++ .addr = child->thread.cr2 });
++ ret = copy_to_user((unsigned long *) data, &fault,
++ sizeof(fault));
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+Index: linux-2.6.16/arch/i386/kernel/sys_i386.c
+===================================================================
+--- linux-2.6.16.orig/arch/i386/kernel/sys_i386.c
++++ linux-2.6.16/arch/i386/kernel/sys_i386.c
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ goto out;
+ }
+
+- down_write(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->mm->mmap_sem);
++ down_write(&mm->mmap_sem);
++ error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++ up_write(&mm->mmap_sem);
+
+ if (file)
+ fput(file);
+@@ -70,7 +70,12 @@ asmlinkage long sys_mmap2(unsigned long
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+ {
+- return do_mmap2(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;
+ }
+
+ /*
+@@ -101,7 +106,10 @@ asmlinkage int old_mmap(struct mmap_arg_
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+- err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++ /* 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;
+ }
+Index: linux-2.6.16/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.6.16.orig/arch/um/include/skas_ptrace.h
++++ linux-2.6.16/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
+Index: linux-2.6.16/arch/x86_64/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/ia32/ptrace32.c
++++ linux-2.6.16/arch/x86_64/ia32/ptrace32.c
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+
+ /*
+ * Determines which flags the user has access to [1 = access, 0 = no access].
+@@ -224,6 +227,12 @@ asmlinkage long sys32_ptrace(long reques
+ case PTRACE_SETFPXREGS:
+ case PTRACE_GETFPXREGS:
+ case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++ case PTRACE_EX_FAULTINFO:
++ case PTRACE_FAULTINFO:
++ case PTRACE_LDT:
++ case PTRACE_SWITCH_MM:
++#endif
+ break;
+ }
+
+@@ -343,6 +352,65 @@ asmlinkage long sys32_ptrace(long reques
+ ret = 0;
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ child->mm = new;
++ child->active_mm = new;
++
++ task_unlock(child);
++
++ 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.16/arch/x86_64/ia32/sys_ia32.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/ia32/sys_ia32.c
++++ linux-2.6.16/arch/x86_64/ia32/sys_ia32.c
+@@ -855,11 +855,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 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;
+
+@@ -871,7 +870,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)
+@@ -879,6 +878,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 error;
+Index: linux-2.6.16/arch/x86_64/Kconfig
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/Kconfig
++++ linux-2.6.16/arch/x86_64/Kconfig
+@@ -378,6 +378,26 @@ config SWIOTLB
+ default y
+ depends on GART_IOMMU
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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.16/arch/x86_64/kernel/ldt.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/kernel/ldt.c
++++ linux-2.6.16/arch/x86_64/kernel/ldt.c
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,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;
+@@ -64,12 +66,14 @@ static int alloc_ldt(mm_context_t *pc, u
+
+ 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) {
+@@ -81,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;
+ }
+
+@@ -94,22 +98,24 @@ 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);
++ 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);
++}
++
+ /*
+ *
+ * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,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 +175,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 +201,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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -231,23 +234,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.16/arch/x86_64/kernel/ptrace.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/kernel/ptrace.c
++++ linux-2.6.16/arch/x86_64/kernel/ptrace.c
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -564,6 +565,75 @@ long arch_ptrace(struct task_struct *chi
+ break;
+ }
+
++#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));
++ break;
++ }
++
++ /*Don't extend this broken interface to x86-64*/
++#if 0
++ 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));
++ break;
++ }
++#endif
++
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+Index: linux-2.6.16/arch/x86_64/kernel/sys_x86_64.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/kernel/sys_x86_64.c
++++ linux-2.6.16/arch/x86_64/kernel/sys_x86_64.c
+@@ -19,6 +19,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+
+ /*
+ * 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.16/arch/x86_64/mm/Makefile
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/mm/Makefile
++++ linux-2.6.16/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.16/arch/x86_64/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.16/arch/x86_64/mm/proc_mm.c
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++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.16/include/asm-i386/desc.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-i386/desc.h
++++ linux-2.6.16/include/asm-i386/desc.h
+@@ -162,6 +162,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.16/include/asm-i386/mmu_context.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-i386/mmu_context.h
++++ linux-2.6.16/include/asm-i386/mmu_context.h
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+Index: linux-2.6.16/include/asm-i386/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.16/include/asm-i386/proc_mm.h
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++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 */
+Index: linux-2.6.16/include/asm-i386/ptrace.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-i386/ptrace.h
++++ linux-2.6.16/include/asm-i386/ptrace.h
+@@ -87,4 +87,33 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif /* __KERNEL__ */
+
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO 52
++/* 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;
++ unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+Index: linux-2.6.16/include/asm-x86_64/desc.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-x86_64/desc.h
++++ linux-2.6.16/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.16/include/asm-x86_64/mmu_context.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-x86_64/mmu_context.h
++++ linux-2.6.16/include/asm-x86_64/mmu_context.h
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+ * 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
+@@ -32,6 +47,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 */
+ clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -48,8 +66,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(!test_and_set_bit(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.16/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.16/include/asm-x86_64/proc_mm.h
+@@ -0,0 +1,58 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++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 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);
++
++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.16/include/asm-x86_64/ptrace.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-x86_64/ptrace.h
++++ linux-2.6.16/include/asm-x86_64/ptrace.h
+@@ -64,6 +64,59 @@ struct pt_regs {
+ /* top of stack page */
+ };
+
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#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_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.*/
++ compat_ulong_t bytecount;
++};
++
++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;
++ unsigned long bytecount;
++};
++
++#undef compat_int_t
++#undef compat_long_t
++#undef compat_uint_t
++#undef compat_ulong_t
++#undef compat_uptr_t
++
+ #endif
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@ struct pt_regs {
+ #define PTRACE_GETFPXREGS 18
+ #define PTRACE_SETFPXREGS 19
+
++#define PTRACE_FAULTINFO 52
++/* 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
+ #define PTRACE_SET_THREAD_AREA 26
+Index: linux-2.6.16/include/linux/mm.h
+===================================================================
+--- linux-2.6.16.orig/include/linux/mm.h
++++ linux-2.6.16/include/linux/mm.h
+@@ -918,9 +918,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,
+@@ -937,6 +943,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.16/include/linux/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.16/include/linux/proc_mm.h
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* 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 <asm/proc_mm.h>
++
++/*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
++#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);
++
++/* 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.16/localversion-skas
+===================================================================
+--- /dev/null
++++ linux-2.6.16/localversion-skas
+@@ -0,0 +1 @@
++-skas3-v9-pre9
+Index: linux-2.6.16/mm/Makefile
+===================================================================
+--- linux-2.6.16.orig/mm/Makefile
++++ linux-2.6.16/mm/Makefile
+@@ -22,3 +22,9 @@ obj-$(CONFIG_SLOB) += slob.o
+ obj-$(CONFIG_SLAB) += slab.o
+ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
++
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m += proc_mm-mod.o
++endif
+Index: linux-2.6.16/mm/mmap.c
+===================================================================
+--- linux-2.6.16.orig/mm/mmap.c
++++ linux-2.6.16/mm/mmap.c
+@@ -868,11 +868,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;
+@@ -1147,7 +1147,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.16/mm/mprotect.c
+===================================================================
+--- linux-2.6.16.orig/mm/mprotect.c
++++ linux-2.6.16/mm/mprotect.c
+@@ -176,8 +176,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;
+@@ -208,9 +209,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;
+@@ -277,6 +278,15 @@ 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)
++{
++ 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;
++}
+Index: linux-2.6.16/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.16/mm/proc_mm.c
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#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>
++
++#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
++ * {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
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++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);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++ mm->dumpable = current->mm->dumpable;
++ wmb();
++#endif
++
++ 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;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++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;
++ 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_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_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_native(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;
++}
++
++/*These three are all for /proc/mm.*/
++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);
++}
++
++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;
++
++ 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);
++
++/*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
++ * 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.16/mm/proc_mm-mod.c
+===================================================================
+--- /dev/null
++++ linux-2.6.16/mm/proc_mm-mod.c
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#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);
Added: trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch 2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch 2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1863 @@
+Index: linux-2.6.git/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.git.orig/arch/i386/Kconfig
++++ linux-2.6.git/arch/i386/Kconfig
+@@ -512,6 +512,26 @@ config X86_PAE
+ depends on HIGHMEM64G
+ default y
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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/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;
+@@ -59,13 +60,15 @@ static int alloc_ldt(mm_context_t *pc, i
+ #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;
+ }
+
+@@ -90,22 +93,24 @@ 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);
++ 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 @@ 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 +180,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 +205,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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -231,23 +235,33 @@ 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)
++{
++ 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/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 <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -625,6 +626,66 @@ long arch_ptrace(struct task_struct *chi
+ (struct user_desc __user *) data);
+ 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));
++ break;
++ }
++
++ case PTRACE_FAULTINFO: {
++ struct ptrace_faultinfo fault;
++
++ fault = ((struct ptrace_faultinfo)
++ { .is_write = child->thread.error_code,
++ .addr = child->thread.cr2 });
++ ret = copy_to_user((unsigned long *) data, &fault,
++ sizeof(fault));
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+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
+@@ -22,6 +22,7 @@
+
+ #include <asm/uaccess.h>
+ #include <asm/ipc.h>
++#include <asm/proc_mm.h>
+
+ /*
+ * sys_pipe() is the normal C calling standard for creating
+@@ -40,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)) {
+@@ -56,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)
+@@ -65,6 +65,18 @@ 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)
++{
++ 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
+@@ -93,8 +105,11 @@ 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);
++ /* 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;
+ }
+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
+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
+@@ -407,6 +407,26 @@ config SWIOTLB
+ default y
+ depends on GART_IOMMU
+
++config PROC_MM
++ bool "/proc/mm support"
++ default y
++
++config PROC_MM_DUMPABLE
++ bool "Make UML childs /proc/<pid> completely browsable"
++ default n
++ help
++ If in doubt, say N.
++
++ This fiddles with some settings to make sure /proc/<pid> 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/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c
++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+
+ /*
+ * Determines which flags the user has access to [1 = access, 0 = no access].
+@@ -224,6 +227,12 @@ asmlinkage long sys32_ptrace(long reques
+ case PTRACE_SETFPXREGS:
+ case PTRACE_GETFPXREGS:
+ case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++ case PTRACE_EX_FAULTINFO:
++ case PTRACE_FAULTINFO:
++ case PTRACE_LDT:
++ case PTRACE_SWITCH_MM:
++#endif
+ break;
+ }
+
+@@ -343,6 +352,65 @@ asmlinkage long sys32_ptrace(long reques
+ ret = 0;
+ 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;
++
++ 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_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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ child->mm = new;
++ child->active_mm = new;
++
++ task_unlock(child);
++
++ 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/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
+@@ -766,11 +766,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;
+
+@@ -782,7 +781,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)
+@@ -790,6 +789,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 error;
+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 <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,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;
+@@ -64,12 +66,14 @@ static int alloc_ldt(mm_context_t *pc, u
+
+ 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) {
+@@ -81,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;
+ }
+
+@@ -94,22 +98,24 @@ 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);
++ 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);
++}
++
+ /*
+ *
+ * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,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 +175,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 +201,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, ldt_info.entry_number+1, 1);
+ if (error < 0)
+ goto out_unlock;
+ }
+@@ -231,23 +234,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/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 <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -559,6 +560,75 @@ long arch_ptrace(struct task_struct *chi
+ break;
+ }
+
++#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));
++ break;
++ }
++
++ /*Don't extend this broken interface to x86-64*/
++#if 0
++ 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));
++ break;
++ }
++#endif
++
++ 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);
++
++ lock_fix_dumpable_setting(child, new);
++
++ 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;
+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 <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+
+ /*
+ * 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/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/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.git/arch/x86_64/mm/proc_mm.c
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++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-i386/desc.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-i386/desc.h
++++ linux-2.6.git/include/asm-i386/desc.h
+@@ -162,6 +162,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/mmu_context.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-i386/mmu_context.h
++++ linux-2.6.git/include/asm-i386/mmu_context.h
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+- * 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)
+ {
+@@ -29,6 +41,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);
+@@ -50,7 +66,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
+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 <asm/page.h>
++
++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 */
+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
+@@ -87,4 +87,33 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif /* __KERNEL__ */
+
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO 52
++/* 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;
++ unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+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/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
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+
+ /*
+ * 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
+@@ -32,6 +47,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);
+@@ -48,8 +66,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/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.git/include/asm-x86_64/proc_mm.h
+@@ -0,0 +1,58 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++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 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);
++
++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/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
+@@ -64,6 +64,59 @@ struct pt_regs {
+ /* top of stack page */
+ };
+
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#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_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.*/
++ compat_ulong_t bytecount;
++};
++
++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;
++ unsigned long bytecount;
++};
++
++#undef compat_int_t
++#undef compat_long_t
++#undef compat_uint_t
++#undef compat_ulong_t
++#undef compat_uptr_t
++
+ #endif
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@ struct pt_regs {
+ #define PTRACE_GETFPXREGS 18
+ #define PTRACE_SETFPXREGS 19
+
++#define PTRACE_FAULTINFO 52
++/* 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
+ #define PTRACE_SET_THREAD_AREA 26
+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
+@@ -919,9 +919,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,
+@@ -938,6 +944,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,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* 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 <asm/proc_mm.h>
++
++/*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
++#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);
++
++/* 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/localversion-skas
+===================================================================
+--- /dev/null
++++ linux-2.6.git/localversion-skas
+@@ -0,0 +1 @@
++-skas3-v9-pre9
+Index: linux-2.6.git/mm/Makefile
+===================================================================
+--- linux-2.6.git.orig/mm/Makefile
++++ linux-2.6.git/mm/Makefile
+@@ -24,3 +24,8 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_h
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
+ obj-$(CONFIG_MIGRATION) += migrate.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/mmap.c
+===================================================================
+--- linux-2.6.git.orig/mm/mmap.c
++++ linux-2.6.git/mm/mmap.c
+@@ -875,11 +875,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;
+@@ -1153,7 +1153,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
+@@ -179,8 +179,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;
+@@ -211,9 +212,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;
+@@ -275,6 +276,15 @@ 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)
++{
++ 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;
++}
+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 <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#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);
+Index: linux-2.6.git/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.git/mm/proc_mm.c
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#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>
++
++#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
++ * {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
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++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);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++ mm->dumpable = current->mm->dumpable;
++ wmb();
++#endif
++
++ 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;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++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;
++ 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_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_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_native(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;
++}
++
++/*These three are all for /proc/mm.*/
++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);
++}
++
++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;
++
++ 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);
++
++/*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
++ * adjust the settings for this buffer only. This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
More information about the Pkg-uml-commit
mailing list