diff options
Diffstat (limited to 'arch/i386/mm/mprotect.c')
-rw-r--r-- | arch/i386/mm/mprotect.c | 230 |
1 files changed, 0 insertions, 230 deletions
diff --git a/arch/i386/mm/mprotect.c b/arch/i386/mm/mprotect.c deleted file mode 100644 index 99252183b..000000000 --- a/arch/i386/mm/mprotect.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * linux/mm/mprotect.c - * - * (C) Copyright 1994 Linus Torvalds - */ -#include <linux/stat.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/shm.h> -#include <linux/errno.h> -#include <linux/mman.h> -#include <linux/string.h> -#include <linux/malloc.h> - -#include <asm/segment.h> -#include <asm/system.h> - -#define CHG_MASK (PAGE_MASK | PAGE_ACCESSED | PAGE_DIRTY | PAGE_PWT | PAGE_PCD) - -static void change_protection(unsigned long start, unsigned long end, int prot) -{ - unsigned long *page_table, *dir; - unsigned long page, offset; - int nr; - - dir = PAGE_DIR_OFFSET(current->tss.cr3, start); - offset = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); - nr = (end - start) >> PAGE_SHIFT; - while (nr > 0) { - page = *dir; - dir++; - if (!(page & PAGE_PRESENT)) { - nr = nr - PTRS_PER_PAGE + offset; - offset = 0; - continue; - } - page_table = offset + (unsigned long *) (page & PAGE_MASK); - offset = PTRS_PER_PAGE - offset; - if (offset > nr) - offset = nr; - nr = nr - offset; - do { - page = *page_table; - if (page & PAGE_PRESENT) - *page_table = (page & CHG_MASK) | prot; - ++page_table; - } while (--offset); - } - return; -} - -static inline int mprotect_fixup_all(struct vm_area_struct * vma, - int newflags, int prot) -{ - vma->vm_flags = newflags; - vma->vm_page_prot = prot; - return 0; -} - -static inline int mprotect_fixup_start(struct vm_area_struct * vma, - unsigned long end, - int newflags, int prot) -{ - struct vm_area_struct * n; - - n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); - if (!n) - return -ENOMEM; - *n = *vma; - vma->vm_start = end; - n->vm_end = end; - vma->vm_offset += vma->vm_start - n->vm_start; - n->vm_flags = newflags; - n->vm_page_prot = prot; - if (n->vm_inode) - n->vm_inode->i_count++; - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - insert_vm_struct(current, n); - return 0; -} - -static inline int mprotect_fixup_end(struct vm_area_struct * vma, - unsigned long start, - int newflags, int prot) -{ - struct vm_area_struct * n; - - n = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); - if (!n) - return -ENOMEM; - *n = *vma; - vma->vm_end = start; - n->vm_start = start; - n->vm_offset += n->vm_start - vma->vm_start; - n->vm_flags = newflags; - n->vm_page_prot = prot; - if (n->vm_inode) - n->vm_inode->i_count++; - if (n->vm_ops && n->vm_ops->open) - n->vm_ops->open(n); - insert_vm_struct(current, n); - return 0; -} - -static inline int mprotect_fixup_middle(struct vm_area_struct * vma, - unsigned long start, unsigned long end, - int newflags, int prot) -{ - struct vm_area_struct * left, * right; - - left = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); - if (!left) - return -ENOMEM; - right = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); - if (!right) { - kfree(left); - return -ENOMEM; - } - *left = *vma; - *right = *vma; - left->vm_end = start; - vma->vm_start = start; - vma->vm_end = end; - right->vm_start = end; - vma->vm_offset += vma->vm_start - left->vm_start; - right->vm_offset += right->vm_start - left->vm_start; - vma->vm_flags = newflags; - vma->vm_page_prot = prot; - if (vma->vm_inode) - vma->vm_inode->i_count += 2; - if (vma->vm_ops && vma->vm_ops->open) { - vma->vm_ops->open(left); - vma->vm_ops->open(right); - } - insert_vm_struct(current, left); - insert_vm_struct(current, right); - return 0; -} - -static int mprotect_fixup(struct vm_area_struct * vma, - unsigned long start, unsigned long end, unsigned int newflags) -{ - int prot, error; - - if (newflags == vma->vm_flags) - return 0; - prot = PAGE_PRESENT; - if (newflags & (VM_READ | VM_EXEC)) - prot |= PAGE_READONLY; - if (newflags & VM_WRITE) - if (newflags & VM_SHARED) - prot |= PAGE_SHARED; - else - prot |= PAGE_COPY; - - if (start == vma->vm_start) - if (end == vma->vm_end) - error = mprotect_fixup_all(vma, newflags, prot); - else - error = mprotect_fixup_start(vma, end, newflags, prot); - else if (end == vma->vm_end) - error = mprotect_fixup_end(vma, start, newflags, prot); - else - error = mprotect_fixup_middle(vma, start, end, newflags, prot); - - if (error) - return error; - - change_protection(start, end, prot); - return 0; -} - -asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot) -{ - unsigned long end, tmp; - struct vm_area_struct * vma, * next; - int error; - - if (start & ~PAGE_MASK) - return -EINVAL; - len = (len + ~PAGE_MASK) & PAGE_MASK; - end = start + len; - if (end < start) - return -EINVAL; - if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) - return -EINVAL; - if (end == start) - return 0; - for (vma = current->mm->mmap ; ; vma = vma->vm_next) { - if (!vma) - return -EFAULT; - if (vma->vm_end > start) - break; - } - if (vma->vm_start > start) - return -EFAULT; - - for ( ; ; ) { - unsigned int newflags; - - /* Here we know that vma->vm_start <= start < vma->vm_end. */ - - newflags = prot | (vma->vm_flags & ~(PROT_READ | PROT_WRITE | PROT_EXEC)); - if ((newflags & ~(newflags >> 4)) & 0xf) { - error = -EACCES; - break; - } - - if (vma->vm_end >= end) { - error = mprotect_fixup(vma, start, end, newflags); - break; - } - - tmp = vma->vm_end; - next = vma->vm_next; - error = mprotect_fixup(vma, start, tmp, newflags); - if (error) - break; - start = tmp; - vma = next; - if (!vma || vma->vm_start != start) { - error = -EFAULT; - break; - } - } - merge_segments(current->mm->mmap); - return error; -} |