| @@ -174,13 +174,15 @@ int avc_get_hash_stats(char *page) · 173 unmodified lines |
| 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; |
| @@ -205,11 +207,12 @@ avc_xperms_has_perm(struct extended_perms_decision *xpd, · 18 unmodified lines |
| 205 | 207 | } |
| 206 | 208 | |
| 207 | 209 | 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) |
| 209 | 211 | { |
| 210 | 212 | struct extended_perms_decision *xpd; |
| 211 | 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 | 216 | if (xpd && xpd->allowed) |
| 214 | 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 |
| 245 | 248 | static void avc_copy_xperms_decision(struct extended_perms_decision *dest, |
| 246 | 249 | struct extended_perms_decision *src) |
| 247 | 250 | { |
| 251 | + dest->base_perm = src->base_perm; |
| 248 | 252 | dest->driver = src->driver; |
| 249 | 253 | dest->used = src->used; |
| 250 | 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 | 277 | u8 i = perm >> 5; |
| 274 | 278 | |
| 279 | + dest->base_perm = src->base_perm; |
| 275 | 280 | dest->used = src->used; |
| 276 | 281 | if (dest->used & XPERMS_ALLOWED) |
| 277 | 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 | 363 | memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p)); |
| 359 | 364 | dest->xp.len = src->xp.len; |
| 365 | + dest->xp.base_perms = src->xp.base_perms; |
| 360 | 366 | |
| 361 | 367 | /* for each source xpd allocate a destination xpd and copy */ |
| 362 | 368 | list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) { |
| @@ -807,6 +813,7 @@ out: · 444 unmodified lines |
| 807 | 813 | * @event : Updating event |
| 808 | 814 | * @perms : Permission mask bits |
| 809 | 815 | * @driver: xperm driver information |
| 816 | + * @base_perm: the base permission associated with the extended permission |
| 810 | 817 | * @xperm: xperm permissions |
| 811 | 818 | * @ssid: AVC entry source sid |
| 812 | 819 | * @tsid: AVC entry target sid |
| @@ -820,10 +827,9 @@ out: · 7 unmodified lines |
| 820 | 827 | * otherwise, this function updates the AVC entry. The original AVC-entry object |
| 821 | 828 | * will release later by RCU. |
| 822 | 829 | */ |
| 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) |
| 827 | 833 | { |
| 828 | 834 | u32 hvalue; |
| 829 | 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 | 886 | case AVC_CALLBACK_GRANT: |
| 881 | 887 | node->ae.avd.allowed |= perms; |
| 882 | 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 | 890 | break; |
| 885 | 891 | case AVC_CALLBACK_TRY_REVOKE: |
| 886 | 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 | 993 | avc_insert(ssid, tsid, tclass, avd, xp_node); |
| 988 | 994 | } |
| 989 | 995 | |
| 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) |
| 994 | 999 | { |
| 995 | 1000 | if (flags & AVC_STRICT) |
| 996 | 1001 | return -EACCES; |
| @@ -999,7 +1004,7 @@ static noinline int avc_denied(u32 ssid, u32 tsid, · 2 unmodified lines |
| 999 | 1004 | !(avd->flags & AVD_FLAGS_PERMISSIVE)) |
| 1000 | 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 | 1008 | xperm, ssid, tsid, tclass, avd->seqno, NULL, flags); |
| 1004 | 1009 | return 0; |
| 1005 | 1010 | } |
| @@ -1012,7 +1017,8 @@ static noinline int avc_denied(u32 ssid, u32 tsid, · 6 unmodified lines |
| 1012 | 1017 | * driver field is used to specify which set contains the permission. |
| 1013 | 1018 | */ |
| 1014 | 1019 | 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) |
| 1016 | 1022 | { |
| 1017 | 1023 | struct avc_node *node; |
| 1018 | 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 | 1053 | local_xpd.auditallow = &auditallow; |
| 1048 | 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 | 1057 | if (unlikely(!xpd)) { |
| 1052 | 1058 | /* |
| 1053 | 1059 | * Compute the extended_perms_decision only if the driver |
| 1054 | | − * is flagged |
| 1060 | + * 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 | 1064 | avd.allowed &= ~requested; |
| 1058 | 1065 | goto decision; |
| 1059 | 1066 | } |
| 1060 | 1067 | 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); |
| 1063 | 1070 | 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, |
| 1066 | 1073 | &local_xpd, 0); |
| 1067 | 1074 | } else { |
| 1068 | 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 |
| 1075 | 1082 | decision: |
| 1076 | 1083 | denied = requested & ~(avd.allowed); |
| 1077 | 1084 | 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); |
| 1080 | 1087 | |
| 1081 | 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 | 1117 | avc_compute_av(ssid, tsid, tclass, avd, &xp_node); |
| 1111 | 1118 | denied = requested & ~(avd->allowed); |
| 1112 | 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 | 1121 | flags, avd); |
| 1115 | 1122 | return 0; |
| 1116 | 1123 | } |
| @@ -1158,7 +1165,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, · 41 unmodified lines |
| 1158 | 1165 | rcu_read_unlock(); |
| 1159 | 1166 | |
| 1160 | 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 | 1169 | flags, avd); |
| 1163 | 1170 | return 0; |
| 1164 | 1171 | } |