Skip to content

Commit 09a0fa9

Browse files
committed
Merge tag 'selinux-pr-20250107' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux
Pull selinux fix from Paul Moore: "A single SELinux patch to address a problem with a single domain using multiple xperm classes" * tag 'selinux-pr-20250107' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: selinux: match extended permissions to their base permissions
2 parents fbfd64d + 5e7f0ef commit 09a0fa9

File tree

5 files changed

+65
-38
lines changed

5 files changed

+65
-38
lines changed

security/selinux/avc.c

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,15 @@ int avc_get_hash_stats(char *page)
174174
* using a linked list for extended_perms_decision lookup because the list is
175175
* always small. i.e. less than 5, typically 1
176176
*/
177-
static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver,
178-
struct avc_xperms_node *xp_node)
177+
static struct extended_perms_decision *
178+
avc_xperms_decision_lookup(u8 driver, u8 base_perm,
179+
struct avc_xperms_node *xp_node)
179180
{
180181
struct avc_xperms_decision_node *xpd_node;
181182

182183
list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) {
183-
if (xpd_node->xpd.driver == driver)
184+
if (xpd_node->xpd.driver == driver &&
185+
xpd_node->xpd.base_perm == base_perm)
184186
return &xpd_node->xpd;
185187
}
186188
return NULL;
@@ -205,11 +207,12 @@ avc_xperms_has_perm(struct extended_perms_decision *xpd,
205207
}
206208

207209
static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node,
208-
u8 driver, u8 perm)
210+
u8 driver, u8 base_perm, u8 perm)
209211
{
210212
struct extended_perms_decision *xpd;
211213
security_xperm_set(xp_node->xp.drivers.p, driver);
212-
xpd = avc_xperms_decision_lookup(driver, xp_node);
214+
xp_node->xp.base_perms |= base_perm;
215+
xpd = avc_xperms_decision_lookup(driver, base_perm, xp_node);
213216
if (xpd && xpd->allowed)
214217
security_xperm_set(xpd->allowed->p, perm);
215218
}
@@ -245,6 +248,7 @@ static void avc_xperms_free(struct avc_xperms_node *xp_node)
245248
static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
246249
struct extended_perms_decision *src)
247250
{
251+
dest->base_perm = src->base_perm;
248252
dest->driver = src->driver;
249253
dest->used = src->used;
250254
if (dest->used & XPERMS_ALLOWED)
@@ -272,6 +276,7 @@ static inline void avc_quick_copy_xperms_decision(u8 perm,
272276
*/
273277
u8 i = perm >> 5;
274278

279+
dest->base_perm = src->base_perm;
275280
dest->used = src->used;
276281
if (dest->used & XPERMS_ALLOWED)
277282
dest->allowed->p[i] = src->allowed->p[i];
@@ -357,6 +362,7 @@ static int avc_xperms_populate(struct avc_node *node,
357362

358363
memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p));
359364
dest->xp.len = src->xp.len;
365+
dest->xp.base_perms = src->xp.base_perms;
360366

361367
/* for each source xpd allocate a destination xpd and copy */
362368
list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) {
@@ -807,6 +813,7 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
807813
* @event : Updating event
808814
* @perms : Permission mask bits
809815
* @driver: xperm driver information
816+
* @base_perm: the base permission associated with the extended permission
810817
* @xperm: xperm permissions
811818
* @ssid: AVC entry source sid
812819
* @tsid: AVC entry target sid
@@ -820,10 +827,9 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
820827
* otherwise, this function updates the AVC entry. The original AVC-entry object
821828
* will release later by RCU.
822829
*/
823-
static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
824-
u32 tsid, u16 tclass, u32 seqno,
825-
struct extended_perms_decision *xpd,
826-
u32 flags)
830+
static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
831+
u8 xperm, u32 ssid, u32 tsid, u16 tclass, u32 seqno,
832+
struct extended_perms_decision *xpd, u32 flags)
827833
{
828834
u32 hvalue;
829835
int rc = 0;
@@ -880,7 +886,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
880886
case AVC_CALLBACK_GRANT:
881887
node->ae.avd.allowed |= perms;
882888
if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS))
883-
avc_xperms_allow_perm(node->ae.xp_node, driver, xperm);
889+
avc_xperms_allow_perm(node->ae.xp_node, driver, base_perm, xperm);
884890
break;
885891
case AVC_CALLBACK_TRY_REVOKE:
886892
case AVC_CALLBACK_REVOKE:
@@ -987,10 +993,9 @@ static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass,
987993
avc_insert(ssid, tsid, tclass, avd, xp_node);
988994
}
989995

