forked from Minki/linux
userfaultfd: provide properly masked address for huge-pages
Commit824ddc601a
("userfaultfd: provide unmasked address on page-fault") was introduced to fix an old bug, in which the offset in the address of a page-fault was masked. Concerns were raised - although were never backed by actual code - that some userspace code might break because the bug has been around for quite a while. To address these concerns a new flag was introduced, and only when this flag is set by the user, userfaultfd provides the exact address of the page-fault. The commit however had a bug, and if the flag is unset, the offset was always masked based on a base-page granularity. Yet, for huge-pages, the behavior prior to the commit was that the address is masked to the huge-page granulrity. While there are no reports on real breakage, fix this issue. If the flag is unset, use the address with the masking that was done before. Link: https://lkml.kernel.org/r/20220711165906.2682-1-namit@vmware.com Fixes:824ddc601a
("userfaultfd: provide unmasked address on page-fault") Signed-off-by: Nadav Amit <namit@vmware.com> Reported-by: James Houghton <jthoughton@google.com> Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: James Houghton <jthoughton@google.com> Cc: David Hildenbrand <david@redhat.com> Cc: Jan Kara <jack@suse.cz> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
c80af0c250
commit
d172b1a3bd
@ -192,17 +192,19 @@ static inline void msg_init(struct uffd_msg *msg)
|
||||
}
|
||||
|
||||
static inline struct uffd_msg userfault_msg(unsigned long address,
|
||||
unsigned long real_address,
|
||||
unsigned int flags,
|
||||
unsigned long reason,
|
||||
unsigned int features)
|
||||
{
|
||||
struct uffd_msg msg;
|
||||
|
||||
msg_init(&msg);
|
||||
msg.event = UFFD_EVENT_PAGEFAULT;
|
||||
|
||||
if (!(features & UFFD_FEATURE_EXACT_ADDRESS))
|
||||
address &= PAGE_MASK;
|
||||
msg.arg.pagefault.address = address;
|
||||
msg.arg.pagefault.address = (features & UFFD_FEATURE_EXACT_ADDRESS) ?
|
||||
real_address : address;
|
||||
|
||||
/*
|
||||
* These flags indicate why the userfault occurred:
|
||||
* - UFFD_PAGEFAULT_FLAG_WP indicates a write protect fault.
|
||||
@ -488,8 +490,8 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
|
||||
|
||||
init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function);
|
||||
uwq.wq.private = current;
|
||||
uwq.msg = userfault_msg(vmf->real_address, vmf->flags, reason,
|
||||
ctx->features);
|
||||
uwq.msg = userfault_msg(vmf->address, vmf->real_address, vmf->flags,
|
||||
reason, ctx->features);
|
||||
uwq.ctx = ctx;
|
||||
uwq.waken = false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user