kernel: refine syscall_hook_manager
- Don't unmark process when setuid if syscall tracepoint is in use - Remark process when app profile updated - Ensure zygote is marked on first boot
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
#include "syscall_hook_manager.h"
|
||||||
|
|
||||||
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
|
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
|
||||||
#define FILE_FORMAT_VERSION 3 // u32
|
#define FILE_FORMAT_VERSION 3 // u32
|
||||||
@@ -256,8 +257,11 @@ out:
|
|||||||
sizeof(default_root_profile));
|
sizeof(default_root_profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (persist)
|
if (persist) {
|
||||||
persistent_allow_list();
|
persistent_allow_list();
|
||||||
|
// FIXME: use a new flag
|
||||||
|
ksu_mark_running_process();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ void on_boot_completed(void){
|
|||||||
pr_info("on_boot_completed!\n");
|
pr_info("on_boot_completed!\n");
|
||||||
// remark process, we don't want to mark other init
|
// remark process, we don't want to mark other init
|
||||||
// forked process excepte zygote and adbd
|
// forked process excepte zygote and adbd
|
||||||
ksu_unmark_all_process();
|
|
||||||
ksu_mark_running_process();
|
ksu_mark_running_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ bool is_ksu_domain()
|
|||||||
return is_task_ksu_domain(current_cred());
|
return is_task_ksu_domain(current_cred());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_zygote(const struct cred* cred)
|
bool is_context(const struct cred* cred, const char* context)
|
||||||
{
|
{
|
||||||
if (!cred) {
|
if (!cred) {
|
||||||
return false;
|
return false;
|
||||||
@@ -126,11 +126,20 @@ bool is_zygote(const struct cred* cred)
|
|||||||
if (err) {
|
if (err) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = strncmp("u:r:zygote:s0", ctx.context, ctx.len) == 0;
|
result = strncmp(context, ctx.context, ctx.len) == 0;
|
||||||
__security_release_secctx(&ctx);
|
__security_release_secctx(&ctx);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_zygote(const struct cred* cred)
|
||||||
|
{
|
||||||
|
return is_context(cred, "u:r:zygote:s0");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_init(const struct cred* cred) {
|
||||||
|
return is_context(cred, "u:r:init:s0");
|
||||||
|
}
|
||||||
|
|
||||||
#define KSU_FILE_DOMAIN "u:object_r:ksu_file:s0"
|
#define KSU_FILE_DOMAIN "u:object_r:ksu_file:s0"
|
||||||
|
|
||||||
u32 ksu_get_ksu_file_sid()
|
u32 ksu_get_ksu_file_sid()
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ bool is_ksu_domain();
|
|||||||
|
|
||||||
bool is_zygote(const struct cred* cred);
|
bool is_zygote(const struct cred* cred);
|
||||||
|
|
||||||
|
bool is_init(const struct cred* cred);
|
||||||
|
|
||||||
void apply_kernelsu_rules();
|
void apply_kernelsu_rules();
|
||||||
|
|
||||||
u32 ksu_get_ksu_file_sid();
|
u32 ksu_get_ksu_file_sid();
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid)
|
|||||||
}
|
}
|
||||||
ksu_set_task_tracepoint_flag(current);
|
ksu_set_task_tracepoint_flag(current);
|
||||||
} else {
|
} else {
|
||||||
ksu_clear_task_tracepoint_flag(current);
|
ksu_clear_task_tracepoint_flag_if_needed(current);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (ksu_is_allow_uid_for_current(new_uid)) {
|
if (ksu_is_allow_uid_for_current(new_uid)) {
|
||||||
|
|||||||
@@ -20,9 +20,21 @@
|
|||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
|
|
||||||
// Tracepoint registration count management
|
// Tracepoint registration count management
|
||||||
|
// == 1: just us
|
||||||
|
// > 1: someone else is also using syscall tracepoint e.g. ftrace
|
||||||
static int tracepoint_reg_count = 0;
|
static int tracepoint_reg_count = 0;
|
||||||
static DEFINE_SPINLOCK(tracepoint_reg_lock);
|
static DEFINE_SPINLOCK(tracepoint_reg_lock);
|
||||||
|
|
||||||
|
void ksu_clear_task_tracepoint_flag_if_needed(struct task_struct *t)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
spin_lock_irqsave(&tracepoint_reg_lock, flags);
|
||||||
|
if (tracepoint_reg_count <= 1) {
|
||||||
|
ksu_clear_task_tracepoint_flag(t);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&tracepoint_reg_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
// Process marking management
|
// Process marking management
|
||||||
static void handle_process_mark(bool mark)
|
static void handle_process_mark(bool mark)
|
||||||
{
|
{
|
||||||
@@ -49,7 +61,7 @@ void ksu_unmark_all_process(void)
|
|||||||
pr_info("hook_manager: unmark all user process done!\n");
|
pr_info("hook_manager: unmark all user process done!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_mark_running_process(void)
|
static void ksu_mark_running_process_locked()
|
||||||
{
|
{
|
||||||
struct task_struct *p, *t;
|
struct task_struct *p, *t;
|
||||||
read_lock(&tasklist_lock);
|
read_lock(&tasklist_lock);
|
||||||
@@ -70,12 +82,28 @@ void ksu_mark_running_process(void)
|
|||||||
ksu_set_task_tracepoint_flag(t);
|
ksu_set_task_tracepoint_flag(t);
|
||||||
pr_info("hook_manager: mark process: pid:%d, uid: %d, comm:%s\n",
|
pr_info("hook_manager: mark process: pid:%d, uid: %d, comm:%s\n",
|
||||||
t->pid, uid, t->comm);
|
t->pid, uid, t->comm);
|
||||||
|
} else {
|
||||||
|
ksu_clear_task_tracepoint_flag(t);
|
||||||
|
pr_info("hook_manager: unmark process: pid:%d, uid: %d, comm:%s\n",
|
||||||
|
t->pid, uid, t->comm);
|
||||||
}
|
}
|
||||||
put_cred(cred);
|
put_cred(cred);
|
||||||
}
|
}
|
||||||
read_unlock(&tasklist_lock);
|
read_unlock(&tasklist_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ksu_mark_running_process()
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
spin_lock_irqsave(&tracepoint_reg_lock, flags);
|
||||||
|
if (tracepoint_reg_count <= 1) {
|
||||||
|
ksu_mark_running_process_locked();
|
||||||
|
} else {
|
||||||
|
pr_info("hook_manager: not mark running process since syscall tracepoint is in use\n");
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&tracepoint_reg_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
// Get task mark status
|
// Get task mark status
|
||||||
// Returns: 1 if marked, 0 if not marked, -ESRCH if task not found
|
// Returns: 1 if marked, 0 if not marked, -ESRCH if task not found
|
||||||
int ksu_get_task_mark(pid_t pid)
|
int ksu_get_task_mark(pid_t pid)
|
||||||
@@ -169,10 +197,9 @@ static int syscall_regfunc_handler(struct kretprobe_instance *ri, struct pt_regs
|
|||||||
spin_lock_irqsave(&tracepoint_reg_lock, flags);
|
spin_lock_irqsave(&tracepoint_reg_lock, flags);
|
||||||
if (tracepoint_reg_count < 1) {
|
if (tracepoint_reg_count < 1) {
|
||||||
// while install our tracepoint, mark our processes
|
// while install our tracepoint, mark our processes
|
||||||
ksu_unmark_all_process();
|
ksu_mark_running_process_locked();
|
||||||
ksu_mark_running_process();
|
} else if (tracepoint_reg_count == 1) {
|
||||||
} else {
|
// while other tracepoint first added, mark all processes
|
||||||
// while installing other tracepoint, mark all processes
|
|
||||||
ksu_mark_all_process();
|
ksu_mark_all_process();
|
||||||
}
|
}
|
||||||
tracepoint_reg_count++;
|
tracepoint_reg_count++;
|
||||||
@@ -184,15 +211,14 @@ static int syscall_unregfunc_handler(struct kretprobe_instance *ri, struct pt_re
|
|||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
spin_lock_irqsave(&tracepoint_reg_lock, flags);
|
spin_lock_irqsave(&tracepoint_reg_lock, flags);
|
||||||
if (tracepoint_reg_count <= 1) {
|
|
||||||
// while uninstall our tracepoint, unmark all processes
|
|
||||||
ksu_unmark_all_process();
|
|
||||||
} else {
|
|
||||||
// while uninstalling other tracepoint, mark our processes
|
|
||||||
ksu_unmark_all_process();
|
|
||||||
ksu_mark_running_process();
|
|
||||||
}
|
|
||||||
tracepoint_reg_count--;
|
tracepoint_reg_count--;
|
||||||
|
if (tracepoint_reg_count <= 0) {
|
||||||
|
// while no tracepoint left, unmark all processes
|
||||||
|
ksu_unmark_all_process();
|
||||||
|
} else if (tracepoint_reg_count == 1) {
|
||||||
|
// while just our tracepoint left, unmark disallowed processes
|
||||||
|
ksu_mark_running_process_locked();
|
||||||
|
}
|
||||||
spin_unlock_irqrestore(&tracepoint_reg_lock, flags);
|
spin_unlock_irqrestore(&tracepoint_reg_lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -216,9 +242,8 @@ static inline bool check_syscall_fastpath(int nr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_handle_init_mark_tracker(const char __user **filename_user,
|
// Unmark init's child that are not zygote or adbd
|
||||||
void *__never_use_argv, void *__never_use_envp,
|
int ksu_handle_init_mark_tracker(const char __user **filename_user)
|
||||||
int *__never_use_flags)
|
|
||||||
{
|
{
|
||||||
char path[64];
|
char path[64];
|
||||||
|
|
||||||
@@ -228,8 +253,8 @@ int ksu_handle_init_mark_tracker(const char __user **filename_user,
|
|||||||
memset(path, 0, sizeof(path));
|
memset(path, 0, sizeof(path));
|
||||||
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||||
|
|
||||||
if (likely(strstr(path, "adbd") == NULL)){
|
if (likely(strstr(path, "/app_process") == NULL && strstr(path, "/adbd") == NULL)) {
|
||||||
ksu_clear_task_tracepoint_flag(current);
|
ksu_clear_task_tracepoint_flag_if_needed(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -273,8 +298,8 @@ static void ksu_sys_enter_handler(void *data, struct pt_regs *regs, long id)
|
|||||||
if (id == __NR_execve) {
|
if (id == __NR_execve) {
|
||||||
const char __user **filename_user =
|
const char __user **filename_user =
|
||||||
(const char __user **)&PT_REGS_PARM1(regs);
|
(const char __user **)&PT_REGS_PARM1(regs);
|
||||||
if (current->pid == 1) {
|
if (current->pid != 1 && is_init(get_current_cred())) {
|
||||||
ksu_handle_init_mark_tracker(filename_user, NULL, NULL, NULL);
|
ksu_handle_init_mark_tracker(filename_user);
|
||||||
} else {
|
} else {
|
||||||
ksu_handle_execve_sucompat(filename_user, NULL, NULL, NULL);
|
ksu_handle_execve_sucompat(filename_user, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
@@ -316,8 +341,7 @@ void ksu_syscall_hook_manager_init(void)
|
|||||||
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
|
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
|
||||||
ret = register_trace_sys_enter(ksu_sys_enter_handler, NULL);
|
ret = register_trace_sys_enter(ksu_sys_enter_handler, NULL);
|
||||||
#ifndef CONFIG_KRETPROBES
|
#ifndef CONFIG_KRETPROBES
|
||||||
ksu_unmark_all_process();
|
ksu_mark_running_process_locked();
|
||||||
ksu_mark_running_process();
|
|
||||||
#endif
|
#endif
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("hook_manager: failed to register sys_enter tracepoint: %d\n", ret);
|
pr_err("hook_manager: failed to register sys_enter tracepoint: %d\n", ret);
|
||||||
|
|||||||
@@ -42,4 +42,6 @@ static inline void ksu_clear_task_tracepoint_flag(struct task_struct *t)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ksu_clear_task_tracepoint_flag_if_needed(struct task_struct *t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user