This is a SKAS3 patch for Linux 2.6.35.4. 

It is nearly completly revisioned and tidied up.
As a consequence the 64Bit(hostkernel) support 
is gone, maybe I'll patch it in again sometime. 
Also the "PROC_MM_DUMPABLE" option was erased,
after it was used very rare...
Therefore the SKAS3 patch now coexists with
the unpachted kernelversion an can be enabled 
or disabled by kernelconfiguration.
Other benefits are shrinked patchsize, and
because of an "only-insertions" patch, higher
compatibility with non-exact kernelversions.

   THIS PATCH SHOULD BE COMPATIBLE WITH 
     ALL 2.6.35 MAINLINE LINUXKERNELS

If you have any questions or problems, please 
ask on the uml-user list or mail me (URL below).

 -- Stephan Baerwolf <stephan@matrixstorm.com>
 -- http://www.matrixstorm.com/



Download location:
 http://www.matrixstorm.com/software/linux/2.6.35.4-skas3.patch

uml-user list:
 https://lists.sourceforge.net/lists/listinfo/user-mode-linux-user

 arch/x86/Kconfig                   |   24 ++++
 arch/x86/include/asm/desc.h        |    4 
 arch/x86/include/asm/mmu_context.h |   35 ++++++
 arch/x86/include/asm/proc_mm_32.h  |   20 +++
 arch/x86/include/asm/ptrace-abi.h  |    8 +
 arch/x86/include/asm/ptrace.h      |   73 ++++++++++++++
 arch/x86/kernel/ldt.c              |   89 +++++++++++++++++
 arch/x86/kernel/ptrace.c           |   69 +++++++++++++
 include/linux/mm.h                 |   19 +++
 include/linux/proc_mm.h            |   84 ++++++++++++++++
 mm/Makefile                        |    3 
 mm/fremap.c                        |    4 
 mm/mmap.c                          |   53 ++++++++++
 mm/mprotect.c                      |   25 ++++
 mm/proc_mm.c                       |  190 +++++++++++++++++++++++++++++++++++++
 15 files changed, 700 insertions(+)

diff -Nru linux-2.6.35.4.orig/arch/x86/Kconfig linux-2.6.35.4/arch/x86/Kconfig
--- linux-2.6.35.4.orig/arch/x86/Kconfig	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/arch/x86/Kconfig	2010-09-01 00:36:35.000000000 +0200
@@ -1159,6 +1159,30 @@
 	  support it. This can improve the kernel's performance a tiny bit by
 	  reducing TLB pressure. If in doubt, say "Y".
 
+config SKAS3PATCH
+	bool "User-mode Linux (UML) SKAS3 Support"
+	default y
+	depends on X86_32
+	---help---
+	  This option switches to SKAS3 (separate kernel address space) patched kernelcode.
+
+	  This patch for hosting-linux improves performance and security, compared 
+	  to the old traced thread approach where processes running in the UML share
+	  the same address space from the host's point of view, causing memory 
+	  inside the UML to not be protected by the memory management unit. 
+	  In contrast to the current UML using skas, buggy or malicious software 
+	  inside a UML running on a non-skas host could be able to read the memory 
+	  of other UML processes or even the UML kernel memory. Additionaly SKAS3 
+	  also reduces the number of host processes caused by the UML guest.
+	  
+	  
+	  patched by Stephan Baerwolf (stephan@matrixstorm.com), Germany 2010
+
+config PROC_MM
+	bool "/proc/mm support"
+	default y
+	depends on SKAS3PATCH
+
 # Common NUMA Features
 config NUMA
 	bool "Numa Memory Allocation and Scheduler Support"
diff -Nru linux-2.6.35.4.orig/arch/x86/include/asm/desc.h linux-2.6.35.4/arch/x86/include/asm/desc.h
--- linux-2.6.35.4.orig/arch/x86/include/asm/desc.h	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/arch/x86/include/asm/desc.h	2010-09-01 00:36:35.000000000 +0200
@@ -43,6 +43,10 @@
 	return per_cpu(gdt_page, cpu).gdt;
 }
 
+#ifdef CONFIG_SKAS3PATCH
+  extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, unsigned long bytecount);
+#endif
+
 #ifdef CONFIG_X86_64
 
 static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
