1+ #include <linux/rcupdate.h>
2+ #include <linux/limits.h>
3+ #include <linux/rculist.h>
14#include <linux/mutex.h>
25#include <linux/task_work.h>
36#include <linux/capability.h>
1720#include "selinux/selinux.h"
1821#include "allowlist.h"
1922#include "manager.h"
20- #include "syscall_hook_manager.h"
2123#include "su_mount_ns.h"
2224
2325#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
@@ -84,6 +86,7 @@ static void init_default_profiles()
8486
8587struct perm_data {
8688 struct list_head list ;
89+ struct rcu_head rcu ;
8790 struct app_profile profile ;
8891};
8992
@@ -94,18 +97,18 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
9497
9598#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
9699
97- void persistent_allow_list (void );
100+ void ksu_persistent_allow_list (void );
98101
99102void ksu_show_allow_list (void )
100103{
101104 struct perm_data * p = NULL ;
102- struct list_head * pos = NULL ;
103105 pr_info ("ksu_show_allow_list\n" );
104- list_for_each ( pos , & allow_list ) {
105- p = list_entry ( pos , struct perm_data , list );
106+ rcu_read_lock ();
107+ list_for_each_entry_rcu ( p , & allow_list , list ) {
106108 pr_info ("uid :%d, allow: %d\n" , p -> profile .current_uid ,
107109 p -> profile .allow_su );
108110 }
111+ rcu_read_unlock ();
109112}
110113
111114#ifdef CONFIG_KSU_DEBUG
@@ -119,18 +122,17 @@ static void ksu_grant_root_to_shell()
119122 strcpy (profile .key , "com.android.shell" );
120123 strcpy (profile .rp_config .profile .selinux_domain ,
121124 KSU_DEFAULT_SELINUX_DOMAIN );
122- ksu_set_app_profile (& profile , false );
125+ ksu_set_app_profile (& profile );
123126}
124127#endif
125128
126129bool ksu_get_app_profile (struct app_profile * profile )
127130{
128131 struct perm_data * p = NULL ;
129- struct list_head * pos = NULL ;
130132 bool found = false;
131133
132- list_for_each ( pos , & allow_list ) {
133- p = list_entry ( pos , struct perm_data , list );
134+ rcu_read_lock ();
135+ list_for_each_entry_rcu ( p , & allow_list , list ) {
134136 bool uid_match = profile -> current_uid == p -> profile .current_uid ;
135137 if (uid_match ) {
136138 // found it, override it with ours
@@ -141,6 +143,7 @@ bool ksu_get_app_profile(struct app_profile *profile)
141143 }
142144
143145exit :
146+ rcu_read_unlock ();
144147 return found ;
145148}
146149
@@ -175,34 +178,50 @@ static bool profile_valid(struct app_profile *profile)
175178 return true;
176179}
177180
178- bool ksu_set_app_profile (struct app_profile * profile , bool persist )
181+ int ksu_set_app_profile (struct app_profile * profile )
179182{
180- struct perm_data * p = NULL ;
181- struct list_head * pos = NULL ;
182- bool result = false ;
183+ struct perm_data * p = NULL , * np ;
184+ int result = 0 ;
185+ u16 count = 0 ;
183186
184187 if (!profile_valid (profile )) {
185188 pr_err ("Failed to set app profile: invalid profile!\n" );
186- return false ;
189+ return - EINVAL ;
187190 }
188191
189- list_for_each (pos , & allow_list ) {
190- p = list_entry (pos , struct perm_data , list );
192+ mutex_lock (& allowlist_mutex );
193+
194+ list_for_each_entry (p , & allow_list , list ) {
195+ ++ count ;
191196 // both uid and package must match, otherwise it will break multiple package with different user id
192197 if (profile -> current_uid == p -> profile .current_uid &&
193198 !strcmp (profile -> key , p -> profile .key )) {
194199 // found it, just override it all!
195- memcpy (& p -> profile , profile , sizeof (* profile ));
196- result = true;
200+ np = (struct perm_data * )kzalloc (sizeof (struct perm_data ),
201+ GFP_KERNEL );
202+ if (!np ) {
203+ result = - ENOMEM ;
204+ goto out_unlock ;
205+ }
206+ memcpy (& np -> profile , profile , sizeof (* profile ));
207+ list_replace_rcu (& p -> list , & np -> list );
208+ kfree_rcu (p , rcu );
197209 goto out ;
198210 }
199211 }
200212
213+ if (unlikely (count == U16_MAX )) {
214+ pr_err ("too many app profile\n" );
215+ result = - E2BIG ;
216+ goto out_unlock ;
217+ }
218+
201219 // not found, alloc a new node!
202220 p = (struct perm_data * )kzalloc (sizeof (struct perm_data ), GFP_KERNEL );
203221 if (!p ) {
204222 pr_err ("ksu_set_app_profile alloc failed\n" );
205- return false;
223+ result = - ENOMEM ;
224+ goto out_unlock ;
206225 }
207226
208227 memcpy (& p -> profile , profile , sizeof (* profile ));
@@ -216,10 +235,23 @@ bool ksu_set_app_profile(struct app_profile *profile, bool persist)
216235 profile -> key , profile -> current_uid ,
217236 profile -> nrp_config .profile .umount_modules );
218237 }
219- list_add_tail (& p -> list , & allow_list );
238+
239+ list_add_tail_rcu (& p -> list , & allow_list );
220240
221241out :
222- if (profile -> current_uid <= BITMAP_UID_MAX ) {
242+ result = 0 ;
243+
244+ // check if the default profiles is changed, cache it to a single struct to accelerate access.
245+ if (unlikely (!strcmp (profile -> key , "$" ))) {
246+ // set default non root profile
247+ memcpy (& default_non_root_profile , & profile -> nrp_config .profile ,
248+ sizeof (default_non_root_profile ));
249+ } else if (unlikely (!strcmp (profile -> key , "#" ))) {
250+ // set default root profile
251+ // TODO: Do we really need this?
252+ memcpy (& default_root_profile , & profile -> rp_config .profile ,
253+ sizeof (default_root_profile ));
254+ } else if (profile -> current_uid <= BITMAP_UID_MAX ) {
223255 if (profile -> allow_su )
224256 allow_list_bitmap [profile -> current_uid / BITS_PER_BYTE ] |=
225257 1 << (profile -> current_uid % BITS_PER_BYTE );
@@ -235,34 +267,16 @@ bool ksu_set_app_profile(struct app_profile *profile, bool persist)
235267 if (allow_list_pointer >= ARRAY_SIZE (allow_list_arr )) {
236268 pr_err ("too many apps registered\n" );
237269 WARN_ON (1 );
238- return false;
270+ } else {
271+ allow_list_arr [allow_list_pointer ++ ] = profile -> current_uid ;
239272 }
240- allow_list_arr [allow_list_pointer ++ ] = profile -> current_uid ;
241273 } else {
242274 remove_uid_from_arr (profile -> current_uid );
243275 }
244276 }
245- result = true;
246-
247- // check if the default profiles is changed, cache it to a single struct to accelerate access.
248- if (unlikely (!strcmp (profile -> key , "$" ))) {
249- // set default non root profile
250- memcpy (& default_non_root_profile , & profile -> nrp_config .profile ,
251- sizeof (default_non_root_profile ));
252- }
253-
254- if (unlikely (!strcmp (profile -> key , "#" ))) {
255- // set default root profile
256- memcpy (& default_root_profile , & profile -> rp_config .profile ,
257- sizeof (default_root_profile ));
258- }
259-
260- if (persist ) {
261- persistent_allow_list ();
262- // FIXME: use a new flag
263- ksu_mark_running_process ();
264- }
265277
278+ out_unlock :
279+ mutex_unlock (& allowlist_mutex );
266280 return result ;
267281}
268282
@@ -329,55 +343,72 @@ bool ksu_uid_should_umount(uid_t uid)
329343 }
330344}
331345
332- struct root_profile * ksu_get_root_profile (uid_t uid )
346+ void ksu_get_root_profile (uid_t uid , struct root_profile * profile )
333347{
334348 struct perm_data * p = NULL ;
335- struct list_head * pos = NULL ;
336349
337- list_for_each (pos , & allow_list ) {
338- p = list_entry (pos , struct perm_data , list );
350+ if (is_uid_manager (uid )) {
351+ goto use_default ;
352+ }
353+
354+ rcu_read_lock ();
355+ list_for_each_entry_rcu (p , & allow_list , list ) {
339356 if (uid == p -> profile .current_uid && p -> profile .allow_su ) {
340357 if (!p -> profile .rp_config .use_default ) {
341- return & p -> profile .rp_config .profile ;
358+ memcpy (profile , & p -> profile .rp_config .profile ,
359+ sizeof (* profile ));
360+ rcu_read_unlock ();
361+ return ;
342362 }
343363 }
344364 }
365+ rcu_read_unlock ();
345366
367+ use_default :
346368 // use default profile
347- return & default_root_profile ;
369+ memcpy ( profile , & default_root_profile , sizeof ( * profile )) ;
348370}
349371
350- bool ksu_get_allow_list (int * array , int * length , bool allow )
372+ bool ksu_get_allow_list (int * array , u16 length , u16 * out_length , u16 * out_total ,
373+ bool allow )
351374{
352375 struct perm_data * p = NULL ;
353- struct list_head * pos = NULL ;
354- int i = 0 ;
355- list_for_each (pos , & allow_list ) {
356- p = list_entry (pos , struct perm_data , list );
376+ u16 i = 0 , j = 0 ;
377+ rcu_read_lock ();
378+ list_for_each_entry_rcu (p , & allow_list , list ) {
357379 // pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
358- if (p -> profile .allow_su == allow ) {
359- array [i ++ ] = p -> profile .current_uid ;
380+ if (p -> profile .allow_su == allow &&
381+ !is_uid_manager (p -> profile .current_uid )) {
382+ if (j < length ) {
383+ array [j ++ ] = p -> profile .current_uid ;
384+ }
385+ ++ i ;
360386 }
361387 }
362- * length = i ;
388+ rcu_read_unlock ();
389+ if (out_length ) {
390+ * out_length = j ;
391+ }
392+ if (out_total ) {
393+ * out_total = i ;
394+ }
363395
364396 return true;
365397}
366398
399+ // TODO: move to kernel thread or work queue
367400static void do_persistent_allow_list (struct callback_head * _cb )
368401{
369402 u32 magic = FILE_MAGIC ;
370403 u32 version = FILE_FORMAT_VERSION ;
371404 struct perm_data * p = NULL ;
372- struct list_head * pos = NULL ;
373405 loff_t off = 0 ;
374406
375- mutex_lock (& allowlist_mutex );
376407 struct file * fp =
377408 filp_open (KERNEL_SU_ALLOWLIST , O_WRONLY | O_CREAT | O_TRUNC , 0644 );
378409 if (IS_ERR (fp )) {
379410 pr_err ("save_allow_list create file failed: %ld\n" , PTR_ERR (fp ));
380- goto unlock ;
411+ goto out ;
381412 }
382413
383414 // store magic and version
@@ -391,22 +422,22 @@ static void do_persistent_allow_list(struct callback_head *_cb)
391422 goto close_file ;
392423 }
393424
394- list_for_each ( pos , & allow_list ) {
395- p = list_entry ( pos , struct perm_data , list );
425+ mutex_lock ( & allowlist_mutex );
426+ list_for_each_entry ( p , & allow_list , list ) {
396427 pr_info ("save allow list, name: %s uid :%d, allow: %d\n" ,
397428 p -> profile .key , p -> profile .current_uid , p -> profile .allow_su );
398429
399430 kernel_write (fp , & p -> profile , sizeof (p -> profile ), & off );
400431 }
432+ mutex_unlock (& allowlist_mutex );
401433
402434close_file :
403435 filp_close (fp , 0 );
404- unlock :
405- mutex_unlock (& allowlist_mutex );
436+ out :
406437 kfree (_cb );
407438}
408439
409- void persistent_allow_list ()
440+ void ksu_persistent_allow_list ()
410441{
411442 struct task_struct * tsk ;
412443
@@ -478,7 +509,7 @@ void ksu_load_allow_list()
478509
479510 pr_info ("load_allow_uid, name: %s, uid: %d, allow: %d\n" , profile .key ,
480511 profile .current_uid , profile .allow_su );
481- ksu_set_app_profile (& profile , false );
512+ ksu_set_app_profile (& profile );
482513 }
483514
484515exit :
@@ -498,7 +529,6 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *),
498529 }
499530
500531 bool modified = false;
501- // TODO: use RCU!
502532 mutex_lock (& allowlist_mutex );
503533 list_for_each_entry_safe (np , n , & allow_list , list ) {
504534 uid_t uid = np -> profile .current_uid ;
@@ -508,20 +538,20 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *),
508538 if (!is_preserved_uid && !is_uid_valid (uid , package , data )) {
509539 modified = true;
510540 pr_info ("prune uid: %d, package: %s\n" , uid , package );
511- list_del (& np -> list );
541+ list_del_rcu (& np -> list );
542+ kfree_rcu (np , rcu );
512543 if (likely (uid <= BITMAP_UID_MAX )) {
513544 allow_list_bitmap [uid / BITS_PER_BYTE ] &=
514545 ~(1 << (uid % BITS_PER_BYTE ));
515546 }
516547 remove_uid_from_arr (uid );
517- smp_mb ();
518- kfree (np );
519548 }
520549 }
521550 mutex_unlock (& allowlist_mutex );
522551
523552 if (modified ) {
524- persistent_allow_list ();
553+ smp_mb ();
554+ ksu_persistent_allow_list ();
525555 }
526556}
527557
0 commit comments