Received: by 10.223.185.116 with SMTP id b49csp2317960wrg; Thu, 15 Feb 2018 09:45:22 -0800 (PST) X-Google-Smtp-Source: AH8x227dhgz88WYfAr119+6JfCCq9w29jVaftTthO/vYc9jCDgGd+K/r3l6S1y8BbF1w5j95r5xI X-Received: by 2002:a17:902:4906:: with SMTP id u6-v6mr3133192pld.92.1518716722141; Thu, 15 Feb 2018 09:45:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518716722; cv=none; d=google.com; s=arc-20160816; b=Ine8OzmVPc6wFzOwnwlsKNSukaP+fAOBo3tNiiufG8JO4ziJ2R9GlTAwg8MwGbGvGw 7KKOvc2aITVzoiFh9v4wegDfFgbP/Zu9dhPrc0mgA+Sac27FlEBoviM1jV5c6cVyBkcX JNM6EP5yn7GSVjmvElqcQ+CHfwH5Nh6tNyjty9X3IjaXVHISpd+oPYdk0KU3cRa51s9I avs/Nqw38iLXAF/Xi9GrLm3MY+PFFd9oaHGIGDKfVIObJXyHCqJunbGLQd1188FNPbP+ RmxcMSs9ZE9pTEmpV2oMdBKy3hQWlSQdft+AcX2DHngurtzOiFPqrIDEb+wr3NllbCqG bRVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Yq1xwpYqKg9ZEDiqRfzx72s3UAdZzwPo2Wsg8r4RNsQ=; b=LHDhzpnmYC3WbGzl1U+ebuqbCsqrgMT1JkZr8prfBcta4RV59eKyxP+9W6KIDTAgXf Yq0eG0Sd9Ak06DZK27LPP2IVTkH4b/7nimUOWEseIiurHLfsu0fqZF9R8yTYF6xjVFUv FfVpnWgKtzkSVPXozOaq/aG7rJYEQljvfZarR3U1Wb95tIwDuS4SVSf/q69RAebj9uvE 3orxZBgF/7zulcLdJo/QCfgEMyrbI0ZPR3f96ASLERxpatJ5DgJCtT/YTP/DqG7Ct/Kk h0BA9wNI8Rlhe/qTZLDOtfpUijzgeZ6TodSsbNq2i4E4IeCYQbxGSMo6xcfxkhWibxtW LThw== ARC-Authentication-Results: i=1; mx.google.com; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g5-v6si3038400plt.563.2018.02.15.09.45.07; Thu, 15 Feb 2018 09:45:22 -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; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1946079AbeBORnH (ORCPT + 99 others); Thu, 15 Feb 2018 12:43:07 -0500 Received: from mail.linuxfoundation.org ([140.211.169.12]:56238 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1164539AbeBOPcE (ORCPT ); Thu, 15 Feb 2018 10:32:04 -0500 Received: from localhost (LFbn-1-12258-90.w90-92.abo.wanadoo.fr [90.92.71.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id EDE01F73; Thu, 15 Feb 2018 15:32:03 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Robin Murphy , Will Deacon , Catalin Marinas , Ard Biesheuvel Subject: [PATCH 4.14 058/195] [Variant 1/Spectre-v1] arm64: Make USER_DS an inclusive limit Date: Thu, 15 Feb 2018 16:15:49 +0100 Message-Id: <20180215151708.627245239@linuxfoundation.org> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180215151705.738773577@linuxfoundation.org> References: <20180215151705.738773577@linuxfoundation.org> User-Agent: quilt/0.65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.14-stable review patch. If anyone has any objections, please let me know. ------------------ From: Robin Murphy Commit 51369e398d0d upstream. Currently, USER_DS represents an exclusive limit while KERNEL_DS is inclusive. In order to do some clever trickery for speculation-safe masking, we need them both to behave equivalently - there aren't enough bits to make KERNEL_DS exclusive, so we have precisely one option. This also happens to correct a longstanding false negative for a range ending on the very top byte of kernel memory. Mark Rutland points out that we've actually got the semantics of addresses vs. segments muddled up in most of the places we need to amend, so shuffle the {USER,KERNEL}_DS definitions around such that we can correct those properly instead of just pasting "-1"s everywhere. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Ard Biesheuvel Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/processor.h | 3 ++ arch/arm64/include/asm/uaccess.h | 45 +++++++++++++++++++++---------------- arch/arm64/kernel/entry.S | 4 +-- arch/arm64/mm/fault.c | 4 +-- 4 files changed, 33 insertions(+), 23 deletions(-) --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -21,6 +21,9 @@ #define TASK_SIZE_64 (UL(1) << VA_BITS) +#define KERNEL_DS UL(-1) +#define USER_DS (TASK_SIZE_64 - 1) + #ifndef __ASSEMBLY__ /* --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -35,10 +35,7 @@ #include #include -#define KERNEL_DS (-1UL) #define get_ds() (KERNEL_DS) - -#define USER_DS TASK_SIZE_64 #define get_fs() (current_thread_info()->addr_limit) static inline void set_fs(mm_segment_t fs) @@ -66,22 +63,32 @@ static inline void set_fs(mm_segment_t f * Returns 1 if the range is valid, 0 otherwise. * * This is equivalent to the following test: - * (u65)addr + (u65)size <= current->addr_limit - * - * This needs 65-bit arithmetic. + * (u65)addr + (u65)size <= (u65)current->addr_limit + 1 */ -#define __range_ok(addr, size) \ -({ \ - unsigned long __addr = (unsigned long)(addr); \ - unsigned long flag, roksum; \ - __chk_user_ptr(addr); \ - asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \ - : "=&r" (flag), "=&r" (roksum) \ - : "1" (__addr), "Ir" (size), \ - "r" (current_thread_info()->addr_limit) \ - : "cc"); \ - flag; \ -}) +static inline unsigned long __range_ok(unsigned long addr, unsigned long size) +{ + unsigned long limit = current_thread_info()->addr_limit; + + __chk_user_ptr(addr); + asm volatile( + // A + B <= C + 1 for all A,B,C, in four easy steps: + // 1: X = A + B; X' = X % 2^64 + " adds %0, %0, %2\n" + // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4 + " csel %1, xzr, %1, hi\n" + // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X' + // to compensate for the carry flag being set in step 4. For + // X > 2^64, X' merely has to remain nonzero, which it does. + " csinv %0, %0, xzr, cc\n" + // 4: For X < 2^64, this gives us X' - C - 1 <= 0, where the -1 + // comes from the carry in being clear. Otherwise, we are + // testing X' - C == 0, subject to the previous adjustments. + " sbcs xzr, %0, %1\n" + " cset %0, ls\n" + : "+r" (addr), "+r" (limit) : "Ir" (size) : "cc"); + + return addr; +} /* * When dealing with data aborts, watchpoints, or instruction traps we may end @@ -90,7 +97,7 @@ static inline void set_fs(mm_segment_t f */ #define untagged_addr(addr) sign_extend64(addr, 55) -#define access_ok(type, addr, size) __range_ok(addr, size) +#define access_ok(type, addr, size) __range_ok((unsigned long)(addr), size) #define user_addr_max get_fs #define _ASM_EXTABLE(from, to) \ --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -167,10 +167,10 @@ alternative_else_nop_endif .else add x21, sp, #S_FRAME_SIZE get_thread_info tsk - /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */ + /* Save the task's original addr_limit and set USER_DS */ ldr x20, [tsk, #TSK_TI_ADDR_LIMIT] str x20, [sp, #S_ORIG_ADDR_LIMIT] - mov x20, #TASK_SIZE_64 + mov x20, #USER_DS str x20, [tsk, #TSK_TI_ADDR_LIMIT] /* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */ .endif /* \el == 0 */ --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -242,7 +242,7 @@ static inline bool is_permission_fault(u if (fsc_type == ESR_ELx_FSC_PERM) return true; - if (addr < USER_DS && system_uses_ttbr0_pan()) + if (addr < TASK_SIZE && system_uses_ttbr0_pan()) return fsc_type == ESR_ELx_FSC_FAULT && (regs->pstate & PSR_PAN_BIT); @@ -426,7 +426,7 @@ static int __kprobes do_page_fault(unsig mm_flags |= FAULT_FLAG_WRITE; } - if (addr < USER_DS && is_permission_fault(esr, regs, addr)) { + if (addr < TASK_SIZE && is_permission_fault(esr, regs, addr)) { /* regs->orig_addr_limit may be 0 if we entered from EL0 */ if (regs->orig_addr_limit == KERNEL_DS) die("Accessing user space memory with fs=KERNEL_DS", regs, esr);