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

Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-09-22 23:34:19 +08:00
parent d288b8f24f
commit de92cc4bad
2 changed files with 16 additions and 2 deletions

View File

@@ -826,6 +826,10 @@ 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;
@@ -833,6 +837,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;

View File

@@ -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"