Commit 11ab4cd5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'lsm-pr-20240715' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm

Pull lsm updates from Paul Moore:
 "Two LSM patches focused on cleaning up the inode xattr capability
  handling"

* tag 'lsm-pr-20240715' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm:
  selinux,smack: remove the capability checks in the removexattr hooks
  lsm: fixup the inode xattr capability handling
parents dad8d1a3 dd44477e
......@@ -144,6 +144,7 @@ LSM_HOOK(int, 0, inode_setattr, struct mnt_idmap *idmap, struct dentry *dentry,
LSM_HOOK(void, LSM_RET_VOID, inode_post_setattr, struct mnt_idmap *idmap,
struct dentry *dentry, int ia_valid)
LSM_HOOK(int, 0, inode_getattr, const struct path *path)
LSM_HOOK(int, 0, inode_xattr_skipcap, const char *name)
LSM_HOOK(int, 0, inode_setxattr, struct mnt_idmap *idmap,
struct dentry *dentry, const char *name, const void *value,
size_t size, int flags)
......
......@@ -2278,7 +2278,20 @@ int security_inode_getattr(const struct path *path)
* @size: size of xattr value
* @flags: flags
*
* Check permission before setting the extended attributes.
* This hook performs the desired permission checks before setting the extended
* attributes (xattrs) on @dentry. It is important to note that we have some
* additional logic before the main LSM implementation calls to detect if we
* need to perform an additional capability check at the LSM layer.
*
* Normally we enforce a capability check prior to executing the various LSM
* hook implementations, but if a LSM wants to avoid this capability check,
* it can register a 'inode_xattr_skipcap' hook and return a value of 1 for
* xattrs that it wants to avoid the capability check, leaving the LSM fully
* responsible for enforcing the access control for the specific xattr. If all
* of the enabled LSMs refrain from registering a 'inode_xattr_skipcap' hook,
* or return a 0 (the default return value), the capability check is still
* performed. If no 'inode_xattr_skipcap' hooks are registered the capability
* check is performed.
*
* Return: Returns 0 if permission is granted.
*/
......@@ -2286,20 +2299,20 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
int ret;
int rc;
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
/*
* SELinux and Smack integrate the cap call,
* so assume that all LSMs supplying this call do so.
*/
ret = call_int_hook(inode_setxattr, idmap, dentry, name, value, size,
flags);
if (ret == 1)
ret = cap_inode_setxattr(dentry, name, value, size, flags);
return ret;
/* enforce the capability checks at the lsm layer, if needed */
if (!call_int_hook(inode_xattr_skipcap, name)) {
rc = cap_inode_setxattr(dentry, name, value, size, flags);
if (rc)
return rc;
}
return call_int_hook(inode_setxattr, idmap, dentry, name, value, size,
flags);
}
/**
......@@ -2452,26 +2465,39 @@ int security_inode_listxattr(struct dentry *dentry)
* @dentry: file
* @name: xattr name
*
* Check permission before removing the extended attribute identified by @name
* for @dentry.
* This hook performs the desired permission checks before setting the extended
* attributes (xattrs) on @dentry. It is important to note that we have some
* additional logic before the main LSM implementation calls to detect if we
* need to perform an additional capability check at the LSM layer.
*
* Normally we enforce a capability check prior to executing the various LSM
* hook implementations, but if a LSM wants to avoid this capability check,
* it can register a 'inode_xattr_skipcap' hook and return a value of 1 for
* xattrs that it wants to avoid the capability check, leaving the LSM fully
* responsible for enforcing the access control for the specific xattr. If all
* of the enabled LSMs refrain from registering a 'inode_xattr_skipcap' hook,
* or return a 0 (the default return value), the capability check is still
* performed. If no 'inode_xattr_skipcap' hooks are registered the capability
* check is performed.
*
* Return: Returns 0 if permission is granted.
*/
int security_inode_removexattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name)
{
int ret;
int rc;
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
/*
* SELinux and Smack integrate the cap call,
* so assume that all LSMs supplying this call do so.
*/
ret = call_int_hook(inode_removexattr, idmap, dentry, name);
if (ret == 1)
ret = cap_inode_removexattr(idmap, dentry, name);
return ret;
/* enforce the capability checks at the lsm layer, if needed */
if (!call_int_hook(inode_xattr_skipcap, name)) {
rc = cap_inode_removexattr(idmap, dentry, name);
if (rc)
return rc;
}
return call_int_hook(inode_removexattr, idmap, dentry, name);
}
/**
......
......@@ -3177,6 +3177,23 @@ static bool has_cap_mac_admin(bool audit)
return true;
}
/**
* selinux_inode_xattr_skipcap - Skip the xattr capability checks?
* @name: name of the xattr
*
* Returns 1 to indicate that SELinux "owns" the access control rights to xattrs
* named @name; the LSM layer should avoid enforcing any traditional
* capability based access controls on this xattr. Returns 0 to indicate that
* SELinux does not "own" the access control rights to xattrs named @name and is
* deferring to the LSM layer for further access controls, including capability
* based controls.
*/
static int selinux_inode_xattr_skipcap(const char *name)
{
/* require capability check if not a selinux xattr */
return !strcmp(name, XATTR_NAME_SELINUX);
}
static int selinux_inode_setxattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
......@@ -3188,15 +3205,9 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
u32 newsid, sid = current_sid();
int rc = 0;
if (strcmp(name, XATTR_NAME_SELINUX)) {
rc = cap_inode_setxattr(dentry, name, value, size, flags);
if (rc)
return rc;
/* Not an attribute we recognize, so just check the
ordinary setattr permission. */
/* if not a selinux xattr, only check the ordinary setattr perm */
if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
}
if (!selinux_initialized())
return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
......@@ -3345,15 +3356,9 @@ static int selinux_inode_listxattr(struct dentry *dentry)
static int selinux_inode_removexattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name)
{
if (strcmp(name, XATTR_NAME_SELINUX)) {
int rc = cap_inode_removexattr(idmap, dentry, name);
if (rc)
return rc;
/* Not an attribute we recognize, so just check the
ordinary setattr permission. */
/* if not a selinux xattr, only check the ordinary setattr perm */
if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
}
if (!selinux_initialized())
return 0;
......@@ -7175,6 +7180,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
LSM_HOOK_INIT(inode_xattr_skipcap, selinux_inode_xattr_skipcap),
LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
......
......@@ -1282,6 +1282,33 @@ static int smack_inode_getattr(const struct path *path)
return rc;
}
/**
* smack_inode_xattr_skipcap - Skip the xattr capability checks?
* @name: name of the xattr
*
* Returns 1 to indicate that Smack "owns" the access control rights to xattrs
* named @name; the LSM layer should avoid enforcing any traditional
* capability based access controls on this xattr. Returns 0 to indicate that
* Smack does not "own" the access control rights to xattrs named @name and is
* deferring to the LSM layer for further access controls, including capability
* based controls.
*/
static int smack_inode_xattr_skipcap(const char *name)
{
if (strncmp(name, XATTR_SMACK_SUFFIX, strlen(XATTR_SMACK_SUFFIX)))
return 0;
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
strcmp(name, XATTR_NAME_SMACKMMAP) == 0 ||
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
return 1;
return 0;
}
/**
* smack_inode_setxattr - Smack check for setting xattrs
* @idmap: idmap of the mount
......@@ -1325,8 +1352,7 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
size != TRANS_TRUE_SIZE ||
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
rc = -EINVAL;
} else
rc = cap_inode_setxattr(dentry, name, value, size, flags);
}
if (check_priv && !smack_privileged(CAP_MAC_ADMIN))
rc = -EPERM;
......@@ -1435,8 +1461,7 @@ static int smack_inode_removexattr(struct mnt_idmap *idmap,
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
if (!smack_privileged(CAP_MAC_ADMIN))
rc = -EPERM;
} else
rc = cap_inode_removexattr(idmap, dentry, name);
}
if (rc != 0)
return rc;
......@@ -5053,6 +5078,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_permission, smack_inode_permission),
LSM_HOOK_INIT(inode_setattr, smack_inode_setattr),
LSM_HOOK_INIT(inode_getattr, smack_inode_getattr),
LSM_HOOK_INIT(inode_xattr_skipcap, smack_inode_xattr_skipcap),
LSM_HOOK_INIT(inode_setxattr, smack_inode_setxattr),
LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr),
LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment