Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3316411imu; Sun, 11 Nov 2018 12:13:01 -0800 (PST) X-Google-Smtp-Source: AJdET5fC4VJJngM/emc/lHf33A2cSBUkDHQtPcT6/5uUlK4e9YSKomTqD2y60iwzV+4dCHY/Z09J X-Received: by 2002:a62:15c7:: with SMTP id 190-v6mr17334506pfv.213.1541967181820; Sun, 11 Nov 2018 12:13:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541967181; cv=none; d=google.com; s=arc-20160816; b=Q+YpMTIR+cfi9520pi3HUH26+uLG3UzjkRV6SA77CD/6/stAw9rgPkvaVo4okqw2+X 1v2UN0zG/vbt3NfhNX0gDM/AGsj+dgqxACsr9rWVcjohvxeciBxlNLBCG9mA6vaKuqql A8VNzv18o+V1qmM98GlnPRJXZDY0BWob/kRoqZQjWKQYig80Doa9KjrWDBV1+3KmZk9A PHqvkSo4YQh7bcLTR2ikIbciD/igo5DmRhklY0ytLwI1dSt5Al7M+ppc7QTx/PUPtpOP yUkp5FUDwKJ+kfcF+PTZhgoCsfpOcRh6rVUHSuB97TRWCLK15IhxCGJbcHxjJY0kcK5x ZgRQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-transfer-encoding:content-disposition:mime-version :references:mail-followup-to:message-id:subject:cc:to:from:date :dkim-signature; bh=H7Frku9R4zv02TfxEkiIiYpj1gRppdQqsK+dvbjpF5I=; b=FZK8FgH9mu7mhb00Nu0vUHuDjScemsruP8j43kCkL1CCPQnF36Jr/1rVTRv5SzlGwA OQyk7537EYB88m7wUynq8X22soQyyQ7kl3b0USqk+hWzyGMMErwxKEjLWiRPerY3M8Aw jrMIiHobnTlg03TuBIFCe6ZJ9nvn92bUUxi897XdiNz+imJYepbk9AAaz8wEcP4sxWob snUlyYpPCUw5LAxxUOuEz9Lyf/AzYije10URqb5TK/tMXFYL8PHTwm5qkv0yFVAAXngy z65qNPCET5DmmWbo2k+vnQ2F3zd632uxJCR9sQMkdg7GOw4s3CXpyU0NFEEXvSlQMJ+7 AMRw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@icloud.com header.s=04042017 header.b=iAxhA6B7; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=icloud.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i33-v6si9265774pld.185.2018.11.11.12.12.46; Sun, 11 Nov 2018 12:13:01 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@icloud.com header.s=04042017 header.b=iAxhA6B7; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=icloud.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730766AbeKLGB0 (ORCPT + 99 others); Mon, 12 Nov 2018 01:01:26 -0500 Received: from st13p15im-asmtp003.me.com ([17.164.72.57]:59045 "EHLO st13p15im-asmtp003.me.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727204AbeKLGBY (ORCPT ); Mon, 12 Nov 2018 01:01:24 -0500 X-Greylist: delayed 3614 seconds by postgrey-1.27 at vger.kernel.org; Mon, 12 Nov 2018 01:01:23 EST Received: from process-dkim-sign-daemon.st13p15im-asmtp003.me.com by st13p15im-asmtp003.me.com (Oracle Communications Messaging Server 8.0.2.2.20180531 64bit (built May 31 2018)) id <0PI100Z00MGVL800@st13p15im-asmtp003.me.com> for linux-kernel@vger.kernel.org; Sun, 11 Nov 2018 19:11:48 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=icloud.com; s=04042017; t=1541963508; bh=H7Frku9R4zv02TfxEkiIiYpj1gRppdQqsK+dvbjpF5I=; h=Date:From:To:Subject:Message-id:MIME-version:Content-type; b=iAxhA6B7+HphQqfNQ5U0TqVWsfyKYyulCJuGx2uNcP7GG7wDIiIpHHsuqQET/qXZW CNq12kQ8uRwcVJ8KHKqyD+OAJ3VHz0/3p7FtfoBz4lkvTjTlP08bJRjbLXInYTxePj /P2H/B8bZX4Os8DqLqIiqByITRbAnVyRVfEfkcNPv1Ha+LGn2raYhPxgbbBTKH1r1E jJaN22nAWIECptelY1frItLTLQ4cfRywrPLKjMLB2e9U0YuVYo1DWJXiSAYEsIIZt5 J1yqSOl+pnw3OhODyLSBK7REb7JVVoW2GIIbyS9jdQLT8qbBw9yVuRKJiBHJHyN+YC kysks/0+ZYx6w== Received: from icloud.com ([127.0.0.1]) by st13p15im-asmtp003.me.com (Oracle Communications Messaging Server 8.0.2.2.20180531 64bit (built May 31 2018)) with ESMTPSA id <0PI10109XMNIAK00@st13p15im-asmtp003.me.com>; Sun, 11 Nov 2018 19:11:47 +0000 (GMT) X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 malwarescore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1011 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1807170000 definitions=main-1811110183 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:,, definitions=2018-11-11_13:,, signatures=0 Date: Sun, 11 Nov 2018 20:11:42 +0100 From: Damian Tometzki To: Nadav Amit Cc: Ingo Molnar , linux-kernel@vger.kernel.org, x86@kernel.org, "H. Peter Anvin" , Thomas Gleixner , Borislav Petkov , Dave Hansen , Andy Lutomirski , Kees Cook , Peter Zijlstra , Dave Hansen , Masami Hiramatsu Subject: Re: [PATCH v4 06/10] x86/alternative: use temporary mm for text poking Message-id: <20181111191141.GA1996@Ubuntu-DTI> Mail-followup-to: Nadav Amit , Ingo Molnar , linux-kernel@vger.kernel.org, x86@kernel.org, "H. Peter Anvin" , Thomas Gleixner , Borislav Petkov , Dave Hansen , Andy Lutomirski , Kees Cook , Peter Zijlstra , Dave Hansen , Masami Hiramatsu References: <20181110231732.15060-1-namit@vmware.com> <20181110231732.15060-7-namit@vmware.com> MIME-version: 1.0 Content-type: text/plain; charset=iso-8859-1 Content-disposition: inline Content-transfer-encoding: 8bit In-reply-to: <20181110231732.15060-7-namit@vmware.com> User-Agent: Mutt/1.10.1 (2018-07-13) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Sa, 10. Nov 15:17, Nadav Amit wrote: > text_poke() can potentially compromise the security as it sets temporary > PTEs in the fixmap. These PTEs might be used to rewrite the kernel code > from other cores accidentally or maliciously, if an attacker gains the > ability to write onto kernel memory. > > Moreover, since remote TLBs are not flushed after the temporary PTEs are > removed, the time-window in which the code is writable is not limited if > the fixmap PTEs - maliciously or accidentally - are cached in the TLB. > To address these potential security hazards, we use a temporary mm for > patching the code. > > Finally, text_poke() is also not conservative enough when mapping pages, > as it always tries to map 2 pages, even when a single one is sufficient. > So try to be more conservative, and do not map more than needed. > > Cc: Andy Lutomirski > Cc: Kees Cook > Cc: Peter Zijlstra > Cc: Dave Hansen > Cc: Masami Hiramatsu > Signed-off-by: Nadav Amit > --- > arch/x86/include/asm/fixmap.h | 2 - > arch/x86/kernel/alternative.c | 112 +++++++++++++++++++++++++++------- > 2 files changed, 89 insertions(+), 25 deletions(-) > > diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h > index 50ba74a34a37..9da8cccdf3fb 100644 > --- a/arch/x86/include/asm/fixmap.h > +++ b/arch/x86/include/asm/fixmap.h > @@ -103,8 +103,6 @@ enum fixed_addresses { > #ifdef CONFIG_PARAVIRT > FIX_PARAVIRT_BOOTMAP, > #endif Hello Nadav, with the remove of FIX_TEXT_POKE1 and FIX_TEXT_POKE0 i get the following build error: /home/damian/kernel/linux/arch/x86/xen/mmu_pv.c:2321:7: Fehler: ?FIX_TEXT_POKE0? nicht deklariert (erstmalige Verwendung in dieser Funktion); meinten Sie ?FIX_TBOOT_BASE?? case FIX_TEXT_POKE0: ^~~~~~~~~~~~~~ FIX_TBOOT_BASE /home/damian/kernel/linux/arch/x86/xen/mmu_pv.c:2321:7: Anmerkung: jeder nicht deklarierte Bezeichner wird nur einmal f?r jede Funktion, in der er vorkommt, gemeldet /home/damian/kernel/linux/arch/x86/xen/mmu_pv.c:2322:7: Fehler: ?FIX_TEXT_POKE1? nicht deklariert (erstmalige Verwendung in dieser Funktion); meinten Sie ?FIX_TBOOT_BASE?? case FIX_TEXT_POKE1: ^~~~~~~~~~~~~~ FIX_TBOOT_BASE Best regards Damian > - FIX_TEXT_POKE1, /* reserve 2 pages for text_poke() */ > - FIX_TEXT_POKE0, /* first page is last, because allocation is backward */ > #ifdef CONFIG_X86_INTEL_MID > FIX_LNW_VRTC, > #endif > diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c > index d3ae5c26e5a0..96607ef285c3 100644 > --- a/arch/x86/kernel/alternative.c > +++ b/arch/x86/kernel/alternative.c > @@ -11,6 +11,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -683,43 +684,108 @@ __ro_after_init unsigned long poking_addr; > > static int __text_poke(void *addr, const void *opcode, size_t len) > { > + bool cross_page_boundary = offset_in_page(addr) + len > PAGE_SIZE; > + temporary_mm_state_t prev; > + struct page *pages[2] = {NULL}; > unsigned long flags; > - char *vaddr; > - struct page *pages[2]; > - int i, r = 0; > + pte_t pte, *ptep; > + spinlock_t *ptl; > + int r = 0; > > /* > - * While boot memory allocator is runnig we cannot use struct > - * pages as they are not yet initialized. > + * While boot memory allocator is running we cannot use struct pages as > + * they are not yet initialized. > */ > BUG_ON(!after_bootmem); > > if (!core_kernel_text((unsigned long)addr)) { > pages[0] = vmalloc_to_page(addr); > - pages[1] = vmalloc_to_page(addr + PAGE_SIZE); > + if (cross_page_boundary) > + pages[1] = vmalloc_to_page(addr + PAGE_SIZE); > } else { > pages[0] = virt_to_page(addr); > WARN_ON(!PageReserved(pages[0])); > - pages[1] = virt_to_page(addr + PAGE_SIZE); > + if (cross_page_boundary) > + pages[1] = virt_to_page(addr + PAGE_SIZE); > } > - if (!pages[0]) > + > + if (!pages[0] || (cross_page_boundary && !pages[1])) > return -EFAULT; > + > local_irq_save(flags); > - set_fixmap(FIX_TEXT_POKE0, page_to_phys(pages[0])); > - if (pages[1]) > - set_fixmap(FIX_TEXT_POKE1, page_to_phys(pages[1])); > - vaddr = (char *)fix_to_virt(FIX_TEXT_POKE0); > - memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); > - clear_fixmap(FIX_TEXT_POKE0); > - if (pages[1]) > - clear_fixmap(FIX_TEXT_POKE1); > - local_flush_tlb(); > - sync_core(); > - /* Could also do a CLFLUSH here to speed up CPU recovery; but > - that causes hangs on some VIA CPUs. */ > - for (i = 0; i < len; i++) > - if (((char *)addr)[i] != ((char *)opcode)[i]) > - r = -EFAULT; > + > + /* > + * The lock is not really needed, but this allows to avoid open-coding. > + */ > + ptep = get_locked_pte(poking_mm, poking_addr, &ptl); > + > + /* > + * If we failed to allocate a PTE, fail. This should *never* happen, > + * since we preallocate the PTE. > + */ > + if (WARN_ON_ONCE(!ptep)) > + goto out; > + > + pte = mk_pte(pages[0], PAGE_KERNEL); > + set_pte_at(poking_mm, poking_addr, ptep, pte); > + > + if (cross_page_boundary) { > + pte = mk_pte(pages[1], PAGE_KERNEL); > + set_pte_at(poking_mm, poking_addr + PAGE_SIZE, ptep + 1, pte); > + } > + > + /* > + * Loading the temporary mm behaves as a compiler barrier, which > + * guarantees that the PTE will be set at the time memcpy() is done. > + */ > + prev = use_temporary_mm(poking_mm); > + > + kasan_disable_current(); > + memcpy((u8 *)poking_addr + offset_in_page(addr), opcode, len); > + kasan_enable_current(); > + > + /* > + * Ensure that the PTE is only cleared after the instructions of memcpy > + * were issued by using a compiler barrier. > + */ > + barrier(); > + > + pte_clear(poking_mm, poking_addr, ptep); > + > + /* > + * __flush_tlb_one_user() performs a redundant TLB flush when PTI is on, > + * as it also flushes the corresponding "user" address spaces, which > + * does not exist. > + * > + * Poking, however, is already very inefficient since it does not try to > + * batch updates, so we ignore this problem for the time being. > + * > + * Since the PTEs do not exist in other kernel address-spaces, we do > + * not use __flush_tlb_one_kernel(), which when PTI is on would cause > + * more unwarranted TLB flushes. > + * > + * There is a slight anomaly here: the PTE is a supervisor-only and > + * (potentially) global and we use __flush_tlb_one_user() but this > + * should be fine. > + */ > + __flush_tlb_one_user(poking_addr); > + if (cross_page_boundary) { > + pte_clear(poking_mm, poking_addr + PAGE_SIZE, ptep + 1); > + __flush_tlb_one_user(poking_addr + PAGE_SIZE); > + } > + > + /* > + * Loading the previous page-table hierarchy requires a serializing > + * instruction that already allows the core to see the updated version. > + * Xen-PV is assumed to serialize execution in a similar manner. > + */ > + unuse_temporary_mm(prev); > + > + pte_unmap_unlock(ptep, ptl); > +out: > + if (memcmp(addr, opcode, len)) > + r = -EFAULT; > + > local_irq_restore(flags); > return r; > } > -- > 2.17.1 >