History

selinux: match extended permissions to their base permissions

In commit d1d991efaf34 ("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.

Thiébaud Weksteen committed 1 year ago

Commit 5e7f0ef1 parent 900f83c5 files · +65 −38Browse files

Unified · Split

5 files
  1. security/selinux/avc.c +34 −27
  2. security/selinux/hooks.c +3 −3
  3. security/selinux/include/avc.h +4 −1
  4. security/selinux/include/security.h +3 −0
  5. security/selinux/ss/services.c +21 −7
security/selinux/avc.c+34−27
@@ -174,13 +174,15 @@ int avc_get_hash_stats(char *page) · 173 unmodified lines
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, · 18 unmodified lines
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) · 29 unmodified lines
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, · 21 unmodified lines
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, · 79 unmodified lines
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 @@ out: · 444 unmodified lines
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 @@ out: · 7 unmodified lines
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, · 50 unmodified lines
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, · 100 unmodified lines
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, · 2 unmodified lines
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, · 6 unmodified lines
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, · 28 unmodified lines
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, · 6 unmodified lines
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, · 27 unmodified lines
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, · 41 unmodified lines
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+3−3
@@ -3688,8 +3688,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, · 3687 unmodified lines
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 · 2256 unmodified lines
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+4−1
@@ -136,8 +136,11 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, · 135 unmodified lines
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+3−0
@@ -239,6 +239,7 @@ struct extended_perms_data { · 238 unmodified lines
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;
@@ -246,6 +247,7 @@ struct extended_perms_decision { · 1 unmodified line
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, · 5 unmodified lines
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+21−7
@@ -582,7 +582,7 @@ static void type_attribute_bounds_av(struct policydb *policydb, · 581 unmodified lines
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( · 3 unmodified lines
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, · 27 unmodified lines
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, · 330 unmodified lines
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, · 28 unmodified lines
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, · 7 unmodified lines
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));

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t