From 43569a1e4439dfba000295ce36f0c27806d7f9ba Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 13 Apr 2012 03:01:31 +0000 Subject: [PATCH] hugetlb: fix race condition in hugetlb_fault() svn path=/dists/sid/linux-2.6/; revision=18923 --- debian/changelog | 1 + ...-fix-race-condition-in-hugetlb_fault.patch | 88 +++++++++++++++++++ debian/patches/series/base | 1 + 3 files changed, 90 insertions(+) create mode 100644 debian/patches/bugfix/all/hugetlb-fix-race-condition-in-hugetlb_fault.patch diff --git a/debian/changelog b/debian/changelog index 31307355d..f49cc9495 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,6 +10,7 @@ linux-2.6 (3.2.14-2) UNRELEASED; urgency=low * drm/radeon/kms: fix fans after resume (Closes: #596741) * [x86] hv: Update all Hyper-V drivers to 3.4-rc1 (Closes: #661318) * nfs: Fix length of buffer copied in __nfs4_get_acl_uncached + * hugetlb: fix race condition in hugetlb_fault() [ Jonathan Nieder ] * [x86] ioat: fix size of 'completion' for Xen (Closes: #660554) diff --git a/debian/patches/bugfix/all/hugetlb-fix-race-condition-in-hugetlb_fault.patch b/debian/patches/bugfix/all/hugetlb-fix-race-condition-in-hugetlb_fault.patch new file mode 100644 index 000000000..ff0795850 --- /dev/null +++ b/debian/patches/bugfix/all/hugetlb-fix-race-condition-in-hugetlb_fault.patch @@ -0,0 +1,88 @@ +From: Chris Metcalf +Date: Thu, 12 Apr 2012 12:49:15 -0700 +Subject: [PATCH] hugetlb: fix race condition in hugetlb_fault() + +commit 66aebce747eaf9bc456bf1f1b217d8db843031d0 upstream. + +The race is as follows: + +Suppose a multi-threaded task forks a new process (on cpu A), thus +bumping up the ref count on all the pages. While the fork is occurring +(and thus we have marked all the PTEs as read-only), another thread in +the original process (on cpu B) tries to write to a huge page, taking an +access violation from the write-protect and calling hugetlb_cow(). Now, +suppose the fork() fails. It will undo the COW and decrement the ref +count on the pages, so the ref count on the huge page drops back to 1. +Meanwhile hugetlb_cow() also decrements the ref count by one on the +original page, since the original address space doesn't need it any +more, having copied a new page to replace the original page. This +leaves the ref count at zero, and when we call unlock_page(), we panic. + + fork on CPU A fault on CPU B + ============= ============== + ... + down_write(&parent->mmap_sem); + down_write_nested(&child->mmap_sem); + ... + while duplicating vmas + if error + break; + ... + up_write(&child->mmap_sem); + up_write(&parent->mmap_sem); ... + down_read(&parent->mmap_sem); + ... + lock_page(page); + handle COW + page_mapcount(old_page) == 2 + alloc and prepare new_page + ... + handle error + page_remove_rmap(page); + put_page(page); + ... + fold new_page into pte + page_remove_rmap(page); + put_page(page); + ... + oops ==> unlock_page(page); + up_read(&parent->mmap_sem); + +The solution is to take an extra reference to the page while we are +holding the lock on it. + +Signed-off-by: Chris Metcalf +Cc: Hillf Danton +Cc: Michal Hocko +Cc: KAMEZAWA Hiroyuki +Cc: Hugh Dickins +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + mm/hugetlb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index b8ce6f4..cd65cb1 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -2791,6 +2791,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, + * so no worry about deadlock. + */ + page = pte_page(entry); ++ get_page(page); + if (page != pagecache_page) + lock_page(page); + +@@ -2822,6 +2823,7 @@ out_page_table_lock: + } + if (page != pagecache_page) + unlock_page(page); ++ put_page(page); + + out_mutex: + mutex_unlock(&hugetlb_instantiation_mutex); +-- +1.7.9.5 + diff --git a/debian/patches/series/base b/debian/patches/series/base index bfdd3fd07..dc9812488 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -179,3 +179,4 @@ + debian/nls-Avoid-ABI-change-from-improvement-to-utf8s_to_ut.patch + bugfix/all/nfs-Fix-length-of-buffer-copied-in-__nfs4_get_acl_uncach.patch ++ bugfix/all/hugetlb-fix-race-condition-in-hugetlb_fault.patch