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
174 * using a linked list for extended_perms_decision lookup because the list is174 * using a linked list for extended_perms_decision lookup because the list is
175 * always small. i.e. less than 5, typically 1175 * always small. i.e. less than 5, typically 1
176 */176 */
177static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver,177static struct extended_perms_decision *
178 struct avc_xperms_node *xp_node)178avc_xperms_decision_lookup(u8 driver, u8 base_perm,
179 struct avc_xperms_node *xp_node)
179{180{
180 struct avc_xperms_decision_node *xpd_node;181 struct avc_xperms_decision_node *xpd_node;
181 182
182 list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) {183 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)
184 return &xpd_node->xpd;186 return &xpd_node->xpd;
185 }187 }
186 return NULL;188 return NULL;
@@ -205,11 +207,12 @@ avc_xperms_has_perm(struct extended_perms_decision *xpd, · 18 unmodified lines
205}207}
206 208
207static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node,209static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node,
208 u8 driver, u8 perm)210 u8 driver, u8 base_perm, u8 perm)
209{211{
210 struct extended_perms_decision *xpd;212 struct extended_perms_decision *xpd;
211 security_xperm_set(xp_node->xp.drivers.p, driver);213 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);
213 if (xpd && xpd->allowed)216 if (xpd && xpd->allowed)
214 security_xperm_set(xpd->allowed->p, perm);217 security_xperm_set(xpd->allowed->p, perm);
215}218}
@@ -245,6 +248,7 @@ static void avc_xperms_free(struct avc_xperms_node *xp_node) · 29 unmodified lines
245static void avc_copy_xperms_decision(struct extended_perms_decision *dest,248static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
246 struct extended_perms_decision *src)249 struct extended_perms_decision *src)
247{250{
251 dest->base_perm = src->base_perm;
248 dest->driver = src->driver;252 dest->driver = src->driver;
249 dest->used = src->used;253 dest->used = src->used;
250 if (dest->used & XPERMS_ALLOWED)254 if (dest->used & XPERMS_ALLOWED)
@@ -272,6 +276,7 @@ static inline void avc_quick_copy_xperms_decision(u8 perm, · 21 unmodified lines
272 */276 */
273 u8 i = perm >> 5;277 u8 i = perm >> 5;
274 278
279 dest->base_perm = src->base_perm;
275 dest->used = src->used;280 dest->used = src->used;
276 if (dest->used & XPERMS_ALLOWED)281 if (dest->used & XPERMS_ALLOWED)
277 dest->allowed->p[i] = src->allowed->p[i];282 dest->allowed->p[i] = src->allowed->p[i];
@@ -357,6 +362,7 @@ static int avc_xperms_populate(struct avc_node *node, · 79 unmodified lines
357 362
358 memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p));363 memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p));
359 dest->xp.len = src->xp.len;364 dest->xp.len = src->xp.len;
365 dest->xp.base_perms = src->xp.base_perms;
360 366
361 /* for each source xpd allocate a destination xpd and copy */367 /* for each source xpd allocate a destination xpd and copy */
362 list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) {368 list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) {
@@ -807,6 +813,7 @@ out: · 444 unmodified lines
807 * @event : Updating event813 * @event : Updating event
808 * @perms : Permission mask bits814 * @perms : Permission mask bits
809 * @driver: xperm driver information815 * @driver: xperm driver information
816 * @base_perm: the base permission associated with the extended permission
810 * @xperm: xperm permissions817 * @xperm: xperm permissions
811 * @ssid: AVC entry source sid818 * @ssid: AVC entry source sid
812 * @tsid: AVC entry target sid819 * @tsid: AVC entry target sid
@@ -820,10 +827,9 @@ out: · 7 unmodified lines
820 * otherwise, this function updates the AVC entry. The original AVC-entry object827 * otherwise, this function updates the AVC entry. The original AVC-entry object
821 * will release later by RCU.828 * will release later by RCU.
822 */829 */
823static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,830static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
824 u32 tsid, u16 tclass, u32 seqno,831 u8 xperm, u32 ssid, u32 tsid, u16 tclass, u32 seqno,
825 struct extended_perms_decision *xpd,832 struct extended_perms_decision *xpd, u32 flags)
826 u32 flags)
827{833{
828 u32 hvalue;834 u32 hvalue;
829 int rc = 0;835 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
880 case AVC_CALLBACK_GRANT:886 case AVC_CALLBACK_GRANT:
881 node->ae.avd.allowed |= perms;887 node->ae.avd.allowed |= perms;
882 if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS))888 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);
884 break;890 break;
885 case AVC_CALLBACK_TRY_REVOKE:891 case AVC_CALLBACK_TRY_REVOKE:
886 case AVC_CALLBACK_REVOKE:892 case AVC_CALLBACK_REVOKE:
@@ -987,10 +993,9 @@ static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass, · 100 unmodified lines
987 avc_insert(ssid, tsid, tclass, avd, xp_node);993 avc_insert(ssid, tsid, tclass, avd, xp_node);
988}994}
989 995
990static noinline int avc_denied(u32 ssid, u32 tsid,996static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested,
991 u16 tclass, u32 requested,997 u8 driver, u8 base_perm, u8 xperm,
992 u8 driver, u8 xperm, unsigned int flags,998 unsigned int flags, struct av_decision *avd)
993 struct av_decision *avd)
994{999{
995 if (flags & AVC_STRICT)1000 if (flags & AVC_STRICT)
996 return -EACCES;1001 return -EACCES;
@@ -999,7 +1004,7 @@ static noinline int avc_denied(u32 ssid, u32 tsid, · 2 unmodified lines
999 !(avd->flags & AVD_FLAGS_PERMISSIVE))1004 !(avd->flags & AVD_FLAGS_PERMISSIVE))
1000 return -EACCES;1005 return -EACCES;
1001 1006
1002 avc_update_node(AVC_CALLBACK_GRANT, requested, driver,1007 avc_update_node(AVC_CALLBACK_GRANT, requested, driver, base_perm,
1003 xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);1008 xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);
1004 return 0;1009 return 0;
1005}1010}
@@ -1012,7 +1017,8 @@ static noinline int avc_denied(u32 ssid, u32 tsid, · 6 unmodified lines
1012 * driver field is used to specify which set contains the permission.1017 * driver field is used to specify which set contains the permission.
1013 */1018 */
1014int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,1019int 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)
1016{1022{
1017 struct avc_node *node;1023 struct avc_node *node;
1018 struct av_decision avd;1024 struct av_decision avd;
@@ -1047,22 +1053,23 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, · 28 unmodified lines
1047 local_xpd.auditallow = &auditallow;1053 local_xpd.auditallow = &auditallow;
1048 local_xpd.dontaudit = &dontaudit;1054 local_xpd.dontaudit = &dontaudit;
1049 1055
1050 xpd = avc_xperms_decision_lookup(driver, xp_node);1056 xpd = avc_xperms_decision_lookup(driver, base_perm, xp_node);
1051 if (unlikely(!xpd)) {1057 if (unlikely(!xpd)) {
1052 /*1058 /*
1053 * Compute the extended_perms_decision only if the driver1059 * Compute the extended_perms_decision only if the driver
1054 * is flagged1060 * is flagged and the base permission is known.
1055 */1061 */
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)) {
1057 avd.allowed &= ~requested;1064 avd.allowed &= ~requested;
1058 goto decision;1065 goto decision;
1059 }1066 }
1060 rcu_read_unlock();1067 rcu_read_unlock();
1061 security_compute_xperms_decision(ssid, tsid, tclass,1068 security_compute_xperms_decision(ssid, tsid, tclass, driver,
1062 driver, &local_xpd);1069 base_perm, &local_xpd);
1063 rcu_read_lock();1070 rcu_read_lock();
1064 avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested,1071 avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver,
1065 driver, xperm, ssid, tsid, tclass, avd.seqno,1072 base_perm, xperm, ssid, tsid, tclass, avd.seqno,
1066 &local_xpd, 0);1073 &local_xpd, 0);
1067 } else {1074 } else {
1068 avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd);1075 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
1075decision:1082decision:
1076 denied = requested & ~(avd.allowed);1083 denied = requested & ~(avd.allowed);
1077 if (unlikely(denied))1084 if (unlikely(denied))
1078 rc = avc_denied(ssid, tsid, tclass, requested,1085 rc = avc_denied(ssid, tsid, tclass, requested, driver,
1079 driver, xperm, AVC_EXTENDED_PERMS, &avd);1086 base_perm, xperm, AVC_EXTENDED_PERMS, &avd);
1080 1087
1081 rcu_read_unlock();1088 rcu_read_unlock();
1082 1089
@@ -1110,7 +1117,7 @@ static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass, · 27 unmodified lines
1110 avc_compute_av(ssid, tsid, tclass, avd, &xp_node);1117 avc_compute_av(ssid, tsid, tclass, avd, &xp_node);
1111 denied = requested & ~(avd->allowed);1118 denied = requested & ~(avd->allowed);
1112 if (unlikely(denied))1119 if (unlikely(denied))
1113 return avc_denied(ssid, tsid, tclass, requested, 0, 0,1120 return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
1114 flags, avd);1121 flags, avd);
1115 return 0;1122 return 0;
1116}1123}
@@ -1158,7 +1165,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, · 41 unmodified lines
1158 rcu_read_unlock();1165 rcu_read_unlock();
1159 1166
1160 if (unlikely(denied))1167 if (unlikely(denied))
1161 return avc_denied(ssid, tsid, tclass, requested, 0, 0,1168 return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
1162 flags, avd);1169 flags, avd);
1163 return 0;1170 return 0;
1164}1171}
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
3688 return 0;3688 return 0;
3689 3689
3690 isec = inode_security(inode);3690 isec = inode_security(inode);
3691 rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,3691 rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, requested,
3692 requested, driver, xperm, &ad);3692 driver, AVC_EXT_IOCTL, xperm, &ad);
3693out:3693out:
3694 return rc;3694 return rc;
3695}3695}
@@ -5952,7 +5952,7 @@ static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_t · 2256 unmodified lines
5952 xperm = nlmsg_type & 0xff;5952 xperm = nlmsg_type & 0xff;
5953 5953
5954 return avc_has_extended_perms(current_sid(), sksec->sid, sksec->sclass,5954 return avc_has_extended_perms(current_sid(), sksec->sid, sksec->sclass,
5955 perms, driver, xperm, &ad);5955 perms, driver, AVC_EXT_NLMSG, xperm, &ad);
5956}5956}
5957 5957
5958static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)5958static 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
136int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,136int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,
137 struct common_audit_data *auditdata);137 struct common_audit_data *auditdata);
138 138
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 */
139int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,141int 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);
141 144
142u32 avc_policy_seqno(void);145u32 avc_policy_seqno(void);
143 146
security/selinux/include/security.h+3−0
@@ -239,6 +239,7 @@ struct extended_perms_data { · 238 unmodified lines
239struct extended_perms_decision {239struct extended_perms_decision {
240 u8 used;240 u8 used;
241 u8 driver;241 u8 driver;
242 u8 base_perm;
242 struct extended_perms_data *allowed;243 struct extended_perms_data *allowed;
243 struct extended_perms_data *auditallow;244 struct extended_perms_data *auditallow;
244 struct extended_perms_data *dontaudit;245 struct extended_perms_data *dontaudit;
@@ -246,6 +247,7 @@ struct extended_perms_decision { · 1 unmodified line
246 247
247struct extended_perms {248struct extended_perms {
248 u16 len; /* length associated decision chain */249 u16 len; /* length associated decision chain */
250 u8 base_perms; /* which base permissions are covered */
249 struct extended_perms_data drivers; /* flag drivers that are used */251 struct extended_perms_data drivers; /* flag drivers that are used */
250};252};
251 253
@@ -257,6 +259,7 @@ void security_compute_av(u32 ssid, u32 tsid, u16 tclass, · 5 unmodified lines
257 struct extended_perms *xperms);259 struct extended_perms *xperms);
258 260
259void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, u8 driver,261void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, u8 driver,
262 u8 base_perm,
260 struct extended_perms_decision *xpermd);263 struct extended_perms_decision *xpermd);
261 264
262void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass,265void 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
582}582}
583 583
584/*584/*
585 * Flag which drivers have permissions.585 * Flag which drivers have permissions and which base permissions are covered.
586 */586 */
587void services_compute_xperms_drivers(587void services_compute_xperms_drivers(
588 struct extended_perms *xperms,588 struct extended_perms *xperms,
@@ -592,12 +592,19 @@ void services_compute_xperms_drivers( · 3 unmodified lines
592 592
593 switch (node->datum.u.xperms->specified) {593 switch (node->datum.u.xperms->specified) {
594 case AVTAB_XPERMS_IOCTLDRIVER:594 case AVTAB_XPERMS_IOCTLDRIVER:
595 xperms->base_perms |= AVC_EXT_IOCTL;
595 /* if one or more driver has all permissions allowed */596 /* if one or more driver has all permissions allowed */
596 for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)597 for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
597 xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];598 xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
598 break;599 break;
599 case AVTAB_XPERMS_IOCTLFUNCTION:600 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;
600 case AVTAB_XPERMS_NLMSG:606 case AVTAB_XPERMS_NLMSG:
607 xperms->base_perms |= AVC_EXT_NLMSG;
601 /* if allowing permissions within a driver */608 /* if allowing permissions within a driver */
602 security_xperm_set(xperms->drivers.p,609 security_xperm_set(xperms->drivers.p,
603 node->datum.u.xperms->driver);610 node->datum.u.xperms->driver);
@@ -631,8 +638,7 @@ static void context_struct_compute_av(struct policydb *policydb, · 27 unmodified lines
631 avd->auditallow = 0;638 avd->auditallow = 0;
632 avd->auditdeny = 0xffffffff;639 avd->auditdeny = 0xffffffff;
633 if (xperms) {640 if (xperms) {
634 memset(&xperms->drivers, 0, sizeof(xperms->drivers));641 memset(xperms, 0, sizeof(*xperms));
635 xperms->len = 0;
636 }642 }
637 643
638 if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {644 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
969{975{
970 switch (node->datum.u.xperms->specified) {976 switch (node->datum.u.xperms->specified) {
971 case AVTAB_XPERMS_IOCTLFUNCTION:977 case AVTAB_XPERMS_IOCTLFUNCTION:
972 case AVTAB_XPERMS_NLMSG:978 if (xpermd->base_perm != AVC_EXT_IOCTL ||
973 if (xpermd->driver != node->datum.u.xperms->driver)979 xpermd->driver != node->datum.u.xperms->driver)
974 return;980 return;
975 break;981 break;
976 case AVTAB_XPERMS_IOCTLDRIVER:982 case AVTAB_XPERMS_IOCTLDRIVER:
977 if (!security_xperm_test(node->datum.u.xperms->perms.p,983 if (xpermd->base_perm != AVC_EXT_IOCTL ||
978 xpermd->driver))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)
979 return;991 return;
980 break;992 break;
981 default:993 default:
@@ -1010,6 +1022,7 @@ void security_compute_xperms_decision(u32 ssid, · 28 unmodified lines
1010 u32 tsid,1022 u32 tsid,
1011 u16 orig_tclass,1023 u16 orig_tclass,
1012 u8 driver,1024 u8 driver,
1025 u8 base_perm,
1013 struct extended_perms_decision *xpermd)1026 struct extended_perms_decision *xpermd)
1014{1027{
1015 struct selinux_policy *policy;1028 struct selinux_policy *policy;
@@ -1023,6 +1036,7 @@ void security_compute_xperms_decision(u32 ssid, · 7 unmodified lines
1023 struct ebitmap_node *snode, *tnode;1036 struct ebitmap_node *snode, *tnode;
1024 unsigned int i, j;1037 unsigned int i, j;
1025 1038
1039 xpermd->base_perm = base_perm;
1026 xpermd->driver = driver;1040 xpermd->driver = driver;
1027 xpermd->used = 0;1041 xpermd->used = 0;
1028 memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));1042 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