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

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));