| @@ -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 is | 174 | * using a linked list for extended_perms_decision lookup because the list is |
| 175 | * always small. i.e. less than 5, typically 1 | 175 | * always small. i.e. less than 5, typically 1 |
| 176 | */ | 176 | */ |
| 177 | static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver, | 177 | static struct extended_perms_decision * |
| 178 | struct avc_xperms_node *xp_node) | 178 | avc_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 | |
| 207 | static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node, | 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 | 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 |
| 245 | static void avc_copy_xperms_decision(struct extended_perms_decision *dest, | 248 | static 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 event | 813 | * @event : Updating event |
| 808 | * @perms : Permission mask bits | 814 | * @perms : Permission mask bits |
| 809 | * @driver: xperm driver information | 815 | * @driver: xperm driver information |
| | 816 | * @base_perm: the base permission associated with the extended permission |
| 810 | * @xperm: xperm permissions | 817 | * @xperm: xperm permissions |
| 811 | * @ssid: AVC entry source sid | 818 | * @ssid: AVC entry source sid |
| 812 | * @tsid: AVC entry target sid | 819 | * @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 object | 827 | * 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 | */ |
| 823 | static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, | 830 | static 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 | |
| 990 | static noinline int avc_denied(u32 ssid, u32 tsid, | 996 | static 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 | */ |
| 1014 | int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | 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 | 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 driver | 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 | 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 |
| 1075 | decision: | 1082 | decision: |
| 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 | } |