kernel: don't use 0(root uid) as manager init uid

This commit is contained in:
weishu
2023-01-17 13:49:30 +07:00
parent ab36e1fa0c
commit 2a1e91cb34
4 changed files with 73 additions and 47 deletions

View File

@@ -1,50 +1,38 @@
#include <asm-generic/errno-base.h>
#include <linux/cpu.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/uidgid.h>
#include <linux/cpu.h>
#include <linux/memory.h>
#include <linux/uaccess.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/version.h> #include <linux/kprobes.h>
#include <linux/memory.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm-generic/errno-base.h> #include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/uidgid.h>
#include <linux/version.h>
#include <linux/rcupdate.h>
#include <linux/fdtable.h> #include <linux/fdtable.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fs_struct.h> #include <linux/fs_struct.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/rcupdate.h>
#include <linux/delay.h> // mslepp #include <linux/delay.h> // msleep
#include "selinux/selinux.h"
#include "klog.h"
#include "apk_sign.h"
#include "allowlist.h" #include "allowlist.h"
#include "apk_sign.h"
#include "arch.h" #include "arch.h"
#include "klog.h"
#include "ksu.h"
#include "selinux/selinux.h"
#include "uid_observer.h" #include "uid_observer.h"
#define KERNEL_SU_VERSION 9
#define KERNEL_SU_OPTION 0xDEADBEEF
#define CMD_GRANT_ROOT 0
#define CMD_BECOME_MANAGER 1
#define CMD_GET_VERSION 2
#define CMD_ALLOW_SU 3
#define CMD_DENY_SU 4
#define CMD_GET_ALLOW_LIST 5
#define CMD_GET_DENY_LIST 6
static struct group_info root_groups = { .usage = ATOMIC_INIT(2) }; static struct group_info root_groups = { .usage = ATOMIC_INIT(2) };
uid_t ksu_manager_uid; uid_t ksu_manager_uid = INVALID_UID;
void escape_to_root() void escape_to_root()
{ {
@@ -66,7 +54,8 @@ void escape_to_root()
memset(&cred->cap_ambient, 0xff, sizeof(cred->cap_ambient)); memset(&cred->cap_ambient, 0xff, sizeof(cred->cap_ambient));
// disable seccomp // disable seccomp
#if defined(CONFIG_GENERIC_ENTRY) && LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) #if defined(CONFIG_GENERIC_ENTRY) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
current_thread_info()->syscall_work &= ~SYSCALL_WORK_SECCOMP; current_thread_info()->syscall_work &= ~SYSCALL_WORK_SECCOMP;
#else #else
current_thread_info()->flags &= ~(TIF_SECCOMP | _TIF_SECCOMP); current_thread_info()->flags &= ~(TIF_SECCOMP | _TIF_SECCOMP);
@@ -94,7 +83,6 @@ int endswith(const char *s, const char *t)
return strcmp(s + slen - tlen, t); return strcmp(s + slen - tlen, t);
} }
static bool is_manager() static bool is_manager()
{ {
return ksu_manager_uid == current_uid().val; return ksu_manager_uid == current_uid().val;
@@ -109,13 +97,14 @@ static bool become_manager(char *pkg)
char *buf; char *buf;
bool result = false; bool result = false;
// must be zygote's direct child, otherwise any app can fork a new process and open manager's apk // must be zygote's direct child, otherwise any app can fork a new process and
// open manager's apk
if (task_uid(current->real_parent).val != 0) { if (task_uid(current->real_parent).val != 0) {
pr_info("parent is not zygote!\n"); pr_info("parent is not zygote!\n");
return false; return false;
} }
if (ksu_manager_uid != 0) { if (ksu_is_manager_uid_valid()) {
pr_info("manager already exist: %d\n", ksu_manager_uid); pr_info("manager already exist: %d\n", ksu_manager_uid);
return is_manager(); return is_manager();
} }
@@ -150,7 +139,7 @@ static bool become_manager(char *pkg)
uid_t uid = current_uid().val; uid_t uid = current_uid().val;
pr_info("manager uid: %d\n", uid); pr_info("manager uid: %d\n", uid);
ksu_manager_uid = uid; ksu_set_manager_uid(uid);
result = true; result = true;
goto clean; goto clean;
@@ -259,7 +248,6 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
return 0; return 0;
} }
// Both root manager and root processes should be allowed to get version // Both root manager and root processes should be allowed to get version
if (arg2 == CMD_GET_VERSION) { if (arg2 == CMD_GET_VERSION) {
if (is_manager() || 0 == current_uid().val) { if (is_manager() || 0 == current_uid().val) {
@@ -361,5 +349,6 @@ MODULE_AUTHOR("weishu");
MODULE_DESCRIPTION("Android GKI KernelSU"); MODULE_DESCRIPTION("Android GKI KernelSU");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); // 5+才需要导出命名空间 MODULE_IMPORT_NS(
VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); // 5+才需要导出命名空间
#endif #endif

38
kernel/ksu.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef __KSU_H_KSU
#define __KSU_H_KSU
#include "linux/uidgid.h"
#define KERNEL_SU_VERSION 9
#define KERNEL_SU_OPTION 0xDEADBEEF
#define CMD_GRANT_ROOT 0
#define CMD_BECOME_MANAGER 1
#define CMD_GET_VERSION 2
#define CMD_ALLOW_SU 3
#define CMD_DENY_SU 4
#define CMD_GET_ALLOW_LIST 5
#define CMD_GET_DENY_LIST 6
#define INVALID_UID -1
extern uid_t ksu_manager_uid;
static inline bool ksu_is_manager_uid_valid() {
return ksu_manager_uid != INVALID_UID;
}
static inline uid_t ksu_get_manager_uid() {
return ksu_manager_uid;
}
static inline void ksu_set_manager_uid(uid_t uid) {
ksu_manager_uid = uid;
}
static inline void ksu_invalidate_manager_uid() {
ksu_manager_uid = INVALID_UID;
}
#endif

View File

@@ -15,12 +15,11 @@
#include "allowlist.h" #include "allowlist.h"
#include "arch.h" #include "arch.h"
#include "klog.h" #include "klog.h"
#include "ksu.h"
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list" #define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
static struct work_struct ksu_update_uid_work; static struct work_struct ksu_update_uid_work;
extern uid_t ksu_manager_uid;
struct uid_data { struct uid_data {
struct list_head list; struct list_head list;
u32 uid; u32 uid;
@@ -100,15 +99,15 @@ static void do_update_uid(struct work_struct *work)
// first, check if manager_uid exist! // first, check if manager_uid exist!
bool manager_exist = false; bool manager_exist = false;
list_for_each_entry (np, &uid_list, list) { list_for_each_entry (np, &uid_list, list) {
if (np->uid == ksu_manager_uid) { if (np->uid == ksu_get_manager_uid()) {
manager_exist = true; manager_exist = true;
break; break;
} }
} }
if (!manager_exist) { if (!manager_exist && ksu_is_manager_uid_valid()) {
pr_info("manager is uninstalled, reset it!\n"); pr_info("manager is uninstalled, invalidate it!\n");
ksu_manager_uid = 0; ksu_invalidate_manager_uid();
} }
// then prune the allowlist // then prune the allowlist