Skip to content

Commit 230b0b9

Browse files
kernel: throne_tracker: offload to kthread (tiann#2632)
Run throne_tracker() in kthread instead of blocking the caller. Prevents full lockup during installation and removing the manager. First run remains synchronous for compatibility purposes (FDE, FBEv1, FBEv2) Features: - run track_throne() in a kthread after the first synchronous run - prevent duplicate thread creation with a single-instance check - spinlock-on-d_lock based polling adressing possible race conditions. Race conditions adressed - single instance kthread lock, smp_mb() - is_manager_apk, apk, spinlock-on-d_lock based polling This is a squash of: tiann#2632 Rebased on top of tiann#2757 Original skeleton based on: `kernelsu: move throne_tracker() to kthread` `kernelsu: check locking before accessing files and dirs during searching manager` `kernelsu: look for manager UID in /data/system/packages.list, not /data/system/packages.list.tmp` acroreiser/android_kernel_lge_hammerhead@0b05e92...8783bad Co-Authored-By: backslashxx <[email protected]> Co-Authored-By: Yaroslav Zviezda <[email protected]> Signed-off-by: backslashxx <[email protected]>
1 parent 0de076f commit 230b0b9

File tree

2 files changed

+108
-2
lines changed

2 files changed

+108
-2
lines changed

kernel/apk_sign.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,39 @@ static bool has_v1_signature_file(struct file *fp)
171171
return false;
172172
}
173173

174+
/*
175+
* small helper to check if lock is held
176+
* false - file is stable
177+
* true - file is being deleted/renamed
178+
* possibly optional
179+
*
180+
*/
181+
static bool is_lock_held(const char *path)
182+
{
183+
struct path kpath;
184+
185+
// kern_path returns 0 on success
186+
if (kern_path(path, 0, &kpath))
187+
return true;
188+
189+
// just being defensive
190+
if (!kpath.dentry) {
191+
path_put(&kpath);
192+
return true;
193+
}
194+
195+
if (!spin_trylock(&kpath.dentry->d_lock)) {
196+
pr_info("%s: lock held, bail out!\n", __func__);
197+
path_put(&kpath);
198+
return true;
199+
}
200+
// we hold it ourselves here!
201+
202+
spin_unlock(&kpath.dentry->d_lock);
203+
path_put(&kpath);
204+
return false;
205+
}
206+
174207
static __always_inline bool check_v2_signature(char *path,
175208
unsigned expected_size,
176209
const char *expected_sha256)
@@ -187,6 +220,23 @@ static __always_inline bool check_v2_signature(char *path,
187220
bool v3_1_signing_exist = false;
188221

189222
int i;
223+
struct path kpath;
224+
if (kern_path(path, 0, &kpath))
225+
return false;
226+
227+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
228+
if (inode_is_locked(kpath.dentry->d_inode))
229+
#else
230+
if (mutex_is_locked(&kpath.dentry->d_inode->i_mutex))
231+
#endif
232+
{
233+
pr_info("%s: inode is locked for %s\n", __func__, path);
234+
path_put(&kpath);
235+
return false;
236+
}
237+
238+
path_put(&kpath);
239+
190240
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
191241
if (IS_ERR(fp)) {
192242
pr_err("open %s error.\n", path);
@@ -316,6 +366,22 @@ module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
316366

317367
bool is_manager_apk(char *path)
318368
{
369+
int tries = 0;
370+
371+
while (tries++ < 10) {
372+
if (!is_lock_held(path))
373+
break;
374+
375+
pr_info("%s: waiting for %s\n", __func__, path);
376+
msleep(100);
377+
}
378+
379+
// let it go, if retry fails, check_v2_signature will fail to open it anyway
380+
if (tries == 10) {
381+
pr_info("%s: timeout for %s\n", __func__, path);
382+
return false;
383+
}
384+
319385
return (check_v2_signature(path, 0x363, "4359c171f32543394cbc23ef908c4bb94cad7c8087002ba164c8230948c21549") // dummy.keystore
320386
|| check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH) // ksu official
321387
/* || check_v2_signature(path, custom_size, custom_hash) // add more as you like */

kernel/throne_tracker.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@
1111
#include "allowlist.h"
1212
#include "klog.h" // IWYU pragma: keep
1313
#include "ksu.h"
14+
#include "ksud.h"
1415
#include "manager.h"
1516
#include "throne_tracker.h"
1617
#include "kernel_compat.h"
1718

19+
#include <linux/kthread.h>
20+
#include <linux/sched.h>
21+
1822
uid_t ksu_manager_uid = KSU_INVALID_UID;
1923

24+
static struct task_struct *throne_thread;
25+
2026
#define USER_DATA_BASE_PATH "/data/user_de"
2127
#define MAX_SUPPORTED_USERS 32 // Supports up to 32 users
2228
#define USER_DATA_PATH_LEN 384 // 384 is enough for /data/user_de/{userid}/<package>
@@ -512,7 +518,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
512518
struct file *file;
513519

514520
if (!stop) {
515-
file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW, 0);
521+
file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW | O_DIRECTORY, 0);
516522
if (IS_ERR(file)) {
517523
pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file));
518524
goto skip_iterate;
@@ -571,7 +577,7 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
571577
return exist;
572578
}
573579

574-
void track_throne()
580+
static void track_throne_function()
575581
{
576582
struct list_head uid_list;
577583
INIT_LIST_HEAD(&uid_list);
@@ -621,6 +627,40 @@ void track_throne()
621627
}
622628
}
623629

630+
static int throne_tracker_thread(void *data)
631+
{
632+
pr_info("%s: pid: %d started\n", __func__, current->pid);
633+
// for the kthread, we need to escape to root
634+
// since it does not inherit the caller's context.
635+
// this runs as root but without the capabilities, so call it with false
636+
escape_to_root(false);
637+
track_throne_function();
638+
throne_thread = NULL;
639+
smp_mb();
640+
pr_info("%s: pid: %d exit!\n", __func__, current->pid);
641+
return 0;
642+
}
643+
644+
void track_throne()
645+
{
646+
static bool throne_tracker_first_run __read_mostly = true;
647+
if (unlikely(throne_tracker_first_run)) {
648+
track_throne_function();
649+
throne_tracker_first_run = false;
650+
return;
651+
}
652+
653+
smp_mb();
654+
if (throne_thread != NULL) // single instance lock
655+
return;
656+
657+
throne_thread = kthread_run(throne_tracker_thread, NULL, "throne_tracker");
658+
if (IS_ERR(throne_thread)) {
659+
throne_thread = NULL;
660+
return;
661+
}
662+
}
663+
624664
void ksu_throne_tracker_init()
625665
{
626666
// nothing to do

0 commit comments

Comments
 (0)