Hook improvements (take 2) (#563)

Hi @tiann.

Thanks for the great project, I had great fun playing around with it.

This PR mainly tries to further minimize the possible delays caused by
KernelSU hooking.

There are 3 major changes:
- Processes with 0 < UID < 2000 are blocked straight-up before going
through the allow_list.
I don't see any need for such processes to be interested in root, and
this allows returning early before going through a more expensive
lookup.
If there's an expected breakage due to this change, I'll remove it. Let
me know.
- A page-sized (4K) bitmap is added.
This allows O(1) lookup for UID <= 32767.
This speeds up `ksu_is_allow_uid()` by about 4.8x by sacrificing a 4K
memory. IMHO, a good trade-off.
Most notably, this reduces the 99.999% result previously from worrying
milliseconds scale to microseconds scale.
For UID > 32767, another page-sized (4K) sequential array is used to
cache allow_list.

Compared to the previous PR #557, this new approach gives another nice
25% performance boost in average, 63-96% boost in worst cases.

Benchmark results are available at
https://docs.google.com/spreadsheets/d/1w_tO1zRLPNMFRer49pL1TQfL6ndEhilRrDU1XFIcWXY/edit?usp=sharing

Thanks!

---------

Signed-off-by: Juhyung Park <qkrwngud825@gmail.com>
This commit is contained in:
Juhyung Park
2023-06-16 20:53:15 +09:00
committed by GitHub
parent c697398893
commit bd8434f4f4
21 changed files with 233 additions and 102 deletions

View File

@@ -52,9 +52,9 @@ static struct work_struct stop_vfs_read_work;
static struct work_struct stop_execve_hook_work;
static struct work_struct stop_input_hook_work;
#else
static bool vfs_read_hook = true;
static bool execveat_hook = true;
static bool input_hook = true;
bool ksu_vfs_read_hook __read_mostly = true;
bool ksu_execveat_hook __read_mostly = true;
bool ksu_input_hook __read_mostly = true;
#endif
void on_post_fs_data(void)
@@ -138,7 +138,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags)
{
#ifndef CONFIG_KPROBES
if (!execveat_hook) {
if (!ksu_execveat_hook) {
return 0;
}
#endif
@@ -157,8 +157,8 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
return 0;
}
if (!memcmp(filename->name, system_bin_init,
sizeof(system_bin_init) - 1)) {
if (unlikely(!memcmp(filename->name, system_bin_init,
sizeof(system_bin_init) - 1))) {
#ifdef __aarch64__
// /system/bin/init executed
struct user_arg_ptr *ptr = (struct user_arg_ptr*) argv;
@@ -200,8 +200,8 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
#endif
}
if (first_app_process &&
!memcmp(filename->name, app_process, sizeof(app_process) - 1)) {
if (unlikely(first_app_process &&
!memcmp(filename->name, app_process, sizeof(app_process) - 1))) {
first_app_process = false;
pr_info("exec app_process, /data prepared, second_stage: %d\n", init_second_stage_executed);
on_post_fs_data(); // we keep this for old ksud
@@ -244,7 +244,7 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
size_t *count_ptr, loff_t **pos)
{
#ifndef CONFIG_KPROBES
if (!vfs_read_hook) {
if (!ksu_vfs_read_hook) {
return 0;
}
#endif
@@ -345,7 +345,7 @@ int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
int *value)
{
#ifndef CONFIG_KPROBES
if (!input_hook) {
if (!ksu_input_hook) {
return 0;
}
#endif
@@ -463,7 +463,7 @@ static void stop_vfs_read_hook()
bool ret = schedule_work(&stop_vfs_read_work);
pr_info("unregister vfs_read kprobe: %d!\n", ret);
#else
vfs_read_hook = false;
ksu_vfs_read_hook = false;
#endif
}
@@ -473,7 +473,7 @@ static void stop_execve_hook()
bool ret = schedule_work(&stop_execve_hook_work);
pr_info("unregister execve kprobe: %d!\n", ret);
#else
execveat_hook = false;
ksu_execveat_hook = false;
#endif
}
@@ -488,7 +488,7 @@ static void stop_input_hook()
bool ret = schedule_work(&stop_input_hook_work);
pr_info("unregister input kprobe: %d!\n", ret);
#else
input_hook = false;
ksu_input_hook = false;
#endif
}