summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-09-28 12:35:07 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2020-09-28 09:21:50 -0700
commita4d63c3732f1a0c91abcf5b7f32b4ef7dcd82025 (patch)
tree8f8a502327c2fbb8c7c6b21c9e77a09c63dfe856 /mm
parenta1b8638ba1320e6684aa98233c15255eb803fac7 (diff)
downloadlwn-a4d63c3732f1a0c91abcf5b7f32b4ef7dcd82025.tar.gz
lwn-a4d63c3732f1a0c91abcf5b7f32b4ef7dcd82025.zip
mm: do not rely on mm == current->mm in __get_user_pages_locked
It seems likely this block was pasted from internal_get_user_pages_fast, which is not passed an mm struct and therefore uses current's. But __get_user_pages_locked is passed an explicit mm, and current->mm is not always valid. This was hit when being called from i915, which uses: pin_user_pages_remote-> __get_user_pages_remote-> __gup_longterm_locked-> __get_user_pages_locked Before, this would lead to an OOPS: BUG: kernel NULL pointer dereference, address: 0000000000000064 #PF: supervisor write access in kernel mode #PF: error_code(0x0002) - not-present page CPU: 10 PID: 1431 Comm: kworker/u33:1 Tainted: P S U O 5.9.0-rc7+ #140 Hardware name: LENOVO 20QTCTO1WW/20QTCTO1WW, BIOS N2OET47W (1.34 ) 08/06/2020 Workqueue: i915-userptr-acquire __i915_gem_userptr_get_pages_worker [i915] RIP: 0010:__get_user_pages_remote+0xd7/0x310 Call Trace: __i915_gem_userptr_get_pages_worker+0xc8/0x260 [i915] process_one_work+0x1ca/0x390 worker_thread+0x48/0x3c0 kthread+0x114/0x130 ret_from_fork+0x1f/0x30 CR2: 0000000000000064 This commit fixes the problem by using the mm pointer passed to the function rather than the bogus one in current. Fixes: 008cfe4418b3 ("mm: Introduce mm_struct.has_pinned") Tested-by: Chris Wilson <chris@chris-wilson.co.uk> Reported-by: Harald Arnesen <harald@skogtun.org> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Peter Xu <peterx@redhat.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/gup.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/mm/gup.c b/mm/gup.c
index dfe781d2ad4c..e869c634cc9a 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1256,7 +1256,7 @@ static __always_inline long __get_user_pages_locked(struct mm_struct *mm,
}
if (flags & FOLL_PIN)
- atomic_set(&current->mm->has_pinned, 1);
+ atomic_set(&mm->has_pinned, 1);
/*
* FOLL_PIN and FOLL_GET are mutually exclusive. Traditional behavior