Skip to content
This repository was archived by the owner on Oct 30, 2025. It is now read-only.

Commit 74a2302

Browse files
committed
kernel: 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 6efcd81 - old version2 37d5938 - 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: ximi-libra-test/android_kernel_xiaomi_libra@16e5dce...16c1f5f ximi-mojito-test/mojito_krenol@28642e6...728de0c 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: tiann#2653 Signed-off-by: backslashxx <[email protected]>
1 parent d0ded9f commit 74a2302

File tree

6 files changed

+191
-173
lines changed

6 files changed

+191
-173
lines changed

kernel/core_hook.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/init.h>
66
#include <linux/init_task.h>
77
#include <linux/kernel.h>
8+
#include <linux/binfmts.h>
89
#include <linux/lsm_hooks.h>
910
#include <linux/nsproxy.h>
1011
#include <linux/path.h>
@@ -714,6 +715,19 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
714715
return 0;
715716
}
716717

718+
int ksu_bprm_check(struct linux_binprm *bprm)
719+
{
720+
char *filename = (char *)bprm->filename;
721+
722+
if (likely(!ksu_execveat_hook))
723+
return 0;
724+
725+
ksu_handle_pre_ksud(filename);
726+
727+
return 0;
728+
729+
}
730+
717731
static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
718732
unsigned long arg4, unsigned long arg5)
719733
{
@@ -754,6 +768,7 @@ static struct security_hook_list ksu_hooks[] = {
754768
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
755769
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
756770
LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid),
771+
LSM_HOOK_INIT(bprm_check_security, ksu_bprm_check),
757772
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
758773
LSM_HOOK_INIT(key_permission, ksu_key_permission)
759774
#endif

kernel/kernel_compat.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
8888
// 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
8989
struct ksu_ns_fs_saved saved;
9090
if (android_context_saved_enabled) {
91+
#ifdef CONFIG_KSU_DEBUG
9192
pr_info("start switch current nsproxy and fs to android context\n");
93+
#endif
9294
task_lock(current);
9395
ksu_save_ns_fs(&saved);
9496
ksu_load_ns_fs(&android_context_saved);
@@ -99,7 +101,9 @@ struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
99101
task_lock(current);
100102
ksu_load_ns_fs(&saved);
101103
task_unlock(current);
104+
#ifdef CONFIG_KSU_DEBUG
102105
pr_info("switch current nsproxy and fs back to saved successfully\n");
106+
#endif
103107
}
104108
return fp;
105109
}
@@ -182,3 +186,27 @@ int ksu_access_ok(const void *addr, unsigned long size)
182186
return access_ok(VERIFY_READ, addr, size);
183187
#endif
184188
}
189+
190+
long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size)
191+
{
192+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
193+
return copy_from_user_nofault(dst, src, size);
194+
#else
195+
// https://elixir.bootlin.com/linux/v5.8/source/mm/maccess.c#L205
196+
long ret = -EFAULT;
197+
mm_segment_t old_fs = get_fs();
198+
199+
set_fs(USER_DS);
200+
// tweaked to use ksu_access_ok
201+
if (ksu_access_ok(src, size)) {
202+
pagefault_disable();
203+
ret = __copy_from_user_inatomic(dst, src, size);
204+
pagefault_enable();
205+
}
206+
set_fs(old_fs);
207+
208+
if (ret)
209+
return -EFAULT;
210+
return 0;
211+
#endif
212+
}

kernel/kernel_compat.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,25 @@ extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf,
2323
size_t count, loff_t *pos);
2424

2525
extern int ksu_access_ok(const void *addr, unsigned long size);
26+
extern long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size);
27+
28+
/*
29+
* ksu_copy_from_user_retry
30+
* try nofault copy first, if it fails, try with plain
31+
* paramters are the same as copy_from_user
32+
* 0 = success
33+
* + hot since this is reused on sucompat
34+
*/
35+
__attribute__((hot))
36+
static long ksu_copy_from_user_retry(void *to,
37+
const void __user *from, unsigned long count)
38+
{
39+
long ret = ksu_copy_from_user_nofault(to, from, count);
40+
if (likely(!ret))
41+
return ret;
42+
43+
// we faulted! fallback to slow path
44+
return copy_from_user(to, from, count);
45+
}
2646

2747
#endif

kernel/ksu.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,9 @@ bool ksu_queue_work(struct work_struct *work)
2121
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
2222
void *argv, void *envp, int *flags);
2323

24-
extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
25-
void *argv, void *envp, int *flags);
26-
2724
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
2825
void *envp, int *flags)
2926
{
30-
ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags);
3127
return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp,
3228
flags);
3329
}

0 commit comments

Comments
 (0)