Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 62 additions & 71 deletions kernel/sucompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,67 +45,88 @@ static char __user *ksud_user_path(void)
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)
__attribute__((hot))
static long ksu_strncpy_from_user_retry(char *dst,
const void __user *unsafe_addr, long count)
{
const char su[] = SU_PATH;
long ret = ksu_strncpy_from_user_nofault(dst, unsafe_addr, count);
if (likely(ret >= 0))
return ret;

if (!ksu_is_allow_uid(current_uid().val)) {
return 0;
}
// we faulted! fallback to slow path
if (unlikely(!access_ok(unsafe_addr, count)))
return -EFAULT;

char path[sizeof(su) + 1];
memset(path, 0, sizeof(path));
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
return strncpy_from_user(dst, unsafe_addr, count);
}

if (unlikely(!memcmp(path, su, sizeof(su)))) {
pr_info("faccessat su->sh!\n");
*filename_user = sh_user_path();
}
// every little bit helps here
__attribute__((hot))
static bool is_su_allowed(const void *ptr_to_check)
{
if (unlikely(!ptr_to_check))
return false;

return 0;
if (likely(!ksu_is_allow_uid(current_uid().val)))
return false;

return true;
}

int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
static int ksu_sucompat_common(const char __user **filename_user, const char *syscall_name,
const bool escalate)
{
// const char sh[] = SH_PATH;
const char su[] = SU_PATH;

if (!ksu_is_allow_uid(current_uid().val)) {
char path[sizeof(su) + 1];
long len = ksu_strncpy_from_user_retry(path, *filename_user, sizeof(path));
if (len <= 0) // sizeof(su) is not zero
return 0;
}

if (unlikely(!filename_user)) {
return 0;
}
path[sizeof(path) - 1] = '\0';

char path[sizeof(su) + 1];
memset(path, 0, sizeof(path));
// 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
// https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216
const char sh[] = SH_PATH;
struct filename *filename = *((struct filename **)filename_user);
if (IS_ERR(filename)) {
return 0;
}
if (likely(memcmp(filename->name, su, sizeof(su))))
if (memcmp(path, su, sizeof(su)))
return 0;
pr_info("vfs_statx su->sh!\n");
memcpy((void *)filename->name, sh, sizeof(sh));
#else
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));

if (unlikely(!memcmp(path, su, sizeof(su)))) {
pr_info("newfstatat su->sh!\n");
if (escalate) {
pr_info("%s su found\n", syscall_name);
*filename_user = ksud_user_path();
escape_to_root(); // escalate !!
} else {
pr_info("%s su->sh!\n", syscall_name);
*filename_user = sh_user_path();
}
#endif

return 0;
}

int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *__unused_flags)
{
if (!is_su_allowed((const void *)filename_user))
return 0;

return ksu_sucompat_common(filename_user, "faccessat", false);
}

int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
{
if (!is_su_allowed((const void *)filename_user))
return 0;

return ksu_sucompat_common(filename_user, "newfstatat", false);
}

int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
void *__never_use_argv, void *__never_use_envp,
int *__never_use_flags)
{
if (!is_su_allowed((const void *)filename_user))
return 0;

return ksu_sucompat_common(filename_user, "sys_execve", true);
}

// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code
int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
void *__never_use_argv, void *__never_use_envp,
Expand All @@ -115,7 +136,7 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
const char sh[] = KSUD_PATH;
const char su[] = SU_PATH;

if (unlikely(!filename_ptr))
if (!is_su_allowed((const void *)filename_ptr))
return 0;

filename = *filename_ptr;
Expand All @@ -126,9 +147,6 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
if (likely(memcmp(filename->name, su, sizeof(su))))
return 0;

if (!ksu_is_allow_uid(current_uid().val))
return 0;

pr_info("do_execveat_common su found\n");
memcpy((void *)filename->name, sh, sizeof(sh));

Expand All @@ -137,33 +155,6 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
return 0;
}

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;
char path[sizeof(su) + 1];

if (unlikely(!filename_user))
return 0;

memset(path, 0, sizeof(path));
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));

if (likely(memcmp(path, su, sizeof(su))))
return 0;

if (!ksu_is_allow_uid(current_uid().val))
return 0;

pr_info("sys_execve su found\n");
*filename_user = ksud_user_path();

escape_to_root();

return 0;
}

int ksu_handle_devpts(struct inode *inode)
{
if (!current->mm) {
Expand Down