From patchwork Wed Jan 22 17:52:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Leroy X-Patchwork-Id: 11346201 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CF6DC921 for ; Wed, 22 Jan 2020 17:52:52 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 9079B20663 for ; Wed, 22 Jan 2020 17:52:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=c-s.fr header.i=@c-s.fr header.b="EgAXh2JV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9079B20663 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=c-s.fr Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id B98996B0273; Wed, 22 Jan 2020 12:52:51 -0500 (EST) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id B22E56B0274; Wed, 22 Jan 2020 12:52:51 -0500 (EST) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A114B6B0275; Wed, 22 Jan 2020 12:52:51 -0500 (EST) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0208.hostedemail.com [216.40.44.208]) by kanga.kvack.org (Postfix) with ESMTP id 8B5D86B0273 for ; Wed, 22 Jan 2020 12:52:51 -0500 (EST) Received: from smtpin04.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with SMTP id 20DEA180AD802 for ; Wed, 22 Jan 2020 17:52:51 +0000 (UTC) X-FDA: 76406015742.04.jam92_52f8753d89d0c X-Spam-Summary: 2,0,0,69e87656e4c1126c,d41d8cd98f00b204,christophe.leroy@c-s.fr,:benh@kernel.crashing.org:paulus@samba.org:mpe@ellerman.id.au:torvalds@linux-foundation.org:viro@zeniv.linux.org.uk:akpm@linux-foundation.org:linux-kernel@vger.kernel.org:linuxppc-dev@lists.ozlabs.org:linux-fsdevel@vger.kernel.org:,RULES_HIT:41:69:355:379:800:960:988:989:1260:1261:1345:1437:1535:1543:1711:1730:1747:1777:1792:2194:2199:2393:2553:2559:2562:2901:3138:3139:3140:3141:3142:3355:3865:3866:3867:3868:3870:3871:4117:4321:5007:6261:6653:7903:8634:9040:10004:11026:11658:11914:12043:12048:12291:12296:12297:12555:12679:12683:12895:13255:14096:14181:14394:14721:21080:21433:21451:21627:21990:30029:30051:30054:30090,0,RBL:93.17.236.30:@c-s.fr:.lbl8.mailshell.net-62.2.5.100 64.100.201.201,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:94,LUA_SUMMARY:none X-HE-Tag: jam92_52f8753d89d0c X-Filterd-Recvd-Size: 6619 Received: from pegase1.c-s.fr (pegase1.c-s.fr [93.17.236.30]) by imf13.hostedemail.com (Postfix) with ESMTP for ; Wed, 22 Jan 2020 17:52:50 +0000 (UTC) Received: from localhost (mailhub1-int [192.168.12.234]) by localhost (Postfix) with ESMTP id 482tKV6dfNz9vBdk; Wed, 22 Jan 2020 18:52:46 +0100 (CET) Authentication-Results: localhost; dkim=pass reason="1024-bit key; insecure key" header.d=c-s.fr header.i=@c-s.fr header.b=EgAXh2JV; dkim-adsp=pass; dkim-atps=neutral X-Virus-Scanned: Debian amavisd-new at c-s.fr Received: from pegase1.c-s.fr ([192.168.12.234]) by localhost (pegase1.c-s.fr [192.168.12.234]) (amavisd-new, port 10024) with ESMTP id NrSstf2601YN; Wed, 22 Jan 2020 18:52:46 +0100 (CET) Received: from messagerie.si.c-s.fr (messagerie.si.c-s.fr [192.168.25.192]) by pegase1.c-s.fr (Postfix) with ESMTP id 482tKV5Fq7z9vBf2; Wed, 22 Jan 2020 18:52:46 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=c-s.fr; s=mail; t=1579715566; bh=BFcMmG1gr6ZHjF96WJjeRbfRazxCfc8BsdIu1Gb0FaQ=; h=From:Subject:To:Cc:Date:From; b=EgAXh2JVdH1m4rMSYMLWOuTFsFapRVRquT4G0KSmacXFMtvAiZSQhAKhlLoOMGcKQ OeUjFyYJdl/Bgobmxh/54lBo9S1Tl0oWUzvVH06axb1PXj3fnyvujIFHX86AFEgaVX Qd+FLSTJKxRGI3RLTRHG+WlUUDXRQM6tzKBihnhE= Received: from localhost (localhost [127.0.0.1]) by messagerie.si.c-s.fr (Postfix) with ESMTP id 6A3478B811; Wed, 22 Jan 2020 18:52:48 +0100 (CET) X-Virus-Scanned: amavisd-new at c-s.fr Received: from messagerie.si.c-s.fr ([127.0.0.1]) by localhost (messagerie.si.c-s.fr [127.0.0.1]) (amavisd-new, port 10023) with ESMTP id gSUFGUjIatac; Wed, 22 Jan 2020 18:52:48 +0100 (CET) Received: from po14934vm.idsi0.si.c-s.fr (unknown [192.168.4.90]) by messagerie.si.c-s.fr (Postfix) with ESMTP id E8EE78B812; Wed, 22 Jan 2020 18:52:47 +0100 (CET) Received: by localhost.localdomain (Postfix, from userid 0) id A4622651E0; Wed, 22 Jan 2020 17:52:47 +0000 (UTC) Message-Id: <12a4be679e43de1eca6e5e2173163f27e2f25236.1579715466.git.christophe.leroy@c-s.fr> From: Christophe Leroy Subject: [PATCH v2 1/6] fs/readdir: Fix filldir() and filldir64() use of user_access_begin() To: Benjamin Herrenschmidt , Paul Mackerras , Michael Ellerman , Linus Torvalds , Alexander Viro , Andrew Morton Cc: linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org Date: Wed, 22 Jan 2020 17:52:47 +0000 (UTC) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Some architectures grand full access to userspace regardless of the address/len passed to user_access_begin(), but other architectures only grand access to the requested area. For exemple, on 32 bits powerpc (book3s/32), access is granted by segments of 256 Mbytes. Modify filldir() and filldir64() to request the real area they need to get access to, i.e. the area covering the parent dirent (if any) and the contiguous current dirent. Fixes: 9f79b78ef744 ("Convert filldir[64]() from __put_user() to unsafe_put_user()") Signed-off-by: Christophe Leroy --- v2: have user_access_begin() cover both parent dirent (if any) and current dirent --- fs/readdir.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/fs/readdir.c b/fs/readdir.c index d26d5ea4de7b..3f9b4488d9b7 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -214,7 +214,7 @@ struct getdents_callback { static int filldir(struct dir_context *ctx, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - struct linux_dirent __user * dirent; + struct linux_dirent __user * dirent, *dirent0; struct getdents_callback *buf = container_of(ctx, struct getdents_callback, ctx); unsigned long d_ino; @@ -232,19 +232,22 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, buf->error = -EOVERFLOW; return -EOVERFLOW; } - dirent = buf->previous; - if (dirent && signal_pending(current)) + dirent0 = buf->previous; + if (dirent0 && signal_pending(current)) return -EINTR; - /* - * Note! This range-checks 'previous' (which may be NULL). - * The real range was checked in getdents - */ - if (!user_access_begin(dirent, sizeof(*dirent))) - goto efault; - if (dirent) - unsafe_put_user(offset, &dirent->d_off, efault_end); dirent = buf->current_dir; + if (dirent0) { + int sz = (void __user *)dirent + reclen - + (void __user *)dirent0; + + if (!user_access_begin(dirent0, sz)) + goto efault; + unsafe_put_user(offset, &dirent0->d_off, efault_end); + } else { + if (!user_access_begin(dirent, reclen)) + goto efault; + } unsafe_put_user(d_ino, &dirent->d_ino, efault_end); unsafe_put_user(reclen, &dirent->d_reclen, efault_end); unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end); @@ -307,7 +310,7 @@ struct getdents_callback64 { static int filldir64(struct dir_context *ctx, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - struct linux_dirent64 __user *dirent; + struct linux_dirent64 __user *dirent, *dirent0; struct getdents_callback64 *buf = container_of(ctx, struct getdents_callback64, ctx); int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, @@ -319,19 +322,22 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen, buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; - dirent = buf->previous; - if (dirent && signal_pending(current)) + dirent0 = buf->previous; + if (dirent0 && signal_pending(current)) return -EINTR; - /* - * Note! This range-checks 'previous' (which may be NULL). - * The real range was checked in getdents - */ - if (!user_access_begin(dirent, sizeof(*dirent))) - goto efault; - if (dirent) - unsafe_put_user(offset, &dirent->d_off, efault_end); dirent = buf->current_dir; + if (dirent0) { + int sz = (void __user *)dirent + reclen - + (void __user *)dirent0; + + if (!user_access_begin(dirent0, sz)) + goto efault; + unsafe_put_user(offset, &dirent0->d_off, efault_end); + } else { + if (!user_access_begin(dirent, reclen)) + goto efault; + } unsafe_put_user(ino, &dirent->d_ino, efault_end); unsafe_put_user(reclen, &dirent->d_reclen, efault_end); unsafe_put_user(d_type, &dirent->d_type, efault_end);