From: Vitaly Kuznetsov <vkuznets@redhat.com>
To: Vlastimil Babka <vbabka@suse.cz>, Ajay Kaher <akaher@vmware.com>
Cc: Peter Zijlstra <peterz@infradead.org>,
gregkh@linuxfoundation.org, stable@vger.kernel.org,
torvalds@linux-foundation.org, punit.agrawal@arm.com,
akpm@linux-foundation.org, kirill.shutemov@linux.intel.com,
willy@infradead.org, will.deacon@arm.com, mszeredi@redhat.com,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
srivatsab@vmware.com, srivatsa@csail.mit.edu,
amakhalov@vmware.com, srinidhir@vmware.com, bvikas@vmware.com,
anishs@vmware.com, vsirnapalli@vmware.com, srostedt@vmware.com,
Oscar Salvador <osalvador@suse.de>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Juergen Gross <jgross@suse.com>,
Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
Andy Lutomirski <luto@kernel.org>
Subject: Re: [PATCH v3 8/8] x86, mm, gup: prevent get_page() race with munmap in paravirt guest
Date: Mon, 16 Dec 2019 17:08:32 +0100 [thread overview]
Message-ID: <87immg9rsv.fsf@vitty.brq.redhat.com> (raw)
In-Reply-To: <1aacc7ac-87b0-e22e-a265-ea175506844d@suse.cz>
Vlastimil Babka <vbabka@suse.cz> writes:
> On 12/16/19 2:47 PM, Peter Zijlstra wrote:
>> On Mon, Dec 16, 2019 at 02:30:44PM +0100, Vitaly Kuznetsov wrote:
>>> Peter Zijlstra <peterz@infradead.org> writes:
>>>
>>>> On Tue, Dec 17, 2019 at 02:15:48AM +0530, Ajay Kaher wrote:
>>>>> From: Vlastimil Babka <vbabka@suse.cz>
>>>>>
>>>>> The x86 version of get_user_pages_fast() relies on disabled interrupts to
>>>>> synchronize gup_pte_range() between gup_get_pte(ptep); and get_page() against
>>>>> a parallel munmap. The munmap side nulls the pte, then flushes TLBs, then
>>>>> releases the page. As TLB flush is done synchronously via IPI disabling
>>>>> interrupts blocks the page release, and get_page(), which assumes existing
>>>>> reference on page, is thus safe.
>>>>> However when TLB flush is done by a hypercall, e.g. in a Xen PV guest, there is
>>>>> no blocking thanks to disabled interrupts, and get_page() can succeed on a page
>>>>> that was already freed or even reused.
>>>>>
>>>>> We have recently seen this happen with our 4.4 and 4.12 based kernels, with
>>>>> userspace (java) that exits a thread, where mm_release() performs a futex_wake()
>>>>> on tsk->clear_child_tid, and another thread in parallel unmaps the page where
>>>>> tsk->clear_child_tid points to. The spurious get_page() succeeds, but futex code
>>>>> immediately releases the page again, while it's already on a freelist. Symptoms
>>>>> include a bad page state warning, general protection faults acessing a poisoned
>>>>> list prev/next pointer in the freelist, or free page pcplists of two cpus joined
>>>>> together in a single list. Oscar has also reproduced this scenario, with a
>>>>> patch inserting delays before the get_page() to make the race window larger.
>>>>>
>>>>> Fix this by removing the dependency on TLB flush interrupts the same way as the
>>>>
>>>> This is suppsed to be fixed by:
>>>>
>>>> arch/x86/Kconfig: select HAVE_RCU_TABLE_FREE if PARAVIRT
>>>>
>>>
>>> Yes,
>
> Well, that commit fixes the "page table can be freed under us" part. But
> this patch is about the "get_page() will succeed on a page that's being
> freed" part. Upstream fixed that unknowingly in 4.13 by a gup.c
> refactoring that would be too risky to backport fully.
>
(I also dislike receiving only this patch of the series, next time
please send the whole thing, it's only 8 patches, our mailfolders will
survive that)
When I was adding Hyper-V PV TLB flush to RHEL7 - which is 3.10 based -
in addition to adding page_cache_get_speculative() to
gup_get_pte()/gup_huge_pmd()/gup_huge_pud() I also had to synchronize
huge PMD split against gup_fast with the following hack:
+static void do_nothing(void *unused)
+{
+
+}
+
+static void serialize_against_pte_lookup(struct mm_struct *mm)
+{
+ smp_mb();
+ smp_call_function_many(mm_cpumask(mm), do_nothing, NULL, 1);
+}
+
void pmdp_splitting_flush(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp)
{
@@ -434,9 +473,10 @@ void pmdp_splitting_flush(struct vm_area_struct *vma,
set = !test_and_set_bit(_PAGE_BIT_SPLITTING,
(unsigned long *)pmdp);
if (set) {
/* need tlb flush only to serialize against gup-fast */
flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
+ if (pv_mmu_ops.flush_tlb_others != native_flush_tlb_others)
+ serialize_against_pte_lookup(vma->vm_mm);
}
}
I'm not sure which stable kernel you're targeting (and if you addressed this
with other patches in the series, if this is needed,...) so JFYI.
--
Vitaly
next prev parent reply other threads:[~2019-12-16 16:08 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-16 20:45 [PATCH v3 0/8] Backported fixes for 4.4 stable tree Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 1/8] mm: make page ref count overflow check tighter and more explicit Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 2/8] mm: add 'try_get_page()' helper function Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 3/8] mm, gup: remove broken VM_BUG_ON_PAGE compound check for hugepages Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 4/8] mm, gup: ensure real head page is ref-counted when using hugepages Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 5/8] mm: prevent get_user_pages() from overflowing page refcount Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 6/8] pipe: add pipe_buf_get() helper Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 7/8] fs: prevent page refcount overflow in pipe_buf_get Ajay Kaher
2019-12-16 20:45 ` [PATCH v3 8/8] x86, mm, gup: prevent get_page() race with munmap in paravirt guest Ajay Kaher
2019-12-16 13:04 ` Peter Zijlstra
2019-12-16 13:30 ` Vitaly Kuznetsov
2019-12-16 13:47 ` Peter Zijlstra
2019-12-16 15:11 ` Vlastimil Babka
2019-12-16 16:08 ` Vitaly Kuznetsov [this message]
2019-12-17 4:13 ` Ajay Kaher
2020-01-31 12:51 ` Ajay Kaher
[not found] <1575999773-4628-1-git-send-email-akaher@vmware.com>
2019-12-10 17:42 ` Ajay Kaher
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87immg9rsv.fsf@vitty.brq.redhat.com \
--to=vkuznets@redhat.com \
--cc=akaher@vmware.com \
--cc=akpm@linux-foundation.org \
--cc=amakhalov@vmware.com \
--cc=anishs@vmware.com \
--cc=bp@alien8.de \
--cc=bvikas@vmware.com \
--cc=dave.hansen@linux.intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=jgross@suse.com \
--cc=kirill.shutemov@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=luto@kernel.org \
--cc=mingo@redhat.com \
--cc=mszeredi@redhat.com \
--cc=osalvador@suse.de \
--cc=peterz@infradead.org \
--cc=punit.agrawal@arm.com \
--cc=srinidhir@vmware.com \
--cc=srivatsa@csail.mit.edu \
--cc=srivatsab@vmware.com \
--cc=srostedt@vmware.com \
--cc=stable@vger.kernel.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=vbabka@suse.cz \
--cc=vsirnapalli@vmware.com \
--cc=will.deacon@arm.com \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.