From patchwork Tue Apr 26 19:36:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seth Forshee X-Patchwork-Id: 8944611 Return-Path: X-Original-To: patchwork-selinux@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id DF2559F1D3 for ; Tue, 26 Apr 2016 20:13:47 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 06BE62014A for ; Tue, 26 Apr 2016 20:13:47 +0000 (UTC) Received: from emsm-gh1-uea11.nsa.gov (emsm-gh1-uea11.nsa.gov [8.44.101.9]) by mail.kernel.org (Postfix) with ESMTP id F0D4520138 for ; Tue, 26 Apr 2016 20:13:44 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.24,538,1454976000"; d="scan'208";a="15644148" IronPort-PHdr: =?us-ascii?q?9a23=3A8TCUixQ40fYLxXMJ9WbJrNHNI9psv+yvbD5Q0YIu?= =?us-ascii?q?jvd0So/mwa65bBeN2/xhgRfzUJnB7Loc0qyN4/CmBj1LuM3f+Fk5M7VyFDY9wf?= =?us-ascii?q?0MmAIhBMPXQWbaF9XNKxIAIcJZSVV+9Gu6O0UGUOz3ZlnVv2HgpWVKQka3CwN5?= =?us-ascii?q?K6zPF5LIiIzvjqbpq82VPFQD3WHjKZpJbzyI7izp/vEMhoVjLqtjgjDomVBvP9?= =?us-ascii?q?ps+GVzOFiIlAz97MrjtLRq8iBXpu5zv5UYCfayV+0CQLdZFDUrNXwurI2u7EGb?= =?us-ascii?q?DFjH2nxJGEgMkxEAPE6NxhD3UprrtyL8/KIp1SObMMH7V7UcSTGj9LxqTxmugy?= =?us-ascii?q?ACYXpx2WXamsV2gK9B6CygvRs3l5DVeoa9Jvd4f72bedIcWHoHWdxeETFCVMf0?= =?us-ascii?q?QJECAKIiJ+FRr8zdrkESqBK4TV2jHu7gyT9ggn7wwL001PknHQja3QsmWdUUvy?= =?us-ascii?q?KHgs/yMfIpXPy1hIfP1y7DYv4ejSzw9IiOfBc7uvGBUJp7eMzWz0gkHgeDhVKV?= =?us-ascii?q?/9+2dwiJ3/gA5jDIp9FrUvii3it+81l8?= X-IPAS-Result: =?us-ascii?q?A2EJBQBiyx9X/wHyM5BeHAGCcCuBULt3H4F2hUVMAQEBAQE?= =?us-ascii?q?BAgJiJ4ItfVs9AQEBAwECDxUTBgEBDCALAQIDCQEBFykICAMBLQMBBQELEQYBB?= =?us-ascii?q?wsFGAQBiAgBpVGBMT4xik+FKAEEjEcBAQgBAQEBFgYKhA2CCohaEQGFdAGOTIl?= =?us-ascii?q?IgVWMRIkqJYVAjXIwgQ5iggUbFoFTTgGHeIE1AQEB?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea11.nsa.gov with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 26 Apr 2016 20:13:14 +0000 Received: from prometheus.infosec.tycho.ncsc.mil (prometheus [192.168.25.40]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id u3QKDDXV022199; Tue, 26 Apr 2016 16:13:13 -0400 Received: from tarius.tycho.ncsc.mil (tarius.infosec.tycho.ncsc.mil [144.51.242.1]) by prometheus.infosec.tycho.ncsc.mil (8.15.2/8.15.2) with ESMTP id u3QJbBSw172321 for ; Tue, 26 Apr 2016 15:37:11 -0400 Received: from goalie.tycho.ncsc.mil (goalie [144.51.242.250]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id u3QJak03011587 for ; Tue, 26 Apr 2016 15:37:10 -0400 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0BABQD9wR9X/yQp0ApeHYJwK4FQt3CECQgXhXgCgUBMAQEBAQEBZieEQgEBAQMSFRkBATcBD1E0AQUBHAYBEiKICAGlV4ExPjGKT4UoAQSMSgEBAQEBAQQCARcGCoQNggqLUgtAgkOOTYlIgVWMRIkqhWWNcjCBDmKBeA0bFoFTTgGJLQEBAQ X-IPAS-Result: A0BABQD9wR9X/yQp0ApeHYJwK4FQt3CECQgXhXgCgUBMAQEBAQEBZieEQgEBAQMSFRkBATcBD1E0AQUBHAYBEiKICAGlV4ExPjGKT4UoAQSMSgEBAQEBAQQCARcGCoQNggqLUgtAgkOOTYlIgVWMRIkqhWWNcjCBDmKBeA0bFoFTTgGJLQEBAQ X-IronPort-AV: E=Sophos;i="5.24,537,1454994000"; d="scan'208";a="5410389" Received: from emsm-gh1-uea10.corp.nsa.gov (HELO emsm-gh1-uea10.nsa.gov) ([10.208.41.36]) by goalie.tycho.ncsc.mil with ESMTP; 26 Apr 2016 15:37:11 -0400 IronPort-PHdr: =?us-ascii?q?9a23=3A8DnloRR/xgp+ugTlQ1G/FpNfAdpsv+yvbD5Q0YIu?= =?us-ascii?q?jvd0So/mwa65bBeN2/xhgRfzUJnB7Loc0qyN4/CmBj1LuM3Z+Fk5M7VyFDY9wf?= =?us-ascii?q?0MmAIhBMPXQWbaF9XNKxIAIcJZSVV+9Gu6O0UGUOz3ZlnVv2HgpWVKQka3CwN5?= =?us-ascii?q?K6zPF5LIiIzvjqbpq82VPFQD3WHlKZpJbzyI7izp/vEMhoVjLqtjgjDomVBvP9?= =?us-ascii?q?ps+GVzOFiIlAz97MrjtLRq8iBXpu5zv5UYCfayV+0CQLdZFDUrNXwurI2u7EGb?= =?us-ascii?q?DFjH2nxJGEgMkxEAPE6NxhD3UprrtyL8/KIp1SObMMH7V7UcSTGj9LxqTxmugy?= =?us-ascii?q?ACYXpx2WXamsV2gK9B6CygvRs3l5DVeoa9Jvd4f72bedIcWHoHWdxeETFCVMf0?= =?us-ascii?q?QJECAKIiJ+FRr8zdrkESqBK4TV2jHu7gyT9ggn7wwL001PknHQja3QsmWdUUvy?= =?us-ascii?q?KHgs/yMfIpXPy1hIfP1y7DYv4ejSzw9IiOfBc7uvGBUJp7eMzWz0gkHgeDhVKV?= =?us-ascii?q?/9+2dwiJ3/gA5jDIp9FrUvii3it+81l8?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0HzAAC5wh9Xj7bfVdFegw2Be7dwhAkIF?= =?us-ascii?q?4F2hAICgUBMAQEBAQEBAgIPAQEBAQcLCwkhL4ItfVs9AQEBAxIVGQEBNwEPUTQ?= =?us-ascii?q?BBQEcBgESIogIAaVXgTE+MYpPhSgBBIxKAQEBAQEBBAIBFwYKhA2CCotSC0CCQ?= =?us-ascii?q?45NiUiBVYxEiSqFZY1yMIEOgloNEQoWgVNOAYktAQEB?= X-IPAS-Result: =?us-ascii?q?A0HzAAC5wh9Xj7bfVdFegw2Be7dwhAkIF4F2hAICgUBMAQE?= =?us-ascii?q?BAQEBAgIPAQEBAQcLCwkhL4ItfVs9AQEBAxIVGQEBNwEPUTQBBQEcBgESIogIA?= =?us-ascii?q?aVXgTE+MYpPhSgBBIxKAQEBAQEBBAIBFwYKhA2CCotSC0CCQ45NiUiBVYxEiSq?= =?us-ascii?q?FZY1yMIEOgloNEQoWgVNOAYktAQEB?= X-IronPort-AV: E=Sophos;i="5.24,537,1454976000"; d="scan'208";a="13051019" Received: from mail-io0-f182.google.com ([209.85.223.182]) by emsm-gh1-uea10.nsa.gov with ESMTP/TLS/AES128-GCM-SHA256; 26 Apr 2016 19:37:09 +0000 Received: by mail-io0-f182.google.com with SMTP id u185so30183434iod.3 for ; Tue, 26 Apr 2016 12:37:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=1tbKZunrJMegwA0vfxknbaa5B2h5x/p0FeewlACWxPY=; b=POXlFD6WVnz1Yrfo/v20J7Q391rEi6zryQ35JOR4bC9cnINIw44pf4sPOyHYHHtG9B 2PbBf06fdwIIfybHYLpcGnwZtzl8NvWW6RPzFrpyCG9D4nIVDJ/n2HZSMPqwUrvgbois 882cATUAq9uDNUUhhYQLKRTte9gCdRjT19z/2BMoHvOcLK3VWhRqBr/8ysfytL2XbugE HjV8Dhm7PRElN5cap+7L1hJK670JePcuRejS1cli8l1otTmqxIsV3mtQHdVOsSwkYB8B EK+7/6SpKY4sO0Ea8THjs41Kcy/WsOCrARP0oMCgR8TnSm2je9SNc/DLvQa82jUBDIen unhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=1tbKZunrJMegwA0vfxknbaa5B2h5x/p0FeewlACWxPY=; b=OkCPR3qJTI0AvF/29sYz1dQddXdDHWcP2CfeHSInExLJbgiI+RyYylrvTZpOKFPGdZ vb2gYvqJ0t9etmDnZUKsiM2MeLssnEMidO83a5PBRPxAIH+f/o5tOA07QlNg7Ld5ofOg U2GUyZ2/cOgWTrWXTJ9nXulJFugBQqt+lV3QCrsTKzfKdDk6f7brOoj6Qj+GyDV9Q+5o 0f5sTo3vT3z6u2zlvF1AqHE541W2Q9c69HGIDZGlR+8v6TJibiMR3eZWsutwZifnFW9P 4Z5IiZry1DXUg74PcKKfxbVl+AMjZxE7K2bx3ZhK6Ut30mu2HtKAzW3Lzfs4SuCHqBBF A5yw== X-Gm-Message-State: AOPr4FV+aPgrlEZOS//sZpbHwNhZ464lPcbgbFnhZmupRJk4JjKQcSwY4UP036qyag7IXTbj X-Received: by 10.107.4.67 with SMTP id 64mr6308365ioe.22.1461699428540; Tue, 26 Apr 2016 12:37:08 -0700 (PDT) Received: from localhost ([2605:a601:aab:f920:39a1:5bcf:aa:5b00]) by smtp.gmail.com with ESMTPSA id o127sm2396218iof.0.2016.04.26.12.37.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 26 Apr 2016 12:37:07 -0700 (PDT) From: Seth Forshee To: "Eric W. Biederman" , Alexander Viro , Greg Kroah-Hartman Subject: [PATCH v4 14/21] fs: Allow superblock owner to change ownership of inodes with unmappable ids Date: Tue, 26 Apr 2016 14:36:27 -0500 Message-Id: <1461699396-33000-15-git-send-email-seth.forshee@canonical.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1461699396-33000-1-git-send-email-seth.forshee@canonical.com> References: <1461699396-33000-1-git-send-email-seth.forshee@canonical.com> X-Mailman-Approved-At: Tue, 26 Apr 2016 16:11:02 -0400 X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: Cc: linux-bcache@vger.kernel.org, Serge Hallyn , Seth Forshee , dm-devel@redhat.com, Miklos Szeredi , Richard Weinberger , linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, linux-raid@vger.kernel.org, fuse-devel@lists.sourceforge.net, Austin S Hemmelgarn , linux-mtd@lists.infradead.org, selinux@tycho.nsa.gov, linux-fsdevel@vger.kernel.org, cgroups@vger.kernel.org, Pavel Tikhomirov MIME-Version: 1.0 Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In a userns mount some on-disk inodes may have ids which do not map into s_user_ns, in which case the in-kernel inodes are owned by invalid users. The superblock owner should be able to change attributes of these inodes but cannot. However it is unsafe to grant the superblock owner privileged access to all inodes in the superblock since proc, sysfs, etc. use DAC to protect files which may not belong to s_user_ns. The problem is restricted to only inodes where the owner or group is an invalid user. We can work around this by allowing users with CAP_CHOWN in s_user_ns to change an invalid owner or group id, so long as the other id is either invalid or mappable in s_user_ns. After changing ownership the user will be privileged towards the inode and thus able to change other attributes. As an precaution, checks for invalid ids are added to the proc and kernfs setattr interfaces. These filesystems are not expected to have inodes with invalid ids, but if it does happen any setattr operations will return -EPERM. Signed-off-by: Seth Forshee Acked-by: Serge Hallyn --- fs/attr.c | 62 ++++++++++++++++++++++++++++++++++++++++++++------- fs/kernfs/inode.c | 2 ++ fs/proc/base.c | 2 ++ fs/proc/generic.c | 3 +++ fs/proc/proc_sysctl.c | 2 ++ 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 3cfaaac4a18e..06bb3f401559 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -16,6 +16,58 @@ #include #include +static bool chown_ok(const struct inode *inode, kuid_t uid) +{ + struct user_namespace *user_ns; + + if (uid_eq(current_fsuid(), inode->i_uid) && uid_eq(uid, inode->i_uid)) + return true; + if (capable_wrt_inode_uidgid(inode, CAP_CHOWN)) + return true; + + /* + * Inode uids/gids are of type kuid_t/kgid_t. As such, they can be + * a) INVALID_UID/INVALID_GID, b) valid and mappable into + * i_sb->s_user_ns, or c) valid but not mappable into + * i_sb->s_user_ns. + * + * For filesystems on user-supplied media ids will either be (a) or + * (b), so we permit CAP_CHOWN in s_user_ns to change INVALID_UID if + * the gid meets these conditions (and vice versa for INVALID_GID). + * + * For psuedo-filesystems like proc or sysfs ids will be either (b) + * or (c), so these conditions do not permit namespace-root to chown + * in those filesystems. + */ + user_ns = inode->i_sb->s_user_ns; + if (!uid_valid(inode->i_uid) && + (!gid_valid(inode->i_gid) || kgid_has_mapping(user_ns, inode->i_gid)) && + ns_capable(user_ns, CAP_CHOWN)) + return true; + + return false; +} + +static bool chgrp_ok(const struct inode *inode, kgid_t gid) +{ + struct user_namespace *user_ns; + + if (uid_eq(current_fsuid(), inode->i_uid) && + (in_group_p(gid) || gid_eq(gid, inode->i_gid))) + return true; + if (capable_wrt_inode_uidgid(inode, CAP_CHOWN)) + return true; + + /* Logic here is the same as in chown_ok(); see comment there. */ + user_ns = inode->i_sb->s_user_ns; + if (!gid_valid(inode->i_gid) && + (!uid_valid(inode->i_uid) || kuid_has_mapping(user_ns, inode->i_uid)) && + ns_capable(user_ns, CAP_CHOWN)) + return true; + + return false; +} + /** * inode_change_ok - check if attribute changes to an inode are allowed * @inode: inode to check @@ -58,17 +110,11 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) return 0; /* Make sure a caller can chown. */ - if ((ia_valid & ATTR_UID) && - (!uid_eq(current_fsuid(), inode->i_uid) || - !uid_eq(attr->ia_uid, inode->i_uid)) && - !capable_wrt_inode_uidgid(inode, CAP_CHOWN)) + if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid)) return -EPERM; /* Make sure caller can chgrp. */ - if ((ia_valid & ATTR_GID) && - (!uid_eq(current_fsuid(), inode->i_uid) || - (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) && - !capable_wrt_inode_uidgid(inode, CAP_CHOWN)) + if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid)) return -EPERM; /* Make sure a caller can chmod. */ diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 16405ae88d2d..2e97a337ee5f 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -117,6 +117,8 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) if (!kn) return -EINVAL; + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) + return -EPERM; mutex_lock(&kernfs_mutex); error = inode_change_ok(inode, iattr); diff --git a/fs/proc/base.c b/fs/proc/base.c index b1755b23893e..648d623e2158 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -711,6 +711,8 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) if (attr->ia_valid & ATTR_MODE) return -EPERM; + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) + return -EPERM; error = inode_change_ok(inode, attr); if (error) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index ff3ffc76a937..1461570c552c 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -105,6 +105,9 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) struct proc_dir_entry *de = PDE(inode); int error; + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) + return -EPERM; + error = inode_change_ok(inode, iattr); if (error) return error; diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index fe5b6e6c4671..f5d575157194 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -752,6 +752,8 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) return -EPERM; + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) + return -EPERM; error = inode_change_ok(inode, attr); if (error)