Message ID | 20220711165906.2682-1-namit@vmware.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | userfaultfd: provide properly masked address for huge-pages | expand |
On Mon, Jul 11, 2022 at 09:59:06AM -0700, Nadav Amit wrote: > From: Nadav Amit <namit@vmware.com> > > Commit 824ddc601adc ("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. > > Fixes: 824ddc601adc ("userfaultfd: provide unmasked address on page-fault") > Reported-by: James Houghton <jthoughton@google.com> > Cc: Peter Xu <peterx@redhat.com> > Cc: David Hildenbrand <david@redhat.com> > Cc: Mike Rapoport <rppt@linux.ibm.com> > Cc: Jan Kara <jack@suse.cz> > Cc: Andrea Arcangeli <aarcange@redhat.com> > Cc: <stable@vger.kernel.org> > Signed-off-by: Nadav Amit <namit@vmware.com> Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> > --- > fs/userfaultfd.c | 12 +++++++----- > 1 file changed, 7 insertions(+), 5 deletions(-) > > diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c > index e943370107d0..de86f5b2859f 100644 > --- a/fs/userfaultfd.c > +++ b/fs/userfaultfd.c > @@ -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; > > -- > 2.25.1 >
On Mon, Jul 11, 2022 at 09:59:06AM -0700, Nadav Amit wrote: > From: Nadav Amit <namit@vmware.com> > > Commit 824ddc601adc ("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. > > Fixes: 824ddc601adc ("userfaultfd: provide unmasked address on page-fault") > Reported-by: James Houghton <jthoughton@google.com> > Cc: Peter Xu <peterx@redhat.com> > Cc: David Hildenbrand <david@redhat.com> > Cc: Mike Rapoport <rppt@linux.ibm.com> > Cc: Jan Kara <jack@suse.cz> > Cc: Andrea Arcangeli <aarcange@redhat.com> > Cc: <stable@vger.kernel.org> > Signed-off-by: Nadav Amit <namit@vmware.com> Reviewed-by: Peter Xu <peterx@redhat.com>
On Mon, Jul 11, 2022 at 5:33 PM Nadav Amit <nadav.amit@gmail.com> wrote: > > From: Nadav Amit <namit@vmware.com> > > Commit 824ddc601adc ("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. > > Fixes: 824ddc601adc ("userfaultfd: provide unmasked address on page-fault") > Reported-by: James Houghton <jthoughton@google.com> > Cc: Peter Xu <peterx@redhat.com> > Cc: David Hildenbrand <david@redhat.com> > Cc: Mike Rapoport <rppt@linux.ibm.com> > Cc: Jan Kara <jack@suse.cz> > Cc: Andrea Arcangeli <aarcange@redhat.com> > Cc: <stable@vger.kernel.org> > Signed-off-by: Nadav Amit <namit@vmware.com> Reviewed-by: James Houghton <jthoughton@google.com> Thanks! > --- > fs/userfaultfd.c | 12 +++++++----- > 1 file changed, 7 insertions(+), 5 deletions(-) > > diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c > index e943370107d0..de86f5b2859f 100644 > --- a/fs/userfaultfd.c > +++ b/fs/userfaultfd.c > @@ -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; > > -- > 2.25.1 >
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index e943370107d0..de86f5b2859f 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -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;