diff -Nru linux-2.6.35.4.orig/arch/x86/include/asm/mmu_context.h linux-2.6.35.4/arch/x86/include/asm/mmu_context.h
--- linux-2.6.35.4.orig/arch/x86/include/asm/mmu_context.h	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/arch/x86/include/asm/mmu_context.h	2010-09-01 00:36:35.000000000 +0200
@@ -15,9 +15,31 @@
 }
 #endif	/* !CONFIG_PARAVIRT */
 
+#ifdef CONFIG_SKAS3PATCH
+/* 
+ * 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.
+ * Used for LDT copy/destruction.
+ */
+#else
 /*
  * Used for LDT copy/destruction.
  */
+#endif
+
+#ifdef CONFIG_SKAS3PATCH
+/* LDT initialization for a clean environment - needed for SKAS. */
+static inline void init_new_empty_context(struct mm_struct *mm)
+{
+	mutex_init(&mm->context.lock);
+	mm->context.size = 0;
+}
+
+/* LDT copy for SKAS - for the above problem.*/
+int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+#endif
+
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 void destroy_context(struct mm_struct *mm);
 
@@ -35,6 +57,16 @@
 {
 	unsigned cpu = smp_processor_id();
 
+#ifdef CONFIG_SKAS3PATCH
+#ifdef CONFIG_SMP
+	#ifdef CONFIG_X86_32
+		prev = per_cpu(cpu_tlbstate, cpu).active_mm;
+	#else
+		prev = read_pda(active_mm);
+	#endif
+#endif
+#endif
+	
 	if (likely(prev != next)) {
 		/* stop flush ipis for the previous mm */
 		cpumask_clear_cpu(cpu, mm_cpumask(prev));
@@ -56,7 +88,10 @@
 #ifdef CONFIG_SMP
 	else {
 		percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+#ifdef CONFIG_SKAS3PATCH
+#else
 		BUG_ON(percpu_read(cpu_tlbstate.active_mm) != next);
+#endif
 
 		if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) {
 			/* We were in lazy tlb mode and leave_mm disabled
diff -Nru linux-2.6.35.4.orig/arch/x86/include/asm/proc_mm_32.h linux-2.6.35.4/arch/x86/include/asm/proc_mm_32.h
--- linux-2.6.35.4.orig/arch/x86/include/asm/proc_mm_32.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.35.4/arch/x86/include/asm/proc_mm_32.h	2010-09-01 00:36:35.000000000 +0200
@@ -0,0 +1,20 @@
+#ifndef __ASM_PROC_MM
+#define __ASM_PROC_MM
+
+#include <asm/page.h>
+
+extern unsigned long __sys_mmap_pgoff(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 __sys_mmap_pgoff(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT);
+}
+
+#endif /* __ASM_PROC_MM */
+
diff -Nru linux-2.6.35.4.orig/arch/x86/include/asm/ptrace-abi.h linux-2.6.35.4/arch/x86/include/asm/ptrace-abi.h
--- linux-2.6.35.4.orig/arch/x86/include/asm/ptrace-abi.h	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/arch/x86/include/asm/ptrace-abi.h	2010-09-01 00:36:35.000000000 +0200
@@ -65,6 +65,14 @@
 #define PTRACE_GETFPXREGS         18
 #define PTRACE_SETFPXREGS         19
 
+#ifdef CONFIG_SKAS3PATCH
+  #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
+#endif
+
 #define PTRACE_OLDSETOPTIONS      21
 
 /* only useful for access 32bit programs / kernels */
diff -Nru linux-2.6.35.4.orig/arch/x86/include/asm/ptrace.h linux-2.6.35.4/arch/x86/include/asm/ptrace.h
--- linux-2.6.35.4.orig/arch/x86/include/asm/ptrace.h	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/arch/x86/include/asm/ptrace.h	2010-09-01 00:36:35.000000000 +0200
@@ -293,4 +293,77 @@
 
 #endif /* !__ASSEMBLY__ */
 
+#ifdef CONFIG_SKAS3PATCH
+
+  /*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*/
+
+#if 0
+  /*******************************************************/
+  /* 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;
+  };
+
+  #undef	compat_int_t
+  #undef	compat_long_t
+  #undef	compat_uint_t
+  #undef	compat_ulong_t
+  #undef	compat_uptr_t
+  /*******************************************************/
+#endif
+
+#endif /* CONFIG_SKAS3PATCH */
+
 #endif /* _ASM_X86_PTRACE_H */
diff -Nru linux-2.6.35.4.orig/arch/x86/kernel/ldt.c linux-2.6.35.4/arch/x86/kernel/ldt.c
--- linux-2.6.35.4.orig/arch/x86/kernel/ldt.c	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/arch/x86/kernel/ldt.c	2010-09-01 00:36:35.000000000 +0200
@@ -29,10 +29,17 @@
 }
 #endif
 
+#ifdef CONFIG_SKAS3PATCH
+static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+#else
 static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
+#endif
 {
 	void *oldldt, *newldt;
 	int oldsize;
+#ifdef CONFIG_SKAS3PATCH
+	mm_context_t * pc = &mm->context;
+#endif
 
 	if (mincount <= pc->size)
 		return 0;
@@ -67,12 +74,20 @@
 	if (reload) {
 #ifdef CONFIG_SMP
 		preempt_disable();
+#if CONFIG_SKAS3PATCH
+		if (&current->active_mm->context == pc) load_LDT(pc);
+		if (!cpumask_equal(mm_cpumask(mm),
+#else
 		load_LDT(pc);
 		if (!cpumask_equal(mm_cpumask(current->mm),
+#endif
 				   cpumask_of(smp_processor_id())))
 			smp_call_function(flush_ldt, current->mm, 1);
 		preempt_enable();
 #else
+#if CONFIG_SKAS3PATCH
+		if (&current->active_mm->context == pc)
+#endif
 		load_LDT(pc);
 #endif
 	}
@@ -86,16 +101,27 @@
 	return 0;
 }
 
+#ifdef CONFIG_SKAS3PATCH
+static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+{
+        int err = alloc_ldt(new, old->context.size, 0);
+#else
 static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
 {
 	int err = alloc_ldt(new, old->size, 0);
+#endif
 	int i;
 
 	if (err < 0)
 		return err;
 
+#ifdef CONFIG_SKAS3PATCH
+	for(i = 0; i < old->context.size; i++)
+		write_ldt_entry(new->context.ldt, i, old->context.ldt + i * LDT_ENTRY_SIZE);
+#else
 	for (i = 0; i < old->size; i++)
 		write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
+#endif
 	return 0;
 }
 
@@ -103,22 +129,42 @@
  * we do not have to muck with descriptors here, that is
  * done in switch_mm() as needed.
  */
+#ifdef CONFIG_SKAS3PATCH
+int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+{
+#else
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
 	struct mm_struct *old_mm;
+#endif
 	int retval = 0;
 
+#ifdef CONFIG_SKAS3PATCH
+#else
 	mutex_init(&mm->context.lock);
 	mm->context.size = 0;
 	old_mm = current->mm;
+#endif
 	if (old_mm && old_mm->context.size > 0) {
 		mutex_lock(&old_mm->context.lock);
+#ifdef CONFIG_SKAS3PATCH
+		retval = copy_ldt(mm, old_mm);
+#else
 		retval = copy_ldt(&mm->context, &old_mm->context);
+#endif
 		mutex_unlock(&old_mm->context.lock);
 	}
 	return retval;
 }
 
+#ifdef CONFIG_SKAS3PATCH
+int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	init_new_empty_context(mm);
+	return copy_context(mm, current->mm);
+}
+#endif
+
 /*
  * No need to lock the MM as we are the last user
  *
@@ -141,11 +187,18 @@
 	}
 }
 
+#ifdef CONFIG_SKAS3PATCH
+static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount)
+#else
 static int read_ldt(void __user *ptr, unsigned long bytecount)
+#endif
 {
 	int err;
 	unsigned long size;
+#ifdef CONFIG_SKAS3PATCH
+#else
 	struct mm_struct *mm = current->mm;
+#endif
 
 	if (!mm->context.size)
 		return 0;
@@ -190,9 +243,14 @@
 	return bytecount;
 }
 
+#ifdef CONFIG_SKAS3PATCH
+static int write_ldt(struct mm_struct * mm, void __user *ptr, unsigned long bytecount, int oldmode)
+{
+#else
 static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
 {
 	struct mm_struct *mm = current->mm;
+#endif
 	struct desc_struct ldt;
 	int error;
 	struct user_desc ldt_info;
@@ -216,8 +274,12 @@
 
 	mutex_lock(&mm->context.lock);
 	if (ldt_info.entry_number >= mm->context.size) {
+#ifdef CONFIG_SKAS3PATCH
+		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+#else
 		error = alloc_ldt(&current->mm->context,
 				  ldt_info.entry_number + 1, 1);
+#endif
 		if (error < 0)
 			goto out_unlock;
 	}
@@ -245,24 +307,51 @@
 	return error;
 }
 
+#ifdef CONFIG_SKAS3PATCH
+int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, unsigned long bytecount)
+#else
 asmlinkage int sys_modify_ldt(int func, void __user *ptr,
 			      unsigned long bytecount)
+#endif
 {
 	int ret = -ENOSYS;
 
 	switch (func) {
 	case 0:
+#ifdef CONFIG_SKAS3PATCH
+		ret = read_ldt(mm, ptr, bytecount);
+#else
 		ret = read_ldt(ptr, bytecount);
+#endif
 		break;
 	case 1:
+#ifdef CONFIG_SKAS3PATCH
+		ret = write_ldt(mm, ptr, bytecount, 1);
+#else
 		ret = write_ldt(ptr, bytecount, 1);
+#endif
 		break;
 	case 2:
 		ret = read_default_ldt(ptr, bytecount);
 		break;
 	case 0x11:
+#ifdef CONFIG_SKAS3PATCH
+		ret = write_ldt(mm, ptr, bytecount, 0);
+#else
 		ret = write_ldt(ptr, bytecount, 0);
+#endif
 		break;
 	}
 	return ret;
 }
+
+#ifdef CONFIG_SKAS3PATCH
+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. */
+	asmlinkage_protect(0, ret);
+	return ret;
+}
+#endif
diff -Nru linux-2.6.35.4.orig/arch/x86/kernel/ptrace.c linux-2.6.35.4/arch/x86/kernel/ptrace.c
--- linux-2.6.35.4.orig/arch/x86/kernel/ptrace.c	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/arch/x86/kernel/ptrace.c	2010-09-01 00:36:35.000000000 +0200
@@ -19,6 +19,11 @@
 #include <linux/audit.h>
 #include <linux/seccomp.h>
 #include <linux/signal.h>
+
+#ifdef CONFIG_SKAS3PATCH
+  #include <linux/proc_mm.h>
+#endif
+
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
 
@@ -911,6 +916,70 @@
 		break;
 #endif
 
+#ifdef CONFIG_SKAS3PATCH
+#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;
+	}
+
+#ifndef CONFIG_X86_64
+	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;
+	}
+#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_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 /* CONFIG_PROC_MM */
+#endif /* CONFIG_SKAS3PATCH */
+
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
diff -Nru linux-2.6.35.4.orig/include/linux/mm.h linux-2.6.35.4/include/linux/mm.h
--- linux-2.6.35.4.orig/include/linux/mm.h	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/include/linux/mm.h	2010-09-01 00:36:35.000000000 +0200
@@ -5,6 +5,10 @@
 
 #ifdef __KERNEL__
 
+#ifdef CONFIG_SKAS3PATCH
+  #include <linux/proc_mm.h>
+#endif
+
 #include <linux/gfp.h>
 #include <linux/list.h>
 #include <linux/mmzone.h>
@@ -1265,10 +1269,20 @@
 
 extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 
+#ifdef CONFIG_SKAS3PATCH
+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);
+#endif
 extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
 	unsigned long len, unsigned long prot,
 	unsigned long flag, unsigned long pgoff);
