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:
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
760
kernel/ksud.c
760
kernel/ksud.c
@@ -27,23 +27,30 @@
|
|||||||
#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"
|
|
||||||
" start logd\n"
|
"on post-fs-data\n"
|
||||||
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
|
" start logd\n"
|
||||||
"\n"
|
// We should wait for the post-fs-data finish
|
||||||
"on nonencrypted\n"
|
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
|
||||||
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
"\n"
|
||||||
"\n"
|
|
||||||
"on property:vold.decrypt=trigger_restart_framework\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:sys.boot_completed=1\n"
|
|
||||||
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
|
"on property:vold.decrypt=trigger_restart_framework\n"
|
||||||
"\n";
|
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
"on property:sys.boot_completed=1\n"
|
||||||
|
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
"\n";
|
||||||
|
|
||||||
static void stop_vfs_read_hook(void);
|
static void stop_vfs_read_hook(void);
|
||||||
static void stop_execve_hook(void);
|
static void stop_execve_hook(void);
|
||||||
@@ -68,24 +75,21 @@ 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;
|
||||||
if (done) {
|
if (done) {
|
||||||
pr_info("%s already done\n", __func__);
|
pr_info("%s already done\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
done = true;
|
done = true;
|
||||||
pr_info("%s!\n", __func__);
|
pr_info("%s!\n", __func__);
|
||||||
ksu_load_allow_list();
|
ksu_load_allow_list();
|
||||||
stop_input_hook();
|
// sanity check, this may influence the performance
|
||||||
|
stop_input_hook();
|
||||||
|
|
||||||
ksu_devpts_sid = ksu_get_devpts_sid();
|
ksu_devpts_sid = ksu_get_devpts_sid();
|
||||||
pr_info("devpts sid: %d\n", ksu_devpts_sid);
|
pr_info("devpts sid: %d\n", ksu_devpts_sid);
|
||||||
|
|
||||||
// End of boot state
|
// End of boot state
|
||||||
is_boot_phase = false;
|
is_boot_phase = false;
|
||||||
@@ -94,36 +98,36 @@ void on_post_fs_data(void)
|
|||||||
#define MAX_ARG_STRINGS 0x7FFFFFFF
|
#define MAX_ARG_STRINGS 0x7FFFFFFF
|
||||||
struct user_arg_ptr {
|
struct user_arg_ptr {
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
bool is_compat;
|
bool is_compat;
|
||||||
#endif
|
#endif
|
||||||
union {
|
union {
|
||||||
const char __user *const __user *native;
|
const char __user *const __user *native;
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
const compat_uptr_t __user *compat;
|
const compat_uptr_t __user *compat;
|
||||||
#endif
|
#endif
|
||||||
} ptr;
|
} ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
|
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
|
||||||
{
|
{
|
||||||
const char __user *native;
|
const char __user *native;
|
||||||
|
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
if (unlikely(argv.is_compat)) {
|
if (unlikely(argv.is_compat)) {
|
||||||
compat_uptr_t compat;
|
compat_uptr_t compat;
|
||||||
|
|
||||||
if (get_user(compat, argv.ptr.compat + nr))
|
if (get_user(compat, argv.ptr.compat + nr))
|
||||||
return ERR_PTR(-EFAULT);
|
return ERR_PTR(-EFAULT);
|
||||||
|
|
||||||
ksu_is_compat = true;
|
ksu_is_compat = true;
|
||||||
return compat_ptr(compat);
|
return compat_ptr(compat);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (get_user(native, argv.ptr.native + nr))
|
if (get_user(native, argv.ptr.native + nr))
|
||||||
return ERR_PTR(-EFAULT);
|
return ERR_PTR(-EFAULT);
|
||||||
|
|
||||||
return native;
|
return native;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -137,156 +141,156 @@ static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
|
|||||||
|
|
||||||
static int __maybe_unused count(struct user_arg_ptr argv, int max)
|
static int __maybe_unused count(struct user_arg_ptr argv, int max)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (argv.ptr.native != NULL) {
|
if (argv.ptr.native != NULL) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char __user *p = get_user_arg_ptr(argv, i);
|
const char __user *p = get_user_arg_ptr(argv, i);
|
||||||
|
|
||||||
if (!p)
|
if (!p)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (IS_ERR(p))
|
if (IS_ERR(p))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (i >= max)
|
if (i >= max)
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (fatal_signal_pending(current))
|
if (fatal_signal_pending(current))
|
||||||
return -ERESTARTNOHAND;
|
return -ERESTARTNOHAND;
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version
|
// IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version
|
||||||
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||||
struct user_arg_ptr *argv,
|
struct user_arg_ptr *argv,
|
||||||
struct user_arg_ptr *envp, int *flags)
|
struct user_arg_ptr *envp, int *flags)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
if (!ksu_execveat_hook) {
|
if (!ksu_execveat_hook) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
struct filename *filename;
|
struct filename *filename;
|
||||||
|
|
||||||
static const char app_process[] = "/system/bin/app_process";
|
static const char app_process[] = "/system/bin/app_process";
|
||||||
static bool first_app_process = true;
|
static bool first_app_process = true;
|
||||||
|
|
||||||
/* This applies to versions Android 10+ */
|
/* This applies to versions Android 10+ */
|
||||||
static const char system_bin_init[] = "/system/bin/init";
|
static const char system_bin_init[] = "/system/bin/init";
|
||||||
/* This applies to versions between Android 6 ~ 9 */
|
/* This applies to versions between Android 6 ~ 9 */
|
||||||
static const char old_system_init[] = "/init";
|
static const char old_system_init[] = "/init";
|
||||||
static bool init_second_stage_executed = false;
|
static bool init_second_stage_executed = false;
|
||||||
|
|
||||||
if (!filename_ptr)
|
if (!filename_ptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
filename = *filename_ptr;
|
filename = *filename_ptr;
|
||||||
if (IS_ERR(filename)) {
|
if (IS_ERR(filename)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!memcmp(filename->name, system_bin_init,
|
if (unlikely(!memcmp(filename->name, system_bin_init,
|
||||||
sizeof(system_bin_init) - 1) &&
|
sizeof(system_bin_init) - 1) &&
|
||||||
argv)) {
|
argv)) {
|
||||||
// /system/bin/init executed
|
// /system/bin/init executed
|
||||||
int argc = count(*argv, MAX_ARG_STRINGS);
|
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||||
pr_info("/system/bin/init argc: %d\n", argc);
|
pr_info("/system/bin/init argc: %d\n", argc);
|
||||||
if (argc > 1 && !init_second_stage_executed) {
|
if (argc > 1 && !init_second_stage_executed) {
|
||||||
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);
|
||||||
if (!strcmp(first_arg, "second_stage")) {
|
if (!strcmp(first_arg, "second_stage")) {
|
||||||
pr_info("/system/bin/init second_stage executed\n");
|
pr_info("/system/bin/init second_stage executed\n");
|
||||||
apply_kernelsu_rules();
|
apply_kernelsu_rules();
|
||||||
init_second_stage_executed = true;
|
init_second_stage_executed = true;
|
||||||
ksu_android_ns_fs_check();
|
ksu_android_ns_fs_check();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pr_err("/system/bin/init parse args err!\n");
|
pr_err("/system/bin/init parse args err!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (unlikely(!memcmp(filename->name, old_system_init,
|
} else if (unlikely(!memcmp(filename->name, old_system_init,
|
||||||
sizeof(old_system_init) - 1) &&
|
sizeof(old_system_init) - 1) &&
|
||||||
argv)) {
|
argv)) {
|
||||||
// /init executed
|
// /init executed
|
||||||
int argc = count(*argv, MAX_ARG_STRINGS);
|
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||||
pr_info("/init argc: %d\n", argc);
|
pr_info("/init argc: %d\n", argc);
|
||||||
if (argc > 1 && !init_second_stage_executed) {
|
if (argc > 1 && !init_second_stage_executed) {
|
||||||
/* This applies to versions between Android 6 ~ 7 */
|
/* This applies to versions between Android 6 ~ 7 */
|
||||||
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")) {
|
||||||
pr_info("/init second_stage executed\n");
|
pr_info("/init second_stage executed\n");
|
||||||
apply_kernelsu_rules();
|
apply_kernelsu_rules();
|
||||||
init_second_stage_executed = true;
|
init_second_stage_executed = true;
|
||||||
ksu_android_ns_fs_check();
|
ksu_android_ns_fs_check();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pr_err("/init parse args err!\n");
|
pr_err("/init parse args err!\n");
|
||||||
}
|
}
|
||||||
} else if (argc == 1 && !init_second_stage_executed && envp) {
|
} else if (argc == 1 && !init_second_stage_executed && envp) {
|
||||||
/* This applies to versions between Android 8 ~ 9 */
|
/* This applies to versions between Android 8 ~ 9 */
|
||||||
int envc = count(*envp, MAX_ARG_STRINGS);
|
int envc = count(*envp, MAX_ARG_STRINGS);
|
||||||
if (envc > 0) {
|
if (envc > 0) {
|
||||||
int n;
|
int n;
|
||||||
for (n = 1; n <= envc; n++) {
|
for (n = 1; n <= envc; n++) {
|
||||||
const char __user *p =
|
const char __user *p =
|
||||||
get_user_arg_ptr(*envp, n);
|
get_user_arg_ptr(*envp, n);
|
||||||
if (!p || IS_ERR(p)) {
|
if (!p || IS_ERR(p)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
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
|
||||||
char *env_name = env;
|
char *env_name = env;
|
||||||
char *env_value = strchr(env, '=');
|
char *env_value = strchr(env, '=');
|
||||||
if (env_value == NULL)
|
if (env_value == NULL)
|
||||||
continue;
|
continue;
|
||||||
// Replace equal sign with string terminator
|
// Replace equal sign with string terminator
|
||||||
*env_value = '\0';
|
*env_value = '\0';
|
||||||
env_value++;
|
env_value++;
|
||||||
// Check if the environment variable name and value are matching
|
// Check if the environment variable name and value are matching
|
||||||
if (!strcmp(env_name,
|
if (!strcmp(env_name,
|
||||||
"INIT_SECOND_STAGE") &&
|
"INIT_SECOND_STAGE") &&
|
||||||
(!strcmp(env_value, "1") ||
|
(!strcmp(env_value, "1") ||
|
||||||
!strcmp(env_value, "true"))) {
|
!strcmp(env_value, "true"))) {
|
||||||
pr_info("/init second_stage executed\n");
|
pr_info("/init second_stage executed\n");
|
||||||
apply_kernelsu_rules();
|
apply_kernelsu_rules();
|
||||||
init_second_stage_executed =
|
init_second_stage_executed =
|
||||||
true;
|
true;
|
||||||
ksu_android_ns_fs_check();
|
ksu_android_ns_fs_check();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(first_app_process && !memcmp(filename->name, app_process,
|
if (unlikely(first_app_process && !memcmp(filename->name, app_process,
|
||||||
sizeof(app_process) - 1))) {
|
sizeof(app_process) - 1))) {
|
||||||
first_app_process = false;
|
first_app_process = false;
|
||||||
pr_info("exec app_process, /data prepared, second_stage: %d\n",
|
pr_info("exec app_process, /data prepared, second_stage: %d\n",
|
||||||
init_second_stage_executed);
|
init_second_stage_executed);
|
||||||
on_post_fs_data(); // we keep this for old ksud
|
on_post_fs_data(); // we keep this for old ksud
|
||||||
stop_execve_hook();
|
stop_execve_hook();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *);
|
static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *);
|
||||||
@@ -295,265 +299,256 @@ static struct file_operations fops_proxy;
|
|||||||
static ssize_t read_count_append = 0;
|
static ssize_t read_count_append = 0;
|
||||||
|
|
||||||
static ssize_t read_proxy(struct file *file, char __user *buf, size_t count,
|
static ssize_t read_proxy(struct file *file, char __user *buf, size_t count,
|
||||||
loff_t *pos)
|
loff_t *pos)
|
||||||
{
|
{
|
||||||
bool first_read = file->f_pos == 0;
|
bool first_read = file->f_pos == 0;
|
||||||
ssize_t ret = orig_read(file, buf, count, pos);
|
ssize_t ret = orig_read(file, buf, count, pos);
|
||||||
if (first_read) {
|
if (first_read) {
|
||||||
pr_info("read_proxy append %ld + %ld\n", ret,
|
pr_info("read_proxy append %ld + %ld\n", ret,
|
||||||
read_count_append);
|
read_count_append);
|
||||||
ret += read_count_append;
|
ret += read_count_append;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to)
|
static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to)
|
||||||
{
|
{
|
||||||
bool first_read = iocb->ki_pos == 0;
|
bool first_read = iocb->ki_pos == 0;
|
||||||
ssize_t ret = orig_read_iter(iocb, to);
|
ssize_t ret = orig_read_iter(iocb, to);
|
||||||
if (first_read) {
|
if (first_read) {
|
||||||
pr_info("read_iter_proxy append %ld + %ld\n", ret,
|
pr_info("read_iter_proxy append %ld + %ld\n", ret,
|
||||||
read_count_append);
|
read_count_append);
|
||||||
ret += read_count_append;
|
ret += read_count_append;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||||
size_t *count_ptr, loff_t **pos)
|
size_t *count_ptr, loff_t **pos)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
if (!ksu_vfs_read_hook) {
|
if (!ksu_vfs_read_hook) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
struct file *file;
|
struct file *file;
|
||||||
char __user *buf;
|
char __user *buf;
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
||||||
if (strcmp(current->comm, "init")) {
|
if (strcmp(current->comm, "init")) {
|
||||||
// we are only interest in `init` process
|
// we are only interest in `init` process
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = *file_ptr;
|
file = *file_ptr;
|
||||||
if (IS_ERR(file)) {
|
if (IS_ERR(file)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!d_is_reg(file->f_path.dentry)) {
|
if (!d_is_reg(file->f_path.dentry)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *short_name = file->f_path.dentry->d_name.name;
|
const char *short_name = file->f_path.dentry->d_name.name;
|
||||||
if (strcmp(short_name, "atrace.rc")) {
|
if (strcmp(short_name, "atrace.rc")) {
|
||||||
// we are only interest `atrace.rc` file name file
|
// we are only interest `atrace.rc` file name file
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
char path[256];
|
char path[256];
|
||||||
char *dpath = d_path(&file->f_path, path, sizeof(path));
|
char *dpath = d_path(&file->f_path, path, sizeof(path));
|
||||||
|
|
||||||
if (IS_ERR(dpath)) {
|
if (IS_ERR(dpath)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(dpath, "/system/etc/init/atrace.rc")) {
|
if (strcmp(dpath, "/system/etc/init/atrace.rc")) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we only process the first read
|
// we only process the first read
|
||||||
static bool rc_inserted = false;
|
static bool rc_inserted = false;
|
||||||
if (rc_inserted) {
|
if (rc_inserted) {
|
||||||
// we don't need this kprobe, unregister it!
|
// we don't need this kprobe, unregister it!
|
||||||
stop_vfs_read_hook();
|
stop_vfs_read_hook();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
rc_inserted = true;
|
rc_inserted = true;
|
||||||
|
|
||||||
// now we can sure that the init process is reading
|
// now we can sure that the init process is reading
|
||||||
// `/system/etc/init/atrace.rc`
|
// `/system/etc/init/atrace.rc`
|
||||||
buf = *buf_ptr;
|
buf = *buf_ptr;
|
||||||
count = *count_ptr;
|
count = *count_ptr;
|
||||||
|
|
||||||
size_t rc_count = strlen(KERNEL_SU_RC);
|
size_t rc_count = strlen(KERNEL_SU_RC);
|
||||||
|
|
||||||
pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath,
|
pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath,
|
||||||
current->comm, count, rc_count);
|
current->comm, count, rc_count);
|
||||||
|
|
||||||
if (count < rc_count) {
|
if (count < rc_count) {
|
||||||
pr_err("count: %zu < rc_count: %zu\n", count, rc_count);
|
pr_err("count: %zu < rc_count: %zu\n", count, rc_count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count);
|
size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("copy ksud.rc failed: %zu\n", ret);
|
pr_err("copy ksud.rc failed: %zu\n", ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we've succeed to insert ksud.rc, now we need to proxy the read and modify the result!
|
// we've succeed to insert ksud.rc, now we need to proxy the read and modify the result!
|
||||||
// But, we can not modify the file_operations directly, because it's in read-only memory.
|
// But, we can not modify the file_operations directly, because it's in read-only memory.
|
||||||
// We just replace the whole file_operations with a proxy one.
|
// We just replace the whole file_operations with a proxy one.
|
||||||
memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations));
|
memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations));
|
||||||
orig_read = file->f_op->read;
|
orig_read = file->f_op->read;
|
||||||
if (orig_read) {
|
if (orig_read) {
|
||||||
fops_proxy.read = read_proxy;
|
fops_proxy.read = read_proxy;
|
||||||
}
|
}
|
||||||
orig_read_iter = file->f_op->read_iter;
|
orig_read_iter = file->f_op->read_iter;
|
||||||
if (orig_read_iter) {
|
if (orig_read_iter) {
|
||||||
fops_proxy.read_iter = read_iter_proxy;
|
fops_proxy.read_iter = read_iter_proxy;
|
||||||
}
|
}
|
||||||
// replace the file_operations
|
// replace the file_operations
|
||||||
file->f_op = &fops_proxy;
|
file->f_op = &fops_proxy;
|
||||||
read_count_append = rc_count;
|
read_count_append = rc_count;
|
||||||
|
|
||||||
*buf_ptr = buf + rc_count;
|
*buf_ptr = buf + rc_count;
|
||||||
*count_ptr = count - rc_count;
|
*count_ptr = count - rc_count;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr,
|
int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr,
|
||||||
size_t *count_ptr)
|
size_t *count_ptr)
|
||||||
{
|
{
|
||||||
struct file *file = fget(fd);
|
struct file *file = fget(fd);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL);
|
int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL);
|
||||||
fput(file);
|
fput(file);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int volumedown_pressed_count = 0;
|
static unsigned int volumedown_pressed_count = 0;
|
||||||
|
|
||||||
static bool is_volumedown_enough(unsigned int count)
|
static bool is_volumedown_enough(unsigned int count)
|
||||||
{
|
{
|
||||||
return count >= 3;
|
return count >= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||||
int *value)
|
int *value)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
if (!ksu_input_hook) {
|
if (!ksu_input_hook) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
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) {
|
||||||
volumedown_pressed_count += 1;
|
// key pressed, count it
|
||||||
if (is_volumedown_enough(volumedown_pressed_count)) {
|
volumedown_pressed_count += 1;
|
||||||
stop_input_hook();
|
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||||
}
|
stop_input_hook();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_is_safe_mode()
|
bool ksu_is_safe_mode()
|
||||||
{
|
{
|
||||||
static bool safe_mode = false;
|
static bool safe_mode = false;
|
||||||
if (safe_mode) {
|
if (safe_mode) {
|
||||||
// don't need to check again, userspace may call multiple times
|
// don't need to check again, userspace may call multiple times
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop hook first!
|
// stop hook first!
|
||||||
stop_input_hook();
|
stop_input_hook();
|
||||||
|
|
||||||
pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count);
|
pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count);
|
||||||
if (is_volumedown_enough(volumedown_pressed_count)) {
|
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||||
// pressed over 3 times
|
// pressed over 3 times
|
||||||
pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n");
|
pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n");
|
||||||
safe_mode = true;
|
safe_mode = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#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);
|
||||||
struct filename **filename_ptr =
|
struct filename **filename_ptr =
|
||||||
(struct filename **)&PT_REGS_PARM2(regs);
|
(struct filename **)&PT_REGS_PARM2(regs);
|
||||||
struct user_arg_ptr argv;
|
struct user_arg_ptr argv;
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
argv.is_compat = PT_REGS_PARM3(regs);
|
argv.is_compat = PT_REGS_PARM3(regs);
|
||||||
if (unlikely(argv.is_compat)) {
|
if (unlikely(argv.is_compat)) {
|
||||||
argv.ptr.compat = PT_REGS_CCALL_PARM4(regs);
|
argv.ptr.compat = PT_REGS_CCALL_PARM4(regs);
|
||||||
} else {
|
} else {
|
||||||
argv.ptr.native = PT_REGS_CCALL_PARM4(regs);
|
argv.ptr.native = PT_REGS_CCALL_PARM4(regs);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
argv.ptr.native = PT_REGS_PARM3(regs);
|
argv.ptr.native = PT_REGS_PARM3(regs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
|
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
static int sys_execve_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);
|
||||||
const char __user **filename_user =
|
const char __user **filename_user =
|
||||||
(const char **)&PT_REGS_PARM1(real_regs);
|
(const char **)&PT_REGS_PARM1(real_regs);
|
||||||
const char __user *const __user *__argv =
|
const char __user *const __user *__argv =
|
||||||
(const char __user *const __user *)PT_REGS_PARM2(real_regs);
|
(const char __user *const __user *)PT_REGS_PARM2(real_regs);
|
||||||
struct user_arg_ptr argv = { .ptr.native = __argv };
|
struct user_arg_ptr argv = { .ptr.native = __argv };
|
||||||
struct filename filename_in, *filename_p;
|
struct filename filename_in, *filename_p;
|
||||||
char path[32];
|
char path[32];
|
||||||
|
|
||||||
if (!filename_user)
|
if (!filename_user)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memset(path, 0, sizeof(path));
|
memset(path, 0, sizeof(path));
|
||||||
ksu_strncpy_from_user_nofault(path, *filename_user, 32);
|
ksu_strncpy_from_user_nofault(path, *filename_user, 32);
|
||||||
filename_in.name = path;
|
filename_in.name = path;
|
||||||
|
|
||||||
filename_p = &filename_in;
|
filename_p = &filename_in;
|
||||||
return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL,
|
return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL,
|
||||||
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);
|
||||||
unsigned int fd = PT_REGS_PARM1(real_regs);
|
unsigned int fd = PT_REGS_PARM1(real_regs);
|
||||||
char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs);
|
char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs);
|
||||||
size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_regs);
|
size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_regs);
|
||||||
|
|
||||||
return ksu_handle_sys_read(fd, buf_ptr, count_ptr);
|
return ksu_handle_sys_read(fd, buf_ptr, count_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int input_handle_event_handler_pre(struct kprobe *p,
|
static int input_handle_event_handler_pre(struct kprobe *p,
|
||||||
struct pt_regs *regs)
|
struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs);
|
unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs);
|
||||||
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs);
|
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs);
|
||||||
int *value = (int *)&PT_REGS_CCALL_PARM4(regs);
|
int *value = (int *)&PT_REGS_CCALL_PARM4(regs);
|
||||||
return ksu_handle_input_handle_event(type, code, value);
|
return ksu_handle_input_handle_event(type, code, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kprobe execve_kp = {
|
static struct kprobe execve_kp = {
|
||||||
.symbol_name = SYS_EXECVE_SYMBOL,
|
.symbol_name = SYS_EXECVE_SYMBOL,
|
||||||
.pre_handler = sys_execve_handler_pre,
|
.pre_handler = sys_execve_handler_pre,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct kprobe vfs_read_kp = {
|
static struct kprobe vfs_read_kp = {
|
||||||
@@ -630,19 +625,19 @@ int __maybe_unused ksu_handle_compat_execve_ksud(const char __user *filename_use
|
|||||||
static void stop_vfs_read_hook(void)
|
static void stop_vfs_read_hook(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
bool ret = schedule_work(&stop_vfs_read_work);
|
bool ret = schedule_work(&stop_vfs_read_work);
|
||||||
pr_info("unregister vfs_read kprobe: %d!\n", ret);
|
pr_info("unregister vfs_read kprobe: %d!\n", ret);
|
||||||
#else
|
#else
|
||||||
ksu_vfs_read_hook = false;
|
ksu_vfs_read_hook = false;
|
||||||
pr_info("stop vfs_read_hook\n");
|
pr_info("stop vfs_read_hook\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_execve_hook(void)
|
static void stop_execve_hook(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
bool ret = schedule_work(&stop_execve_hook_work);
|
bool ret = schedule_work(&stop_execve_hook_work);
|
||||||
pr_info("unregister execve kprobe: %d!\n", ret);
|
pr_info("unregister execve kprobe: %d!\n", ret);
|
||||||
#else
|
#else
|
||||||
ksu_execveat_hook = false;
|
ksu_execveat_hook = false;
|
||||||
pr_info("stop execve_hook\n");
|
pr_info("stop execve_hook\n");
|
||||||
@@ -656,14 +651,13 @@ static void stop_execve_hook(void)
|
|||||||
static void stop_input_hook(void)
|
static void stop_input_hook(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
static bool input_hook_stopped = false;
|
static bool input_hook_stopped = false;
|
||||||
if (input_hook_stopped) {
|
if (input_hook_stopped) {
|
||||||
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
|
||||||
if (!ksu_input_hook) { return; }
|
if (!ksu_input_hook) { return; }
|
||||||
ksu_input_hook = false;
|
ksu_input_hook = false;
|
||||||
@@ -675,30 +669,30 @@ static void stop_input_hook(void)
|
|||||||
void ksu_ksud_init(void)
|
void ksu_ksud_init(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = register_kprobe(&execve_kp);
|
ret = register_kprobe(&execve_kp);
|
||||||
pr_info("ksud: execve_kp: %d\n", ret);
|
pr_info("ksud: execve_kp: %d\n", ret);
|
||||||
|
|
||||||
ret = register_kprobe(&vfs_read_kp);
|
ret = register_kprobe(&vfs_read_kp);
|
||||||
pr_info("ksud: vfs_read_kp: %d\n", ret);
|
pr_info("ksud: vfs_read_kp: %d\n", ret);
|
||||||
|
|
||||||
ret = register_kprobe(&input_event_kp);
|
ret = register_kprobe(&input_event_kp);
|
||||||
pr_info("ksud: input_event_kp: %d\n", ret);
|
pr_info("ksud: input_event_kp: %d\n", ret);
|
||||||
|
|
||||||
INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
|
INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
|
||||||
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
|
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
|
||||||
INIT_WORK(&stop_input_hook_work, do_stop_input_hook);
|
INIT_WORK(&stop_input_hook_work, do_stop_input_hook);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_ksud_exit(void)
|
void ksu_ksud_exit(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
unregister_kprobe(&execve_kp);
|
unregister_kprobe(&execve_kp);
|
||||||
// this should be done before unregister vfs_read_kp
|
// this should be done before unregister vfs_read_kp
|
||||||
// unregister_kprobe(&vfs_read_kp);
|
// unregister_kprobe(&vfs_read_kp);
|
||||||
unregister_kprobe(&input_event_kp);
|
unregister_kprobe(&input_event_kp);
|
||||||
#endif
|
#endif
|
||||||
is_boot_phase = false;
|
is_boot_phase = false;
|
||||||
volumedown_pressed_count = 0;
|
volumedown_pressed_count = 0;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user