From patchwork Wed Apr 16 13:17:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 14053922 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E72261B4145 for ; Wed, 16 Apr 2025 13:17:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744809464; cv=none; b=ncl7FP1mX3cO8v8PITIC45OjwAOVc/eby7RF/UiCPA8eGBcIhrj78oG3RDg3R6aDUoGhc1P05ddCDotRxCNJpLY1AxLbmzI7qQEQr8pbHMbfbNv0a+KReQZtzCrBSw+vn2nC+hypPezQH1fL6IIyjkFna3rFRCVsTczaWm/Fyxs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744809464; c=relaxed/simple; bh=OPm5dygkmkdUOizG0aT5ZDKHH597gfUqDT+Lhg8F8kQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=H3Rzn9lTwyx9lzvRTuNg4zITGoetVzDMFFsofV3OMWQaIiuA1KOCHFuLMso3SgWRjiA1sK1Wh0O8PH3A+HsnTFCY9GUubCFRAwNEjdGYZtXnoPv4ag3Q4zQXhsWUJdlHmDOxvmmGv0APpUooFWNdDN7VZMkBNNHFU5T2YiLA0a0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=IMlJ2neS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IMlJ2neS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 59699C4CEEA; Wed, 16 Apr 2025 13:17:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744809463; bh=OPm5dygkmkdUOizG0aT5ZDKHH597gfUqDT+Lhg8F8kQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IMlJ2neSTDVBNkIKaeLbFx7X3i9UtB6Hk3NIuO2puchuQuwXXPBsNU63q2P7V+WBL M/pGeS+9GGaZ/LMS6PZezWUOjGn4h8P9rI0WMfwrURtKe1Xn0qcCAHikLe+dB3RJ+w JhnDSCwPrpTKA7+aWOj8LRjvyV3rENG6FY0KwSTNYJCu4grZ6FynCSG+/4/chdunL0 BvFTBsGkHMcnkOvuO5JmTNQ22+R+23jrw33Th52jL8V8DhguKtWJ/imwGQ2/1ywAuQ A4tPt4s2O5Wib1xhNpit0QgXM1BA4Sv6X0pQ+A5Q56nJTmzOP6OppSROcqf0PVuyTd k8FVh2retQjPw== From: Christian Brauner To: Linus Torvalds , linux-fsdevel Cc: Christian Brauner , Mateusz Guzik , Al Viro , Jan Kara , Jeff Layton , Josef Bacik Subject: [PATCH RFC 1/3] inode: add fastpath for filesystem user namespace retrieval Date: Wed, 16 Apr 2025 15:17:22 +0200 Message-ID: <20250416-work-mnt_idmap-s_user_ns-v1-1-273bef3a61ec@kernel.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250416-work-mnt_idmap-s_user_ns-v1-0-273bef3a61ec@kernel.org> References: <20250416-work-mnt_idmap-s_user_ns-v1-0-273bef3a61ec@kernel.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mailer: b4 0.15-dev-c25d1 X-Developer-Signature: v=1; a=openpgp-sha256; l=4251; i=brauner@kernel.org; h=from:subject:message-id; bh=OPm5dygkmkdUOizG0aT5ZDKHH597gfUqDT+Lhg8F8kQ=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMaT/X/v41vytObLCB9ctib3nXWNy4nU238fTp9qnX4/5q PumIMQqoKOUhUGMi0FWTJHFod0kXG45T8Vmo0wNmDmsTCBDGLg4BWAiTf4M/703xm3KepXf2CSx aPOMtE/9Eh5Kj3r7CqO7DphOqOdPSGD4w5vfd37SLakNt1r3pJ47F1y1dgebhVLvD9YtJn4BGyZ y8AAA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 We currently always chase a pointer inode->i_sb->s_user_ns whenever we need to map a uid/gid which is noticeable during path lookup as noticed by Linus in [1]. In the majority of cases we don't need to bother with that pointer chase because the inode won't be located on a filesystem that's mounted in a user namespace. The user namespace of the superblock cannot ever change once it's mounted. So introduce and raise IOP_USERNS on all inodes and check for that flag in i_user_ns() when we retrieve the user namespace. Link: https://lore.kernel.org/CAHk-=whJgRDtxTudTQ9HV8BFw5-bBsu+c8Ouwd_PrPqPB6_KEQ@mail.gmail.com [1] Signed-off-by: Christian Brauner --- fs/inode.c | 6 ++++++ fs/mnt_idmapping.c | 14 -------------- include/linux/fs.h | 5 ++++- include/linux/mnt_idmapping.h | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 99318b157a9a..7335d05dd7d5 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -245,6 +245,8 @@ int inode_init_always_gfp(struct super_block *sb, struct inode *inode, gfp_t gfp inode->i_opflags |= IOP_XATTR; if (sb->s_type->fs_flags & FS_MGTIME) inode->i_opflags |= IOP_MGTIME; + if (unlikely(!initial_idmapping(i_user_ns(inode)))) + inode->i_opflags |= IOP_USERNS; i_uid_write(inode, 0); i_gid_write(inode, 0); atomic_set(&inode->i_writecount, 0); @@ -1864,6 +1866,10 @@ static void iput_final(struct inode *inode) WARN_ON(inode->i_state & I_NEW); + /* This is security sensitive so catch missing IOP_USERNS. */ + VFS_WARN_ON_ONCE(!initial_idmapping(i_user_ns(inode)) && + !(inode->i_opflags & IOP_USERNS)); + if (op->drop_inode) drop = op->drop_inode(inode); else diff --git a/fs/mnt_idmapping.c b/fs/mnt_idmapping.c index a37991fdb194..8f7ae908ea16 100644 --- a/fs/mnt_idmapping.c +++ b/fs/mnt_idmapping.c @@ -42,20 +42,6 @@ struct mnt_idmap invalid_mnt_idmap = { }; EXPORT_SYMBOL_GPL(invalid_mnt_idmap); -/** - * initial_idmapping - check whether this is the initial mapping - * @ns: idmapping to check - * - * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, - * [...], 1000 to 1000 [...]. - * - * Return: true if this is the initial mapping, false if not. - */ -static inline bool initial_idmapping(const struct user_namespace *ns) -{ - return ns == &init_user_ns; -} - /** * make_vfsuid - map a filesystem kuid according to an idmapping * @idmap: the mount's idmapping diff --git a/include/linux/fs.h b/include/linux/fs.h index 016b0fe1536e..d28384d5b752 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -663,6 +663,7 @@ is_uncached_acl(struct posix_acl *acl) #define IOP_DEFAULT_READLINK 0x0010 #define IOP_MGTIME 0x0020 #define IOP_CACHED_LINK 0x0040 +#define IOP_USERNS 0x0080 /* * Keep mostly read-only and often accessed (especially for @@ -1454,7 +1455,9 @@ struct super_block { static inline struct user_namespace *i_user_ns(const struct inode *inode) { - return inode->i_sb->s_user_ns; + if (unlikely(inode->i_opflags & IOP_USERNS)) + return inode->i_sb->s_user_ns; + return &init_user_ns; } /* Helper functions so that in most cases filesystems will diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h index e71a6070a8f8..85553b3a7904 100644 --- a/include/linux/mnt_idmapping.h +++ b/include/linux/mnt_idmapping.h @@ -25,6 +25,20 @@ static_assert(sizeof(vfsgid_t) == sizeof(kgid_t)); static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val)); static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val)); +/** + * initial_idmapping - check whether this is the initial mapping + * @ns: idmapping to check + * + * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, + * [...], 1000 to 1000 [...]. + * + * Return: true if this is the initial mapping, false if not. + */ +static inline bool initial_idmapping(const struct user_namespace *ns) +{ + return ns == &init_user_ns; +} + static inline bool is_valid_mnt_idmap(const struct mnt_idmap *idmap) { return idmap != &nop_mnt_idmap && idmap != &invalid_mnt_idmap; From patchwork Wed Apr 16 13:17:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 14053923 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E04F1BC07A for ; Wed, 16 Apr 2025 13:17:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744809466; cv=none; b=Tr8HG6skFwRS8gNkxvU1o7Y92RjipYaVLrm0tzk2fODFH+jB/Rip/LvDIiu88sIPJhcJERbpKG9I1RQDVFPwSHkiGYlua85HYd9S7KwtQKbNnflt9Pp1sLITIYMyuE6+WfNA7MClm/u9COhtgVyt+zOozI+OoWg80qKH6Ibq0xo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744809466; c=relaxed/simple; bh=we5F9y+12G5ioorWPSE8WE8Y3WemBLh+b3ZiiWrpCxI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hvePvNIm4dAu1lBnAZXBqamUAKdnTFgGLlSP3UFpVaPyBV23hraJDyuZZCqW5bfD+ZmeWBhA+8y7fN0Eh9bKTBkqB+HXCcp6veytu6oa2oyR8NQARcg9OYlnKCEakDkNZY/o+lm29uTXFdNlIJI8BYr9ZQfQpN1pxNgUQScZal0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UUqaS0B6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UUqaS0B6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ECAABC113CF; Wed, 16 Apr 2025 13:17:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744809466; bh=we5F9y+12G5ioorWPSE8WE8Y3WemBLh+b3ZiiWrpCxI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UUqaS0B6BJdcsxjqHX7g/hyBKuFf/SYtMyHNWonEb68qkA9v81pLHsqE1sEinqKLp B58R0nvRpwqiATOjhLV2eoJB70a8Pp21AhcvZvauc3cTOBZYZi/IQqrPr6hV5cy2Vk /D3PuilPIh1d32yN9yRpRxXnPeMW4FOiP1zRM3Av1a4eT0KQOK8lpVHBA5Seb5KHJ9 PPPDs+dX3YOBjmDFkRXpByj77emN86OoqomBwt1BxO19L1W54WIBphTJXOeuoJnhm4 57f6ycEDbfnY5INZj0GSxMNp0JtXorCxTGX0E9WuZFV2kXDTXLsbaLFiiO51J9iwS+ w2y7YWkEAMBmA== From: Christian Brauner To: Linus Torvalds , linux-fsdevel Cc: Christian Brauner , Mateusz Guzik , Al Viro , Jan Kara , Jeff Layton , Josef Bacik Subject: [PATCH RFC 2/3] mnt_idmapping: add struct mnt_idmap to header Date: Wed, 16 Apr 2025 15:17:23 +0200 Message-ID: <20250416-work-mnt_idmap-s_user_ns-v1-2-273bef3a61ec@kernel.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250416-work-mnt_idmap-s_user_ns-v1-0-273bef3a61ec@kernel.org> References: <20250416-work-mnt_idmap-s_user_ns-v1-0-273bef3a61ec@kernel.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mailer: b4 0.15-dev-c25d1 X-Developer-Signature: v=1; a=openpgp-sha256; l=3213; i=brauner@kernel.org; h=from:subject:message-id; bh=we5F9y+12G5ioorWPSE8WE8Y3WemBLh+b3ZiiWrpCxI=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMaT/X/tkw5k167x2Fx5ua1rP/Msg2Caj7tShDz6ZQUcj4 muKfDbs7ShlYRDjYpAVU2RxaDcJl1vOU7HZKFMDZg4rE8gQBi5OAZjIHDVGhhWBTwoSJc57yB4P Wshi1mf9vWv/dzUrpfeZD6fE/NjHbMzI8Dhlwvvfd+tqF25+6Cu7avLEvgquZzOX2C6skJDaF73 ZhQ0A X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 The next patch will inline all current helpers for that we need access to struct mnt_idmap internals from the header. Not my favorite but whatever. Signed-off-by: Christian Brauner --- fs/mnt_idmapping.c | 6 ------ include/linux/mnt_idmapping.h | 7 +++++++ include/linux/uidgid.h | 23 ++++++++++++++++++++++- include/linux/user_namespace.h | 23 +---------------------- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/fs/mnt_idmapping.c b/fs/mnt_idmapping.c index 8f7ae908ea16..5c7e1db8fef8 100644 --- a/fs/mnt_idmapping.c +++ b/fs/mnt_idmapping.c @@ -17,12 +17,6 @@ #define VFSUIDT_INIT_RAW(val) (vfsuid_t){ val } #define VFSGIDT_INIT_RAW(val) (vfsgid_t){ val } -struct mnt_idmap { - struct uid_gid_map uid_map; - struct uid_gid_map gid_map; - refcount_t count; -}; - /* * Carries the initial idmapping of 0:0:4294967295 which is an identity * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h index 85553b3a7904..4410672c2828 100644 --- a/include/linux/mnt_idmapping.h +++ b/include/linux/mnt_idmapping.h @@ -8,6 +8,13 @@ struct mnt_idmap; struct user_namespace; +/* Don't touch directly! All fields private. */ +struct mnt_idmap { + struct uid_gid_map uid_map; + struct uid_gid_map gid_map; + refcount_t count; +}; + extern struct mnt_idmap nop_mnt_idmap; extern struct mnt_idmap invalid_mnt_idmap; extern struct user_namespace init_user_ns; diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index 2dc767e08f54..5696c870fd0b 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -17,7 +17,28 @@ struct user_namespace; extern struct user_namespace init_user_ns; -struct uid_gid_map; + +#define UID_GID_MAP_MAX_BASE_EXTENTS 5 +#define UID_GID_MAP_MAX_EXTENTS 340 + +struct uid_gid_extent { + u32 first; + u32 lower_first; + u32 count; +}; + +struct uid_gid_map { /* 64 bytes -- 1 cache line */ + union { + struct { + struct uid_gid_extent extent[UID_GID_MAP_MAX_BASE_EXTENTS]; + u32 nr_extents; + }; + struct { + struct uid_gid_extent *forward; + struct uid_gid_extent *reverse; + }; + }; +}; #define KUIDT_INIT(value) (kuid_t){ value } #define KGIDT_INIT(value) (kgid_t){ value } diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index a0bb6d012137..6feae94c3661 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -12,28 +12,7 @@ #include #include #include - -#define UID_GID_MAP_MAX_BASE_EXTENTS 5 -#define UID_GID_MAP_MAX_EXTENTS 340 - -struct uid_gid_extent { - u32 first; - u32 lower_first; - u32 count; -}; - -struct uid_gid_map { /* 64 bytes -- 1 cache line */ - union { - struct { - struct uid_gid_extent extent[UID_GID_MAP_MAX_BASE_EXTENTS]; - u32 nr_extents; - }; - struct { - struct uid_gid_extent *forward; - struct uid_gid_extent *reverse; - }; - }; -}; +#include #define USERNS_SETGROUPS_ALLOWED 1UL From patchwork Wed Apr 16 13:17:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 14053924 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A703E1DED76 for ; Wed, 16 Apr 2025 13:17:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744809468; cv=none; b=OiQY5xUnqNzzpKgZ1Yq1Doy1yIhEURSIprk+PxWQEOylK/HcpsHIU3xsdfFvw8nCrCCxmezu8jakxnht+c6R618oEh5+j/s6bgD3lAMG4uB1V+styqRGmOYTSdTmuQWcTLLDnW58xhMEtPZAposNNGQNBnH5Iys9FdMxiBOlk4Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744809468; c=relaxed/simple; bh=ZpcBoDRaLJjfUNCD42ZoutluKwLn0eAAED/EEx7Y08g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=c2i/eI+KwiMsdNp743Y4Zf6ZvRryMOOGukijQYGDWbSdSMWniGXu53BSoNPFgR9apTLHdIIynFOlyGHzvdafSygQ3WRc9GvXQ95cpVdO0DNy3BGiYaYx+oy1xvfeklv6W98R0bkOJi4hOc+mlPcGtIOXko3u4issJLVj9Y6Go88= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Jtu0KuJy; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Jtu0KuJy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8F684C4CEE2; Wed, 16 Apr 2025 13:17:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744809468; bh=ZpcBoDRaLJjfUNCD42ZoutluKwLn0eAAED/EEx7Y08g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jtu0KuJy14v81mVGZ7bwQBsw32DhRDh3ItXaLS4dDeu+hUZLvc/m10rxu8H1lLmr+ Ff+R34c3IHLEgeQ2Q21+E3t5QfVcgW+oirS7eeGb7cJRJwv54Oq+XAX/CBoyNesgkW x6/esFJQrkhZIN02zjwLzGDm3qmYd2EvqDWf4ZF3E9oQJ6M4acs3bJMF5pxzCHMBCt 0XX9bjqnYwrw840Vxom+Vjj+j/+JtSLmvScgE2Gf+iUT8a9BGe5h8W9p8jYnlnnUj9 Gv7ei5LcW0KubDLUv9wkrXO5w+hVG1f8Ciycr6VywWNh3wZwH2gpsRzzH0E1IECjId XLY2NxOmVJWQA== From: Christian Brauner To: Linus Torvalds , linux-fsdevel Cc: Christian Brauner , Mateusz Guzik , Al Viro , Jan Kara , Jeff Layton , Josef Bacik Subject: [PATCH RFC 3/3] mnt_idmapping: inline all low-level helpers Date: Wed, 16 Apr 2025 15:17:24 +0200 Message-ID: <20250416-work-mnt_idmap-s_user_ns-v1-3-273bef3a61ec@kernel.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250416-work-mnt_idmap-s_user_ns-v1-0-273bef3a61ec@kernel.org> References: <20250416-work-mnt_idmap-s_user_ns-v1-0-273bef3a61ec@kernel.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mailer: b4 0.15-dev-c25d1 X-Developer-Signature: v=1; a=openpgp-sha256; l=12181; i=brauner@kernel.org; h=from:subject:message-id; bh=ZpcBoDRaLJjfUNCD42ZoutluKwLn0eAAED/EEx7Y08g=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMaT/X/uk8mhfsqbf9OTfyyy+12quiZi8a4r5on/2tWZpS mf6LzDu6ihlYRDjYpAVU2RxaDcJl1vOU7HZKFMDZg4rE8gQBi5OAZhIAwvDP5Wo4hB7JWbHTxv1 q7wPVR2fOPG+Z8yvncmhJz9XPv/3dA8jw4LDWyW9W40uG8vK2FVs9t+iJq5lXf7a9nLf55Wb7va dYwYA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Let's inline all low-level helpers and use likely()/unlikely() to help the compiler along. Signed-off-by: Christian Brauner --- fs/mnt_idmapping.c | 145 ----------------------------------------- include/linux/mnt_idmapping.h | 147 +++++++++++++++++++++++++++++++++++++++--- kernel/user_namespace.c | 2 + 3 files changed, 141 insertions(+), 153 deletions(-) diff --git a/fs/mnt_idmapping.c b/fs/mnt_idmapping.c index 5c7e1db8fef8..ba1f752b6fa7 100644 --- a/fs/mnt_idmapping.c +++ b/fs/mnt_idmapping.c @@ -10,13 +10,6 @@ #include "internal.h" -/* - * Outside of this file vfs{g,u}id_t are always created from k{g,u}id_t, - * never from raw values. These are just internal helpers. - */ -#define VFSUIDT_INIT_RAW(val) (vfsuid_t){ val } -#define VFSGIDT_INIT_RAW(val) (vfsgid_t){ val } - /* * Carries the initial idmapping of 0:0:4294967295 which is an identity * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is @@ -36,144 +29,6 @@ struct mnt_idmap invalid_mnt_idmap = { }; EXPORT_SYMBOL_GPL(invalid_mnt_idmap); -/** - * make_vfsuid - map a filesystem kuid according to an idmapping - * @idmap: the mount's idmapping - * @fs_userns: the filesystem's idmapping - * @kuid : kuid to be mapped - * - * Take a @kuid and remap it from @fs_userns into @idmap. Use this - * function when preparing a @kuid to be reported to userspace. - * - * If initial_idmapping() determines that this is not an idmapped mount - * we can simply return @kuid unchanged. - * If initial_idmapping() tells us that the filesystem is not mounted with an - * idmapping we know the value of @kuid won't change when calling - * from_kuid() so we can simply retrieve the value via __kuid_val() - * directly. - * - * Return: @kuid mapped according to @idmap. - * If @kuid has no mapping in either @idmap or @fs_userns INVALID_UID is - * returned. - */ - -vfsuid_t make_vfsuid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, - kuid_t kuid) -{ - uid_t uid; - - if (idmap == &nop_mnt_idmap) - return VFSUIDT_INIT(kuid); - if (idmap == &invalid_mnt_idmap) - return INVALID_VFSUID; - if (initial_idmapping(fs_userns)) - uid = __kuid_val(kuid); - else - uid = from_kuid(fs_userns, kuid); - if (uid == (uid_t)-1) - return INVALID_VFSUID; - return VFSUIDT_INIT_RAW(map_id_down(&idmap->uid_map, uid)); -} -EXPORT_SYMBOL_GPL(make_vfsuid); - -/** - * make_vfsgid - map a filesystem kgid according to an idmapping - * @idmap: the mount's idmapping - * @fs_userns: the filesystem's idmapping - * @kgid : kgid to be mapped - * - * Take a @kgid and remap it from @fs_userns into @idmap. Use this - * function when preparing a @kgid to be reported to userspace. - * - * If initial_idmapping() determines that this is not an idmapped mount - * we can simply return @kgid unchanged. - * If initial_idmapping() tells us that the filesystem is not mounted with an - * idmapping we know the value of @kgid won't change when calling - * from_kgid() so we can simply retrieve the value via __kgid_val() - * directly. - * - * Return: @kgid mapped according to @idmap. - * If @kgid has no mapping in either @idmap or @fs_userns INVALID_GID is - * returned. - */ -vfsgid_t make_vfsgid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, kgid_t kgid) -{ - gid_t gid; - - if (idmap == &nop_mnt_idmap) - return VFSGIDT_INIT(kgid); - if (idmap == &invalid_mnt_idmap) - return INVALID_VFSGID; - if (initial_idmapping(fs_userns)) - gid = __kgid_val(kgid); - else - gid = from_kgid(fs_userns, kgid); - if (gid == (gid_t)-1) - return INVALID_VFSGID; - return VFSGIDT_INIT_RAW(map_id_down(&idmap->gid_map, gid)); -} -EXPORT_SYMBOL_GPL(make_vfsgid); - -/** - * from_vfsuid - map a vfsuid into the filesystem idmapping - * @idmap: the mount's idmapping - * @fs_userns: the filesystem's idmapping - * @vfsuid : vfsuid to be mapped - * - * Map @vfsuid into the filesystem idmapping. This function has to be used in - * order to e.g. write @vfsuid to inode->i_uid. - * - * Return: @vfsuid mapped into the filesystem idmapping - */ -kuid_t from_vfsuid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, vfsuid_t vfsuid) -{ - uid_t uid; - - if (idmap == &nop_mnt_idmap) - return AS_KUIDT(vfsuid); - if (idmap == &invalid_mnt_idmap) - return INVALID_UID; - uid = map_id_up(&idmap->uid_map, __vfsuid_val(vfsuid)); - if (uid == (uid_t)-1) - return INVALID_UID; - if (initial_idmapping(fs_userns)) - return KUIDT_INIT(uid); - return make_kuid(fs_userns, uid); -} -EXPORT_SYMBOL_GPL(from_vfsuid); - -/** - * from_vfsgid - map a vfsgid into the filesystem idmapping - * @idmap: the mount's idmapping - * @fs_userns: the filesystem's idmapping - * @vfsgid : vfsgid to be mapped - * - * Map @vfsgid into the filesystem idmapping. This function has to be used in - * order to e.g. write @vfsgid to inode->i_gid. - * - * Return: @vfsgid mapped into the filesystem idmapping - */ -kgid_t from_vfsgid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, vfsgid_t vfsgid) -{ - gid_t gid; - - if (idmap == &nop_mnt_idmap) - return AS_KGIDT(vfsgid); - if (idmap == &invalid_mnt_idmap) - return INVALID_GID; - gid = map_id_up(&idmap->gid_map, __vfsgid_val(vfsgid)); - if (gid == (gid_t)-1) - return INVALID_GID; - if (initial_idmapping(fs_userns)) - return KGIDT_INIT(gid); - return make_kgid(fs_userns, gid); -} -EXPORT_SYMBOL_GPL(from_vfsgid); - #ifdef CONFIG_MULTIUSER /** * vfsgid_in_group_p() - check whether a vfsuid matches the caller's groups diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h index 4410672c2828..e6fb905c39bd 100644 --- a/include/linux/mnt_idmapping.h +++ b/include/linux/mnt_idmapping.h @@ -140,22 +140,153 @@ static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid) #define AS_KUIDT(val) (kuid_t){ __vfsuid_val(val) } #define AS_KGIDT(val) (kgid_t){ __vfsgid_val(val) } +/* + * Outside of this file vfs{g,u}id_t are always created from k{g,u}id_t, + * never from raw values. These are just internal helpers. + */ +#define VFSUIDT_INIT_RAW(val) (vfsuid_t){ val } +#define VFSGIDT_INIT_RAW(val) (vfsgid_t){ val } + int vfsgid_in_group_p(vfsgid_t vfsgid); struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap); void mnt_idmap_put(struct mnt_idmap *idmap); -vfsuid_t make_vfsuid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, kuid_t kuid); +/** + * make_vfsuid - map a filesystem kuid according to an idmapping + * @idmap: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @kuid : kuid to be mapped + * + * Take a @kuid and remap it from @fs_userns into @idmap. Use this + * function when preparing a @kuid to be reported to userspace. + * + * If initial_idmapping() determines that this is not an idmapped mount + * we can simply return @kuid unchanged. + * If initial_idmapping() tells us that the filesystem is not mounted with an + * idmapping we know the value of @kuid won't change when calling + * from_kuid() so we can simply retrieve the value via __kuid_val() + * directly. + * + * Return: @kuid mapped according to @idmap. + * If @kuid has no mapping in either @idmap or @fs_userns INVALID_UID is + * returned. + */ +static inline vfsuid_t make_vfsuid(struct mnt_idmap *idmap, + struct user_namespace *fs_userns, + kuid_t kuid) +{ + uid_t uid; + + if (likely(idmap == &nop_mnt_idmap)) + return VFSUIDT_INIT(kuid); + if (unlikely(idmap == &invalid_mnt_idmap)) + return INVALID_VFSUID; + if (likely(initial_idmapping(fs_userns))) + uid = __kuid_val(kuid); + else + uid = from_kuid(fs_userns, kuid); + if (unlikely(uid == (uid_t)-1)) + return INVALID_VFSUID; + return VFSUIDT_INIT_RAW(map_id_down(&idmap->uid_map, uid)); +} -vfsgid_t make_vfsgid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, kgid_t kgid); +/** + * make_vfsgid - map a filesystem kgid according to an idmapping + * @idmap: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @kgid : kgid to be mapped + * + * Take a @kgid and remap it from @fs_userns into @idmap. Use this + * function when preparing a @kgid to be reported to userspace. + * + * If initial_idmapping() determines that this is not an idmapped mount + * we can simply return @kgid unchanged. + * If initial_idmapping() tells us that the filesystem is not mounted with an + * idmapping we know the value of @kgid won't change when calling + * from_kgid() so we can simply retrieve the value via __kgid_val() + * directly. + * + * Return: @kgid mapped according to @idmap. + * If @kgid has no mapping in either @idmap or @fs_userns INVALID_GID is + * returned. + */ +static inline vfsgid_t make_vfsgid(struct mnt_idmap *idmap, + struct user_namespace *fs_userns, + kgid_t kgid) +{ + gid_t gid; + + if (likely(idmap == &nop_mnt_idmap)) + return VFSGIDT_INIT(kgid); + if (unlikely(idmap == &invalid_mnt_idmap)) + return INVALID_VFSGID; + if (likely(initial_idmapping(fs_userns))) + gid = __kgid_val(kgid); + else + gid = from_kgid(fs_userns, kgid); + if (unlikely(gid == (gid_t)-1)) + return INVALID_VFSGID; + return VFSGIDT_INIT_RAW(map_id_down(&idmap->gid_map, gid)); +} -kuid_t from_vfsuid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, vfsuid_t vfsuid); +/** + * from_vfsuid - map a vfsuid into the filesystem idmapping + * @idmap: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @vfsuid : vfsuid to be mapped + * + * Map @vfsuid into the filesystem idmapping. This function has to be used in + * order to e.g. write @vfsuid to inode->i_uid. + * + * Return: @vfsuid mapped into the filesystem idmapping + */ +static inline kuid_t from_vfsuid(struct mnt_idmap *idmap, + struct user_namespace *fs_userns, + vfsuid_t vfsuid) +{ + uid_t uid; + + if (likely(idmap == &nop_mnt_idmap)) + return AS_KUIDT(vfsuid); + if (unlikely(idmap == &invalid_mnt_idmap)) + return INVALID_UID; + uid = map_id_up(&idmap->uid_map, __vfsuid_val(vfsuid)); + if (unlikely(uid == (uid_t)-1)) + return INVALID_UID; + if (likely(initial_idmapping(fs_userns))) + return KUIDT_INIT(uid); + return make_kuid(fs_userns, uid); +} -kgid_t from_vfsgid(struct mnt_idmap *idmap, - struct user_namespace *fs_userns, vfsgid_t vfsgid); +/** + * from_vfsgid - map a vfsgid into the filesystem idmapping + * @idmap: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @vfsgid : vfsgid to be mapped + * + * Map @vfsgid into the filesystem idmapping. This function has to be used in + * order to e.g. write @vfsgid to inode->i_gid. + * + * Return: @vfsgid mapped into the filesystem idmapping + */ +static inline kgid_t from_vfsgid(struct mnt_idmap *idmap, + struct user_namespace *fs_userns, + vfsgid_t vfsgid) +{ + gid_t gid; + + if (likely(idmap == &nop_mnt_idmap)) + return AS_KGIDT(vfsgid); + if (unlikely(idmap == &invalid_mnt_idmap)) + return INVALID_GID; + gid = map_id_up(&idmap->gid_map, __vfsgid_val(vfsgid)); + if (unlikely(gid == (gid_t)-1)) + return INVALID_GID; + if (likely(initial_idmapping(fs_userns))) + return KGIDT_INIT(gid); + return make_kgid(fs_userns, gid); +} /** * vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 682f40d5632d..693c62587571 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -336,6 +336,7 @@ u32 map_id_down(struct uid_gid_map *map, u32 id) { return map_id_range_down(map, id, 1); } +EXPORT_SYMBOL_GPL(map_id_down); /* * map_id_up_base - Find idmap via binary search in static extent array. @@ -402,6 +403,7 @@ u32 map_id_up(struct uid_gid_map *map, u32 id) { return map_id_range_up(map, id, 1); } +EXPORT_SYMBOL_GPL(map_id_up); /** * make_kuid - Map a user-namespace uid pair into a kuid.