Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp1172768pxb; Fri, 20 Nov 2020 03:06:51 -0800 (PST) X-Google-Smtp-Source: ABdhPJyZLs9UVjUADM6W/rByc1z3bHvNUzoatZ/mwgko06g7s9a6/IH+LVn38W37QVdNIC5ZpRBS X-Received: by 2002:a17:906:d8b0:: with SMTP id qc16mr31973640ejb.268.1605870411625; Fri, 20 Nov 2020 03:06:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605870411; cv=none; d=google.com; s=arc-20160816; b=gBrwW77dLusqrBp6lb5AwbuDLjZj4c/DtIGT+tOrSRWk74QjT76ryZilVpiicDVRzf hSVyFzMAXF0J1RIlVQZc6q3Y5MXWabTwxTeZQ7gkmyzkxt0msMEGqzpmD+E+JcnQjPFU 71duCopZNR62Z4lBeZWsBCrW5bfC/4TeBr3IApu9/Rc4o9LFUOzRgySq+jcm6Y5pFIIK kP5GsgUea0nvv6LBMyn4q0reYg3xg74uZ05j33Q09m5gIVKHGuiikOw3LnZkB5AfTcwu tvWS0rmifQSEz51hdtQgQxTmOyUjbxLEFMOVwnSXrumBh7blnIMbFW1eRQicmE7Eov0f 95dg== 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=T0DqtHN9uFn1/8krPu5CSyPmiO1I+wvJ6E9GfakF/Ys=; b=VjInWCQpcoVovEOcU2PRgvb/S1vZEiL5g1EfH0B3V07vIS0h1q7AVarVQ3wWsZTjAb zWY3z0SDfeeMLCfwuyvj2Wvuayft9Gff4DWIThIiU3mQX5n303U5pzYR3Nwc11uIr6QH 0JdU39JetECSxw9JuYUA7Omcxkb6K34HCIWmVvAjMPlglxTSFvG1ZEFGSTwggyOGk2sf eC0jYWwKUEULlJ+KhhgSBJm1T/l+aMPhFyBFzJ8yuiD5Sv5EoS7bEZ6IHmcno0lfqHwU PjMtjvwPMN4cyff27k+IoQTvqBgLIiUznMII+Gw3IdENKpUyFhF0SRBQIRG9CstEcvQX fMNw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=pnwFi98A; 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 hb20si1505749ejc.664.2020.11.20.03.06.25; Fri, 20 Nov 2020 03:06:51 -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=pnwFi98A; 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 S1727701AbgKTLDi (ORCPT + 99 others); Fri, 20 Nov 2020 06:03:38 -0500 Received: from mail.kernel.org ([198.145.29.99]:50794 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725789AbgKTLDi (ORCPT ); Fri, 20 Nov 2020 06:03:38 -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 DDA742222F; Fri, 20 Nov 2020 11:03:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1605870217; bh=Um0+BTFE2VcED6m12jRqJW+pKq4ESzJlQHf2RM0pr7o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pnwFi98Aw6mJ263uiFXcuUb0HKXDzQg+IMGzCdJVs3rlWmPThX+dY0IATRUHiXJGL 9t9n+KhcxeDHUl9y10B5cH99jyPsfnmK/+VHFhKCBks75NhAj+Twu6lOzzEXK70EEe gCxFYu9Oc6YhQjfknMMI4yGIqjLjTOACMCMPW2+c= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Greg Kroah-Hartman , dja@axtens.net, Nicholas Piggin , Michael Ellerman Subject: [PATCH 4.4 07/15] powerpc/uaccess: Evaluate macro arguments once, before user access is allowed Date: Fri, 20 Nov 2020 12:03:05 +0100 Message-Id: <20201120104539.913287326@linuxfoundation.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201120104539.534424264@linuxfoundation.org> References: <20201120104539.534424264@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: Nicholas Piggin commit d02f6b7dab8228487268298ea1f21081c0b4b3eb upstream. get/put_user() can be called with nontrivial arguments. fs/proc/page.c has a good example: if (put_user(stable_page_flags(ppage), out)) { stable_page_flags() is quite a lot of code, including spin locks in the page allocator. Ensure these arguments are evaluated before user access is allowed. This improves security by reducing code with access to userspace, but it also fixes a PREEMPT bug with KUAP on powerpc/64s: stable_page_flags() is currently called with AMR set to allow writes, it ends up calling spin_unlock(), which can call preempt_schedule. But the task switch code can not be called with AMR set (it relies on interrupts saving the register), so this blows up. It's fine if the code inside allow_user_access() is preemptible, because a timer or IPI will save the AMR, but it's not okay to explicitly cause a reschedule. Fixes: de78a9c42a79 ("powerpc: Add a framework for Kernel Userspace Access Protection") Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200407041245.600651-1-npiggin@gmail.com Signed-off-by: Daniel Axtens Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/uaccess.h | 49 ++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -190,13 +190,17 @@ do { \ ({ \ long __pu_err; \ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ + __typeof__(*(ptr)) __pu_val = (x); \ + __typeof__(size) __pu_size = (size); \ + \ if (!is_kernel_addr((unsigned long)__pu_addr)) \ might_fault(); \ - __chk_user_ptr(ptr); \ + __chk_user_ptr(__pu_addr); \ if (do_allow) \ - __put_user_size((x), __pu_addr, (size), __pu_err); \ + __put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err); \ else \ - __put_user_size_allowed((x), __pu_addr, (size), __pu_err); \ + __put_user_size_allowed(__pu_val, __pu_addr, __pu_size, __pu_err); \ + \ __pu_err; \ }) @@ -204,9 +208,13 @@ do { \ ({ \ long __pu_err = -EFAULT; \ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ + __typeof__(*(ptr)) __pu_val = (x); \ + __typeof__(size) __pu_size = (size); \ + \ might_fault(); \ - if (access_ok(VERIFY_WRITE, __pu_addr, size)) \ - __put_user_size((x), __pu_addr, (size), __pu_err); \ + if (access_ok(VERIFY_WRITE, __pu_addr, __pu_size)) \ + __put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err); \ + \ __pu_err; \ }) @@ -214,8 +222,12 @@ do { \ ({ \ long __pu_err; \ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ - __chk_user_ptr(ptr); \ - __put_user_size((x), __pu_addr, (size), __pu_err); \ + __typeof__(*(ptr)) __pu_val = (x); \ + __typeof__(size) __pu_size = (size); \ + \ + __chk_user_ptr(__pu_addr); \ + __put_user_size(__pu_val, __pu_addr, __pu_size, __pu_err); \ + \ __pu_err; \ }) @@ -289,15 +301,18 @@ do { \ long __gu_err; \ unsigned long __gu_val; \ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ - __chk_user_ptr(ptr); \ + __typeof__(size) __gu_size = (size); \ + \ + __chk_user_ptr(__gu_addr); \ if (!is_kernel_addr((unsigned long)__gu_addr)) \ might_fault(); \ barrier_nospec(); \ if (do_allow) \ - __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ + __get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \ else \ - __get_user_size_allowed(__gu_val, __gu_addr, (size), __gu_err); \ + __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ + \ __gu_err; \ }) @@ -322,12 +337,15 @@ do { \ long __gu_err = -EFAULT; \ unsigned long __gu_val = 0; \ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ + __typeof__(size) __gu_size = (size); \ + \ might_fault(); \ - if (access_ok(VERIFY_READ, __gu_addr, (size))) { \ + if (access_ok(VERIFY_READ, __gu_addr, __gu_size)) { \ barrier_nospec(); \ - __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ + __get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \ } \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ + \ __gu_err; \ }) @@ -336,10 +354,13 @@ do { \ long __gu_err; \ unsigned long __gu_val; \ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ - __chk_user_ptr(ptr); \ + __typeof__(size) __gu_size = (size); \ + \ + __chk_user_ptr(__gu_addr); \ barrier_nospec(); \ - __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ + __get_user_size(__gu_val, __gu_addr, __gu_size, __gu_err); \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ + \ __gu_err; \ })