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 -- 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 + +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 ; we can't include it because + there is a nasty ciclic include chain. + */ + + #include + + #define compat_int_t s32 + #define compat_long_t s32 + #define compat_uint_t u32 + #define compat_ulong_t u32 + #define compat_uptr_t u32 + + struct ptrace_faultinfo32 { + compat_int_t is_write; + compat_ulong_t addr; + }; + + struct ptrace_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 (¤t->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 (¤t->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(¤t->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 #include #include + +#ifdef CONFIG_SKAS3PATCH + #include +#endif + #include #include @@ -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 +#endif + #include #include #include @@ -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 +#include + +/* The differences between this one and do_mmap are that: + * - we must perform controls for userspace-supplied params (which are + * arch-specific currently). And also fget(fd) if needed and so on... + * - we must accept the struct mm_struct on which to act as first param, and the + * offset in byte rather than page units as last param. + */ +static inline long __do_mmap(struct mm_struct *mm, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long off); + + +#include +#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(¤t->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(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->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(¤t->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(¤t->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 +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Naming conventions are a mess, so I note them down. + * + * Things ending in _mm can be for everything. It's only for + * {open,release}_proc_mm. + * + * For the rest: + * + * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure + * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or + * /proc/mm64; for instance the /proc handling). + * + * While for what is conversion dependant, we use the suffix _native and _emul. + * In some cases, there is a mapping between these ones (defined by + * ). + */ + +/*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);