@@ -174,13 +174,15 @@ int avc_get_hash_stats(char *page)
174174 * using a linked list for extended_perms_decision lookup because the list is
175175 * always small. i.e. less than 5, typically 1
176176 */
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 )
179180{
180181 struct avc_xperms_decision_node * xpd_node ;
181182
182183 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 )
184186 return & xpd_node -> xpd ;
185187 }
186188 return NULL ;
@@ -205,11 +207,12 @@ avc_xperms_has_perm(struct extended_perms_decision *xpd,
205207}
206208
207209static void avc_xperms_allow_perm (struct avc_xperms_node * xp_node ,
208- u8 driver , u8 perm )
210+ u8 driver , u8 base_perm , u8 perm )
209211{
210212 struct extended_perms_decision * xpd ;
211213 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 );
213216 if (xpd && xpd -> allowed )
214217 security_xperm_set (xpd -> allowed -> p , perm );
215218}
@@ -245,6 +248,7 @@ static void avc_xperms_free(struct avc_xperms_node *xp_node)
245248static void avc_copy_xperms_decision (struct extended_perms_decision * dest ,
246249 struct extended_perms_decision * src )
247250{
251+ dest -> base_perm = src -> base_perm ;
248252 dest -> driver = src -> driver ;
249253 dest -> used = src -> used ;
250254 if (dest -> used & XPERMS_ALLOWED )
@@ -272,6 +276,7 @@ static inline void avc_quick_copy_xperms_decision(u8 perm,
272276 */
273277 u8 i = perm >> 5 ;
274278
279+ dest -> base_perm = src -> base_perm ;
275280 dest -> used = src -> used ;
276281 if (dest -> used & XPERMS_ALLOWED )
277282 dest -> allowed -> p [i ] = src -> allowed -> p [i ];
@@ -357,6 +362,7 @@ static int avc_xperms_populate(struct avc_node *node,
357362
358363 memcpy (dest -> xp .drivers .p , src -> xp .drivers .p , sizeof (dest -> xp .drivers .p ));
359364 dest -> xp .len = src -> xp .len ;
365+ dest -> xp .base_perms = src -> xp .base_perms ;
360366
361367 /* for each source xpd allocate a destination xpd and copy */
362368 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)
807813 * @event : Updating event
808814 * @perms : Permission mask bits
809815 * @driver: xperm driver information
816+ * @base_perm: the base permission associated with the extended permission
810817 * @xperm: xperm permissions
811818 * @ssid: AVC entry source sid
812819 * @tsid: AVC entry target sid
@@ -820,10 +827,9 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
820827 * otherwise, this function updates the AVC entry. The original AVC-entry object
821828 * will release later by RCU.
822829 */
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 )
827833{
828834 u32 hvalue ;
829835 int rc = 0 ;
@@ -880,7 +886,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
880886 case AVC_CALLBACK_GRANT :
881887 node -> ae .avd .allowed |= perms ;
882888 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 );
884890 break ;
885891 case AVC_CALLBACK_TRY_REVOKE :
886892 case AVC_CALLBACK_REVOKE :
@@ -987,10 +993,9 @@ static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass,
987993 avc_insert (ssid , tsid , tclass , avd , xp_node );
988994}
989995
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 )
994999{
9951000 if (flags & AVC_STRICT )
9961001 return - EACCES ;
@@ -999,7 +1004,7 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
9991004 !(avd -> flags & AVD_FLAGS_PERMISSIVE ))
10001005 return - EACCES ;
10011006
1002- avc_update_node (AVC_CALLBACK_GRANT , requested , driver ,
1007+ avc_update_node (AVC_CALLBACK_GRANT , requested , driver , base_perm ,
10031008 xperm , ssid , tsid , tclass , avd -> seqno , NULL , flags );
10041009 return 0 ;
10051010}
@@ -1012,7 +1017,8 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
10121017 * driver field is used to specify which set contains the permission.
10131018 */
10141019int 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 )
10161022{
10171023 struct avc_node * node ;
10181024 struct av_decision avd ;
@@ -1047,22 +1053,23 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
10471053 local_xpd .auditallow = & auditallow ;
10481054 local_xpd .dontaudit = & dontaudit ;
10491055
1050- xpd = avc_xperms_decision_lookup (driver , xp_node );
1056+ xpd = avc_xperms_decision_lookup (driver , base_perm , xp_node );
10511057 if (unlikely (!xpd )) {
10521058 /*
10531059 * Compute the extended_perms_decision only if the driver
1054- * is flagged
1060+ * is flagged and the base permission is known.
10551061 */
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 )) {
10571064 avd .allowed &= ~requested ;
10581065 goto decision ;
10591066 }
10601067 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 );
10631070 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 ,
10661073 & local_xpd , 0 );
10671074 } else {
10681075 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,
10751082decision :
10761083 denied = requested & ~(avd .allowed );
10771084 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 );
10801087
10811088 rcu_read_unlock ();
10821089
@@ -1110,7 +1117,7 @@ static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
11101117 avc_compute_av (ssid , tsid , tclass , avd , & xp_node );
11111118 denied = requested & ~(avd -> allowed );
11121119 if (unlikely (denied ))
1113- return avc_denied (ssid , tsid , tclass , requested , 0 , 0 ,
1120+ return avc_denied (ssid , tsid , tclass , requested , 0 , 0 , 0 ,
11141121 flags , avd );
11151122 return 0 ;
11161123}
@@ -1158,7 +1165,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
11581165 rcu_read_unlock ();
11591166
11601167 if (unlikely (denied ))
1161- return avc_denied (ssid , tsid , tclass , requested , 0 , 0 ,
1168+ return avc_denied (ssid , tsid , tclass , requested , 0 , 0 , 0 ,
11621169 flags , avd );
11631170 return 0 ;
11641171}
0 commit comments