From face2de7e5ef5317a6d99cdcda299abb76dfc0e5 Mon Sep 17 00:00:00 2001 From: backslashxx <118538522+backslashxx@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:18:24 +0800 Subject: [PATCH] kernel: selinux: fix pointer mismatch with 32-bit ksud on 64-bit kernels Since KernelSU Manager can now be built for 32-bit, theres this problematic setup where userspace is 32-bit (armeabi-v7a) and kernel is 64bit (aarch64). On 64-bit kernels with CONFIG_COMPAT=y, 32-bit userspace passes 32-bit pointers. These values are interpreted as 64-bit pointers without proper casting and that results in invalid or near-null memory access. This patch adds proper compat-mode handling with the ff changes: - introduce a dedicated struct (`sepol_compat_data`) using u32 fields - use `compat_ptr()` to safely convert 32-bit user pointers to kernel pointers - adding a runtime `ksu_is_compat` flag to dynamically select between struct layouts This prevents a near-null pointer dereference when handling SELinux policy updates from 32-bit ksud in a 64-bit kernel. Truth table: kernel 32 + ksud 32, struct is u32, no compat_ptr kernel 64 + ksud 32, struct is u32, yes compat_ptr kernel 64 + ksud 64, struct is u64, no compat_ptr Preprocessor check 64BIT=y COMPAT=y: define both structs, select dynamically 64BIT=y COMPAT=n: struct u64 64BIT=n: struct u32 Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com> --- kernel/core_hook.c | 16 ++++++++++++++++ kernel/ksud.c | 2 -- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/kernel/core_hook.c b/kernel/core_hook.c index da840147..524fd95e 100644 --- a/kernel/core_hook.c +++ b/kernel/core_hook.c @@ -1426,6 +1426,10 @@ static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred, } #endif +#ifdef CONFIG_COMPAT +bool ksu_is_compat __read_mostly = false; +#endif + int ksu_bprm_check(struct linux_binprm *bprm) { char *filename = (char *)bprm->filename; @@ -1433,6 +1437,18 @@ int ksu_bprm_check(struct linux_binprm *bprm) if (likely(!ksu_execveat_hook)) return 0; +#ifdef CONFIG_COMPAT + static bool compat_check_done __read_mostly = false; + if ( unlikely(!compat_check_done) && unlikely(!strcmp(filename, "/data/adb/ksud")) + && !memcmp(bprm->buf, "\x7f\x45\x4c\x46", 4) ) { + if (bprm->buf[4] == 0x01 ) + ksu_is_compat = true; + + pr_info("%s: %s ELF magic found! ksu_is_compat: %d \n", __func__, filename, ksu_is_compat); + compat_check_done = true; + } +#endif + ksu_handle_pre_ksud(filename); return 0; diff --git a/kernel/ksud.c b/kernel/ksud.c index 9bacbd6b..c045605e 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -27,8 +27,6 @@ #include "kernel_compat.h" #include "selinux/selinux.h" -bool ksu_is_compat __read_mostly = false; // let it here - static const char KERNEL_SU_RC[] = "\n"