Received: by 2002:a05:6a10:9e8c:0:0:0:0 with SMTP id y12csp254916pxx; Thu, 29 Oct 2020 01:36:19 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxq71sTw3Xwze8Saf7hbplDpgJkDFWNE5LqY93T52CUbLDNvzKCwvxfgUDxBvM5iOK8U6ep X-Received: by 2002:a05:6402:1686:: with SMTP id a6mr2775403edv.106.1603960578894; Thu, 29 Oct 2020 01:36:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1603960578; cv=none; d=google.com; s=arc-20160816; b=VnnBk15xM6k081ZWrUICRr1JYYtjONo0KAfNiVd+K9zjVmVRebXaBf5+P2Erl3I83k veW8OoK+7u3npVzXAuKNK7IXztfQ19Ydg1S8Nh6w5B4InwsOv8Q6JwS00eMWyEDnaHZb AQF4ZsTzgdAQXt3skhg+8VG8c69fludkLsHlZtR4y72vd6jEYsqmhgXGTNEWs77nEsBY UDUXkgMsgJ2vW0tHelXlnpECED2z8DIyaNlFTvzuRkwTS0CgEBq1QZkH4vJjjFlKhHr4 vvozRdWHeZ4HhTPQoEf1vHbolF9FWVPWHAn71NWIOAMYnN1g9cHByFNzKCi4/smN2yB5 gXyQ== 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 :references:in-reply-to:message-id:date:subject:cc:to:from; bh=+JQ8b0+mZAtoX/e/xlT/Z7WMLr12iE+xfAwEHBm+Z2g=; b=bCPr98DlCS7StRbbF47RDt5appxaQi/Avb4F+VVA2jGWW8nNDKGCWyru6UtGHo63HH 16cdNzucM44jM/GguYytTazxTy/IaDltnYXyFcdLHaQQseUCRhZie35u8W5AVJGTGH/S cp0UwyKhCVtnsaERTHO5u2G/g8opeiCseXbMJj1QAeemlBUlNrqxsp8EdAMIvRFWzhZt 7gUogxeKjiONPoEjJkqKpO1mNJuec49Hourm3mAfx1EsTFC0bI/ujM3ht2KD372DjqyI pqbU6l0LtGZbucmyn4L/p3u6bFmO/Hs6T+g8OhCu/nX7gM0Gcg6X0Bk/w4CpLEiAW9od 6icQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id p61si1546025edd.445.2020.10.29.01.35.55; Thu, 29 Oct 2020 01:36:18 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389971AbgJ2Axb (ORCPT + 99 others); Wed, 28 Oct 2020 20:53:31 -0400 Received: from youngberry.canonical.com ([91.189.89.112]:60647 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730334AbgJ2Afc (ORCPT ); Wed, 28 Oct 2020 20:35:32 -0400 Received: from ip5f5af0a0.dynamic.kabel-deutschland.de ([95.90.240.160] helo=wittgenstein.fritz.box) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1kXvuZ-0008Ep-AG; Thu, 29 Oct 2020 00:35:27 +0000 From: Christian Brauner To: Alexander Viro , Christoph Hellwig , linux-fsdevel@vger.kernel.org Cc: John Johansen , James Morris , Mimi Zohar , Dmitry Kasatkin , Stephen Smalley , Casey Schaufler , Arnd Bergmann , Andreas Dilger , OGAWA Hirofumi , Geoffrey Thomas , Mrunal Patel , Josh Triplett , Andy Lutomirski , Amir Goldstein , Miklos Szeredi , Theodore Tso , Alban Crequy , Tycho Andersen , David Howells , James Bottomley , Jann Horn , Seth Forshee , =?UTF-8?q?St=C3=A9phane=20Graber?= , Aleksa Sarai , Lennart Poettering , "Eric W. Biederman" , smbarber@chromium.org, Phil Estes , Serge Hallyn , Kees Cook , Todd Kjos , Jonathan Corbet , containers@lists.linux-foundation.org, linux-security-module@vger.kernel.org, linux-api@vger.kernel.org, linux-ext4@vger.kernel.org, linux-unionfs@vger.kernel.org, linux-audit@redhat.com, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, Christian Brauner Subject: [PATCH 09/34] inode: add idmapped mount aware init and permission helpers Date: Thu, 29 Oct 2020 01:32:27 +0100 Message-Id: <20201029003252.2128653-10-christian.brauner@ubuntu.com> X-Mailer: git-send-email 2.29.0 In-Reply-To: <20201029003252.2128653-1-christian.brauner@ubuntu.com> References: <20201029003252.2128653-1-christian.brauner@ubuntu.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org The inode_owner_or_capable() helper determines whether the caller is the owner of the inode or is capable with respect to that inode. Add a new mapped_inode_owner_or_capable() helper to handle idmapped mounts. If the If the inode is accessed through an idmapped mount we first need to map it according to the mount's user namespace. Afterwards the checks are identical to non-idmapped mounts. If the initial user namespace is passed all operations are a nop so non-idmapped mounts will not see a change in behavior and will also not see any performance impact. It also means that the inode_owner_or_capable() helper can be implemented on top of mapped_inode_owner_or_capable() by passing in the initial user namespace. Similarly, we add a new mapped_inode_init_owner() helper which initializes a new inode on idmapped mounts by mapping the fsuid and fsgid of the caller from the mount's user namespace. If the initial user namespace is passed all operations are a nop so non-idmapped mounts will not see a change in behavior and will also not see any performance impact. It also means that the inode_init_owner() helper can be implemented on top of mapped_inode_init_owner() by passing in the initial user namespace. Signed-off-by: Christian Brauner --- fs/inode.c | 53 ++++++++++++++++++++++++++++++++++++---------- include/linux/fs.h | 4 ++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 9d78c37b00b8..22de3cb3b1f4 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2130,15 +2130,17 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) EXPORT_SYMBOL(init_special_inode); /** - * inode_init_owner - Init uid,gid,mode for new inode according to posix standards + * mapped_inode_init_owner - Init uid,gid,mode for new inode according to posix + * standards on idmapped mounts * @inode: New inode + * @user_ns: User namespace the inode is accessed from * @dir: Directory inode * @mode: mode of the new inode */ -void inode_init_owner(struct inode *inode, const struct inode *dir, - umode_t mode) +void mapped_inode_init_owner(struct inode *inode, struct user_namespace *user_ns, + const struct inode *dir, umode_t mode) { - inode->i_uid = current_fsuid(); + inode->i_uid = fsuid_into_mnt(user_ns); if (dir && dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; @@ -2146,34 +2148,63 @@ void inode_init_owner(struct inode *inode, const struct inode *dir, if (S_ISDIR(mode)) mode |= S_ISGID; else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) && - !in_group_p(inode->i_gid) && - !capable_wrt_inode_uidgid(dir, CAP_FSETID)) + !in_group_p(i_gid_into_mnt(user_ns, inode)) && + !capable_wrt_mapped_inode_uidgid(user_ns, dir, CAP_FSETID)) mode &= ~S_ISGID; } else - inode->i_gid = current_fsgid(); + inode->i_gid = fsgid_into_mnt(user_ns); inode->i_mode = mode; } +EXPORT_SYMBOL(mapped_inode_init_owner); + +/** + * inode_init_owner - Init uid,gid,mode for new inode according to posix standards + * @inode: New inode + * @dir: Directory inode + * @mode: mode of the new inode + */ +void inode_init_owner(struct inode *inode, const struct inode *dir, + umode_t mode) +{ + return mapped_inode_init_owner(inode, &init_user_ns, dir, mode); +} EXPORT_SYMBOL(inode_init_owner); /** - * inode_owner_or_capable - check current task permissions to inode + * mapped_inode_owner_or_capable - check current task permissions to inode on idmapped mounts + * @user_ns: User namespace the inode is accessed from * @inode: inode being checked * * Return true if current either has CAP_FOWNER in a namespace with the * inode owner uid mapped, or owns the file. */ -bool inode_owner_or_capable(const struct inode *inode) +bool mapped_inode_owner_or_capable(struct user_namespace *user_ns, const struct inode *inode) { + kuid_t i_uid; struct user_namespace *ns; - if (uid_eq(current_fsuid(), inode->i_uid)) + i_uid = i_uid_into_mnt(user_ns, inode); + if (uid_eq(current_fsuid(), i_uid)) return true; ns = current_user_ns(); - if (kuid_has_mapping(ns, inode->i_uid) && ns_capable(ns, CAP_FOWNER)) + if (kuid_has_mapping(ns, i_uid) && ns_capable(ns, CAP_FOWNER)) return true; return false; } +EXPORT_SYMBOL(mapped_inode_owner_or_capable); + +/** + * inode_owner_or_capable - check current task permissions to inode + * @inode: inode being checked + * + * Return true if current either has CAP_FOWNER in a namespace with the + * inode owner uid mapped, or owns the file. + */ +bool inode_owner_or_capable(const struct inode *inode) +{ + return mapped_inode_owner_or_capable(&init_user_ns, inode); +} EXPORT_SYMBOL(inode_owner_or_capable); /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 750ca4b3d89f..f9e2d292b7b6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1777,6 +1777,8 @@ static inline int sb_start_intwrite_trylock(struct super_block *sb) extern bool inode_owner_or_capable(const struct inode *inode); +extern bool mapped_inode_owner_or_capable(struct user_namespace *ns, + const struct inode *inode); /* * VFS helper functions.. @@ -1820,6 +1822,8 @@ extern long compat_ptr_ioctl(struct file *file, unsigned int cmd, */ extern void inode_init_owner(struct inode *inode, const struct inode *dir, umode_t mode); +extern void mapped_inode_init_owner(struct inode *inode, struct user_namespace *user_ns, + const struct inode *dir, umode_t mode); extern bool may_open_dev(const struct path *path); /* -- 2.29.0