Received: by 2002:a05:7412:419a:b0:f3:1519:9f41 with SMTP id i26csp4890183rdh; Wed, 29 Nov 2023 13:52:02 -0800 (PST) X-Google-Smtp-Source: AGHT+IE6NJxeuM10FsBxLKSEWrxHoDAT9E1zXJ3hf3e3IHDjlwOVD5BGVhEi4ih+fPSg4xIS+TlY X-Received: by 2002:a17:90a:d152:b0:280:29df:747e with SMTP id t18-20020a17090ad15200b0028029df747emr32142229pjw.1.1701294722383; Wed, 29 Nov 2023 13:52:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1701294722; cv=none; d=google.com; s=arc-20160816; b=rj9NFzQkdM9UMe564iiQM1+37gn02VhA1QRDXaow4eKuqSu82P6x6soEHbAIH+Vhw3 lTi58KttacaCnM+92PivFkk//r5X3pL9/Kl6T8mqHynAfIw1VEf2oRakjgVZz1FDWZFD ZPhWCOjqMW1+rHOAkvGyOOfINJuRmCgBSmhw0hMaf0QN4xGHKHKYDTROtEFPCMXkNHPl vuBmnLQKzGrp4sPY7HmcwnJYCFBHaVWRK1PMaKvc+yA7XbTDxS59J1eSXOgCFyZ2g7nq 0l2ZAqDGQn3rNbSYvRRTs7AaASX+D0btZyn2n4PoftptCLtmC74E0sHxxoqjTPD6Ivme wWYA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=gJfsJcaPt1V0dxGW2ecGymT3LDle7gIqI9NZcQd0Xt8=; fh=4HVRO6f3g8DInYYG3BlLnBn0oEBT/lWvUFCM3YKQyDw=; b=mJ03e7CKWXtmJbxwEFYQi10WuF3C9jOZhsmHJBVQhokEQz7kZKEMj6mJIuALL3O7Oj o722uCijiv7ZYQsvMECZyzvl0crpRGTbuhy5Vvwh9sUVwfqgdlSgxkJLY0iYgdJb4x2u FZ0tncal3BT7HoZsai+1z2QSiSxshqOnWgkB/cVuN1XkWaByvqQgoEVvR91E90W6HwGQ wv0xUu1zgLDwcrfGJ52ELQFvOd/rPjdW0Q+B3wWf4nNzhyue1bWvUXvcfeBmc26o4DYc S2phF//5hUhTAfZ4/XHgpNk4B5VAXitGiGnyy8TaVx/p8hmvTBNaXrV5RQV+ukommEsW J8zA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=EOaZfNhq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from lipwig.vger.email (lipwig.vger.email. [23.128.96.33]) by mx.google.com with ESMTPS id p2-20020a17090a868200b00285e7d48fdesi2093157pjn.4.2023.11.29.13.52.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Nov 2023 13:52:02 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) client-ip=23.128.96.33; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=EOaZfNhq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by lipwig.vger.email (Postfix) with ESMTP id B5D8A8032A37; Wed, 29 Nov 2023 13:51:56 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at lipwig.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343490AbjK2Vvf (ORCPT + 99 others); Wed, 29 Nov 2023 16:51:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46464 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234525AbjK2Vuy (ORCPT ); Wed, 29 Nov 2023 16:50:54 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5525F10CB for ; Wed, 29 Nov 2023 13:51:00 -0800 (PST) Received: by smtp.kernel.org (Postfix) with ESMTPS id 215A3C433C7; Wed, 29 Nov 2023 21:50:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1701294658; bh=2HiADlLvgGW720oIUK6woDmD2V9EI+/r0VTeM20LPPs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=EOaZfNhqvhlO8BZ4PLdI0JgXRNglutJeDpDR46JAPYU7frD9BNZA0I4AOCKObzayW GCwsJvfneErUDdYut0s8slvX2MRREyyu7kla6KAGaGpbjp/4vCi25bbnh7t4SAyiLr M+hlrB6h+IS6N+vB1UyUQ/LjxMjwrXk3DMqgp4dx7JXYqrzMoZ6jcaEGVRLJ11ElPv LBPPPqyACX6l0ay8zeu2VL+3fGGWMtaW2tZohzQPmaJKlo2VxdFh/eKRysVqanoiPN sfGTuWmq8HeFfnwr1v3QuplABP1yvb7Gdx/9GYFZY0XV3+Ge7Aa1+88eYIyxvi6xzF qe14FbjluFU4A== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 13130C07CB1; Wed, 29 Nov 2023 21:50:58 +0000 (UTC) From: "Seth Forshee (DigitalOcean)" Date: Wed, 29 Nov 2023 15:50:31 -0600 Subject: [PATCH 13/16] fs: use vfs interfaces for capabilities xattrs MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20231129-idmap-fscap-refactor-v1-13-da5a26058a5b@kernel.org> References: <20231129-idmap-fscap-refactor-v1-0-da5a26058a5b@kernel.org> In-Reply-To: <20231129-idmap-fscap-refactor-v1-0-da5a26058a5b@kernel.org> To: Christian Brauner , Serge Hallyn , Paul Moore , Eric Paris , James Morris , Alexander Viro , Miklos Szeredi , Amir Goldstein Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-security-module@vger.kernel.org, audit@vger.kernel.org, linux-unionfs@vger.kernel.org, "Seth Forshee (DigitalOcean)" X-Mailer: b4 0.12.4 X-Developer-Signature: v=1; a=openpgp-sha256; l=8524; i=sforshee@kernel.org; h=from:subject:message-id; bh=2HiADlLvgGW720oIUK6woDmD2V9EI+/r0VTeM20LPPs=; =?utf-8?q?b=3DowEBbQGS/pANAwAKAVMDma7l9DHJAcsmYgBlZ7I84eoLP86nEuxsd0EOX/Og5?= =?utf-8?q?0rHT0ZAzT63Z49r_9RiM2oOJATMEAAEKAB0WIQSQnt+rKAvnETy4Hc9TA5mu5fQxy?= =?utf-8?q?QUCZWeyPAAKCRBTA5mu5fQxyZhyB/_9gYYIbkYFa10api1PrNd0MoEaeKZ/aJybzo?= =?utf-8?q?VQjHKThBmpvtRrAxol4IrKQr4Gruq6rBfw62ZdbflNs_AgQHicVr/QIC6zxyar2Vo?= =?utf-8?q?a6KkLhLKnAajluGF6ghiJG+gkoOd+qRPX6HmmOfUH8ge7hAK+ils71Wdb_emuoGBO?= =?utf-8?q?u7J4L1641adZs1rEEfEBzVhPAT/2lPD2rvpco0QupuBPFU9ty3XyQdtRF6Gb3vuxF?= =?utf-8?q?UnGWzm_rkoNeZCp6VhQkcEpsCQ6nF8ypGwiTXGUsf6+aJy1+LK/gsgNSq519SdLiQ?= =?utf-8?q?0i5VlzDTtQOb4qIHrm6/?= QazLsgiYauqobTgzmjki+Qj658voFS X-Developer-Key: i=sforshee@kernel.org; a=openpgp; fpr=2ABCA7498D83E1D32D51D3B5AB4800A62DB9F73A X-Endpoint-Received: by B4 Relay for sforshee@kernel.org/default with auth_id=103 X-Spam-Status: No, score=-1.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lipwig.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (lipwig.vger.email [0.0.0.0]); Wed, 29 Nov 2023 13:51:56 -0800 (PST) Now that all the plumbing is in place, switch over to using the new inode operations to get/set fs caps. This pushes all mapping of ids into the caller's user ns to above the vfs_*() level, making this consistent with other vfs_*() interfaces. cap_convert_nscap() is updated to return vfs_caps and moved to be called from the new code path for setting fscaps. This means that use of vfs_setxattr() will no longer remap ids in fscap xattrs, but all code which used vfs_setxattr() for fscaps xattrs has been converted to the new interfaces. Removing the mapping of fscaps rootids from vfs_getxattr() is more invovled and will be addressed in a later commit. Signed-off-by: Seth Forshee (DigitalOcean) --- fs/xattr.c | 49 ++++++++++++++++++++++++---- include/linux/capability.h | 2 +- security/commoncap.c | 79 +++++++++++++++------------------------------- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/fs/xattr.c b/fs/xattr.c index f60ef2a79dfa..372644b15457 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -540,13 +540,6 @@ vfs_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, const void *orig_value = value; int error; - if (size && strcmp(name, XATTR_NAME_CAPS) == 0) { - error = cap_convert_nscap(idmap, dentry, &value, size); - if (error < 0) - return error; - size = error; - } - retry_deleg: inode_lock(inode); error = __vfs_setxattr_locked(idmap, dentry, name, value, size, @@ -857,6 +850,24 @@ int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, return do_set_acl(idmap, dentry, ctx->kname->name, ctx->kvalue, ctx->size); + if (strcmp(ctx->kname->name, XATTR_NAME_CAPS) == 0) { + struct vfs_caps caps; + int ret; + + /* + * rootid is already in the mount idmap, so pass nop_mnt_idmap + * so that it won't be mapped. + */ + ret = vfs_caps_from_xattr(&nop_mnt_idmap, current_user_ns(), + &caps, ctx->kvalue, ctx->size); + if (ret) + return ret; + ret = cap_convert_nscap(idmap, dentry, &caps); + if (ret) + return ret; + return vfs_set_fscaps(idmap, dentry, &caps, ctx->flags); + } + return vfs_setxattr(idmap, dentry, ctx->kname->name, ctx->kvalue, ctx->size, ctx->flags); } @@ -955,6 +966,27 @@ do_getxattr(struct mnt_idmap *idmap, struct dentry *d, ssize_t error; char *kname = ctx->kname->name; + if (strcmp(kname, XATTR_NAME_CAPS) == 0) { + struct vfs_caps caps; + struct vfs_ns_cap_data data; + int ret; + + ret = vfs_get_fscaps(idmap, d, &caps); + if (ret) + return ret; + /* + * rootid is already in the mount idmap, so pass nop_mnt_idmap + * so that it won't be mapped. + */ + ret = vfs_caps_to_user_xattr(&nop_mnt_idmap, current_user_ns(), + &caps, &data, ctx->size); + if (ret < 0) + return ret; + if (ctx->size && copy_to_user(ctx->value, &data, ret)) + return -EFAULT; + return ret; + } + if (ctx->size) { if (ctx->size > XATTR_SIZE_MAX) ctx->size = XATTR_SIZE_MAX; @@ -1145,6 +1177,9 @@ removexattr(struct mnt_idmap *idmap, struct dentry *d, if (is_posix_acl_xattr(kname)) return vfs_remove_acl(idmap, d, kname); + if (strcmp(kname, XATTR_NAME_CAPS) == 0) + return vfs_remove_fscaps(idmap, d); + return vfs_removexattr(idmap, d, kname); } diff --git a/include/linux/capability.h b/include/linux/capability.h index c0bd9447685b..563f084e9453 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -229,6 +229,6 @@ int get_vfs_caps_from_disk(struct mnt_idmap *idmap, struct vfs_caps *cpu_caps); int cap_convert_nscap(struct mnt_idmap *idmap, struct dentry *dentry, - const void **ivalue, size_t size); + struct vfs_caps *caps); #endif /* !_LINUX_CAPABILITY_H */ diff --git a/security/commoncap.c b/security/commoncap.c index c645330f83a0..bd95b806af2f 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -484,27 +484,21 @@ int cap_inode_getsecurity(struct mnt_idmap *idmap, } /** - * rootid_from_xattr - translate root uid of vfs caps + * rootid_from_vfs_caps - translate root uid of vfs caps * - * @value: vfs caps value which may be modified by this function - * @size: size of @ivalue + * @caps: vfs caps value which may be modified by this function * @task_ns: user namespace of the caller + * + * Return the rootid from a v3 fs cap, or the id of root in the task's user + * namespace for v1 and v2 fs caps. */ -static vfsuid_t rootid_from_xattr(const void *value, size_t size, - struct user_namespace *task_ns) +static vfsuid_t rootid_from_vfs_caps(const struct vfs_caps *caps, + struct user_namespace *task_ns) { - const struct vfs_ns_cap_data *nscap = value; - uid_t rootid = 0; - - if (size == XATTR_CAPS_SZ_3) - rootid = le32_to_cpu(nscap->rootid); - - return VFSUIDT_INIT(make_kuid(task_ns, rootid)); -} + if ((caps->magic_etc & VFS_CAP_REVISION_MASK) == VFS_CAP_REVISION_3) + return caps->rootid; -static bool validheader(size_t size, const struct vfs_cap_data *cap) -{ - return is_v2header(size, cap) || is_v3header(size, cap); + return VFSUIDT_INIT(make_kuid(task_ns, 0)); } /** @@ -512,11 +506,10 @@ static bool validheader(size_t size, const struct vfs_cap_data *cap) * * @idmap: idmap of the mount the inode was found from * @dentry: used to retrieve inode to check permissions on - * @ivalue: vfs caps value which may be modified by this function - * @size: size of @ivalue + * @caps: vfs caps which may be modified by this function * - * User requested a write of security.capability. If needed, update the - * xattr to change from v2 to v3, or to fixup the v3 rootid. + * User requested a write of security.capability. Check permissions, and if + * needed, update the xattr to change from v2 to v3. * * If the inode has been found through an idmapped mount the idmap of * the vfsmount must be passed through @idmap. This function will then @@ -524,59 +517,39 @@ static bool validheader(size_t size, const struct vfs_cap_data *cap) * permissions. On non-idmapped mounts or if permission checking is to be * performed on the raw inode simply pass @nop_mnt_idmap. * - * Return: On success, return the new size; on error, return < 0. + * Return: On success, return 0; on error, return < 0. */ int cap_convert_nscap(struct mnt_idmap *idmap, struct dentry *dentry, - const void **ivalue, size_t size) + struct vfs_caps *caps) { - struct vfs_ns_cap_data *nscap; - uid_t nsrootid; - const struct vfs_cap_data *cap = *ivalue; - __u32 magic, nsmagic; struct inode *inode = d_backing_inode(dentry); struct user_namespace *task_ns = current_user_ns(), *fs_ns = inode->i_sb->s_user_ns; - kuid_t rootid; vfsuid_t vfsrootid; - size_t newsize; + __u32 revision; - if (!*ivalue) - return -EINVAL; - if (!validheader(size, cap)) + revision = sansflags(caps->magic_etc); + if (revision != VFS_CAP_REVISION_2 && revision != VFS_CAP_REVISION_3) return -EINVAL; if (!capable_wrt_inode_uidgid(idmap, inode, CAP_SETFCAP)) return -EPERM; - if (size == XATTR_CAPS_SZ_2 && (idmap == &nop_mnt_idmap)) + if (revision == VFS_CAP_REVISION_2 && (idmap == &nop_mnt_idmap)) if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP)) /* user is privileged, just write the v2 */ - return size; + return 0; - vfsrootid = rootid_from_xattr(*ivalue, size, task_ns); + vfsrootid = rootid_from_vfs_caps(caps, task_ns); if (!vfsuid_valid(vfsrootid)) return -EINVAL; - rootid = from_vfsuid(idmap, fs_ns, vfsrootid); - if (!uid_valid(rootid)) + if (!vfsuid_has_fsmapping(idmap, fs_ns, vfsrootid)) return -EINVAL; - nsrootid = from_kuid(fs_ns, rootid); - if (nsrootid == -1) - return -EINVAL; + caps->rootid = vfsrootid; + caps->magic_etc = VFS_CAP_REVISION_3 | + (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE); - newsize = sizeof(struct vfs_ns_cap_data); - nscap = kmalloc(newsize, GFP_ATOMIC); - if (!nscap) - return -ENOMEM; - nscap->rootid = cpu_to_le32(nsrootid); - nsmagic = VFS_CAP_REVISION_3; - magic = le32_to_cpu(cap->magic_etc); - if (magic & VFS_CAP_FLAGS_EFFECTIVE) - nsmagic |= VFS_CAP_FLAGS_EFFECTIVE; - nscap->magic_etc = cpu_to_le32(nsmagic); - memcpy(&nscap->data, &cap->data, sizeof(__le32) * 2 * VFS_CAP_U32); - - *ivalue = nscap; - return newsize; + return 0; } /* -- 2.43.0