@@ -174,13 +174,15 @@ int avc_get_hash_stats(char *page)
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,
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)
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,
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,
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 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
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 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
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,
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,
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,
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,
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,
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,
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,
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,
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
}
0 commit comments