+#ifdef CONFIG_SKAS3PATCH
+extern unsigned long mmap_region(struct mm_struct *mm, struct file *file, unsigned long addr,
+#else
 extern unsigned long mmap_region(struct file *file, unsigned long addr,
+#endif
 	unsigned long len, unsigned long flags,
 	unsigned int vm_flags, unsigned long pgoff);
 
@@ -1287,6 +1301,11 @@
 
 extern int do_munmap(struct mm_struct *, unsigned long, size_t);
 
+#ifdef CONFIG_SKAS3PATCH
+extern long do_mprotect(struct mm_struct *mm, unsigned long start,
+			size_t len, unsigned long prot);
+#endif
+
 extern unsigned long do_brk(unsigned long, unsigned long);
 
 /* filemap.c */
diff -Nru linux-2.6.35.4.orig/include/linux/proc_mm.h linux-2.6.35.4/include/linux/proc_mm.h
--- linux-2.6.35.4.orig/include/linux/proc_mm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.35.4/include/linux/proc_mm.h	2010-09-01 00:36:35.000000000 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PROC_MM_H
+#define __PROC_MM_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);
+
+
+#include <asm/proc_mm_32.h>
+#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
+
+
+#define MM_MMAP 54
+#define MM_MUNMAP 55
+#define MM_MPROTECT 56
+#define MM_COPY_SEGMENTS 57
+
+// XXX: Codeduplication with "struct mmap_arg_struct32"@arch/x86/ia32/sys_ia32.c 
+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
+
+static inline void lock_fix_dumpable_setting(struct task_struct * child,
+		struct mm_struct* new) __acquires(child->alloc_lock)
+{
+	task_lock(child);
+}
+
+#endif
diff -Nru linux-2.6.35.4.orig/mm/Makefile linux-2.6.35.4/mm/Makefile
--- linux-2.6.35.4.orig/mm/Makefile	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/mm/Makefile	2010-09-01 00:36:35.000000000 +0200
@@ -41,6 +41,9 @@
 else
 obj-y += percpu_up.o
 endif
+ifdef CONFIG_PROC_MM
+obj-y += proc_mm.o
+endif
 obj-$(CONFIG_QUICKLIST) += quicklist.o
 obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o
 obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
diff -Nru linux-2.6.35.4.orig/mm/fremap.c linux-2.6.35.4/mm/fremap.c
--- linux-2.6.35.4.orig/mm/fremap.c	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/mm/fremap.c	2010-09-01 00:36:35.000000000 +0200
@@ -197,7 +197,11 @@
 
 			flags &= MAP_NONBLOCK;
 			get_file(file);
+#ifdef CONFIG_SKAS3PATCH
+			addr = mmap_region(current->mm, file, start, size,
+#else
 			addr = mmap_region(file, start, size,
+#endif					   
 					flags, vma->vm_flags, pgoff);
 			fput(file);
 			if (IS_ERR_VALUE(addr)) {
diff -Nru linux-2.6.35.4.orig/mm/mmap.c linux-2.6.35.4/mm/mmap.c
--- linux-2.6.35.4.orig/mm/mmap.c	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/mm/mmap.c	2010-09-01 00:36:35.000000000 +0200
@@ -950,11 +950,18 @@
  * The caller must hold down_write(&current->mm->mmap_sem).
  */
 
+#ifdef CONFIG_SKAS3PATCH
+unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file, unsigned long addr,
+#else
 unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+#endif			    
 			unsigned long len, unsigned long prot,
 			unsigned long flags, unsigned long pgoff)
 {
+#ifdef CONFIG_SKAS3PATCH
+#else
 	struct mm_struct * mm = current->mm;
+#endif
 	struct inode *inode;
 	unsigned int vm_flags;
 	int error;
@@ -1084,13 +1091,32 @@
 	if (error)
 		return error;
 
+#ifdef CONFIG_SKAS3PATCH
+	return mmap_region(mm, file, addr, len, flags, vm_flags, pgoff);
+}
+EXPORT_SYMBOL(__do_mmap_pgoff);
+
+unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+			unsigned long len, unsigned long prot,
+			unsigned long flags, unsigned long pgoff) {
+  return __do_mmap_pgoff(current->mm, file, addr, len, prot, flags, pgoff);
+}
+#else
 	return mmap_region(file, addr, len, flags, vm_flags, pgoff);
 }
