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.

Fixes: d1d991efaf34 ("selinux: Add netlink xperm support")
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>

authored by Thiébaud Weksteen and committed by Paul Moore 5e7f0efd 900f83cf

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