kernel: handle optional backport for selinux_inode

* For supporting kernel 4.19 with 5.10 bpf backports.

Co-authored-by: rsuntk <rsuntk@yukiprjkt.my.id>
This commit is contained in:
ShirkNeko
2025-09-12 14:37:39 +08:00
parent 840f7a0ff2
commit eebde9be16
9 changed files with 429 additions and 432 deletions

View File

@@ -105,27 +105,14 @@ else
$(info -- KPM is disabled) $(info -- KPM is disabled)
endif endif
# SELinux 驱动程序检查 # SELinux drivers check
ifeq ($(shell grep -q "current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0) ifeq ($(shell grep -q "current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID
endif endif
ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0) ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE
endif endif
# 该功能在 linux 5.0-rc1 中引入
ifeq ($(shell grep -q "get_cred_rcu" $(srctree)/include/linux/cred.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_GET_CRED_RCU
else
ifeq ($(shell grep -q "atomic_long_t\s\+usage" $(srctree)/include/linux/cred.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_ATOMIC_LONG
endif
ifeq ($(shell grep -q "int\s\+non_rcu" $(srctree)/include/linux/cred.h; echo $$?),0)
ccflags-y += -DKSU_COMPAT_HAS_NONCONST_CRED
endif
endif
# Handle optional backports # Handle optional backports
ifeq ($(shell grep -q "strncpy_from_user_nofault" $(srctree)/include/linux/uaccess.h; echo $$?),0) ifeq ($(shell grep -q "strncpy_from_user_nofault" $(srctree)/include/linux/uaccess.h; echo $$?),0)
ccflags-y += -DKSU_OPTIONAL_STRNCPY ccflags-y += -DKSU_OPTIONAL_STRNCPY
@@ -136,6 +123,10 @@ endif
ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q "const void" ; echo $$?),0) ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q "const void" ; echo $$?),0)
ccflags-y += -DKSU_OPTIONAL_KERNEL_WRITE ccflags-y += -DKSU_OPTIONAL_KERNEL_WRITE
endif endif
ifeq ($(shell grep -q "inode_security_struct\s\+\*selinux_inode" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
$(info -- KernelSU: kernel has selinux_inode.)
ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE
endif
ifeq ($(shell grep -q "int\s\+path_umount" $(srctree)/fs/namespace.c; echo $$?),0) ifeq ($(shell grep -q "int\s\+path_umount" $(srctree)/fs/namespace.c; echo $$?),0)
ccflags-y += -DKSU_HAS_PATH_UMOUNT ccflags-y += -DKSU_HAS_PATH_UMOUNT
ifneq ($(shell grep -Eq "^int path_umount" $(srctree)/fs/internal.h; echo $$?),0) ifneq ($(shell grep -Eq "^int path_umount" $(srctree)/fs/internal.h; echo $$?),0)
@@ -143,7 +134,6 @@ $(shell sed -i '/^extern void __init mnt_init/a int path_umount(struct path *pat
$(info -- KernelSU: SusFS: Adding 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/internal.h) $(info -- KernelSU: SusFS: Adding 'int path_umount(struct path *path, int flags);' to $(srctree)/fs/internal.h)
endif endif
endif endif
# Checks Samsung UH drivers # Checks Samsung UH drivers
ifeq ($(shell grep -q "CONFIG_KDP_CRED" $(srctree)/kernel/cred.c; echo $$?),0) ifeq ($(shell grep -q "CONFIG_KDP_CRED" $(srctree)/kernel/cred.c; echo $$?),0)
ccflags-y += -DSAMSUNG_UH_DRIVER_EXIST ccflags-y += -DSAMSUNG_UH_DRIVER_EXIST

View File

@@ -79,7 +79,6 @@ void ksu_android_ns_fs_check(void)
task_unlock(current); task_unlock(current);
} }
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode) struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
{ {
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
@@ -179,3 +178,33 @@ long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
return ret; return ret;
} }
#endif #endif
long ksu_strncpy_from_user_retry(char *dst, const void __user *unsafe_addr,
long count)
{
long ret;
ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count);
if (likely(ret >= 0))
return ret;
// we faulted! fallback to slow path
if (unlikely(!ksu_access_ok(unsafe_addr, count))) {
#ifdef CONFIG_KSU_DEBUG
pr_err("%s: faulted!\n", __func__);
#endif
return -EFAULT;
}
// why we don't do like how strncpy_from_user_nofault?
ret = strncpy_from_user(dst, unsafe_addr, count);
if (ret >= count) {
ret = count;
dst[ret - 1] = '\0';
} else if (likely(ret >= 0)) {
ret++;
}
return ret;
}

View File

