Commit 11ab4cd5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+48 −22
Original line number Diff line number Diff line
@@ -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);
}

/**
+22 −16
Original line number Diff line number Diff line
@@ -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),
+30 −4
Original line number Diff line number Diff line
@@ -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),