kernel: Apply the SUSFS patch

This commit is contained in:
ShirkNeko
2025-11-09 18:32:16 +08:00
parent a2caa9432f
commit ad0f3f6025
11 changed files with 946 additions and 19 deletions

View File

@@ -12,6 +12,9 @@
#else
#include <linux/sched.h>
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_SU
#include <linux/susfs_def.h>
#endif
#include "allowlist.h"
#include "feature.h"
@@ -22,6 +25,7 @@
#include "syscall_hook_manager.h"
#include "sulog.h"
#include "kernel_compat.h"
#define SU_PATH "/system/bin/su"
#define SH_PATH "/system/bin/sh"
@@ -37,8 +41,10 @@ static int su_compat_feature_get(u64 *value)
static int su_compat_feature_set(u64 value)
{
bool enable = value != 0;
ksu_su_compat_enabled = enable;
pr_info("su_compat: set to %d\n", enable);
return 0;
}
@@ -49,7 +55,13 @@ static const struct ksu_feature_handler su_compat_handler = {
.set_handler = su_compat_feature_set,
};
static void __user *userspace_stack_buffer(const void *d, size_t len)
static const char sh_path[] = "/system/bin/sh";
static const char ksud_path[] = KSUD_PATH;
static const char su[] = SU_PATH;
bool ksu_sucompat_hook_state __read_mostly = true;
static inline void __user *userspace_stack_buffer(const void *d, size_t len)
{
/* To avoid having to mmap a page in userspace, just write below the stack
* pointer. */
@@ -58,24 +70,19 @@ static void __user *userspace_stack_buffer(const void *d, size_t len)
return copy_to_user(p, d, len) ? NULL : p;
}
static char __user *sh_user_path(void)
static inline char __user *sh_user_path(void)
{
static const char sh_path[] = "/system/bin/sh";
return userspace_stack_buffer(sh_path, sizeof(sh_path));
}
static char __user *ksud_user_path(void)
static inline char __user *ksud_user_path(void)
{
static const char ksud_path[] = KSUD_PATH;
return userspace_stack_buffer(ksud_path, sizeof(ksud_path));
}
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *__unused_flags)
{
const char su[] = SU_PATH;
#ifdef KSU_MANUAL_HOOK
if (!ksu_su_compat_enabled) {
@@ -83,13 +90,19 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
}
#endif
#ifndef CONFIG_KSU_SUSFS_SUS_SU
if (!ksu_is_allow_uid_for_current(current_uid().val)) {
return 0;
}
#endif
#ifdef CONFIG_KSU_SUSFS_SUS_SU
char path[sizeof(su) + 1] = {0};
#else
char path[sizeof(su) + 1];
memset(path, 0, sizeof(path));
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
#endif
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
if (unlikely(!memcmp(path, su, sizeof(su)))) {
#if __SULOG_GATE
@@ -102,26 +115,53 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) && defined(CONFIG_KSU_SUSFS_SUS_SU)
struct filename* susfs_ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) {
struct filename *name = getname_flags(*filename_user, getname_statx_lookup_flags(*flags), NULL);
if (unlikely(IS_ERR(name) || name->name == NULL)) {
return name;
}
if (likely(memcmp(name->name, su, sizeof(su)))) {
return name;
}
const char sh[] = SH_PATH;
#if __SULOG_GATE
ksu_sulog_report_syscall(current_uid().val, NULL, "vfs_fstatat", sh);
#endif
pr_info("vfs_fstatat su->sh!\n");
memcpy((void *)name->name, sh, sizeof(sh));
return name;
}
#endif
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
{
// const char sh[] = SH_PATH;
const char su[] = SU_PATH;
#ifdef KSU_MANUAL_HOOK
if (!ksu_su_compat_enabled) {
return 0;
}
#endif
#ifndef CONFIG_KSU_SUSFS_SUS_SU
if (!ksu_is_allow_uid_for_current(current_uid().val)) {
return 0;
}
#endif
if (unlikely(!filename_user)) {
return 0;
}
#ifdef CONFIG_KSU_SUSFS_SUS_SU
char path[sizeof(su) + 1] = {0};
#else
char path[sizeof(su) + 1];
memset(path, 0, sizeof(path));
#endif
// Remove this later!! we use syscall hook, so this will never happen!!!!!
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) && 0
// it becomes a `struct filename *` after 5.18
@@ -136,7 +176,7 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
pr_info("vfs_statx su->sh!\n");
memcpy((void *)filename->name, sh, sizeof(sh));
#else
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
if (unlikely(!memcmp(path, su, sizeof(su)))) {
#if __SULOG_GATE
@@ -154,30 +194,46 @@ int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
void *__never_use_argv, void *__never_use_envp,
int *__never_use_flags)
{
const char su[] = SU_PATH;
//const char su[] = SU_PATH;
#ifdef CONFIG_KSU_SUSFS_SUS_SU
char path[sizeof(su) + 1] = {0};
#else
char path[sizeof(su) + 1];
#endif
#ifdef KSU_MANUAL_HOOK
if (!ksu_su_compat_enabled){
return 0;
}
#endif
if (unlikely(!filename_user))
return 0;
memset(path, 0, sizeof(path));
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
/*
* nofault variant fails silently due to pagefault_disable
* some cpus dont really have that good speculative execution
* access_ok to substitute set_fs, we check if pointer is accessible
*/
if (!ksu_access_ok(*filename_user, sizeof(path)))
return 0;
// success = returns number of bytes and should be less than path
long len = strncpy_from_user(path, *filename_user, sizeof(path));
if (len <= 0 || len > sizeof(path))
return 0;
// strncpy_from_user_nofault does this too
path[sizeof(path) - 1] = '\0';
if (likely(memcmp(path, su, sizeof(su))))
return 0;
#if __SULOG_GATE
bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val);
ksu_sulog_report_syscall(current_uid().val, NULL, "execve", path);
bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val);
if (!is_allowed)
return 0;
ksu_sulog_report_su_attempt(current_uid().val, NULL, path, is_allowed);
#else
if (!ksu_is_allow_uid_for_current(current_uid().val)) {