Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 11ab4cd

Browse files
committed
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
2 parents dad8d1a + dd44477 commit 11ab4cd

File tree

4 files changed

+101
-42
lines changed

4 files changed

+101
-42
lines changed

include/linux/lsm_hook_defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ LSM_HOOK(int, 0, inode_setattr, struct mnt_idmap *idmap, struct dentry *dentry,
144144
LSM_HOOK(void, LSM_RET_VOID, inode_post_setattr, struct mnt_idmap *idmap,
145145
struct dentry *dentry, int ia_valid)
146146
LSM_HOOK(int, 0, inode_getattr, const struct path *path)
147+
LSM_HOOK(int, 0, inode_xattr_skipcap, const char *name)
147148
LSM_HOOK(int, 0, inode_setxattr, struct mnt_idmap *idmap,
148149
struct dentry *dentry, const char *name, const void *value,
149150
size_t size, int flags)

security/security.c

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,28 +2278,41 @@ int security_inode_getattr(const struct path *path)
22782278
* @size: size of xattr value
22792279
* @flags: flags
22802280
*
2281-
* Check permission before setting the extended attributes.
2281+
* This hook performs the desired permission checks before setting the extended
2282+
* attributes (xattrs) on @dentry. It is important to note that we have some
2283+
* additional logic before the main LSM implementation calls to detect if we
2284+
* need to perform an additional capability check at the LSM layer.
2285+
*
2286+
* Normally we enforce a capability check prior to executing the various LSM
2287+
* hook implementations, but if a LSM wants to avoid this capability check,
2288+
* it can register a 'inode_xattr_skipcap' hook and return a value of 1 for
2289+
* xattrs that it wants to avoid the capability check, leaving the LSM fully
2290+
* responsible for enforcing the access control for the specific xattr. If all
2291+
* of the enabled LSMs refrain from registering a 'inode_xattr_skipcap' hook,
2292+
* or return a 0 (the default return value), the capability check is still
2293+
* performed. If no 'inode_xattr_skipcap' hooks are registered the capability
2294+
* check is performed.
22822295
*
22832296
* Return: Returns 0 if permission is granted.
22842297
*/
22852298
int security_inode_setxattr(struct mnt_idmap *idmap,
22862299
struct dentry *dentry, const char *name,
22872300
const void *value, size_t size, int flags)
22882301
{
2289-
int ret;
2302+
int rc;
22902303

22912304
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
22922305
return 0;
2293-
/*
2294-
* SELinux and Smack integrate the cap call,
2295-
* so assume that all LSMs supplying this call do so.
2296-
*/
2297-
ret = call_int_hook(inode_setxattr, idmap, dentry, name, value, size,
2298-
flags);
22992306

2300-
if (ret == 1)
2301-
ret = cap_inode_setxattr(dentry, name, value, size, flags);
2302-
return ret;
2307+
/* enforce the capability checks at the lsm layer, if needed */
2308+
if (!call_int_hook(inode_xattr_skipcap, name)) {
2309+
rc = cap_inode_setxattr(dentry, name, value, size, flags);
2310+
if (rc)
2311+
return rc;
2312+
}
2313+
2314+
return call_int_hook(inode_setxattr, idmap, dentry, name, value, size,
2315+
flags);
23032316
}
23042317

23052318
/**
@@ -2452,26 +2465,39 @@ int security_inode_listxattr(struct dentry *dentry)
24522465
* @dentry: file
24532466
* @name: xattr name
24542467
*
2455-
* Check permission before removing the extended attribute identified by @name
2456-
* for @dentry.
2468+
* This hook performs the desired permission checks before setting the extended
2469+
* attributes (xattrs) on @dentry. It is important to note that we have some
2470+
* additional logic before the main LSM implementation calls to detect if we
2471+
* need to perform an additional capability check at the LSM layer.
2472+
*
2473+
* Normally we enforce a capability check prior to executing the various LSM
2474+
* hook implementations, but if a LSM wants to avoid this capability check,
2475+
* it can register a 'inode_xattr_skipcap' hook and return a value of 1 for
2476+
* xattrs that it wants to avoid the capability check, leaving the LSM fully
2477+
* responsible for enforcing the access control for the specific xattr. If all
2478+
* of the enabled LSMs refrain from registering a 'inode_xattr_skipcap' hook,
2479+
* or return a 0 (the default return value), the capability check is still
2480+
* performed. If no 'inode_xattr_skipcap' hooks are registered the capability
2481+
* check is performed.
24572482
*
24582483
* Return: Returns 0 if permission is granted.
24592484
*/
24602485
int security_inode_removexattr(struct mnt_idmap *idmap,
24612486
struct dentry *dentry, const char *name)
24622487
{
2463-
int ret;
2488+
int rc;
24642489

24652490
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
24662491
return 0;
2467-
/*
2468-
* SELinux and Smack integrate the cap call,
2469-
* so assume that all LSMs supplying this call do so.
2470-
*/
2471-
ret = call_int_hook(inode_removexattr, idmap, dentry, name);
2472-
if (ret == 1)
2473-
ret = cap_inode_removexattr(idmap, dentry, name);
2474-
return ret;
2492+
2493+
/* enforce the capability checks at the lsm layer, if needed */
2494+
if (!call_int_hook(inode_xattr_skipcap, name)) {
2495+
rc = cap_inode_removexattr(idmap, dentry, name);
2496+
if (rc)
2497+
return rc;
2498+
}
2499+
2500+
return call_int_hook(inode_removexattr, idmap, dentry, name);
24752501
}
24762502

24772503
/**

security/selinux/hooks.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3177,6 +3177,23 @@ static bool has_cap_mac_admin(bool audit)
31773177
return true;
31783178
}
31793179

3180+
/**
3181+
* selinux_inode_xattr_skipcap - Skip the xattr capability checks?
3182+
* @name: name of the xattr
3183+
*
3184+
* Returns 1 to indicate that SELinux "owns" the access control rights to xattrs
3185+
* named @name; the LSM layer should avoid enforcing any traditional
3186+
* capability based access controls on this xattr. Returns 0 to indicate that
3187+
* SELinux does not "own" the access control rights to xattrs named @name and is
3188+
* deferring to the LSM layer for further access controls, including capability
3189+
* based controls.
3190+
*/
3191+
static int selinux_inode_xattr_skipcap(const char *name)
3192+
{
3193+
/* require capability check if not a selinux xattr */
3194+
return !strcmp(name, XATTR_NAME_SELINUX);
3195+
}
3196+
31803197
static int selinux_inode_setxattr(struct mnt_idmap *idmap,
31813198
struct dentry *dentry, const char *name,
31823199
const void *value, size_t size, int flags)
@@ -3188,15 +3205,9 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
31883205
u32 newsid, sid = current_sid();
31893206
int rc = 0;
31903207

3191-
if (strcmp(name, XATTR_NAME_SELINUX)) {
3192-
rc = cap_inode_setxattr(dentry, name, value, size, flags);
3193-
if (rc)
3194-
return rc;
3195-
3196-
/* Not an attribute we recognize, so just check the
3197-
ordinary setattr permission. */
3208+
/* if not a selinux xattr, only check the ordinary setattr perm */
3209+
if (strcmp(name, XATTR_NAME_SELINUX))
31983210
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
3199-
}
32003211

32013212
if (!selinux_initialized())
32023213
return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
@@ -3345,15 +3356,9 @@ static int selinux_inode_listxattr(struct dentry *dentry)
33453356
static int selinux_inode_removexattr(struct mnt_idmap *idmap,
33463357
struct dentry *dentry, const char *name)
33473358
{
3348-
if (strcmp(name, XATTR_NAME_SELINUX)) {
3349-
int rc = cap_inode_removexattr(idmap, dentry, name);
3350-
if (rc)
3351-
return rc;
3352-
3353-
/* Not an attribute we recognize, so just check the
3354-
ordinary setattr permission. */
3359+
/* if not a selinux xattr, only check the ordinary setattr perm */
3360+
if (strcmp(name, XATTR_NAME_SELINUX))
33553361
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
3356-
}
33573362

33583363
if (!selinux_initialized())
33593364
return 0;
@@ -7175,6 +7180,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
71757180
LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
71767181
LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
71777182
LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
7183+
LSM_HOOK_INIT(inode_xattr_skipcap, selinux_inode_xattr_skipcap),
71787184
LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
71797185
LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
71807186
LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),

security/smack/smack_lsm.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,33 @@ static int smack_inode_getattr(const struct path *path)
12821282
return rc;
12831283
}
12841284

