ksud: migrate ksud execution to security_bprm_check (tiann#2653)

This migrates ksud execution decision-making to bprm_check_security.
This requires passing proper argv and envp to a modified _ksud handler
aptly named 'ksu_handle_bprm_ksud'.

Introduces:
int ksu_handle_bprm_ksud(const char *filename, const char *argv1,
const char *envp, size_t envp_len)

which is adapted from:
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
struct user_arg_ptr *argv,
struct user_arg_ptr *envp,
int *flags)

ksu_handle_bprm_ksud handles all the decision making, it decides when it is
time to apply_kernelsu_rules depending if it sees "second_stage".

For LSM hook, turns out we can pull out argv and envp from mm_struct.
The code in here explains itself on how to do it.

whole blob exists on arg_start to arg_end, so we just pull it out and grab next
array after the first null terminator.

as for envp, we pass the pointer then hunt for it when needed

My reasoning on adding a fallback on usercopy is that on some devices a fault
happens, and it copies garbled data. On my creation of this, I actually had to lock
that _nofault copy on a spinlock as a way to mimic preempt_disable/enable without
actually doing it. As per user reports, no failed _nofault copies anyway but we
have-to-have a fallback for resilience.

References:
- old version1 6efcd8193e
- old version2 37d5938e66
- bad usercopy #21

This now provides a small helper function, ksu_copy_from_user_retry, which explains
itself. First we attempt a _nofault copy, if that fails, we try plain.

With that, It also provides an inlined copy_from_user_nofault for < 5.8.

While using strncpy_from_user_nofault was considered, this wont do, this will
only copy up to the first \0.

devlog:
16e5dce9e7...16c1f5f521
28642e60d7...728de0c571

References:
https://elixir.bootlin.com/linux/v4.14.1/source/include/linux/mm_types.h#L429
https://elixir.bootlin.com/linux/v4.14.1/source/include/linux/lsm_hooks.h

Stale: https://github.com/tiann/KernelSU/pull/2653

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
This commit is contained in:
backslashxx
2025-09-22 12:08:39 +08:00
committed by ShirkNeko
parent d542fd0672
commit e00923f0bc
5 changed files with 217 additions and 195 deletions

View File

@@ -70,8 +70,10 @@ void ksu_android_ns_fs_check(void)
if (current->nsproxy && current->fs &&
current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) {
android_context_saved_enabled = true;
#ifdef CONFIG_KSU_DEBUG
pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n",
current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns);
#endif
ksu_save_ns_fs(&android_context_saved);
} else {
pr_info("android context saved disabled\n");
@@ -93,7 +95,9 @@ struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
// switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns
struct ksu_ns_fs_saved saved;
if (android_context_saved_enabled) {
#ifdef CONFIG_KSU_DEBUG
pr_info("start switch current nsproxy and fs to android context\n");
#endif
task_lock(current);
ksu_save_ns_fs(&saved);
ksu_load_ns_fs(&android_context_saved);
@@ -104,7 +108,9 @@ struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
task_lock(current);
ksu_load_ns_fs(&saved);
task_unlock(current);
#ifdef CONFIG_KSU_DEBUG
pr_info("switch current nsproxy and fs back to saved successfully\n");
#endif
}
return fp;
}
@@ -208,3 +214,27 @@ long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr,
return ret;
}
long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
return copy_from_user_nofault(dst, src, size);
#else
// https://elixir.bootlin.com/linux/v5.8/source/mm/maccess.c#L205
long ret = -EFAULT;
mm_segment_t old_fs = get_fs();
set_fs(USER_DS);
// tweaked to use ksu_access_ok
if (ksu_access_ok(src, size)) {
pagefault_disable();
ret = __copy_from_user_inatomic(dst, src, size);
pagefault_enable();
}
set_fs(old_fs);
if (ret)
return -EFAULT;
return 0;
#endif
}