Commit d172b1a3 authored by Nadav Amit's avatar Nadav Amit Committed by akpm

userfaultfd: provide properly masked address for huge-pages

Commit 824ddc60 ("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: 824ddc60 ("userfaultfd: provide unmasked address on page-fault")
Signed-off-by: default avatarNadav Amit <namit@vmware.com>
Reported-by: default avatarJames Houghton <jthoughton@google.com>
Reviewed-by: default avatarMike Rapoport <rppt@linux.ibm.com>
Reviewed-by: default avatarPeter Xu <peterx@redhat.com>
Reviewed-by: default avatarJames 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: default avatarAndrew Morton <akpm@linux-foundation.org>
parent c80af0c2
...@@ -192,17 +192,19 @@ static inline void msg_init(struct uffd_msg *msg) ...@@ -192,17 +192,19 @@ static inline void msg_init(struct uffd_msg *msg)
} }
static inline struct uffd_msg userfault_msg(unsigned long address, static inline struct uffd_msg userfault_msg(unsigned long address,
unsigned long real_address,
unsigned int flags, unsigned int flags,
unsigned long reason, unsigned long reason,
unsigned int features) unsigned int features)
{ {
struct uffd_msg msg; struct uffd_msg msg;
msg_init(&msg); msg_init(&msg);
msg.event = UFFD_EVENT_PAGEFAULT; msg.event = UFFD_EVENT_PAGEFAULT;
if (!(features & UFFD_FEATURE_EXACT_ADDRESS)) msg.arg.pagefault.address = (features & UFFD_FEATURE_EXACT_ADDRESS) ?
address &= PAGE_MASK; real_address : address;
msg.arg.pagefault.address = address;
/* /*
* These flags indicate why the userfault occurred: * These flags indicate why the userfault occurred:
* - UFFD_PAGEFAULT_FLAG_WP indicates a write protect fault. * - 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) ...@@ -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); init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function);
uwq.wq.private = current; uwq.wq.private = current;
uwq.msg = userfault_msg(vmf->real_address, vmf->flags, reason, uwq.msg = userfault_msg(vmf->address, vmf->real_address, vmf->flags,
ctx->features); reason, ctx->features);
uwq.ctx = ctx; uwq.ctx = ctx;
uwq.waken = false; uwq.waken = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment