Skip to content

Commit 5e7f0ef

Browse files
tweksteenpcmoore
authored andcommitted
selinux: match extended permissions to their base permissions
In commit d1d991e ("selinux: Add netlink xperm support") a new extended permission was added ("nlmsg"). This was the second extended permission implemented in selinux ("ioctl" being the first one). Extended permissions are associated with a base permission. It was found that, in the access vector cache (avc), the extended permission did not keep track of its base permission. This is an issue for a domain that is using both extended permissions (i.e., a domain calling ioctl() on a netlink socket). In this case, the extended permissions were overlapping. Keep track of the base permission in the cache. A new field "base_perm" is added to struct extended_perms_decision to make sure that the extended permission refers to the correct policy permission. A new field "base_perms" is added to struct extended_perms to quickly decide if extended permissions apply. While it is in theory possible to retrieve the base permission from the access vector, the same base permission may not be mapped to the same bit for each class (e.g., "nlmsg" is mapped to a different bit for "netlink_route_socket" and "netlink_audit_socket"). Instead, use a constant (AVC_EXT_IOCTL or AVC_EXT_NLMSG) provided by the caller. Fixes: d1d991e ("selinux: Add netlink xperm support") Signed-off-by: Thiébaud Weksteen <[email protected]> Signed-off-by: Paul Moore <[email protected]>
1 parent 900f83c commit 5e7f0ef

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)