Skip to content

Commit 9f68f23

Browse files
authored
kernel: use rcu to access allowlist, refactor get allowlist api (#3093)
1 parent c44adc1 commit 9f68f23

11 files changed

Lines changed: 254 additions & 136 deletions

File tree

kernel/allowlist.c

Lines changed: 101 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
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>
@@ -17,7 +20,6 @@
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

8587
struct 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

99102
void 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

126129
bool 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

143145
exit:
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

221241
out:
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
367400
static 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

402434
close_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

484515
exit:
@@ -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

kernel/allowlist.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,18 @@ bool __ksu_is_allow_uid_for_current(uid_t uid);
2828
#define ksu_is_allow_uid_for_current(uid) \
2929
unlikely(__ksu_is_allow_uid_for_current(uid))
3030

31-
bool ksu_get_allow_list(int *array, int *length, bool allow);
31+
bool ksu_get_allow_list(int *array, u16 length, u16 *out_length, u16 *out_total,
32+
bool allow);
3233

3334
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *),
3435
void *data);
36+
void ksu_persistent_allow_list();
3537

3638
bool ksu_get_app_profile(struct app_profile *);
37-
bool ksu_set_app_profile(struct app_profile *, bool persist);
39+
int ksu_set_app_profile(struct app_profile *);
3840

3941
bool ksu_uid_should_umount(uid_t uid);
40-
struct root_profile *ksu_get_root_profile(uid_t uid);
42+
void ksu_get_root_profile(uid_t uid, struct root_profile *);
4143

4244
static inline bool is_appuid(uid_t uid)
4345
{

0 commit comments

Comments
 (0)