Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp1176862pxb; Fri, 20 Nov 2020 03:13:13 -0800 (PST) X-Google-Smtp-Source: ABdhPJzyhDvXNIfPgjN+7ch6h+YeX+CCwn1Kx73DuxJYLKTZiyg/ll9bA/J71kAy3uNXp36RR59c X-Received: by 2002:a17:906:e0d2:: with SMTP id gl18mr11168700ejb.412.1605870793168; Fri, 20 Nov 2020 03:13:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605870793; cv=none; d=google.com; s=arc-20160816; b=B1vSuSW8toiWnaEzDFWgZJzOkbBLvqBZRSD2nffPt0ROnW85b0eAJ/MqYvu+Yqv4T6 M+lGzX1QbnWgiiCOqpMb2WpIRBvp6DgkBY6Z7cZJOmOWqnp0Wpn9sARPg7SSSZfxj52q RISsTgSXDvxw8IJalrgrt8hicipixAYSBKQK0PWP+19wGugg3Hg6mbI+VnfwKD/NOjCu C18MoKqv3xen9RXQJw36eSvOmeQHqppt3n1YsY1fXLUDuW8f5Ggv+Qj5TjQr6t55YdNU s2WayOYenm08vP9hgbGeGPHyZfqNCPQsjZK1NK39GztvJ54v4aeBFfDgHxUmjg8xdkOG XlOA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=fNgJOJehulAHrANSxZqLzW07I9ZTdunjEQY4qj7lUyY=; b=zagdGZFJdu3D2Keqf32LFiThN7IEW3n4m86LVmk3XyR6NLuebnqLiukFkjb6QIqSbP eagHZ5hKsm6TcMyTNzQV/eBpDhOTSpUaGlIXHtKL3O+sdOW+8dZYPT4jt8xBPvRsaAjm 2+l8+BKriJiz8kCQyIgFt4cFXOhQD+8qnOg89bb+OGLilmzww0V240NHTDH2Ax2ZJtIS QkzjC/agS+Np9TowyE9SkrKglyWSsgaDIdBzTrTU8jVphX5uJAm9FI5Z5Mhoou5JOSxs 8gW0PzhkziMX8i63lFX0TSMcjlFm2MskrOKq/xrpfRy3GiXrVHK8n3X9de4Pl0n+vlxE aY7A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=O1EksPrk; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id e23si1667716edq.24.2020.11.20.03.12.50; Fri, 20 Nov 2020 03:13:13 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=O1EksPrk; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727998AbgKTLEh (ORCPT + 99 others); Fri, 20 Nov 2020 06:04:37 -0500 Received: from mail.kernel.org ([198.145.29.99]:52076 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727988AbgKTLEf (ORCPT ); Fri, 20 Nov 2020 06:04:35 -0500 Received: from localhost (83-86-74-64.cable.dynamic.v4.ziggo.nl [83.86.74.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 9C83F2222F; Fri, 20 Nov 2020 11:04:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1605870274; bh=dTD2DLGty+aIUP0OGK41KfWgrqWTj1EVwmM4aNhXhnw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=O1EksPrkv1RWr7Yy5fAhByfUEbToql5zhu8VumJp49mDLej79A+y2VrscvwVFh6iG 6ceChTf820k5fsJmymG2+G9j3A+wdGUTnyZd+9kfHHKzudUVQcu+3se9zKaH7fP1Qb w3U8lPLHl7shLLRGpDUJ51lpeYUXGlybCIco/ghU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Greg Kroah-Hartman , dja@axtens.net, Christophe Leroy , Michael Ellerman Subject: [PATCH 4.9 05/16] powerpc: Implement user_access_begin and friends Date: Fri, 20 Nov 2020 12:03:10 +0100 Message-Id: <20201120104539.991842563@linuxfoundation.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201120104539.706905067@linuxfoundation.org> References: <20201120104539.706905067@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Christophe Leroy commit 5cd623333e7cf4e3a334c70529268b65f2a6c2c7 upstream. Today, when a function like strncpy_from_user() is called, the userspace access protection is de-activated and re-activated for every word read. By implementing user_access_begin and friends, the protection is de-activated at the beginning of the copy and re-activated at the end. Implement user_access_begin(), user_access_end() and unsafe_get_user(), unsafe_put_user() and unsafe_copy_to_user() For the time being, we keep user_access_save() and user_access_restore() as nops. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/36d4fbf9e56a75994aca4ee2214c77b26a5a8d35.1579866752.git.christophe.leroy@c-s.fr Signed-off-by: Daniel Axtens Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/uaccess.h | 60 ++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 14 deletions(-) --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -106,9 +106,14 @@ struct exception_table_entry { __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) #define __get_user(x, ptr) \ - __get_user_nocheck((x), (ptr), sizeof(*(ptr))) + __get_user_nocheck((x), (ptr), sizeof(*(ptr)), true) #define __put_user(x, ptr) \ - __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) + __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), true) + +#define __get_user_allowed(x, ptr) \ + __get_user_nocheck((x), (ptr), sizeof(*(ptr)), false) +#define __put_user_allowed(x, ptr) \ + __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), false) #define __get_user_inatomic(x, ptr) \ __get_user_nosleep((x), (ptr), sizeof(*(ptr))) @@ -162,10 +167,9 @@ extern long __put_user_bad(void); : "r" (x), "b" (addr), "i" (-EFAULT), "0" (err)) #endif /* __powerpc64__ */ -#define __put_user_size(x, ptr, size, retval) \ +#define __put_user_size_allowed(x, ptr, size, retval) \ do { \ retval = 0; \ - allow_write_to_user(ptr, size); \ switch (size) { \ case 1: __put_user_asm(x, ptr, retval, "stb"); break; \ case 2: __put_user_asm(x, ptr, retval, "sth"); break; \ @@ -173,17 +177,26 @@ do { \ case 8: __put_user_asm2(x, ptr, retval); break; \ default: __put_user_bad(); \ } \ +} while (0) + +#define __put_user_size(x, ptr, size, retval) \ +do { \ + allow_write_to_user(ptr, size); \ + __put_user_size_allowed(x, ptr, size, retval); \ prevent_write_to_user(ptr, size); \ } while (0) -#define __put_user_nocheck(x, ptr, size) \ +#define __put_user_nocheck(x, ptr, size, do_allow) \ ({ \ long __pu_err; \ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ if (!is_kernel_addr((unsigned long)__pu_addr)) \ might_fault(); \ __chk_user_ptr(ptr); \ - __put_user_size((x), __pu_addr, (size), __pu_err); \ + if (do_allow) \ + __put_user_size((x), __pu_addr, (size), __pu_err); \ + else \ + __put_user_size_allowed((x), __pu_addr, (size), __pu_err); \ __pu_err; \ }) @@ -249,13 +262,12 @@ extern long __get_user_bad(void); : "b" (addr), "i" (-EFAULT), "0" (err)) #endif /* __powerpc64__ */ -#define __get_user_size(x, ptr, size, retval) \ +#define __get_user_size_allowed(x, ptr, size, retval) \ do { \ retval = 0; \ __chk_user_ptr(ptr); \ if (size > sizeof(x)) \ (x) = __get_user_bad(); \ - allow_read_from_user(ptr, size); \ switch (size) { \ case 1: __get_user_asm(x, ptr, retval, "lbz"); break; \ case 2: __get_user_asm(x, ptr, retval, "lhz"); break; \ @@ -263,10 +275,16 @@ do { \ case 8: __get_user_asm2(x, ptr, retval); break; \ default: (x) = __get_user_bad(); \ } \ +} while (0) + +#define __get_user_size(x, ptr, size, retval) \ +do { \ + allow_read_from_user(ptr, size); \ + __get_user_size_allowed(x, ptr, size, retval); \ prevent_read_from_user(ptr, size); \ } while (0) -#define __get_user_nocheck(x, ptr, size) \ +#define __get_user_nocheck(x, ptr, size, do_allow) \ ({ \ long __gu_err; \ unsigned long __gu_val; \ @@ -275,7 +293,10 @@ do { \ if (!is_kernel_addr((unsigned long)__gu_addr)) \ might_fault(); \ barrier_nospec(); \ - __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ + if (do_allow) \ + __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ + else \ + __get_user_size_allowed(__gu_val, __gu_addr, (size), __gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ }) @@ -396,21 +417,22 @@ static inline unsigned long __copy_to_us const void *from, unsigned long n) { unsigned long ret; + if (__builtin_constant_p(n) && (n <= 8)) { ret = 1; switch (n) { case 1: - __put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret); + __put_user_size_allowed(*(u8 *)from, (u8 __user *)to, 1, ret); break; case 2: - __put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret); + __put_user_size_allowed(*(u16 *)from, (u16 __user *)to, 2, ret); break; case 4: - __put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret); + __put_user_size_allowed(*(u32 *)from, (u32 __user *)to, 4, ret); break; case 8: - __put_user_size(*(u64 *)from, (u64 __user *)to, 8, ret); + __put_user_size_allowed(*(u64 *)from, (u64 __user *)to, 8, ret); break; } if (ret == 0) @@ -456,6 +478,16 @@ extern long strncpy_from_user(char *dst, extern __must_check long strlen_user(const char __user *str); extern __must_check long strnlen_user(const char __user *str, long n); + +#define user_access_begin() do { } while (0) +#define user_access_end() prevent_user_access(NULL, NULL, ~0ul) + +#define unsafe_op_wrap(op, err) do { if (unlikely(op)) goto err; } while (0) +#define unsafe_get_user(x, p, e) unsafe_op_wrap(__get_user_allowed(x, p), e) +#define unsafe_put_user(x, p, e) unsafe_op_wrap(__put_user_allowed(x, p), e) +#define unsafe_copy_to_user(d, s, l, e) \ + unsafe_op_wrap(__copy_to_user_inatomic(d, s, l), e) + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */