kernel: throne_tracker: offload to kthread (tiann[#2632](https://github.com/SukiSU-Ultra/SukiSU-Ultra/issues/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:
https://github.com/tiann/KernelSU/pull/2632
Rebased on top of
https://github.com/tiann/KernelSU/pull/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`
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:
@@ -11,13 +11,19 @@
|
||||
#include "allowlist.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksu.h"
|
||||
#include "ksud.h"
|
||||
#include "manager.h"
|
||||
#include "throne_tracker.h"
|
||||
#include "kernel_compat.h"
|
||||
#include "dynamic_manager.h"
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
uid_t ksu_manager_uid = KSU_INVALID_UID;
|
||||
|
||||
static struct task_struct *throne_thread;
|
||||
|
||||
#define USER_DATA_BASE_PATH "/data/user_de"
|
||||
#define MAX_SUPPORTED_USERS 32 // Supports up to 32 users
|
||||
#define DATA_PATH_LEN 384 // 384 is enough for /data/app/<package>/base.apk and /data/user_de/{userid}/<package>
|
||||
@@ -526,7 +532,7 @@ void search_manager(const char *path, int depth, struct list_head *uid_data)
|
||||
struct file *file;
|
||||
|
||||
if (!stop) {
|
||||
file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW, 0);
|
||||
file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW | O_DIRECTORY, 0);
|
||||
if (IS_ERR(file)) {
|
||||
pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file));
|
||||
goto skip_iterate;
|
||||
@@ -584,7 +590,7 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
|
||||
return exist;
|
||||
}
|
||||
|
||||
void track_throne(void)
|
||||
static void track_throne_function(void)
|
||||
{
|
||||
struct list_head uid_list;
|
||||
INIT_LIST_HEAD(&uid_list);
|
||||
@@ -652,6 +658,41 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int throne_tracker_thread(void *data)
|
||||
{
|
||||
pr_info("%s: pid: %d started\n", __func__, current->pid);
|
||||
// for the kthread, we need to escape to root
|
||||
// since it does not inherit the caller's context.
|
||||
// this runs as root but without the capabilities, so call it with false
|
||||
escape_to_root(false);
|
||||
track_throne_function();
|
||||
throne_thread = NULL;
|
||||
smp_mb();
|
||||
pr_info("%s: pid: %d exit!\n", __func__, current->pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void track_throne(void)
|
||||
{
|
||||
static bool throne_tracker_first_run __read_mostly = true;
|
||||
if (unlikely(throne_tracker_first_run)) {
|
||||
track_throne_function();
|
||||
throne_tracker_first_run = false;
|
||||
return;
|
||||
}
|
||||
|
||||
smp_mb();
|
||||
if (throne_thread != NULL) // single instance lock
|
||||
return;
|
||||
|
||||
throne_thread = kthread_run(throne_tracker_thread, NULL, "throne_tracker");
|
||||
if (IS_ERR(throne_thread)) {
|
||||
throne_thread = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ksu_throne_tracker_init(void)
|
||||
{
|
||||
// nothing to do
|
||||
|
||||
Reference in New Issue
Block a user