From patchwork Fri Apr 2 12:35:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12180827 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id AA881C433ED for ; Fri, 2 Apr 2021 12:37:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 831E261159 for ; Fri, 2 Apr 2021 12:37:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235307AbhDBMhX (ORCPT ); Fri, 2 Apr 2021 08:37:23 -0400 Received: from mail.kernel.org ([198.145.29.99]:53574 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229599AbhDBMhU (ORCPT ); Fri, 2 Apr 2021 08:37:20 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 571D26113D; Fri, 2 Apr 2021 12:37:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1617367039; bh=9GuXs4JFL9lprrwhKcXigHOxwumN2t08r+Qo5w/YarA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HEGDpzdbze4dLz3ugi0T2/Ezlabeg33O55oUdO3NB/o9Zox0pSnkrbUAQZDcvRtPm +UHRUfhIxIXxzuHh+lAMQnObqnQuHhADAsLYYAQaclOzFMf2bacpn9hhpQoft3NcRg GwJNw/VTDvEqaxZzOMbobUwKEZhtFGhxokunjDdPHTwFfxcwkfC+kRRgKcpsebussn y8xuYkF0aTnBnp9sksfxbUt460uZq5nTw4/Lf+wnAv+7r8OgjTCwruEXL/W0hZRhyr uNlNNP/xAM2wtldDYBcPMPbiPVNpmSxQTxRp3BOQOM80+0veog1+vsXlc7ZyGINKAb K2PRMSgfmGAmQ== From: Christian Brauner To: linux-fsdevel@vger.kernel.org Cc: Al Viro , Linus Torvalds , Dmitry Vyukov , Christian Brauner , syzbot+283ce5a46486d6acdbaf@syzkaller.appspotmail.com, Christoph Hellwig , Giuseppe Scrivano , stable@vger.kernel.org Subject: [PATCH 1/3] file: fix close_range() for unshare+cloexec Date: Fri, 2 Apr 2021 14:35:46 +0200 Message-Id: <20210402123548.108372-2-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <00000000000069c40405be6bdad4@google.com> References: <00000000000069c40405be6bdad4@google.com> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=DDPyKPZCC8FIkQkPEEkdiKdYYPVAVuw4Qg1xYqd73jY=; m=8/Zhg3Z3pa7YXOyLuaIwanqtd/bcMtM1+zAN4ociwX4=; p=Clx1VMg4laFLwVnvcDU1YDrFJZstmZPkSo4NueEmkzM=; g=785a20cb6d48830f588c9624bf8dc10727ee1a6e X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGcPkgAKCRCRxhvAZXjcom/0AQCRgpV 1s1KSk2tQVNpOvgDp3CttvF5o7UoOwNBe9CFntgEAtWznzqPnGQ+fVu+7jHN/vWgo9Zc/jv9rhbqa fzfpLwg= Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org From: Christian Brauner syzbot reported a bug when putting the last reference to a tasks file descriptor table. Debugging this showed we didn't recalculate the current maximum fd number for CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC after we unshared the file descriptors table. So max_fd could exceed the current fdtable maximum causing us to set excessive bits. As a concrete example, let's say the user requested everything from fd 4 to ~0UL to be closed and their current fdtable size is 256 with their highest open fd being 4. With CLOSE_RANGE_UNSHARE the caller will end up with a new fdtable which has room for 64 file descriptors since that is the lowest fdtable size we accept. But now max_fd will still point to 255 and needs to be adjusted. Fix this by retrieving the correct maximum fd value in __range_cloexec(). Reported-by: syzbot+283ce5a46486d6acdbaf@syzkaller.appspotmail.com Fixes: 582f1fb6b721 ("fs, close_range: add flag CLOSE_RANGE_CLOEXEC") Fixes: fec8a6a69103 ("close_range: unshare all fds for CLOSE_RANGE_UNSHARE | CLOSE_RANGE_CLOEXEC") Cc: Christoph Hellwig Cc: Giuseppe Scrivano Cc: Al Viro Cc: linux-fsdevel@vger.kernel.org Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner --- fs/file.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/fs/file.c b/fs/file.c index f3a4bac2cbe9..f633348029a5 100644 --- a/fs/file.c +++ b/fs/file.c @@ -629,17 +629,30 @@ int close_fd(unsigned fd) } EXPORT_SYMBOL(close_fd); /* for ksys_close() */ +/** + * last_fd - return last valid index into fd table + * @cur_fds: files struct + * + * Context: Either rcu read lock or files_lock must be held. + * + * Returns: Last valid index into fdtable. + */ +static inline unsigned last_fd(struct fdtable *fdt) +{ + return fdt->max_fds - 1; +} + static inline void __range_cloexec(struct files_struct *cur_fds, unsigned int fd, unsigned int max_fd) { struct fdtable *fdt; - if (fd > max_fd) - return; - + /* make sure we're using the correct maximum value */ spin_lock(&cur_fds->file_lock); fdt = files_fdtable(cur_fds); - bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1); + max_fd = min(last_fd(fdt), max_fd); + if (fd <= max_fd) + bitmap_set(fdt->close_on_exec, fd, max_fd - fd + 1); spin_unlock(&cur_fds->file_lock); } From patchwork Fri Apr 2 12:35:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12180829 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 332B5C43460 for ; Fri, 2 Apr 2021 12:37:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0F1CA61159 for ; Fri, 2 Apr 2021 12:37:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235441AbhDBMhY (ORCPT ); Fri, 2 Apr 2021 08:37:24 -0400 Received: from mail.kernel.org ([198.145.29.99]:53622 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235444AbhDBMhW (ORCPT ); Fri, 2 Apr 2021 08:37:22 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id DBDB561158; Fri, 2 Apr 2021 12:37:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1617367041; bh=H6rhK7YrJlG/TnSxkRrxaV6rrHER++o1pLWVgVT/hFM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mwQQARNS0037UZK89bxhtfJS0qxf3bmbfYK+TSZ2aszVj1R0CFT5JWFSJa+408xbU LduHUJs3023xhEbFZhCn9rWliymuJQihvvlT/k4PyYw/dVN7so8BbUicQxSYGHqjpJ yxPiGwKCz0d0/Eu7M3+QqU+oAwyvEDgvnc/XhMgLJ1uxl69N1AKaXGL40+mNnPjcwQ LFpJJ+nr4QGnfFXH6RhXc0kaeXLdo5IXiKKUNnfRLYZJPmjLDnQe+p7vAdgblMxPj7 TAa8toiH/NVpeHJnh//typ7l7XiZAYoQU6/FgIBSJxxofEGYeleXfhb+bY1MkoiQwA k3MHO07+sRL/w== From: Christian Brauner To: linux-fsdevel@vger.kernel.org Cc: Al Viro , Linus Torvalds , Dmitry Vyukov , Christian Brauner , Christoph Hellwig , Giuseppe Scrivano Subject: [PATCH 2/3] file: let pick_file() tell caller it's done Date: Fri, 2 Apr 2021 14:35:47 +0200 Message-Id: <20210402123548.108372-3-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <00000000000069c40405be6bdad4@google.com> References: <00000000000069c40405be6bdad4@google.com> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=u3FypIfYYEuouoQtFnkkSF1BaueP8r/+poOiz25rjy0=; m=XxDs1iQXFGporBJagccdLRPprhMJ0YTgd0CCqHCv/W0=; p=1aFtf2Ns3INd5B6Bg/dGOcnyrKqqA2iROlkVMFoo6vQ=; g=08c35118ac0e088c52bdd2f77bea1f7f51a1a5e2 X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGcPkgAKCRCRxhvAZXjcojxNAPsGKlX WDUEjrlXQwYn36lKSceQnpjvrryk0HoPfwLIR8AD+JW8wb+JEIELp2e+5u4hkMuWqLAgTWIgHDw4/ akXT3wE= Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org From: Christian Brauner Let pick_file() report back that the fd it was passed exceeded the maximum fd in that fdtable. This allows us to simplify the caller of this helper because it doesn't need to care anymore whether the passed in max_fd is excessive. It can rely on pick_file() telling it that it's past the last valid fd. Cc: Christoph Hellwig Cc: Giuseppe Scrivano Cc: Al Viro Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner --- fs/file.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/fs/file.c b/fs/file.c index f633348029a5..740040346a98 100644 --- a/fs/file.c +++ b/fs/file.c @@ -596,18 +596,32 @@ void fd_install(unsigned int fd, struct file *file) EXPORT_SYMBOL(fd_install); +/** + * pick_file - return file associatd with fd + * @files: file struct to retrieve file from + * @fd: file descriptor to retrieve file for + * + * If this functions returns an EINVAL error pointer the fd was beyond the + * current maximum number of file descriptors for that fdtable. + * + * Returns: The file associated with @fd, on error returns an error pointer. + */ static struct file *pick_file(struct files_struct *files, unsigned fd) { - struct file *file = NULL; + struct file *file; struct fdtable *fdt; spin_lock(&files->file_lock); fdt = files_fdtable(files); - if (fd >= fdt->max_fds) + if (fd >= fdt->max_fds) { + file = ERR_PTR(-EINVAL); goto out_unlock; + } file = fdt->fd[fd]; - if (!file) + if (!file) { + file = ERR_PTR(-EBADF); goto out_unlock; + } rcu_assign_pointer(fdt->fd[fd], NULL); __put_unused_fd(files, fd); @@ -622,7 +636,7 @@ int close_fd(unsigned fd) struct file *file; file = pick_file(files, fd); - if (!file) + if (IS_ERR(file)) return -EBADF; return filp_close(file, files); @@ -663,11 +677,16 @@ static inline void __range_close(struct files_struct *cur_fds, unsigned int fd, struct file *file; file = pick_file(cur_fds, fd++); - if (!file) + if (!IS_ERR(file)) { + /* found a valid file to close */ + filp_close(file, cur_fds); + cond_resched(); continue; + } - filp_close(file, cur_fds); - cond_resched(); + /* beyond the last fd in that table */ + if (PTR_ERR(file) == -EINVAL) + return; } } From patchwork Fri Apr 2 12:35:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12180831 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9B2D7C433ED for ; Fri, 2 Apr 2021 12:37:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7410D61164 for ; Fri, 2 Apr 2021 12:37:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235464AbhDBMh1 (ORCPT ); Fri, 2 Apr 2021 08:37:27 -0400 Received: from mail.kernel.org ([198.145.29.99]:53680 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229932AbhDBMhZ (ORCPT ); Fri, 2 Apr 2021 08:37:25 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 57E0C61002; Fri, 2 Apr 2021 12:37:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1617367044; bh=dUbTt4/JMI0Wi0hAdKMzvQDwqNf84SO9tY537ehAXeA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GoIkUPhVFBewCC2U86mUUUZBWAT3+TSZeHX0eLYf1HjbOXexFNb0w4byPaAZw2uz7 sYQKo13OrjfIUT/qN8HEeAy0iTENDkwDfpBHGb+0mlrrb/KjvCb4ncuh7+trLlHUkf lN4hU35ettriK4Aod/Q/TIF/G6M7Ib5HGHmGvyjk2QGbK6RcjtkPtMGi2iE3yrsEdU f4cDGxteEW8A4lxLeBtfy0/H7cokFtVWI8zjwjjXm+R/uL/qZuzdLBlLQsIJMqndX8 G2zAL9DUVnfWOdtG7Zx4BBJcpwN++FpZ6VbC6Ok/m1Z8RQybs4iny9ee995OpzlmNj i2I0m69ageftQ== From: Christian Brauner To: linux-fsdevel@vger.kernel.org Cc: Al Viro , Linus Torvalds , Dmitry Vyukov , Christian Brauner , Christoph Hellwig , Giuseppe Scrivano Subject: [PATCH 3/3] file: simplify logic in __close_range() Date: Fri, 2 Apr 2021 14:35:48 +0200 Message-Id: <20210402123548.108372-4-brauner@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <00000000000069c40405be6bdad4@google.com> References: <00000000000069c40405be6bdad4@google.com> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=hxAQsk9Vm8whjH4fxdkcMpV9D/g/lrfRks3myDn8G5c=; m=nVAEuvMh4LK8seH9ue5IB38FN/6opr9N10BP3dDo73k=; p=c6iH7+6Y7h0lMivORcnihZU6RmsASk6k6ixprq2fgP8=; g=d55e07709d088c140ca4de213024a3759b86a094 X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCYGcPkwAKCRCRxhvAZXjcoiIYAQDvmHB 2mTiXLZaKEdlR+VJV0L4UXsCsU8pj5ca3PqhcdQD/eYIC8ayng5KsrLzBotDqfWYDVGfDAnoHymoI cURv1g4= Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org From: Christian Brauner It never looked too pleasant and it doesn't really buy us anything anymore now that CLOSE_RANGE_CLOEXEC exists and we need to retake the current maximum under the lock for it anyway. This also makes the logic easier to follow. Cc: Christoph Hellwig Cc: Giuseppe Scrivano Cc: Al Viro Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner --- fs/file.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/fs/file.c b/fs/file.c index 740040346a98..ed46cd3ae225 100644 --- a/fs/file.c +++ b/fs/file.c @@ -701,7 +701,6 @@ static inline void __range_close(struct files_struct *cur_fds, unsigned int fd, */ int __close_range(unsigned fd, unsigned max_fd, unsigned int flags) { - unsigned int cur_max; struct task_struct *me = current; struct files_struct *cur_fds = me->files, *fds = NULL; @@ -711,26 +710,26 @@ int __close_range(unsigned fd, unsigned max_fd, unsigned int flags) if (fd > max_fd) return -EINVAL; - rcu_read_lock(); - cur_max = files_fdtable(cur_fds)->max_fds; - rcu_read_unlock(); - - /* cap to last valid index into fdtable */ - cur_max--; - if (flags & CLOSE_RANGE_UNSHARE) { int ret; unsigned int max_unshare_fds = NR_OPEN_MAX; /* - * If the requested range is greater than the current maximum, - * we're closing everything so only copy all file descriptors - * beneath the lowest file descriptor. - * If the caller requested all fds to be made cloexec copy all - * of the file descriptors since they still want to use them. + * If the caller requested all fds to be made cloexec we always + * copy all of the file descriptors since they still want to + * use them. */ - if (!(flags & CLOSE_RANGE_CLOEXEC) && (max_fd >= cur_max)) - max_unshare_fds = fd; + if (!(flags & CLOSE_RANGE_CLOEXEC)) { + /* + * If the requested range is greater than the current + * maximum, we're closing everything so only copy all + * file descriptors beneath the lowest file descriptor. + */ + rcu_read_lock(); + if (max_fd >= last_fd(files_fdtable(cur_fds))) + max_unshare_fds = fd; + rcu_read_unlock(); + } ret = unshare_fd(CLONE_FILES, max_unshare_fds, &fds); if (ret) @@ -744,8 +743,6 @@ int __close_range(unsigned fd, unsigned max_fd, unsigned int flags) swap(cur_fds, fds); } - max_fd = min(max_fd, cur_max); - if (flags & CLOSE_RANGE_CLOEXEC) __range_cloexec(cur_fds, fd, max_fd); else