From patchwork Tue Jan 12 22:01:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brauner X-Patchwork-Id: 12015363 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 04FB2C07EBB for ; Tue, 12 Jan 2021 22:18:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E0E4B23127 for ; Tue, 12 Jan 2021 22:18:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2436732AbhALWPu (ORCPT ); Tue, 12 Jan 2021 17:15:50 -0500 Received: from youngberry.canonical.com ([91.189.89.112]:44579 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2403998AbhALWON (ORCPT ); Tue, 12 Jan 2021 17:14:13 -0500 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 1kzRlS-0003bd-Sd; Tue, 12 Jan 2021 22:03:47 +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 , Theodore Tso , Alban Crequy , Tycho Andersen , David Howells , James Bottomley , Seth Forshee , =?utf-8?q?St=C3=A9phane_Graber?= , Linus Torvalds , Aleksa Sarai , Lennart Poettering , "Eric W. Biederman" , smbarber@chromium.org, Phil Estes , Serge Hallyn , Kees Cook , Todd Kjos , Paul Moore , Jonathan Corbet , containers@lists.linux-foundation.org, linux-security-module@vger.kernel.org, linux-api@vger.kernel.org, linux-ext4@vger.kernel.org, linux-xfs@vger.kernel.org, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, Christian Brauner , Christoph Hellwig Subject: [PATCH v5 23/42] open: handle idmapped mounts Date: Tue, 12 Jan 2021 23:01:05 +0100 Message-Id: <20210112220124.837960-24-christian.brauner@ubuntu.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210112220124.837960-1-christian.brauner@ubuntu.com> References: <20210112220124.837960-1-christian.brauner@ubuntu.com> MIME-Version: 1.0 X-Patch-Hashes: v=1; h=sha256; i=YKSd0FdGGLgCSTeDw7b6sTvRU/kXPfMpmc0z0c+ceJs=; m=AxYKhdYprzCvMt0kry+LbZ/gM5Cfh7tpdts7ieUNsD0=; p=c80yLYHWwcOTQmoErBkESbLUftwV7AnXz3vjhvFqrkU=; g=84e0417ac78ec9ee77a9341d2daa78d7d94f34c8 X-Patch-Sig: m=pgp; i=christian.brauner@ubuntu.com; s=0x0x91C61BC06578DCA2; b=iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCX/4YtwAKCRCRxhvAZXjconyxAPsG/hp JWZxsQjrINS8IOFAvVcvXwvob/K7Zf8blrWRz0QD/b4f9FIXMTluFOVMjbOFVPWoZGN/zTSM4fsOy q2wulg0= Precedence: bulk List-ID: For core file operations such as changing directories or chrooting, determining file access, changing mode or ownership the vfs will verify that the caller is privileged over the inode. Extend the various helpers to handle idmapped mounts. If the inode is accessed through an idmapped mount it is mapped according to the mount's user namespace. Afterwards the permissions checks are identical to non-idmapped mounts. When changing file ownership we need to map the uid and gid from the mount's user namespace. If the initial user namespace is passed nothing changes so non-idmapped mounts will see identical behavior as before. Cc: Christoph Hellwig Cc: David Howells Cc: Al Viro Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner --- /* v2 */ unchanged /* v3 */ - David Howells : - Remove mnt_idmapped() check after removing mnt_idmapped() helper in earlier patches. /* v4 */ - Serge Hallyn : - Use "mnt_userns" to refer to a vfsmount's userns everywhere to make terminology consistent. /* v5 */ base-commit: 7c53f6b671f4aba70ff15e1b05148b10d58c2837 - Christoph Hellwig : - Use new file_userns_helper(). --- fs/open.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/fs/open.c b/fs/open.c index a9f3a3b46ef1..ac26f0a363a0 100644 --- a/fs/open.c +++ b/fs/open.c @@ -401,6 +401,7 @@ static const struct cred *access_override_creds(void) static long do_faccessat(int dfd, const char __user *filename, int mode, int flags) { + struct user_namespace *mnt_userns; struct path path; struct inode *inode; int res; @@ -441,7 +442,8 @@ static long do_faccessat(int dfd, const char __user *filename, int mode, int fla goto out_path_release; } - res = inode_permission(&init_user_ns, inode, mode | MAY_ACCESS); + mnt_userns = mnt_user_ns(path.mnt); + res = inode_permission(mnt_userns, inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; @@ -489,6 +491,7 @@ SYSCALL_DEFINE2(access, const char __user *, filename, int, mode) SYSCALL_DEFINE1(chdir, const char __user *, filename) { + struct user_namespace *mnt_userns; struct path path; int error; unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; @@ -497,7 +500,8 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) if (error) goto out; - error = inode_permission(&init_user_ns, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + mnt_userns = mnt_user_ns(path.mnt); + error = inode_permission(mnt_userns, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -515,6 +519,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) SYSCALL_DEFINE1(fchdir, unsigned int, fd) { + struct user_namespace *mnt_userns; struct fd f = fdget_raw(fd); int error; @@ -526,7 +531,8 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) if (!d_can_lookup(f.file->f_path.dentry)) goto out_putf; - error = inode_permission(&init_user_ns, file_inode(f.file), MAY_EXEC | MAY_CHDIR); + mnt_userns = file_user_ns(f.file); + error = inode_permission(mnt_userns, file_inode(f.file), MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: @@ -537,6 +543,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) SYSCALL_DEFINE1(chroot, const char __user *, filename) { + struct user_namespace *mnt_userns; struct path path; int error; unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; @@ -545,7 +552,8 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) if (error) goto out; - error = inode_permission(&init_user_ns, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + mnt_userns = mnt_user_ns(path.mnt); + error = inode_permission(mnt_userns, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -570,6 +578,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) int chmod_common(const struct path *path, umode_t mode) { + struct user_namespace *mnt_userns; struct inode *inode = path->dentry->d_inode; struct inode *delegated_inode = NULL; struct iattr newattrs; @@ -585,7 +594,8 @@ int chmod_common(const struct path *path, umode_t mode) goto out_unlock; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(&init_user_ns, path->dentry, &newattrs, &delegated_inode); + mnt_userns = mnt_user_ns(path->mnt); + error = notify_change(mnt_userns, path->dentry, &newattrs, &delegated_inode); out_unlock: inode_unlock(inode); if (delegated_inode) { @@ -646,6 +656,7 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode) int chown_common(const struct path *path, uid_t user, gid_t group) { + struct user_namespace *mnt_userns; struct inode *inode = path->dentry->d_inode; struct inode *delegated_inode = NULL; int error; @@ -656,6 +667,10 @@ int chown_common(const struct path *path, uid_t user, gid_t group) uid = make_kuid(current_user_ns(), user); gid = make_kgid(current_user_ns(), group); + mnt_userns = mnt_user_ns(path->mnt); + uid = kuid_from_mnt(mnt_userns, uid); + gid = kgid_from_mnt(mnt_userns, gid); + retry_deleg: newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { @@ -676,7 +691,7 @@ int chown_common(const struct path *path, uid_t user, gid_t group) inode_lock(inode); error = security_path_chown(path, uid, gid); if (!error) - error = notify_change(&init_user_ns, path->dentry, &newattrs, &delegated_inode); + error = notify_change(mnt_userns, path->dentry, &newattrs, &delegated_inode); inode_unlock(inode); if (delegated_inode) { error = break_deleg_wait(&delegated_inode); @@ -1137,7 +1152,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode) { struct filename *name = getname_kernel(filename); struct file *file = ERR_CAST(name); - + if (!IS_ERR(name)) { file = file_open_name(name, flags, mode); putname(name);