1285+
/**
1286+
* smack_inode_xattr_skipcap - Skip the xattr capability checks?
1287+
* @name: name of the xattr
1288+
*
1289+
* Returns 1 to indicate that Smack "owns" the access control rights to xattrs
1290+
* named @name; the LSM layer should avoid enforcing any traditional
1291+
* capability based access controls on this xattr. Returns 0 to indicate that
1292+
* Smack does not "own" the access control rights to xattrs named @name and is
1293+
* deferring to the LSM layer for further access controls, including capability
1294+
* based controls.
1295+
*/
1296+
static int smack_inode_xattr_skipcap(const char *name)
1297+
{
1298+
if (strncmp(name, XATTR_SMACK_SUFFIX, strlen(XATTR_SMACK_SUFFIX)))
1299+
return 0;
1300+
1301+
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
1302+
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
1303+
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
1304+
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
1305+
strcmp(name, XATTR_NAME_SMACKMMAP) == 0 ||
1306+
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
1307+
return 1;
1308+
1309+
return 0;
1310+
}
1311+
12851312
/**
12861313
* smack_inode_setxattr - Smack check for setting xattrs
12871314
* @idmap: idmap of the mount
@@ -1325,8 +1352,7 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
13251352
size != TRANS_TRUE_SIZE ||
13261353
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
13271354
rc = -EINVAL;
1328-
} else
1329-
rc = cap_inode_setxattr(dentry, name, value, size, flags);
1355+
}
13301356

13311357
if (check_priv && !smack_privileged(CAP_MAC_ADMIN))
13321358
rc = -EPERM;
@@ -1435,8 +1461,7 @@ static int smack_inode_removexattr(struct mnt_idmap *idmap,
14351461
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
14361462
if (!smack_privileged(CAP_MAC_ADMIN))
14371463
rc = -EPERM;
1438-
} else
1439-
rc = cap_inode_removexattr(idmap, dentry, name);
1464+
}
14401465

14411466
if (rc != 0)
14421467
return rc;
@@ -5053,6 +5078,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
50535078
LSM_HOOK_INIT(inode_permission, smack_inode_permission),
50545079
LSM_HOOK_INIT(inode_setattr, smack_inode_setattr),
50555080
LSM_HOOK_INIT(inode_getattr, smack_inode_getattr),
5081+
LSM_HOOK_INIT(inode_xattr_skipcap, smack_inode_xattr_skipcap),
50565082
LSM_HOOK_INIT(inode_setxattr, smack_inode_setxattr),
50575083
LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr),
50585084
LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr),

0 commit comments

Comments
 (0)