@@ -4,30 +4,9 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/list.h>
#include "ss/policydb.h" #include "ss/policydb.h"
#include "linux/key.h" #include "linux/key.h"
#include <linux/list.h>
// for kernel without get_cred_rcu
#ifndef KSU_COMPAT_HAS_GET_CRED_RCU
static inline const struct cred *get_cred_rcu(const struct cred *cred)
{
struct cred *nonconst_cred = (struct cred *) cred;
if (!cred)
return NULL;
#ifdef KSU_COMPAT_ATOMIC_LONG
if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
#else
if (!atomic_inc_not_zero(&nonconst_cred->usage))
#endif
return NULL;
validate_creds(cred);
#ifdef KSU_COMPAT_HAS_NONCONST_CRED
nonconst_cred->non_rcu = 0;
#endif
return cred;
}
#endif
/** /**
* list_count_nodes - count the number of nodes in a list * list_count_nodes - count the number of nodes in a list
@@ -82,8 +61,13 @@ static inline __maybe_unused size_t list_count_nodes(const struct list_head *hea
extern long ksu_strncpy_from_user_nofault(char *dst, extern long ksu_strncpy_from_user_nofault(char *dst,
const void __user *unsafe_addr, const void __user *unsafe_addr,
long count); long count);
extern long ksu_strncpy_from_user_retry(char *dst,
const void __user *unsafe_addr,
long count);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND) #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
defined(CONFIG_IS_HW_HISI) || \
defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
extern struct key *init_session_keyring; extern struct key *init_session_keyring;
#endif #endif
@@ -96,9 +80,9 @@ extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf,
size_t count, loff_t *pos); size_t count, loff_t *pos);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
#define ksu_access_ok(addr, size) (access_ok(addr, size)) #define ksu_access_ok(addr, size) access_ok(addr, size)
#else #else
#define ksu_access_ok(addr, size) (access_ok(VERIFY_READ, addr, size)) #define ksu_access_ok(addr, size) access_ok(VERIFY_READ, addr, size)
#endif #endif
#endif #endif

View File

@@ -66,7 +66,7 @@ extern void ksu_trace_unregister();
int __init kernelsu_init(void) int __init kernelsu_init(void)
{ {
pr_info("kernelsu.enabled=%d\n", pr_info("kernelsu.enabled=%d\n",
get_ksu_state()); (int)get_ksu_state());
#ifdef CONFIG_KSU_CMDLINE #ifdef CONFIG_KSU_CMDLINE
if (!get_ksu_state()) { if (!get_ksu_state()) {
@@ -74,6 +74,7 @@ int __init kernelsu_init(void)
return 0; return 0;
} }
#endif #endif
#ifdef CONFIG_KSU_DEBUG #ifdef CONFIG_KSU_DEBUG
pr_alert("*************************************************************"); pr_alert("*************************************************************");
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **"); pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
@@ -101,7 +102,7 @@ int __init kernelsu_init(void)
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef CONFIG_KSU_KPROBES_HOOK
ksu_ksud_init(); ksu_ksud_init();
#else #else
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html"); pr_debug("init ksu driver\n");
#endif #endif
#ifdef CONFIG_KSU_TRACEPOINT_HOOK #ifdef CONFIG_KSU_TRACEPOINT_HOOK

View File

@@ -27,22 +27,29 @@
#include "kernel_compat.h" #include "kernel_compat.h"
#include "selinux/selinux.h" #include "selinux/selinux.h"
#define KERNEL_VERSION_5_10 KERNEL_VERSION(5, 10, 0) bool ksu_is_compat __read_mostly = false; // let it here
static const char KERNEL_SU_RC[] = static const char KERNEL_SU_RC[] =
"\n" "\n"
"on post-fs-data\n" "on post-fs-data\n"
" start logd\n" " start logd\n"
// We should wait for the post-fs-data finish
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n" " exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
"\n" "\n"
"on nonencrypted\n" "on nonencrypted\n"
" exec u:r:su:s0 root -- " KSUD_PATH " services\n" " exec u:r:su:s0 root -- " KSUD_PATH " services\n"
"\n" "\n"
"on property:vold.decrypt=trigger_restart_framework\n" "on property:vold.decrypt=trigger_restart_framework\n"
" exec u:r:su:s0 root -- " KSUD_PATH " services\n" " exec u:r:su:s0 root -- " KSUD_PATH " services\n"
"\n" "\n"
"on property:sys.boot_completed=1\n" "on property:sys.boot_completed=1\n"
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n" " exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
"\n"
"\n"; "\n";
static void stop_vfs_read_hook(void); static void stop_vfs_read_hook(void);
@@ -68,10 +75,6 @@ u32 ksu_devpts_sid;
// Detect whether it is on or not // Detect whether it is on or not
static bool is_boot_phase = true; static bool is_boot_phase = true;
#ifdef CONFIG_COMPAT
bool ksu_is_compat __read_mostly = false;
#endif
void on_post_fs_data(void) void on_post_fs_data(void)
{ {
static bool done = false; static bool done = false;
@@ -82,6 +85,7 @@ void on_post_fs_data(void)
done = true; done = true;
pr_info("%s!\n", __func__); pr_info("%s!\n", __func__);
ksu_load_allow_list(); ksu_load_allow_list();
// sanity check, this may influence the performance
stop_input_hook(); stop_input_hook();
ksu_devpts_sid = ksu_get_devpts_sid(); ksu_devpts_sid = ksu_get_devpts_sid();
@@ -200,7 +204,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
const char __user *p = get_user_arg_ptr(*argv, 1); const char __user *p = get_user_arg_ptr(*argv, 1);
if (p && !IS_ERR(p)) { if (p && !IS_ERR(p)) {
char first_arg[16]; char first_arg[16];
ksu_strncpy_from_user_nofault( ksu_strncpy_from_user_retry(
first_arg, p, sizeof(first_arg)); first_arg, p, sizeof(first_arg));
pr_info("/system/bin/init first arg: %s\n", pr_info("/system/bin/init first arg: %s\n",
first_arg); first_arg);
@@ -225,7 +229,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
const char __user *p = get_user_arg_ptr(*argv, 1); const char __user *p = get_user_arg_ptr(*argv, 1);
if (p && !IS_ERR(p)) { if (p && !IS_ERR(p)) {
char first_arg[16]; char first_arg[16];
ksu_strncpy_from_user_nofault( ksu_strncpy_from_user_retry(
first_arg, p, sizeof(first_arg)); first_arg, p, sizeof(first_arg));
pr_info("/init first arg: %s\n", first_arg); pr_info("/init first arg: %s\n", first_arg);
if (!strcmp(first_arg, "--second-stage")) { if (!strcmp(first_arg, "--second-stage")) {
@@ -250,7 +254,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
} }
char env[256]; char env[256];
// Reading environment variable strings from user space // Reading environment variable strings from user space
if (ksu_strncpy_from_user_nofault( if (ksu_strncpy_from_user_retry(
env, p, sizeof(env)) < 0) env, p, sizeof(env)) < 0)
continue; continue;
// Parsing environment variable names and values // Parsing environment variable names and values
@@ -443,7 +447,8 @@ int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) { if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) {
int val = *value; int val = *value;
pr_info("KEY_VOLUMEDOWN val: %d\n", val); pr_info("KEY_VOLUMEDOWN val: %d\n", val);
if (val && is_boot_phase) { // Accumulates only during the power-up phase if (val && is_boot_phase) {
// key pressed, count it
volumedown_pressed_count += 1; volumedown_pressed_count += 1;
if (is_volumedown_enough(volumedown_pressed_count)) { if (is_volumedown_enough(volumedown_pressed_count)) {
stop_input_hook(); stop_input_hook();
@@ -478,6 +483,7 @@ bool ksu_is_safe_mode()
#ifdef CONFIG_KSU_KPROBES_HOOK #ifdef CONFIG_KSU_KPROBES_HOOK
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs) static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{ {
int *fd = (int *)&PT_REGS_PARM1(regs); int *fd = (int *)&PT_REGS_PARM1(regs);
@@ -521,17 +527,6 @@ static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
NULL); NULL);
} }
__maybe_unused static int vfs_read_handler_pre(struct kprobe *p,
struct pt_regs *regs)
{
struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs);
char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs);
size_t *count_ptr = (size_t *)&PT_REGS_PARM3(regs);
loff_t **pos_ptr = (loff_t **)&PT_REGS_CCALL_PARM4(regs);
return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr);
}
static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs) static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs)
{ {
struct pt_regs *real_regs = PT_REAL_REGS(regs); struct pt_regs *real_regs = PT_REAL_REGS(regs);
@@ -661,7 +656,6 @@ static void stop_input_hook(void)
return; return;
} }
input_hook_stopped = true; input_hook_stopped = true;
bool ret = schedule_work(&stop_input_hook_work); bool ret = schedule_work(&stop_input_hook_work);
pr_info("unregister input kprobe: %d!\n", ret); pr_info("unregister input kprobe: %d!\n", ret);
#else #else

View File

@@ -37,7 +37,6 @@ static struct policydb *get_policydb(void)
} }
static DEFINE_MUTEX(ksu_rules); static DEFINE_MUTEX(ksu_rules);
void apply_kernelsu_rules(void) void apply_kernelsu_rules(void)
{ {
struct policydb *db; struct policydb *db;

View File

@@ -264,7 +264,7 @@ int ksu_handle_devpts(struct inode *inode)
return 0; return 0;
if (ksu_devpts_sid) { if (ksu_devpts_sid) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || defined(KSU_OPTIONAL_SELINUX_INODE)
struct inode_security_struct *sec = selinux_inode(inode); struct inode_security_struct *sec = selinux_inode(inode);
#else #else
struct inode_security_struct *sec = struct inode_security_struct *sec =

View File

@@ -1,5 +1,5 @@
#ifndef __KSU_H_UID_OBSERVER #ifndef __KSU_H_THRONE_TRACKER
#define __KSU_H_UID_OBSERVER #define __KSU_H_THRONE_TRACKER
void ksu_throne_tracker_init(void); void ksu_throne_tracker_init(void);