Message ID | 20240221-idmap-fscap-refactor-v2-24-3039364623bd@kernel.org |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-75545-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:693c:2685:b0:108:e6aa:91d0 with SMTP id mn5csp1314986dyc; Wed, 21 Feb 2024 13:46:43 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCWn+14LpycVPFjP8axl4dK18XKK+B2ulgBjCWel51C2Ibnq7Md+4wWnK8trDc5AT0PbsCLg8At8IoVVWgD0DO96+lWhKA== X-Google-Smtp-Source: AGHT+IHJ0Rh4AtSH41OVD3L1Pbqcz4oWh9qZY7vMttge/8o9W7MKkePEpYQ7FReYh/PkZhdPAnbx X-Received: by 2002:a17:902:d48e:b0:1dc:1e7c:6dd4 with SMTP id c14-20020a170902d48e00b001dc1e7c6dd4mr6781467plg.68.1708552003418; Wed, 21 Feb 2024 13:46:43 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1708552003; cv=pass; d=google.com; s=arc-20160816; b=MkYAKrhT8bgjnjpHAFL/0q8FmlyTo5ydNtY/qcG4JAKTk9h63vmnhjSiTHsiT4S5Xj T1Bi2m5ZQGGOCe/DqboQ61nuJuxLgpkt6iL738KGIqXjhBIzAOmnXreBFbMsgwRVNtxn 0JwFVcc4GjMmP7BOvyO8HMlcGPc+cI09yLGQEFJgEZGqxR2vDuUjlbVbLmxCosUeY8dS ufnJ24pEEOoC0HSatpKXJJRAkT+Gptto2UdCH0Z/QrA4355P1Kx17//mHdj2KzyrdasF i/2gwHc5UV27EJENWFL78mU4v0iWdGDEZJV/9uWpoG6aUjBwSzzfCROwnRPuQ058RBII b2Ww== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from:dkim-signature; bh=U41+CaG3SJ34szpRIDOot4FEUYppHGvei22FBnSTrKw=; fh=hxP78V52DM11AQyZLnuoXzboSedtf373GjK953393po=; b=h4rh6VDSuxx2Nf0ujL/9SDjBwSWnED9YbjI5dweEAuFbaJFwJSeswlxUjzql+Jc9NK LIFdBmfkehSYzR25QfRNRnE4Y2MoeGEEnHcozI3yp7x2e8jnwP20Lh5rPMhqTBjIY9Hd Oub7ZBqCyABqIqvGBQTukfeQL6crUW1spDxwVdsM2Anjvpu+s7igAJmPUYNlD9mYUfQt gxao4B4jtR+4I9d0kVSPiiAAArvVt5of0+/GtWAXPwLu0oHF51FOYpI5XqAasawVSwLo I+2ESc6vzlfzeth9FvlDt+Ei7XcuoBegrENzLkoyjaoTyBPrq7kr9ccoeWf7uoLR9Wlo 0hzg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=SKRsQRoc; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-75545-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-75545-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [147.75.48.161]) by mx.google.com with ESMTPS id y22-20020a17090264d600b001dbe268a07fsi6817085pli.16.2024.02.21.13.46.43 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Feb 2024 13:46:43 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-75545-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) client-ip=147.75.48.161; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=SKRsQRoc; arc=pass (i=1 dkim=pass dkdomain=kernel.org); spf=pass (google.com: domain of linux-kernel+bounces-75545-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-75545-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id D5D45B28F07 for <ouuuleilei@gmail.com>; Wed, 21 Feb 2024 21:35:29 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9111D158D99; Wed, 21 Feb 2024 21:25:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SKRsQRoc" Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B1C9F12F5B3; Wed, 21 Feb 2024 21:25:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708550707; cv=none; b=hCfJhxaFG5Tfcfr1kq1ZVLI8znJ1I9RlfwmnwyVIz+ZRmCTNFWiI/2xDU11RPmDK2QRUXgwW3tOBIPeeZE0mlR5bvBgQJWHXyA8ZOeUs2vOZWNJocxJKESkoF3bFoIhlLWRSaPGjvi4OfpQfXsi8sDbWafWpjGGuY4okn47xoY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708550707; c=relaxed/simple; bh=zvbUblF/TCnxaSxVn34c8qD/M35GRlC4hQ2KeRAG42o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pwPR5pnB80Y05/NSyV+T8CCBnRtFql7ZOv/ahG5Q9dq4JW8KOI24P7/Ef0uyEd3DXWUIxFiseOg7K7F7Iy2QWu6bbxszunBI3zOazP4WDlafHkzXNx9iQbBsA92GWNvisEuQunS2R5v/n1uuDlR96uAqJkoY9iL48humC5nlxec= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SKRsQRoc; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPS id 68AF3C4160D; Wed, 21 Feb 2024 21:25:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708550707; bh=zvbUblF/TCnxaSxVn34c8qD/M35GRlC4hQ2KeRAG42o=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=SKRsQRocESZKds2vMmzDujSVC0SaK+TPB9iVo2XR4q47+NE6qs231rq9rzz933lJ5 oPVzUdevmGiNU9XRdwvvFnMaFD1ajdUz3cg/gsMYIk9Y4aVeS3vFCAjku65uyfG3Do su9OTtRzMfobX+5JdtwaJjMHr4k49WoRZY4SgkF52OWD63ZsSUUvHJwPlsmICJ0ahH 8fBe0zR8kwd0wtnJ+mqSGj9Nl2YRaen+lV7gGxd0aD7DA6IXBiQK4WRRkOw5QmwAUc jcxuZZAtzdHfaz3fHsCRfBb4H0Im2TZYioWp185DZbzBfKIhCVqwcm/1bwCa6TUEtB ePUEa8FJldjMA== 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 53EA3C5478C; Wed, 21 Feb 2024 21:25:07 +0000 (UTC) From: "Seth Forshee (DigitalOcean)" <sforshee@kernel.org> Date: Wed, 21 Feb 2024 15:24:55 -0600 Subject: [PATCH v2 24/25] commoncap: use vfs fscaps interfaces Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20240221-idmap-fscap-refactor-v2-24-3039364623bd@kernel.org> References: <20240221-idmap-fscap-refactor-v2-0-3039364623bd@kernel.org> In-Reply-To: <20240221-idmap-fscap-refactor-v2-0-3039364623bd@kernel.org> To: Christian Brauner <brauner@kernel.org>, Seth Forshee <sforshee@kernel.org>, Serge Hallyn <serge@hallyn.com>, Paul Moore <paul@paul-moore.com>, Eric Paris <eparis@redhat.com>, James Morris <jmorris@namei.org>, Alexander Viro <viro@zeniv.linux.org.uk>, Jan Kara <jack@suse.cz>, Stephen Smalley <stephen.smalley.work@gmail.com>, Ondrej Mosnacek <omosnace@redhat.com>, Casey Schaufler <casey@schaufler-ca.com>, Mimi Zohar <zohar@linux.ibm.com>, Roberto Sassu <roberto.sassu@huawei.com>, Dmitry Kasatkin <dmitry.kasatkin@gmail.com>, Eric Snowberg <eric.snowberg@oracle.com>, "Matthew Wilcox (Oracle)" <willy@infradead.org>, Jonathan Corbet <corbet@lwn.net>, Miklos Szeredi <miklos@szeredi.hu>, Amir Goldstein <amir73il@gmail.com> Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-security-module@vger.kernel.org, audit@vger.kernel.org, selinux@vger.kernel.org, linux-integrity@vger.kernel.org, linux-doc@vger.kernel.org, linux-unionfs@vger.kernel.org X-Mailer: b4 0.12.4 X-Developer-Signature: v=1; a=openpgp-sha256; l=2792; i=sforshee@kernel.org; h=from:subject:message-id; bh=zvbUblF/TCnxaSxVn34c8qD/M35GRlC4hQ2KeRAG42o=; =?utf-8?q?b=3DowEBbQGS/pANAwAKAVMDma7l9DHJAcsmYgBl1motMsHmTPRzonCbUf17MUmkA?= =?utf-8?q?trgRQQP52t1limF_xnRCVamJATMEAAEKAB0WIQSQnt+rKAvnETy4Hc9TA5mu5fQxy?= =?utf-8?q?QUCZdZqLQAKCRBTA5mu5fQxySjhB/_9/xvaR6j6ROnXfKTxmKnKxnszhmNMXT1obo?= =?utf-8?q?WqLVttCDoIEShnCN3jNsyIpALo6DQpAxED7nadYlW2F_vDcaQlOVAqpLDZExtPdSn?= =?utf-8?q?IAd61AuZiTbo96dmmNv46xSZbKz4YFtYStNCCynSuEuJ6T5hDfXI8ZC7l_D++5+5X?= =?utf-8?q?5lQSz00p/UyCKeSsMVATo8TLtwEQ0z6Z+55owxbqadtCXLzeeT9jYnv43ixJny2K5?= =?utf-8?q?DFwAT/_ONWSTYt66Dh/JR/D5nJ8mlOrqPvXlnOYpONu68LvMfAd5c3IWAYp3NeQYi?= =?utf-8?q?6GFXjBbQuE0sXInhC7rb?= xFOguuTz0t3YgEiStWMwzbqX0R1zY8 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-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1791546625386912610 X-GMAIL-MSGID: 1791546625386912610 |
Series |
fs: use type-safe uid representation for filesystem capabilities
|
|
Commit Message
Seth Forshee (DigitalOcean)
Feb. 21, 2024, 9:24 p.m. UTC
Use the vfs interfaces for fetching file capabilities for killpriv
checks and from get_vfs_caps_from_disk(). While there, update the
kerneldoc for get_vfs_caps_from_disk() to explain how it is different
from vfs_get_fscaps_nosec().
Signed-off-by: Seth Forshee (DigitalOcean) <sforshee@kernel.org>
---
security/commoncap.c | 30 +++++++++++++-----------------
1 file changed, 13 insertions(+), 17 deletions(-)
Comments
On Wed, 2024-02-21 at 15:24 -0600, Seth Forshee (DigitalOcean) wrote: > Use the vfs interfaces for fetching file capabilities for killpriv > checks and from get_vfs_caps_from_disk(). While there, update the > kerneldoc for get_vfs_caps_from_disk() to explain how it is different > from vfs_get_fscaps_nosec(). > > Signed-off-by: Seth Forshee (DigitalOcean) <sforshee@kernel.org> > --- > security/commoncap.c | 30 +++++++++++++----------------- > 1 file changed, 13 insertions(+), 17 deletions(-) > > diff --git a/security/commoncap.c b/security/commoncap.c > index a0ff7e6092e0..751bb26a06a6 100644 > --- a/security/commoncap.c > +++ b/security/commoncap.c > @@ -296,11 +296,12 @@ int cap_capset(struct cred *new, > */ > int cap_inode_need_killpriv(struct dentry *dentry) > { > - struct inode *inode = d_backing_inode(dentry); > + struct vfs_caps caps; > int error; > > - error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0); > - return error > 0; > + /* Use nop_mnt_idmap for no mapping here as mapping is unimportant */ > + error = vfs_get_fscaps_nosec(&nop_mnt_idmap, dentry, &caps); > + return error == 0; > } > > /** > @@ -323,7 +324,7 @@ int cap_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry) > { > int error; > > - error = __vfs_removexattr(idmap, dentry, XATTR_NAME_CAPS); > + error = vfs_remove_fscaps_nosec(idmap, dentry); Uhm, I see that the change is logically correct... but the original code was not correct, since the EVM post hook is not called (thus the HMAC is broken, or an xattr change is allowed on a portable signature which should be not). For completeness, the xattr change on a portable signature should not happen in the first place, so cap_inode_killpriv() would not be called. However, since EVM allows same value change, we are here. Here is how I discovered this problem. Example: # ls -l test-file -rw-r-Sr--. 1 3001 3001 5 Mar 4 10:11 test-file # getfattr -m - -d -e hex test-file # file: test-file security.capability=0x0100000202300000023000000000000000000000 security.evm=0x05020498c82b5300663064023052a1aa6200d08b3db60a1c636b97b52658af369ee0bf521cfca6c733671ebf5764b1b122f67030cfc688a111c19a7ed3023039895966cf92217ea55c1405212ced1396c2d830ae55dbdb517c5d199c5a43638f90d430bad48191149dcc7c01f772ac security.ima=0x0404f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2 security.selinux=0x756e636f6e66696e65645f753a6f626a6563745f723a756e6c6162656c65645f743a733000 # chown 3001 test-file # ls -l test-file -rw-r-Sr--. 1 3001 3001 5 Mar 4 10:14 test-file # getfattr -m - -d -e hex test-file # file: test-file security.evm=0x05020498c82b5300673065023100cdd772fa7f9c17aa66e654c7f9c124de1ccfd36abbe5b8100b64a296164da45d0025fd2a2dec2e9580d5c82e5a32bfca02305ea3458b74e53d743408f65e748dc6ee52964e3aedac7367a43080248f4e000c655eb8e1f4338becb81797ea37f0bca6 security.ima=0x0404f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2 security.selinux=0x756e636f6e66696e65645f753a6f626a6563745f723a756e6c6162656c65645f743a733000 which breaks EVM verification. Roberto > if (error == -EOPNOTSUPP) > error = 0; > return error; > @@ -719,6 +720,10 @@ ssize_t vfs_caps_to_user_xattr(struct mnt_idmap *idmap, > * @cpu_caps: vfs capabilities > * > * Extract the on-exec-apply capability sets for an executable file. > + * For version 3 capabilities xattrs, returns the capabilities only if > + * they are applicable to current_user_ns() (i.e. that the rootid > + * corresponds to an ID which maps to ID 0 in current_user_ns() or an > + * ancestor), and returns -ENODATA otherwise. > * > * If the inode has been found through an idmapped mount the idmap of > * the vfsmount must be passed through @idmap. This function will then > @@ -731,25 +736,16 @@ int get_vfs_caps_from_disk(struct mnt_idmap *idmap, > struct vfs_caps *cpu_caps) > { > struct inode *inode = d_backing_inode(dentry); > - int size, ret; > - struct vfs_ns_cap_data data, *nscaps = &data; > + int ret; > > if (!inode) > return -ENODATA; > > - size = __vfs_getxattr((struct dentry *)dentry, inode, > - XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ); > - if (size == -ENODATA || size == -EOPNOTSUPP) > + ret = vfs_get_fscaps_nosec(idmap, (struct dentry *)dentry, cpu_caps); > + if (ret == -EOPNOTSUPP || ret == -EOVERFLOW) > /* no data, that's ok */ > - return -ENODATA; > + ret = -ENODATA; > > - if (size < 0) > - return size; > - > - ret = vfs_caps_from_xattr(idmap, inode->i_sb->s_user_ns, > - cpu_caps, nscaps, size); > - if (ret == -EOVERFLOW) > - return -ENODATA; > if (ret) > return ret; > >
On Mon, Mar 04, 2024 at 11:19:54AM +0100, Roberto Sassu wrote: > On Wed, 2024-02-21 at 15:24 -0600, Seth Forshee (DigitalOcean) wrote: > > Use the vfs interfaces for fetching file capabilities for killpriv > > checks and from get_vfs_caps_from_disk(). While there, update the > > kerneldoc for get_vfs_caps_from_disk() to explain how it is different > > from vfs_get_fscaps_nosec(). > > > > Signed-off-by: Seth Forshee (DigitalOcean) <sforshee@kernel.org> > > --- > > security/commoncap.c | 30 +++++++++++++----------------- > > 1 file changed, 13 insertions(+), 17 deletions(-) > > > > diff --git a/security/commoncap.c b/security/commoncap.c > > index a0ff7e6092e0..751bb26a06a6 100644 > > --- a/security/commoncap.c > > +++ b/security/commoncap.c > > @@ -296,11 +296,12 @@ int cap_capset(struct cred *new, > > */ > > int cap_inode_need_killpriv(struct dentry *dentry) > > { > > - struct inode *inode = d_backing_inode(dentry); > > + struct vfs_caps caps; > > int error; > > > > - error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0); > > - return error > 0; > > + /* Use nop_mnt_idmap for no mapping here as mapping is unimportant */ > > + error = vfs_get_fscaps_nosec(&nop_mnt_idmap, dentry, &caps); > > + return error == 0; > > } > > > > /** > > @@ -323,7 +324,7 @@ int cap_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry) > > { > > int error; > > > > - error = __vfs_removexattr(idmap, dentry, XATTR_NAME_CAPS); > > + error = vfs_remove_fscaps_nosec(idmap, dentry); > > Uhm, I see that the change is logically correct... but the original > code was not correct, since the EVM post hook is not called (thus the > HMAC is broken, or an xattr change is allowed on a portable signature > which should be not). > > For completeness, the xattr change on a portable signature should not > happen in the first place, so cap_inode_killpriv() would not be called. > However, since EVM allows same value change, we are here. I really don't understand EVM that well and am pretty hesitant to try an change any of the logic around it. But I'll hazard a thought: should EVM have a inode_need_killpriv hook which returns an error in this situation?
On Mon, 2024-03-04 at 09:31 -0600, Seth Forshee (DigitalOcean) wrote: > On Mon, Mar 04, 2024 at 11:19:54AM +0100, Roberto Sassu wrote: > > On Wed, 2024-02-21 at 15:24 -0600, Seth Forshee (DigitalOcean) wrote: > > > Use the vfs interfaces for fetching file capabilities for killpriv > > > checks and from get_vfs_caps_from_disk(). While there, update the > > > kerneldoc for get_vfs_caps_from_disk() to explain how it is different > > > from vfs_get_fscaps_nosec(). > > > > > > Signed-off-by: Seth Forshee (DigitalOcean) <sforshee@kernel.org> > > > --- > > > security/commoncap.c | 30 +++++++++++++----------------- > > > 1 file changed, 13 insertions(+), 17 deletions(-) > > > > > > diff --git a/security/commoncap.c b/security/commoncap.c > > > index a0ff7e6092e0..751bb26a06a6 100644 > > > --- a/security/commoncap.c > > > +++ b/security/commoncap.c > > > @@ -296,11 +296,12 @@ int cap_capset(struct cred *new, > > > */ > > > int cap_inode_need_killpriv(struct dentry *dentry) > > > { > > > - struct inode *inode = d_backing_inode(dentry); > > > + struct vfs_caps caps; > > > int error; > > > > > > - error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0); > > > - return error > 0; > > > + /* Use nop_mnt_idmap for no mapping here as mapping is unimportant */ > > > + error = vfs_get_fscaps_nosec(&nop_mnt_idmap, dentry, &caps); > > > + return error == 0; > > > } > > > > > > /** > > > @@ -323,7 +324,7 @@ int cap_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry) > > > { > > > int error; > > > > > > - error = __vfs_removexattr(idmap, dentry, XATTR_NAME_CAPS); > > > + error = vfs_remove_fscaps_nosec(idmap, dentry); > > > > Uhm, I see that the change is logically correct... but the original > > code was not correct, since the EVM post hook is not called (thus the > > HMAC is broken, or an xattr change is allowed on a portable signature > > which should be not). > > > > For completeness, the xattr change on a portable signature should not > > happen in the first place, so cap_inode_killpriv() would not be called. > > However, since EVM allows same value change, we are here. > > I really don't understand EVM that well and am pretty hesitant to try an > change any of the logic around it. But I'll hazard a thought: should EVM > have a inode_need_killpriv hook which returns an error in this > situation? Uhm, I think it would not work without modifying security_inode_need_killpriv() and the hook definition. Since cap_inode_need_killpriv() returns 1, the loop stops and EVM would not be invoked. We would need to continue the loop and let EVM know what is the current return value. Then EVM can reject the change. An alternative way would be to detect that actually we are setting the same value for inode metadata, and maybe not returning 1 from cap_inode_need_killpriv(). I would prefer the second, since EVM allows same value change and we would have an exception if there are fscaps. This solves only the case of portable signatures. We would need to change cap_inode_need_killpriv() anyway to update the HMAC for mutable files. Roberto
On Mon, Mar 04, 2024 at 05:17:57PM +0100, Roberto Sassu wrote: > On Mon, 2024-03-04 at 09:31 -0600, Seth Forshee (DigitalOcean) wrote: > > On Mon, Mar 04, 2024 at 11:19:54AM +0100, Roberto Sassu wrote: > > > On Wed, 2024-02-21 at 15:24 -0600, Seth Forshee (DigitalOcean) wrote: > > > > Use the vfs interfaces for fetching file capabilities for killpriv > > > > checks and from get_vfs_caps_from_disk(). While there, update the > > > > kerneldoc for get_vfs_caps_from_disk() to explain how it is different > > > > from vfs_get_fscaps_nosec(). > > > > > > > > Signed-off-by: Seth Forshee (DigitalOcean) <sforshee@kernel.org> > > > > --- > > > > security/commoncap.c | 30 +++++++++++++----------------- > > > > 1 file changed, 13 insertions(+), 17 deletions(-) > > > > > > > > diff --git a/security/commoncap.c b/security/commoncap.c > > > > index a0ff7e6092e0..751bb26a06a6 100644 > > > > --- a/security/commoncap.c > > > > +++ b/security/commoncap.c > > > > @@ -296,11 +296,12 @@ int cap_capset(struct cred *new, > > > > */ > > > > int cap_inode_need_killpriv(struct dentry *dentry) > > > > { > > > > - struct inode *inode = d_backing_inode(dentry); > > > > + struct vfs_caps caps; > > > > int error; > > > > > > > > - error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0); > > > > - return error > 0; > > > > + /* Use nop_mnt_idmap for no mapping here as mapping is unimportant */ > > > > + error = vfs_get_fscaps_nosec(&nop_mnt_idmap, dentry, &caps); > > > > + return error == 0; > > > > } > > > > > > > > /** > > > > @@ -323,7 +324,7 @@ int cap_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry) > > > > { > > > > int error; > > > > > > > > - error = __vfs_removexattr(idmap, dentry, XATTR_NAME_CAPS); > > > > + error = vfs_remove_fscaps_nosec(idmap, dentry); > > > > > > Uhm, I see that the change is logically correct... but the original > > > code was not correct, since the EVM post hook is not called (thus the > > > HMAC is broken, or an xattr change is allowed on a portable signature > > > which should be not). > > > > > > For completeness, the xattr change on a portable signature should not > > > happen in the first place, so cap_inode_killpriv() would not be called. > > > However, since EVM allows same value change, we are here. > > > > I really don't understand EVM that well and am pretty hesitant to try an > > change any of the logic around it. But I'll hazard a thought: should EVM > > have a inode_need_killpriv hook which returns an error in this > > situation? > > Uhm, I think it would not work without modifying > security_inode_need_killpriv() and the hook definition. > > Since cap_inode_need_killpriv() returns 1, the loop stops and EVM would > not be invoked. We would need to continue the loop and let EVM know > what is the current return value. Then EVM can reject the change. > > An alternative way would be to detect that actually we are setting the > same value for inode metadata, and maybe not returning 1 from > cap_inode_need_killpriv(). > > I would prefer the second, since EVM allows same value change and we > would have an exception if there are fscaps. > > This solves only the case of portable signatures. We would need to > change cap_inode_need_killpriv() anyway to update the HMAC for mutable > files. I see. In any case this sounds like a matter for a separate patch series.
diff --git a/security/commoncap.c b/security/commoncap.c index a0ff7e6092e0..751bb26a06a6 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -296,11 +296,12 @@ int cap_capset(struct cred *new, */ int cap_inode_need_killpriv(struct dentry *dentry) { - struct inode *inode = d_backing_inode(dentry); + struct vfs_caps caps; int error; - error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0); - return error > 0; + /* Use nop_mnt_idmap for no mapping here as mapping is unimportant */ + error = vfs_get_fscaps_nosec(&nop_mnt_idmap, dentry, &caps); + return error == 0; } /** @@ -323,7 +324,7 @@ int cap_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry) { int error; - error = __vfs_removexattr(idmap, dentry, XATTR_NAME_CAPS); + error = vfs_remove_fscaps_nosec(idmap, dentry); if (error == -EOPNOTSUPP) error = 0; return error; @@ -719,6 +720,10 @@ ssize_t vfs_caps_to_user_xattr(struct mnt_idmap *idmap, * @cpu_caps: vfs capabilities * * Extract the on-exec-apply capability sets for an executable file. + * For version 3 capabilities xattrs, returns the capabilities only if + * they are applicable to current_user_ns() (i.e. that the rootid + * corresponds to an ID which maps to ID 0 in current_user_ns() or an + * ancestor), and returns -ENODATA otherwise. * * If the inode has been found through an idmapped mount the idmap of * the vfsmount must be passed through @idmap. This function will then @@ -731,25 +736,16 @@ int get_vfs_caps_from_disk(struct mnt_idmap *idmap, struct vfs_caps *cpu_caps) { struct inode *inode = d_backing_inode(dentry); - int size, ret; - struct vfs_ns_cap_data data, *nscaps = &data; + int ret; if (!inode) return -ENODATA; - size = __vfs_getxattr((struct dentry *)dentry, inode, - XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ); - if (size == -ENODATA || size == -EOPNOTSUPP) + ret = vfs_get_fscaps_nosec(idmap, (struct dentry *)dentry, cpu_caps); + if (ret == -EOPNOTSUPP || ret == -EOVERFLOW) /* no data, that's ok */ - return -ENODATA; + ret = -ENODATA; - if (size < 0) - return size; - - ret = vfs_caps_from_xattr(idmap, inode->i_sb->s_user_ns, - cpu_caps, nscaps, size); - if (ret == -EOVERFLOW) - return -ENODATA; if (ret) return ret;