Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp2385639pxb; Sun, 15 Nov 2020 02:50:45 -0800 (PST) X-Google-Smtp-Source: ABdhPJy1tjEY4CsIvf02nRRMQ22u3XYtDAcTRrc9CtCJzZyrsiPkmM4GzFbIKanmrQG+vUt/hK1N X-Received: by 2002:a05:6402:1a33:: with SMTP id be19mr11372210edb.47.1605437445412; Sun, 15 Nov 2020 02:50:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605437445; cv=none; d=google.com; s=arc-20160816; b=PVEPyLfKdpwQvrH5PpMcCyEqvYPwIICkn+5GEQy2joBm+lsQu+HxHCMOI4391UnYfi A84E8NOijvUfpWbO4IX5SeyctRgKslHG8zxz3dfpFcA5g+l2BDcckxZzqnrc20eqCyo1 LG+ygIPdaNUZDEvKvlOSI8CU/VVVCHr6AkM9l2ZDqdTLEexxld/+lAzkueyKNuH/RxYd 3Mte2vtZo57r8Ud1s2j0i1hc9H7zjyVtBPaSa+ayim3kixvV5QTDM3gZk9UXPPF6Y7lK x1AKMXUrLZ8wHHc1cH6kw7qlfaIo0Ba/IEY2j90E9odxOtbnzAvQ6wpeufCarka/c/G5 WYlg== 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=mpStrDDjK+7LI3BNkFofIIMQWQzSzKThC6UGNceDc/I=; b=YwcRXrATmkZ5eycZGexbD3suIWEony/h880ANA3lM/EljA81/H2rKPAG7WuPjxPnh0 X2K/+ax2RcMx8vdJmWKcESE+wGUnrOcKNwmRULz+bdvPyJFPa+5jlmtLUziogJFvDNHH r4mlx4VNmOlgOMPuHcGls6NE1wqcVDkJQgO10FTWhCGbE1cXxdGg9GU1JqQbTEb9Skr/ fRs/R3RiZWg9RzbStEt8jk1+QCmQM/SGd+du3zPB1D+ujdXMrEF9PAqKkY3s8JmtNklO XaPyVb/yWVLJF6ojpsdEFpG8FQEbZCAB+H4Zd4rNnLa5hzdUE3yDEPwu2I2S3kkJ6Fe6 O0yw== 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 w19si9660116edi.177.2020.11.15.02.50.22; Sun, 15 Nov 2020 02:50:45 -0800 (PST) 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 S1727088AbgKOKss (ORCPT + 99 others); Sun, 15 Nov 2020 05:48:48 -0500 Received: from youngberry.canonical.com ([91.189.89.112]:59901 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726808AbgKOKsj (ORCPT ); Sun, 15 Nov 2020 05:48:39 -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 1keFRC-0000Kt-3n; Sun, 15 Nov 2020 10:39:14 +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 , 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-audit@redhat.com, linux-integrity@vger.kernel.org, selinux@vger.kernel.org, Christian Brauner , Christoph Hellwig Subject: [PATCH v2 20/39] open: handle idmapped mounts Date: Sun, 15 Nov 2020 11:36:59 +0100 Message-Id: <20201115103718.298186-21-christian.brauner@ubuntu.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201115103718.298186-1-christian.brauner@ubuntu.com> References: <20201115103718.298186-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 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 mount from the mount's user namespace. If the initial user namespace is passed all mapping operations are a nop so non-idmapped mounts will not see a change in behavior and will also not see any performance impact. Cc: Christoph Hellwig Cc: David Howells Cc: Al Viro Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Christian Brauner --- /* v2 */ unchanged --- fs/open.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/fs/open.c b/fs/open.c index 137dcc52d2f8..2e2eb55976b1 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 *user_ns; 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); + user_ns = mnt_user_ns(path.mnt); + res = inode_permission(user_ns, 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 *user_ns; 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); + user_ns = mnt_user_ns(path.mnt); + error = inode_permission(user_ns, 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 *user_ns; 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); + user_ns = mnt_user_ns(f.file->f_path.mnt); + error = inode_permission(user_ns, 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 *user_ns; 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); + user_ns = mnt_user_ns(path.mnt); + error = inode_permission(user_ns, 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 *user_ns; 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); + user_ns = mnt_user_ns(path->mnt); + error = notify_change(user_ns, 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 *user_ns; struct inode *inode = path->dentry->d_inode; struct inode *delegated_inode = NULL; int error; @@ -656,6 +667,12 @@ 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); + user_ns = mnt_user_ns(path->mnt); + if (mnt_idmapped(path->mnt)) { + uid = kuid_from_mnt(user_ns, uid); + gid = kgid_from_mnt(user_ns, gid); + } + retry_deleg: newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { @@ -676,7 +693,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(user_ns, path->dentry, &newattrs, &delegated_inode); inode_unlock(inode); if (delegated_inode) { error = break_deleg_wait(&delegated_inode); @@ -1133,7 +1150,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); -- 2.29.2