From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754083AbdKAHnD (ORCPT ); Wed, 1 Nov 2017 03:43:03 -0400 Received: from mx2.suse.de ([195.135.220.15]:35968 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751185AbdKAHnC (ORCPT ); Wed, 1 Nov 2017 03:43:02 -0400 Subject: Re: KASAN: use-after-free Read in __do_page_fault To: Andrea Arcangeli Cc: "Kirill A. Shutemov" , Dmitry Vyukov , syzbot , Jan Beulich , "H. Peter Anvin" , Josh Poimboeuf , "Kirill A. Shutemov" , ldufour@linux.vnet.ibm.com, LKML , Andy Lutomirski , Ingo Molnar , syzkaller-bugs@googlegroups.com, Thomas Gleixner , the arch/x86 maintainers , Andrew Morton , Michal Hocko , Hugh Dickins , David Rientjes , linux-mm@kvack.org, Linus Torvalds , Thorsten Leemhuis References: <94eb2c0433c8f42cac055cc86991@google.com> <8e92c891-a9e0-efed-f0b9-9bf567d8fbcd@suse.cz> <4bc852be-7ef3-0b60-6dbb-81139d25a817@suse.cz> <20171031141152.tzx47fy26pvx7xug@node.shutemov.name> <20171031191506.GB2799@redhat.com> From: Vlastimil Babka Message-ID: <94aa563c-14da-7892-51a0-e1799cdad050@suse.cz> Date: Wed, 1 Nov 2017 08:42:57 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.4.0 MIME-Version: 1.0 In-Reply-To: <20171031191506.GB2799@redhat.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 10/31/2017 08:15 PM, Andrea Arcangeli wrote: > On Tue, Oct 31, 2017 at 03:28:26PM +0100, Vlastimil Babka wrote: >> Hmm that could indeed work, Dmitry can you try the patch below? >> But it still seems rather fragile so I'd hope Andrea can do it more >> robust, or at least make sure that we don't reintroduce this kind of >> problem in the future (explicitly set vma to NULL with a comment?). > > Reviewed-by: Andrea Arcangeli Thanks. OK so here's the full patch for the immediate issue, unless we decide to do something more general. ----8<---- >>From a5f887fcac65372f4e76a290ed59855de0b08e2e Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Wed, 1 Nov 2017 08:21:25 +0100 Subject: [PATCH] x86/mm: fix use-after-free of vma during userfaultfd fault Syzkaller with KASAN has reported a use-after-free of vma->vm_flags in __do_page_fault() with the following reproducer: #{Threaded:true Collide:true Repeat:true Procs:8 Sandbox:none Fault:false FaultCall:-1 FaultNth:0 EnableTun:true UseTmpDir:true HandleSegv:true WaitRepeat:true Debug:false Repro:false} mmap(&(0x7f0000000000/0xfff000)=nil, 0xfff000, 0x3, 0x32, 0xffffffffffffffff, 0x0) mmap(&(0x7f0000011000/0x3000)=nil, 0x3000, 0x1, 0x32, 0xffffffffffffffff, 0x0) r0 = userfaultfd(0x0) ioctl$UFFDIO_API(r0, 0xc018aa3f, &(0x7f0000002000-0x18)={0xaa, 0x0, 0x0}) ioctl$UFFDIO_REGISTER(r0, 0xc020aa00, &(0x7f0000019000)={{&(0x7f0000012000/0x2000)=nil, 0x2000}, 0x1, 0x0}) r1 = gettid() syz_open_dev$evdev(&(0x7f0000013000-0x12)="2f6465762f696e7075742f6576656e742300", 0x0, 0x0) tkill(r1, 0x7) The vma should be pinned by mmap_sem, but handle_userfault() will in some scenarios release it and then acquire again, so when we return to __do_page_fault() with other result than VM_FAULT_RETRY, the vma might be gone. However, since a3c4fb7c9c2e ("x86/mm: Fix fault error path using unsafe vma pointer") there is a vma_pkey() read of vma->vm_flags after that point, which can thus become use-after-free. Fix this by moving the read before calling handle_mm_fault(). Reported-by: syzbot Reported-by: Dmitry Vyukov Suggested-by: Kirill A. Shutemov Fixes: 3c4fb7c9c2e ("x86/mm: Fix fault error path using unsafe vma pointer") Reviewed-by: Andrea Arcangeli Signed-off-by: Vlastimil Babka --- arch/x86/mm/fault.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index e2baeaa053a5..2f45a959aec2 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1440,7 +1440,13 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, * make sure we exit gracefully rather than endlessly redo * the fault. Since we never set FAULT_FLAG_RETRY_NOWAIT, if * we get VM_FAULT_RETRY back, the mmap_sem has been unlocked. + * + * Since handle_userfault() may also release and reacquire mmap_sem + * in some scenario (and not return VM_FAULT_RETRY), we have to be + * careful about not touching vma after handling the fault. So we + * read the pkey beforehand. */ + pkey = vma_pkey(vma); fault = handle_mm_fault(vma, address, flags); major |= fault & VM_FAULT_MAJOR; @@ -1467,7 +1473,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code, return; } - pkey = vma_pkey(vma); up_read(&mm->mmap_sem); if (unlikely(fault & VM_FAULT_ERROR)) { mm_fault_error(regs, error_code, address, &pkey, fault); -- 2.14.3