+#endif
 EXPORT_SYMBOL(do_mmap_pgoff);
 
+
+#ifdef CONFIG_SKAS3PATCH
+unsigned long __sys_mmap_pgoff(struct mm_struct *mm, unsigned long addr, unsigned long len,
+		unsigned long prot, unsigned long flags,
+		unsigned long fd, unsigned long pgoff)
+#else
 SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
 		unsigned long, prot, unsigned long, flags,
 		unsigned long, fd, unsigned long, pgoff)
+#endif
 {
 	struct file *file = NULL;
 	unsigned long retval = -EBADF;
@@ -1118,15 +1144,35 @@
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
+#ifdef CONFIG_SKAS3PATCH
+	down_write(&mm->mmap_sem);
+	retval = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+	up_write(&mm->mmap_sem);
+#else
 	down_write(&current->mm->mmap_sem);
 	retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
+#endif
 
 	if (file)
 		fput(file);
 out:
 	return retval;
 }
+#ifdef CONFIG_SKAS3PATCH
+EXPORT_SYMBOL(__sys_mmap_pgoff);
+
+SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
+		unsigned long, prot, unsigned long, flags,
+		unsigned long, fd, unsigned long, pgoff)
+{
+	unsigned long ret = __sys_mmap_pgoff(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. */
+	asmlinkage_protect(0, ret);
+	return ret;
+}
+#endif
 
 #ifdef __ARCH_WANT_SYS_OLD_MMAP
 struct mmap_arg_struct {
@@ -1200,11 +1246,18 @@
 	return (vm_flags & (VM_NORESERVE | VM_SHARED | VM_WRITE)) == VM_WRITE;
 }
 
+#ifdef CONFIG_SKAS3PATCH
+unsigned long mmap_region(struct mm_struct *mm, struct file *file, unsigned long addr,
+#else
 unsigned long mmap_region(struct file *file, unsigned long addr,
+#endif
 			  unsigned long len, unsigned long flags,
 			  unsigned int vm_flags, unsigned long pgoff)
 {
+#ifdef CONFIG_SKAS3PATCH
+#else
 	struct mm_struct *mm = current->mm;
+#endif
 	struct vm_area_struct *vma, *prev;
 	int correct_wcount = 0;
 	int error;
diff -Nru linux-2.6.35.4.orig/mm/mprotect.c linux-2.6.35.4/mm/mprotect.c
--- linux-2.6.35.4.orig/mm/mprotect.c	2010-08-27 01:47:12.000000000 +0200
+++ linux-2.6.35.4/mm/mprotect.c	2010-09-01 00:36:35.000000000 +0200
@@ -218,8 +218,12 @@
 	return error;
 }
 
+#ifdef CONFIG_SKAS3PATCH
+long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, unsigned long prot)
+#else
 SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
 		unsigned long, prot)
