From patchwork Thu Jun 12 15:58:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell King - ARM Linux X-Patchwork-Id: 4343031 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id DBCD59F3B4 for ; Thu, 12 Jun 2014 16:01:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D563E2037A for ; Thu, 12 Jun 2014 16:01:27 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 03A442035D for ; Thu, 12 Jun 2014 16:01:22 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wv7PO-0004nN-7s; Thu, 12 Jun 2014 15:59:22 +0000 Received: from pandora.arm.linux.org.uk ([2001:4d48:ad52:3201:214:fdff:fe10:1be6]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wv7PF-0004dn-99 for linux-arm-kernel@lists.infradead.org; Thu, 12 Jun 2014 15:59:14 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=arm.linux.org.uk; s=pandora; h=Sender:In-Reply-To:Content-Type:MIME-Version:References:Message-ID:Subject:Cc:To:From:Date; bh=RVE///ZGkaiuR7Ks7bKmQyVE32E2xmW48k3/NDyehzc=; b=EQmNTPOw/qnZiBPxNQx8OmPh+uqgTYbuIixegub9VX62OKvTpvwTPbtrmYdKw87EBEZQiSEyEBJziDo8tK90tkfeUe1Vm3/WZ4C8bYZQ6CQB6Zbhea0An9DEWkeCjoBJiZHQXgyK7xeFKdMz2GIEOMxfIy8B6XB03pLe3Unbx6w=; Received: from n2100.arm.linux.org.uk ([2001:4d48:ad52:3201:214:fdff:fe10:4f86]:37151) by pandora.arm.linux.org.uk with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.76) (envelope-from ) id 1Wv7On-000480-MY; Thu, 12 Jun 2014 16:58:46 +0100 Received: from linux by n2100.arm.linux.org.uk with local (Exim 4.76) (envelope-from ) id 1Wv7Om-0001y2-HG; Thu, 12 Jun 2014 16:58:44 +0100 Date: Thu, 12 Jun 2014 16:58:44 +0100 From: Russell King - ARM Linux To: Daniel Thompson Subject: Re: [PATCH v3] ARM: add get_user() support for 8 byte types Message-ID: <20140612155843.GK23430@n2100.arm.linux.org.uk> References: <1402587755-29245-1-git-send-email-daniel.thompson@linaro.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1402587755-29245-1-git-send-email-daniel.thompson@linaro.org> User-Agent: Mutt/1.5.19 (2009-01-05) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140612_085913_716068_AC3CD0E0 X-CRM114-Status: GOOD ( 18.69 ) X-Spam-Score: -0.8 (/) Cc: Nicolas Pitre , linaro-kernel@lists.linaro.org, patches@linaro.org, linux-kernel@vger.kernel.org, Rob Clark , Arnd Bergmann , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On Thu, Jun 12, 2014 at 04:42:35PM +0100, Daniel Thompson wrote: > A new atomic modeset/pageflip ioctl being developed in DRM requires > get_user() to work for 64bit types (in addition to just put_user()). > > v1: original > v2: pass correct size to check_uaccess, and better handling of narrowing > double word read with __get_user_xb() (Russell King's suggestion) > v3: fix a couple of checkpatch issues This is still unsafe. > #define __get_user_check(x,p) \ > ({ \ > unsigned long __limit = current_thread_info()->addr_limit - 1; \ > register const typeof(*(p)) __user *__p asm("r0") = (p);\ > - register unsigned long __r2 asm("r2"); \ > + register typeof(x) __r2 asm("r2"); \ So, __r2 becomes the type of 'x'. If 'x' is a 64-bit type, and *p is an 8-bit, 16-bit, or 32-bit type, this fails horribly by leaving the upper word of __r2 undefined. __r2 must follow the size of the value we are reading. I think the last solution which was proposed was this: arch/arm/include/asm/uaccess.h | 17 +++++++++++++---- arch/arm/lib/getuser.S | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 72abdc5..747f2cb 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -93,6 +93,9 @@ static inline void set_fs(mm_segment_t fs) : "cc"); \ flag; }) +#define __inttype(x) \ + __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) + /* * Single-value transfer routines. They automatically use the right * size if we just have the right pointer type. Note that the functions @@ -107,14 +110,16 @@ static inline void set_fs(mm_segment_t fs) extern int __get_user_1(void *); extern int __get_user_2(void *); extern int __get_user_4(void *); +extern int __get_user_8(void *); -#define __GUP_CLOBBER_1 "lr", "cc" +#define __GUP_CLOBBER_1 "lr", "cc" #ifdef CONFIG_CPU_USE_DOMAINS -#define __GUP_CLOBBER_2 "ip", "lr", "cc" +#define __GUP_CLOBBER_2 "ip", "lr", "cc" #else #define __GUP_CLOBBER_2 "lr", "cc" #endif -#define __GUP_CLOBBER_4 "lr", "cc" +#define __GUP_CLOBBER_4 "lr", "cc" +#define __GUP_CLOBBER_8 "lr", "cc" #define __get_user_x(__r2,__p,__e,__l,__s) \ __asm__ __volatile__ ( \ @@ -129,7 +134,7 @@ extern int __get_user_4(void *); ({ \ unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __user *__p asm("r0") = (p);\ - register unsigned long __r2 asm("r2"); \ + register __inttype(*p) __r2 asm("r2"); \ register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ @@ -142,6 +147,9 @@ extern int __get_user_4(void *); case 4: \ __get_user_x(__r2, __p, __e, __l, 4); \ break; \ + case 8: \ + __get_user_x(__r2, __p, __e, __l, 8); \ + break; \ default: __e = __get_user_bad(); break; \ } \ x = (typeof(*(p))) __r2; \ @@ -150,6 +158,7 @@ extern int __get_user_4(void *); #define get_user(x,p) \ ({ \ + __chk_user_ptr(ptr); \ might_fault(); \ __get_user_check(x,p); \ }) diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 9b06bb4..3583c83 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -18,7 +18,7 @@ * Inputs: r0 contains the address * r1 contains the address limit, which must be preserved * Outputs: r0 is the error code - * r2 contains the zero-extended value + * r2/r3 contains the zero-extended value * lr corrupted * * No other registers must be altered. (see @@ -32,6 +32,14 @@ #include #include +#ifdef __ARMEB__ +#define rlo8 r3 +#define rhi8 r2 +#else +#define rlo8 r2 +#define rhi8 r3 +#endif + ENTRY(__get_user_1) check_uaccess r0, 1, r1, r2, __get_user_bad 1: TUSER(ldrb) r2, [r0] @@ -66,15 +74,38 @@ ENTRY(__get_user_4) mov pc, lr ENDPROC(__get_user_4) +ENTRY(__get_user_8) + check_uaccess r0, 4, r1, r2, __get_user_bad8 +#ifdef CONFIG_CPU_USE_DOMAINS +#define GU8_FIXUPS 5b, 6b +5: ldrt rlo8, [r0], #4 +6: ldrt rhi8, [r0], #0 +#elif __LINUX_ARM_ARCH__ >= 6 +#define GU8_FIXUPS 5b +5: ldrd r2, [r0] +#else +#define GU8_FIXUPS 5b, 6b +5: ldr rlo8, [r0, #0] +6: ldr rhi8, [r0, #4] +#endif + mov r0, #0 + mov pc, lr + +__get_user_bad8: + mov r3, #0 __get_user_bad: mov r2, #0 mov r0, #-EFAULT mov pc, lr ENDPROC(__get_user_bad) +ENDPROC(__get_user_bad8) .pushsection __ex_table, "a" .long 1b, __get_user_bad .long 2b, __get_user_bad .long 3b, __get_user_bad .long 4b, __get_user_bad + .irp param, GU8_FIXUPS + .long \param, __get_user_bad8 + .endr .popsection