From patchwork Wed May 4 14:26:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Djalal Harouni X-Patchwork-Id: 9014681 Return-Path: X-Original-To: patchwork-linux-fsdevel@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 0C09D9F39D for ; Wed, 4 May 2016 14:31:40 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 60EC4203AB for ; Wed, 4 May 2016 14:31:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9E0E9203A1 for ; Wed, 4 May 2016 14:31:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753104AbcEDO3u (ORCPT ); Wed, 4 May 2016 10:29:50 -0400 Received: from mail-wm0-f52.google.com ([74.125.82.52]:38095 "EHLO mail-wm0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753059AbcEDO3s (ORCPT ); Wed, 4 May 2016 10:29:48 -0400 Received: by mail-wm0-f52.google.com with SMTP id g17so97566460wme.1; Wed, 04 May 2016 07:29:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=IVQbwq8yhP5PQL3OKK2a4GH9nPXvJ3QjvK/bhqDJFqE=; b=FexFlbuL5ncVWxWwuRbdkuGKAbOgcj0Afw6+wglYz8SNcO9ac/lEnqVWleGqjw4+DB 6V0SNaNMINPHqpClTZ4VcbxxiJ/rl0e4Ch58ORrzKmURm7nR507T3NOAbVSTkYMdgp1q VJlhFXmUeUj0i2F/Fud7kX8gZP9mCQ+hshy4ChG8JA3Mso7s+AhnAjs3oBYKlj22LqgH QoaTflmGl7MB5vtYMVl8RwqyYREaY+y1nhZ0dnub+mP+2ctClFfshsGSTeELWeFr+tDV ufm10HBNefK83/okBT+yaARH3rEVPK5cFXqEo6DmEVXnR8oe101Cs7T/S8XYeJyId5QH wyJA== 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=IVQbwq8yhP5PQL3OKK2a4GH9nPXvJ3QjvK/bhqDJFqE=; b=hFfmphoa3guKdtPU2SdvCVOecLfn6vIdjsBU9OK8sDgp+Hceid7ayN9YasbcjuSbJf qSuS5i1kcQ9jMkdPB//+N1FkSwMw67Al8Da+9WNjpWYivycsT7cjgxeel1uXFCvT6dN5 IqG3pbiGEp4Tx4Bz3HkMH5K3Wkjkagxevg2rPO6xDB9es0BOtRljqAofm4y07mPalLON hdCpD9AbCIMCzK4y0kFr3g9XcRucYUDNg1jsw/imLqQgh1WuaDPSLbmNp6+lk8aoPlvu 0gYz5s+tKIXQ3lJhpiSNXSCMu+vsqkGcWp2O5yyEE3ZkL66cL8uhYCxJRb3yb9HjqJxI anuA== X-Gm-Message-State: AOPr4FUXtJJ/+y/2eIxMTVT66o7osSSA6PYTPOx6pZDMB+yMUKDjLHB/+uhp+/7DgiEa+Q== X-Received: by 10.28.213.137 with SMTP id m131mr9861291wmg.24.1462372185695; Wed, 04 May 2016 07:29:45 -0700 (PDT) Received: from dztty2.localdomain (ip5b42f9c9.dynamic.kabel-deutschland.de. [91.66.249.201]) by smtp.gmail.com with ESMTPSA id a75sm4615505wme.18.2016.05.04.07.29.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 May 2016 07:29:44 -0700 (PDT) From: Djalal Harouni To: Alexander Viro , Chris Mason , , Serge Hallyn , Josh Triplett , "Eric W. Biederman" , Andy Lutomirski , Seth Forshee , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, Dongsu Park , David Herrmann , Miklos Szeredi , Alban Crequy Cc: Djalal Harouni , Djalal Harouni Subject: [RFC v2 PATCH 4/8] VFS:userns: shift UID/GID to virtual view during permission access Date: Wed, 4 May 2016 16:26:50 +0200 Message-Id: <1462372014-3786-5-git-send-email-tixxdz@gmail.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1462372014-3786-1-git-send-email-tixxdz@gmail.com> References: <1462372014-3786-1-git-send-email-tixxdz@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-8.9 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, 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 If both the mount namespace and the mount point support UID/GID shifts, then before doing any permission check, translate inode->{i_uid|i_gid} into the kernel virtual view, then use the result to do the permission checks. If there is no support for UID/GID shifts, we fallback to inode->{i_uid|i_gid} on-disk values. The VFS will shift these values to the virtual view, the result will be used to compare with current's fsuid and fsgid and to perform classic or capable checks. Since inode->{i_uid|i_gid} will always contain the on-disk values we do the virtual translation when an access is needed. This solves the problem of privileged userns or users inside containers that want to access files, but the access fails since VFS uses their global kuid/kgid. Permission checks inside user_ns_X ---------------------------------- Without this Patch: ------------------------------------------------------------------------- inode->uid on Disk | init_user_ns uid | user_ns_X uid | Access ------------------------------------------------------------------------- 0 | 1000000 | 0 (userns root) | Denied ------------------------------------------------------------------------- 999 | 1000999 | 999 | Denied ------------------------------------------------------------------------- 1000 | 1001000 | 1000 | Denied ------------------------------------------------------------------------- 1000 | 1000000 | 0 (userns root CAPS) | Denied ------------------------------------------------------------------------- 0 | 1001000 | 1000 | Denied ------------------------------------------------------------------------- With this patch: -------------------------------------------------------------------------- inode->uid on Disk | init_user_ns uid | user_ns_X uid | Access -------------------------------------------------------------------------- 0 | 1000000 | 0 (userns root) | Granted -------------------------------------------------------------------------- 999 | 1000999 | 999 | Granted -------------------------------------------------------------------------- 1000 | 1001000 | 1000 | Granted -------------------------------------------------------------------------- 1000 | 1000000 | 0 (userns root CAPS) | Granted -------------------------------------------------------------------------- 999 | 1000000 | 0 (userns root CAPS) | Granted -------------------------------------------------------------------------- 0 | 1001000 | 1000 | Denied -------------------------------------------------------------------------- 0 | 1000999 | 999 | Denied -------------------------------------------------------------------------- 1000 | 1000999 | 999 | Denied -------------------------------------------------------------------------- * CAPS: means capabilities, the access was granted due to the capabilities of the caller inside user_ns_X and the shifted UID/GID of the inode are also mapped in that user_ns_X Privileged root user namespaces with uid 0 inside the container will be able to access inodes->i_uid == 0 on-disk if that inode is on a file system that supports VFS UID/GID shifts and the caller is inside a mount namespace that also supports the above. Signed-off-by: Dongsu Park Signed-off-by: Djalal Harouni --- fs/inode.c | 5 +++-- fs/namei.c | 6 ++++-- kernel/capability.c | 14 ++++++++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 69b8b52..07daf5f 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1961,12 +1961,13 @@ EXPORT_SYMBOL(inode_init_owner); bool inode_owner_or_capable(const struct inode *inode) { struct user_namespace *ns; + kuid_t i_uid = vfs_shift_i_uid_to_virtual(inode); - if (uid_eq(current_fsuid(), inode->i_uid)) + if (uid_eq(current_fsuid(), i_uid)) return true; ns = current_user_ns(); - if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, inode->i_uid)) + if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, i_uid)) return true; return false; } diff --git a/fs/namei.c b/fs/namei.c index 1d9ca2d..f7ee498 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -289,8 +289,10 @@ static int check_acl(struct inode *inode, int mask) static int acl_permission_check(struct inode *inode, int mask) { unsigned int mode = inode->i_mode; + kuid_t i_uid = vfs_shift_i_uid_to_virtual(inode); + kgid_t i_gid = vfs_shift_i_gid_to_virtual(inode); - if (likely(uid_eq(current_fsuid(), inode->i_uid))) + if (likely(uid_eq(current_fsuid(), i_uid))) mode >>= 6; else { if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { @@ -299,7 +301,7 @@ static int acl_permission_check(struct inode *inode, int mask) return error; } - if (in_group_p(inode->i_gid)) + if (in_group_p(i_gid)) mode >>= 3; } diff --git a/kernel/capability.c b/kernel/capability.c index 45432b5..fdc8afb 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -441,9 +441,19 @@ EXPORT_SYMBOL(file_ns_capable); */ bool capable_wrt_inode_uidgid(const struct inode *inode, int cap) { + kuid_t i_uid; + kgid_t i_gid; struct user_namespace *ns = current_user_ns(); - return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) && - kgid_has_mapping(ns, inode->i_gid); + /* + * Check if inode's UID/GID are mean to be shifted into the current + * mount namespace, if so we use the result to check if the shifted + * UID/GID have a mapping in current's user namespace. + */ + i_uid = vfs_shift_i_uid_to_virtual(inode); + i_gid = vfs_shift_i_gid_to_virtual(inode); + + return ns_capable(ns, cap) && kuid_has_mapping(ns, i_uid) && + kgid_has_mapping(ns, i_gid); } EXPORT_SYMBOL(capable_wrt_inode_uidgid);