diff options
Diffstat (limited to 'mm/mprotect.c')
| -rw-r--r-- | mm/mprotect.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/mm/mprotect.c b/mm/mprotect.c index 57577f63b305..17a2b52b753b 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
| @@ -29,8 +29,9 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd, | |||
| 29 | unsigned long addr, unsigned long end, pgprot_t newprot) | 29 | unsigned long addr, unsigned long end, pgprot_t newprot) |
| 30 | { | 30 | { |
| 31 | pte_t *pte; | 31 | pte_t *pte; |
| 32 | spinlock_t *ptl; | ||
| 32 | 33 | ||
| 33 | pte = pte_offset_map(pmd, addr); | 34 | pte = pte_offset_map_lock(mm, pmd, addr, &ptl); |
| 34 | do { | 35 | do { |
| 35 | if (pte_present(*pte)) { | 36 | if (pte_present(*pte)) { |
| 36 | pte_t ptent; | 37 | pte_t ptent; |
| @@ -44,7 +45,7 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd, | |||
| 44 | lazy_mmu_prot_update(ptent); | 45 | lazy_mmu_prot_update(ptent); |
| 45 | } | 46 | } |
| 46 | } while (pte++, addr += PAGE_SIZE, addr != end); | 47 | } while (pte++, addr += PAGE_SIZE, addr != end); |
| 47 | pte_unmap(pte - 1); | 48 | pte_unmap_unlock(pte - 1, ptl); |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | static inline void change_pmd_range(struct mm_struct *mm, pud_t *pud, | 51 | static inline void change_pmd_range(struct mm_struct *mm, pud_t *pud, |
| @@ -88,7 +89,6 @@ static void change_protection(struct vm_area_struct *vma, | |||
| 88 | BUG_ON(addr >= end); | 89 | BUG_ON(addr >= end); |
| 89 | pgd = pgd_offset(mm, addr); | 90 | pgd = pgd_offset(mm, addr); |
| 90 | flush_cache_range(vma, addr, end); | 91 | flush_cache_range(vma, addr, end); |
| 91 | spin_lock(&mm->page_table_lock); | ||
| 92 | do { | 92 | do { |
| 93 | next = pgd_addr_end(addr, end); | 93 | next = pgd_addr_end(addr, end); |
| 94 | if (pgd_none_or_clear_bad(pgd)) | 94 | if (pgd_none_or_clear_bad(pgd)) |
| @@ -96,7 +96,6 @@ static void change_protection(struct vm_area_struct *vma, | |||
| 96 | change_pud_range(mm, pgd, addr, next, newprot); | 96 | change_pud_range(mm, pgd, addr, next, newprot); |
| 97 | } while (pgd++, addr = next, addr != end); | 97 | } while (pgd++, addr = next, addr != end); |
| 98 | flush_tlb_range(vma, start, end); | 98 | flush_tlb_range(vma, start, end); |
| 99 | spin_unlock(&mm->page_table_lock); | ||
| 100 | } | 99 | } |
| 101 | 100 | ||
| 102 | static int | 101 | static int |
| @@ -125,6 +124,14 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, | |||
| 125 | * a MAP_NORESERVE private mapping to writable will now reserve. | 124 | * a MAP_NORESERVE private mapping to writable will now reserve. |
| 126 | */ | 125 | */ |
| 127 | if (newflags & VM_WRITE) { | 126 | if (newflags & VM_WRITE) { |
| 127 | if (oldflags & VM_RESERVED) { | ||
| 128 | BUG_ON(oldflags & VM_WRITE); | ||
| 129 | printk(KERN_WARNING "program %s is using MAP_PRIVATE, " | ||
| 130 | "PROT_WRITE mprotect of VM_RESERVED memory, " | ||
| 131 | "which is deprecated. Please report this to " | ||
| 132 | "linux-kernel@vger.kernel.org\n",current->comm); | ||
| 133 | return -EACCES; | ||
| 134 | } | ||
| 128 | if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_SHARED|VM_HUGETLB))) { | 135 | if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_SHARED|VM_HUGETLB))) { |
| 129 | charged = nrpages; | 136 | charged = nrpages; |
| 130 | if (security_vm_enough_memory(charged)) | 137 | if (security_vm_enough_memory(charged)) |
| @@ -168,8 +175,8 @@ success: | |||
| 168 | vma->vm_flags = newflags; | 175 | vma->vm_flags = newflags; |
| 169 | vma->vm_page_prot = newprot; | 176 | vma->vm_page_prot = newprot; |
| 170 | change_protection(vma, start, end, newprot); | 177 | change_protection(vma, start, end, newprot); |
| 171 | __vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); | 178 | vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); |
| 172 | __vm_stat_account(mm, newflags, vma->vm_file, nrpages); | 179 | vm_stat_account(mm, newflags, vma->vm_file, nrpages); |
| 173 | return 0; | 180 | return 0; |
| 174 | 181 | ||
| 175 | fail: | 182 | fail: |