990-
static noinline int avc_denied(u32 ssid, u32 tsid,
991-
u16 tclass, u32 requested,
992-
u8 driver, u8 xperm, unsigned int flags,
993-
struct av_decision *avd)
996+
static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested,
997+
u8 driver, u8 base_perm, u8 xperm,
998+
unsigned int flags, struct av_decision *avd)
994999
{
9951000
if (flags & AVC_STRICT)
9961001
return -EACCES;
@@ -999,7 +1004,7 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
9991004
!(avd->flags & AVD_FLAGS_PERMISSIVE))
10001005
return -EACCES;
10011006

1002-
avc_update_node(AVC_CALLBACK_GRANT, requested, driver,
1007+
avc_update_node(AVC_CALLBACK_GRANT, requested, driver, base_perm,
10031008
xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);
10041009
return 0;
10051010
}
@@ -1012,7 +1017,8 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
10121017
* driver field is used to specify which set contains the permission.
10131018
*/
10141019
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
1015-
u8 driver, u8 xperm, struct common_audit_data *ad)
1020+
u8 driver, u8 base_perm, u8 xperm,
1021+
struct common_audit_data *ad)
10161022
{
10171023
struct avc_node *node;
10181024
struct av_decision avd;
@@ -1047,22 +1053,23 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
10471053
local_xpd.auditallow = &auditallow;
10481054
local_xpd.dontaudit = &dontaudit;
10491055

1050-
xpd = avc_xperms_decision_lookup(driver, xp_node);
1056+
xpd = avc_xperms_decision_lookup(driver, base_perm, xp_node);
10511057
if (unlikely(!xpd)) {
10521058
/*
10531059
* Compute the extended_perms_decision only if the driver
1054-
* is flagged
1060+
* is flagged and the base permission is known.
10551061
*/
1056-
if (!security_xperm_test(xp_node->xp.drivers.p, driver)) {
1062+
if (!security_xperm_test(xp_node->xp.drivers.p, driver) ||
1063+
!(xp_node->xp.base_perms & base_perm)) {
10571064
avd.allowed &= ~requested;
10581065
goto decision;
10591066
}
10601067
rcu_read_unlock();
1061-
security_compute_xperms_decision(ssid, tsid, tclass,
1062-
driver, &local_xpd);
1068+
security_compute_xperms_decision(ssid, tsid, tclass, driver,
1069+
base_perm, &local_xpd);
10631070
rcu_read_lock();
1064-
avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested,
1065-
driver, xperm, ssid, tsid, tclass, avd.seqno,
1071+
avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver,
1072+
base_perm, xperm, ssid, tsid, tclass, avd.seqno,
10661073
&local_xpd, 0);
10671074
} else {
10681075
avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd);
@@ -1075,8 +1082,8 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
10751082
decision:
10761083
denied = requested & ~(avd.allowed);
10771084
if (unlikely(denied))
1078-
rc = avc_denied(ssid, tsid, tclass, requested,
1079-
driver, xperm, AVC_EXTENDED_PERMS, &avd);
1085+
rc = avc_denied(ssid, tsid, tclass, requested, driver,
1086+
base_perm, xperm, AVC_EXTENDED_PERMS, &avd);
10801087

10811088
rcu_read_unlock();
10821089

@@ -1110,7 +1117,7 @@ static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
11101117
avc_compute_av(ssid, tsid, tclass, avd, &xp_node);
11111118
denied = requested & ~(avd->allowed);
11121119
if (unlikely(denied))
1113-
return avc_denied(ssid, tsid, tclass, requested, 0, 0,
1120+
return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
11141121
flags, avd);
11151122
return 0;
11161123
}
@@ -1158,7 +1165,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
11581165
rcu_read_unlock();
11591166

11601167
if (unlikely(denied))
1161-
return avc_denied(ssid, tsid, tclass, requested, 0, 0,
1168+
return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
11621169
flags, avd);
11631170
return 0;
11641171
}

security/selinux/hooks.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3688,8 +3688,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
36883688
return 0;
36893689

36903690
isec = inode_security(inode);
3691-
rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
3692-
requested, driver, xperm, &ad);
3691+
rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, requested,
3692+
driver, AVC_EXT_IOCTL, xperm, &ad);
36933693
out:
36943694
return rc;
36953695
}
@@ -5952,7 +5952,7 @@ static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_t
59525952
xperm = nlmsg_type & 0xff;
59535953

59545954
return avc_has_extended_perms(current_sid(), sksec->sid, sksec->sclass,
5955-
perms, driver, xperm, &ad);
5955+
perms, driver, AVC_EXT_NLMSG, xperm, &ad);
59565956
}
59575957

59585958
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)

security/selinux/include/avc.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,11 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
136136
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,
137137
struct common_audit_data *auditdata);
138138

