From: Hugh Dickins The do_wp_page page_mkwrite breakage went unnoticed because do_no_page was as usual giving write permission to the pte in handling a read fault on a shared writable mapping, thus sneaking around page_mkwrite. It could likewise be evaded by do_file_page->populate->install_page. And if those were to write protect the pte, mprotect back and forth could be used to reinstate write permission without going through page_mkwrite. No explicit change to those: deal with it by using the vm_page_prot of a private mapping on any shared mapping which has a page_mkwrite. Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton --- mm/mmap.c | 9 +++++++-- mm/mprotect.c | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff -puN mm/mmap.c~fix-page-becoming-writable-vm_page_prot mm/mmap.c --- 25/mm/mmap.c~fix-page-becoming-writable-vm_page_prot Wed Jul 13 14:21:32 2005 +++ 25-akpm/mm/mmap.c Wed Jul 13 14:21:32 2005 @@ -1055,7 +1055,8 @@ munmap_back: vma->vm_start = addr; vma->vm_end = addr + len; vma->vm_flags = vm_flags; - vma->vm_page_prot = protection_map[vm_flags & 0x0f]; + vma->vm_page_prot = protection_map[vm_flags & + (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]; vma->vm_pgoff = pgoff; if (file) { @@ -1078,6 +1079,9 @@ munmap_back: if (error) goto free_vma; } + if (vma->vm_ops && vma->vm_ops->page_mkwrite) + vma->vm_page_prot = protection_map[vm_flags & + (VM_READ|VM_WRITE|VM_EXEC)]; /* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform * shmem_zero_setup (perhaps called through /dev/zero's ->mmap) @@ -1914,7 +1918,8 @@ unsigned long do_brk(unsigned long addr, vma->vm_end = addr + len; vma->vm_pgoff = pgoff; vma->vm_flags = flags; - vma->vm_page_prot = protection_map[flags & 0x0f]; + vma->vm_page_prot = protection_map[flags & + (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]; vma_link(mm, vma, prev, rb_link, rb_parent); out: mm->total_vm += len >> PAGE_SHIFT; diff -puN mm/mprotect.c~fix-page-becoming-writable-vm_page_prot mm/mprotect.c --- 25/mm/mprotect.c~fix-page-becoming-writable-vm_page_prot Wed Jul 13 14:21:32 2005 +++ 25-akpm/mm/mprotect.c Wed Jul 13 14:21:32 2005 @@ -107,6 +107,7 @@ mprotect_fixup(struct vm_area_struct *vm unsigned long oldflags = vma->vm_flags; long nrpages = (end - start) >> PAGE_SHIFT; unsigned long charged = 0; + unsigned int mask; pgprot_t newprot; pgoff_t pgoff; int error; @@ -133,8 +134,6 @@ mprotect_fixup(struct vm_area_struct *vm } } - newprot = protection_map[newflags & 0xf]; - /* * First try to merge with previous and/or next vma. */ @@ -161,6 +160,11 @@ mprotect_fixup(struct vm_area_struct *vm } success: + mask = VM_READ|VM_WRITE|VM_EXEC|VM_SHARED; + if (vma->vm_ops && vma->vm_ops->page_mkwrite) + mask &= ~VM_SHARED; + newprot = protection_map[newflags & mask]; + /* * vm_flags and vm_page_prot are protected by the mmap_sem * held in write mode. _