+#endif
 {
 	unsigned long vm_flags, nstart, end, tmp, reqprot;
 	struct vm_area_struct *vma, *prev;
@@ -249,9 +253,14 @@
 
 	vm_flags = calc_vm_prot_bits(prot);
 
+#ifdef CONFIG_SKAS3PATCH
+	down_write(&mm->mmap_sem);
+	vma = find_vma_prev(mm, start, &prev);
+#else
 	down_write(&current->mm->mmap_sem);
 
 	vma = find_vma_prev(current->mm, start, &prev);
+#endif
 	error = -ENOMEM;
 	if (!vma)
 		goto out;
@@ -314,6 +323,22 @@
 		}
 	}
 out:
+#ifdef CONFIG_SKAS3PATCH
+	up_write(&mm->mmap_sem);
+#else
 	up_write(&current->mm->mmap_sem);
+#endif
 	return error;
 }
+
+#ifdef CONFIG_SKAS3PATCH
+SYSCALL_DEFINE3(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. */
+       asmlinkage_protect(0, ret);
+       return ret;
+}
+#endif
diff -Nru linux-2.6.35.4.orig/mm/proc_mm.c linux-2.6.35.4/mm/proc_mm.c
--- linux-2.6.35.4.orig/mm/proc_mm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.35.4/mm/proc_mm.c	2010-09-01 01:06:13.000000000 +0200
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#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>
+
+
+/* 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);
+
+	file->private_data = mm;
+
+	//printk("SKAS3: open_proc_mm just created a new mm (greetings from stephan@matrixstorm.com)\n");
+	return 0;
+
+out_mem:
+	printk("SKAS3: open_proc_mm is out of memory! (greetings from stephan@matrixstorm.com)\n");
+	return ret;
+}
+
+static int release_proc_mm(struct inode *inode, struct file *file)
+{
+	struct mm_struct *mm = file->private_data;
+
+	mmput(mm);
+
+	//printk("SKAS3: release_proc_mm released a mm (greetings from stephan@matrixstorm.com)\n");
+
+	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(PDE(file->f_path.dentry->d_inode)->proc_fops != &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;
+
+	printk("SKAS3: this kernel is able of skas3, patched by Stephan Baerwolf (stephan@matrixstorm.com)\n");
+	ent = create_proc_entry("mm", 0222, NULL);
+	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);