139+
#define AVC_EXT_IOCTL (1 << 0) /* Cache entry for an ioctl extended permission */
140+
#define AVC_EXT_NLMSG (1 << 1) /* Cache entry for an nlmsg extended permission */
139141
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
140-
u8 driver, u8 perm, struct common_audit_data *ad);
142+
u8 driver, u8 base_perm, u8 perm,
143+
struct common_audit_data *ad);
141144

142145
u32 avc_policy_seqno(void);
143146

security/selinux/include/security.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,15 @@ struct extended_perms_data {
239239
struct extended_perms_decision {
240240
u8 used;
241241
u8 driver;
242+
u8 base_perm;
242243
struct extended_perms_data *allowed;
243244
struct extended_perms_data *auditallow;
244245
struct extended_perms_data *dontaudit;
245246
};
246247

247248
struct extended_perms {
248249
u16 len; /* length associated decision chain */
250+
u8 base_perms; /* which base permissions are covered */
249251
struct extended_perms_data drivers; /* flag drivers that are used */
250252
};
251253

@@ -257,6 +259,7 @@ void security_compute_av(u32 ssid, u32 tsid, u16 tclass,
257259
struct extended_perms *xperms);
258260

259261
void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, u8 driver,
262+
u8 base_perm,
260263
struct extended_perms_decision *xpermd);
261264

262265
void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass,

security/selinux/ss/services.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ static void type_attribute_bounds_av(struct policydb *policydb,
582582
}
583583

584584
/*
585-
* Flag which drivers have permissions.
585+
* Flag which drivers have permissions and which base permissions are covered.
586586
*/
587587
void services_compute_xperms_drivers(
588588
struct extended_perms *xperms,
@@ -592,12 +592,19 @@ void services_compute_xperms_drivers(
592592

593593
switch (node->datum.u.xperms->specified) {
594594
case AVTAB_XPERMS_IOCTLDRIVER:
595+
xperms->base_perms |= AVC_EXT_IOCTL;
595596
/* if one or more driver has all permissions allowed */
596597
for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
597598
xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
598599
break;
599600
case AVTAB_XPERMS_IOCTLFUNCTION:
601+
xperms->base_perms |= AVC_EXT_IOCTL;
602+
/* if allowing permissions within a driver */
603+
security_xperm_set(xperms->drivers.p,
604+
node->datum.u.xperms->driver);
605+
break;
600606
case AVTAB_XPERMS_NLMSG:
607+
xperms->base_perms |= AVC_EXT_NLMSG;
601608
/* if allowing permissions within a driver */
602609
security_xperm_set(xperms->drivers.p,
603610
node->datum.u.xperms->driver);
@@ -631,8 +638,7 @@ static void context_struct_compute_av(struct policydb *policydb,
631638
avd->auditallow = 0;
632639
avd->auditdeny = 0xffffffff;
633640
if (xperms) {
634-
memset(&xperms->drivers, 0, sizeof(xperms->drivers));
635-
xperms->len = 0;
641+
memset(xperms, 0, sizeof(*xperms));
636642
}
637643

638644
if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
@@ -969,13 +975,19 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
969975
{
970976
switch (node->datum.u.xperms->specified) {
971977
case AVTAB_XPERMS_IOCTLFUNCTION:
972-
case AVTAB_XPERMS_NLMSG:
973-
if (xpermd->driver != node->datum.u.xperms->driver)
978+
if (xpermd->base_perm != AVC_EXT_IOCTL ||
979+
xpermd->driver != node->datum.u.xperms->driver)
974980
return;
975981
break;
976982
case AVTAB_XPERMS_IOCTLDRIVER:
977-
if (!security_xperm_test(node->datum.u.xperms->perms.p,
978-
xpermd->driver))
983+
if (xpermd->base_perm != AVC_EXT_IOCTL ||
984+
!security_xperm_test(node->datum.u.xperms->perms.p,
985+
xpermd->driver))
986+
return;
987+
break;
988+
case AVTAB_XPERMS_NLMSG:
989+
if (xpermd->base_perm != AVC_EXT_NLMSG ||
990+
xpermd->driver != node->datum.u.xperms->driver)
979991
return;
980992
break;
981993
default:
@@ -1010,6 +1022,7 @@ void security_compute_xperms_decision(u32 ssid,
10101022
u32 tsid,
10111023
u16 orig_tclass,
10121024
u8 driver,
1025+
u8 base_perm,
10131026
struct extended_perms_decision *xpermd)
10141027
{
10151028
struct selinux_policy *policy;
@@ -1023,6 +1036,7 @@ void security_compute_xperms_decision(u32 ssid,
10231036
struct ebitmap_node *snode, *tnode;
10241037
unsigned int i, j;
10251038

1039+
xpermd->base_perm = base_perm;
10261040
xpermd->driver = driver;
10271041
xpermd->used = 0;
10281042
memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));

0 commit comments

Comments
 (0)