diff -Naur linux-2.6.1/arch/i386/Kconfig linux-2.6.1-skas3/arch/i386/Kconfig --- linux-2.6.1/arch/i386/Kconfig 2004-01-09 01:59:10.000000000 -0500 +++ linux-2.6.1-skas3/arch/i386/Kconfig 2004-01-10 08:16:49.000000000 -0500 @@ -822,6 +822,15 @@ endmenu +menu "Special options" + +config PROC_MM + bool "proc/mm support" + ---help--- + /proc/mm is used by a User Mode Linux kernel to support SKAS + mode. If you need this, you'll know it. + +endmenu menu "Power management options (ACPI, APM)" depends on !X86_VOYAGER diff -Naur linux-2.6.1/arch/i386/kernel/ldt.c linux-2.6.1-skas3/arch/i386/kernel/ldt.c --- linux-2.6.1/arch/i386/kernel/ldt.c 2004-01-09 01:59:46.000000000 -0500 +++ linux-2.6.1-skas3/arch/i386/kernel/ldt.c 2004-01-10 08:16:49.000000000 -0500 @@ -105,6 +105,20 @@ return retval; } +int mm_init_new_context(struct mm_struct *old_mm, struct mm_struct *mm) +{ + int retval = 0; + + init_MUTEX(&mm->context.sem); + mm->context.size = 0; + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); + retval = copy_ldt(&mm->context, &old_mm->context); + up(&old_mm->context.sem); + } + return retval; +} + /* * No need to lock the MM as we are the last user */ @@ -121,11 +135,11 @@ } } -static int read_ldt(void __user * ptr, unsigned long bytecount) +static int read_ldt(struct task_struct *task, void __user * ptr, unsigned long bytecount) { int err; unsigned long size; - struct mm_struct * mm = current->mm; + struct mm_struct * mm = task->mm; if (!mm->context.size) return 0; @@ -169,9 +183,9 @@ return err; } -static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) +static int write_ldt(struct task_struct *task, void __user * 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 user_desc ldt_info; @@ -228,23 +242,29 @@ return error; } -asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +int modify_ldt(struct task_struct *task, int func, void __user *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 linux-2.6.1/arch/i386/kernel/ptrace.c linux-2.6.1-skas3/arch/i386/kernel/ptrace.c --- linux-2.6.1/arch/i386/kernel/ptrace.c 2004-01-09 01:59:19.000000000 -0500 +++ linux-2.6.1-skas3/arch/i386/kernel/ptrace.c 2004-01-10 08:16:49.000000000 -0500 @@ -229,6 +229,11 @@ return 0; } +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; @@ -355,6 +360,52 @@ } 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; + } case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ long tmp; diff -Naur linux-2.6.1/arch/i386/kernel/sys_i386.c linux-2.6.1-skas3/arch/i386/kernel/sys_i386.c --- linux-2.6.1/arch/i386/kernel/sys_i386.c 2004-01-09 02:00:04.000000000 -0500 +++ linux-2.6.1-skas3/arch/i386/kernel/sys_i386.c 2004-01-10 08:16:49.000000000 -0500 @@ -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 linux-2.6.1/include/asm-i386/processor.h linux-2.6.1-skas3/include/asm-i386/processor.h --- linux-2.6.1/include/asm-i386/processor.h 2004-01-09 01:59:06.000000000 -0500 +++ linux-2.6.1-skas3/include/asm-i386/processor.h 2004-01-10 08:58:43.000000000 -0500 @@ -474,6 +474,8 @@ struct task_struct; struct mm_struct; +int mm_init_new_context(struct mm_struct *old_mm, struct mm_struct *mm); + /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); diff -Naur linux-2.6.1/include/asm-i386/ptrace.h linux-2.6.1-skas3/include/asm-i386/ptrace.h --- linux-2.6.1/include/asm-i386/ptrace.h 2004-01-09 01:59:07.000000000 -0500 +++ linux-2.6.1-skas3/include/asm-i386/ptrace.h 2004-01-10 08:16:49.000000000 -0500 @@ -41,6 +41,23 @@ int xss; }; + +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 + /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ #define PTRACE_GETREGS 12 #define PTRACE_SETREGS 13 diff -Naur linux-2.6.1/include/linux/mm.h linux-2.6.1-skas3/include/linux/mm.h --- linux-2.6.1/include/linux/mm.h 2004-01-09 01:59:06.000000000 -0500 +++ linux-2.6.1-skas3/include/linux/mm.h 2004-01-10 08:43:14.000000000 -0500 @@ -445,6 +445,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); + int __set_page_dirty_buffers(struct page *page); int __set_page_dirty_nobuffers(struct page *page); int set_page_dirty_lock(struct page *page); @@ -519,9 +522,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, @@ -531,7 +535,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 linux-2.6.1/include/linux/proc_mm.h linux-2.6.1-skas3/include/linux/proc_mm.h --- linux-2.6.1/include/linux/proc_mm.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.1-skas3/include/linux/proc_mm.h 2004-01-10 08:51:54.000000000 -0500 @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PROC_MM_H +#define __PROC_MM_H + +#define MM_MMAP 54 +#define MM_MUNMAP 55 +#define MM_MPROTECT 56 +#define MM_COPY_SEGMENTS 57 + +struct mm_mmap { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +struct mm_munmap { + unsigned long addr; + unsigned long len; +}; + +struct mm_mprotect { + unsigned long addr; + unsigned long len; + unsigned int prot; +}; + +struct proc_mm_op { + int op; + union { + struct mm_mmap mmap; + struct mm_munmap munmap; + struct mm_mprotect mprotect; + int copy_segments; + } u; +}; + +#endif diff -Naur linux-2.6.1/mm/Makefile linux-2.6.1-skas3/mm/Makefile --- linux-2.6.1/mm/Makefile 2004-01-09 01:59:45.000000000 -0500 +++ linux-2.6.1-skas3/mm/Makefile 2004-01-10 08:28:34.000000000 -0500 @@ -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 diff -Naur linux-2.6.1/mm/mmap.c linux-2.6.1-skas3/mm/mmap.c --- linux-2.6.1/mm/mmap.c 2004-01-09 01:59:45.000000000 -0500 +++ linux-2.6.1-skas3/mm/mmap.c 2004-01-10 08:47:57.000000000 -0500 @@ -462,11 +462,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; diff -Naur linux-2.6.1/mm/mprotect.c linux-2.6.1-skas3/mm/mprotect.c --- linux-2.6.1/mm/mprotect.c 2004-01-09 01:59:26.000000000 -0500 +++ linux-2.6.1-skas3/mm/mprotect.c 2004-01-10 08:49:45.000000000 -0500 @@ -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)); +} diff -Naur linux-2.6.1/mm/proc_mm.c linux-2.6.1-skas3/mm/proc_mm.c --- linux-2.6.1/mm/proc_mm.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.1-skas3/mm/proc_mm.c 2004-01-10 09:20:13.000000000 -0500 @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include + +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_init_new_context(from, mm); +// 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 __init 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);