kernel: Apply the SUSFS patch
This commit is contained in:
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user