Commit 878b63ac889df706d01048f2c110e322ad2f996d
Committed by
Linus Torvalds
1 parent
2da02997e0
Exists in
master
and in
4 other branches
mm: gup persist for write permission
do_wp_page()'s VM_FAULT_WRITE return value tells __get_user_pages() that COW has been done if necessary, though it may be leaving the pte without write permission - for the odd case of forced writing to a readonly vma for ptrace. At present GUP then retries the follow_page() without asking for write permission, to escape an endless loop when forced. But an application may be relying on GUP to guarantee a writable page which won't be COWed again when written from userspace, whereas a race here might leave a readonly pte in place? Change the VM_FAULT_WRITE handling to ask follow_page() for write permission again, except in that odd case of forced writing to a readonly vma. Signed-off-by: Hugh Dickins <hugh@veritas.com> Cc: Lee Schermerhorn <lee.schermerhorn@hp.com> Cc: Rik van Riel <riel@redhat.com> Cc: Nick Piggin <nickpiggin@yahoo.com.au> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Robin Holt <holt@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 8 additions and 2 deletions Side-by-side Diff
mm/memory.c
... | ... | @@ -1264,9 +1264,15 @@ |
1264 | 1264 | * do_wp_page has broken COW when necessary, |
1265 | 1265 | * even if maybe_mkwrite decided not to set |
1266 | 1266 | * pte_write. We can thus safely do subsequent |
1267 | - * page lookups as if they were reads. | |
1267 | + * page lookups as if they were reads. But only | |
1268 | + * do so when looping for pte_write is futile: | |
1269 | + * in some cases userspace may also be wanting | |
1270 | + * to write to the gotten user page, which a | |
1271 | + * read fault here might prevent (a readonly | |
1272 | + * page might get reCOWed by userspace write). | |
1268 | 1273 | */ |
1269 | - if (ret & VM_FAULT_WRITE) | |
1274 | + if ((ret & VM_FAULT_WRITE) && | |
1275 | + !(vma->vm_flags & VM_WRITE)) | |
1270 | 1276 | foll_flags &= ~FOLL_WRITE; |
1271 | 1277 | |
1272 | 1278 | cond_resched(); |