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.

By default, first run remains synchronous for compatibility purposes
(FDE, FBEv1, FBEv2)

Features:
- looks and waits for manager UID in /data/system/packages.list
- 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()
- track_throne_function, packages.list, spinlock-on-d_lock based polling
- is_manager_apk, apk, spinlock-on-d_lock based polling

This is a squash of:
https://github.com/tiann/KernelSU/pull/2632

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`
0b05e927...8783badd

Co-Authored-By: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-Authored-By: Yaroslav Zviezda <10716792+acroreiser@users.noreply.github.com>
Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-09-24 01:50:49 +08:00
parent 23dde3f863
commit 86ccca18eb
4 changed files with 130 additions and 2 deletions

View File

@@ -19,6 +19,7 @@
#include "klog.h" // IWYU pragma: keep
#include "kernel_compat.h"
#include "manager_sign.h"
#include "throne_tracker.h"
struct sdesc {
struct shash_desc shash;
@@ -265,6 +266,23 @@ check_v2_signature(char *path, bool check_multi_manager, int *signature_index)
bool v3_1_signing_exist = false;
int matched_index = -1;
int i;
struct path kpath;
if (kern_path(path, 0, &kpath))
return false;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
if (inode_is_locked(kpath.dentry->d_inode))
#else
if (mutex_is_locked(&kpath.dentry->d_inode->i_mutex))
#endif
{
pr_info("%s: inode is locked for %s\n", __func__, path);
path_put(&kpath);
return false;
}
path_put(&kpath);
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("open %s error.\n", path);
@@ -420,10 +438,42 @@ module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
bool is_manager_apk(char *path)
{
int tries = 0;
while (tries++ < 10) {
if (!is_lock_held(path))
break;
pr_info("%s: waiting for %s\n", __func__, path);
msleep(100);
}
// let it go, if retry fails, check_v2_signature will fail to open it anyway
if (tries == 10) {
pr_info("%s: timeout for %s\n", __func__, path);
return false;
}
return check_v2_signature(path, false, NULL);
}
bool is_dynamic_manager_apk(char *path, int *signature_index)
{
int tries = 0;
while (tries++ < 10) {
if (!is_lock_held(path))
break;
pr_info("%s: waiting for %s\n", __func__, path);
msleep(100);
}
// let it go, if retry fails, check_v2_signature will fail to open it anyway
if (tries == 10) {
pr_info("%s: timeout for %s\n", __func__, path);
return false;
}
return check_v2_signature(path, true, signature_index);
}