kernel: fmt
This commit is contained in:
778
kernel/ksud.c
778
kernel/ksud.c
@@ -40,27 +40,27 @@ bool ksu_module_mounted __read_mostly = false;
|
||||
bool ksu_boot_completed __read_mostly = false;
|
||||
|
||||
static const char KERNEL_SU_RC[] =
|
||||
"\n"
|
||||
"\n"
|
||||
|
||||
"on post-fs-data\n"
|
||||
" start logd\n"
|
||||
// We should wait for the post-fs-data finish
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
|
||||
"\n"
|
||||
"on post-fs-data\n"
|
||||
" start logd\n"
|
||||
// We should wait for the post-fs-data finish
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
|
||||
"\n"
|
||||
|
||||
"on nonencrypted\n"
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
||||
"\n"
|
||||
"on nonencrypted\n"
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
||||
"\n"
|
||||
|
||||
"on property:vold.decrypt=trigger_restart_framework\n"
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
||||
"\n"
|
||||
"on property:vold.decrypt=trigger_restart_framework\n"
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
|
||||
"\n"
|
||||
|
||||
"on property:sys.boot_completed=1\n"
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
|
||||
"\n"
|
||||
"on property:sys.boot_completed=1\n"
|
||||
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
|
||||
"\n"
|
||||
|
||||
"\n";
|
||||
"\n";
|
||||
|
||||
static void stop_vfs_read_hook(void);
|
||||
static void stop_execve_hook(void);
|
||||
@@ -83,22 +83,22 @@ static bool is_boot_phase = true;
|
||||
|
||||
void on_post_fs_data(void)
|
||||
{
|
||||
static bool done = false;
|
||||
if (done) {
|
||||
pr_info("on_post_fs_data already done\n");
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
pr_info("on_post_fs_data!\n");
|
||||
ksu_load_allow_list();
|
||||
ksu_observer_init();
|
||||
// sanity check, this may influence the performance
|
||||
stop_input_hook();
|
||||
static bool done = false;
|
||||
if (done) {
|
||||
pr_info("on_post_fs_data already done\n");
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
pr_info("on_post_fs_data!\n");
|
||||
ksu_load_allow_list();
|
||||
ksu_observer_init();
|
||||
// sanity check, this may influence the performance
|
||||
stop_input_hook();
|
||||
|
||||
// End of boot state
|
||||
is_boot_phase = false;
|
||||
// End of boot state
|
||||
is_boot_phase = false;
|
||||
|
||||
ksu_file_sid = ksu_get_ksu_file_sid();
|
||||
ksu_file_sid = ksu_get_ksu_file_sid();
|
||||
pr_info("ksu_file sid: %d\n", ksu_file_sid);
|
||||
}
|
||||
|
||||
@@ -106,73 +106,73 @@ extern void ext4_unregister_sysfs(struct super_block *sb);
|
||||
int nuke_ext4_sysfs(const char* mnt)
|
||||
{
|
||||
#ifdef CONFIG_EXT4_FS
|
||||
struct path path;
|
||||
int err = kern_path(mnt, 0, &path);
|
||||
if (err) {
|
||||
pr_err("nuke path err: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
struct path path;
|
||||
int err = kern_path(mnt, 0, &path);
|
||||
if (err) {
|
||||
pr_err("nuke path err: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct super_block *sb = path.dentry->d_inode->i_sb;
|
||||
const char *name = sb->s_type->name;
|
||||
if (strcmp(name, "ext4") != 0) {
|
||||
pr_info("nuke but module aren't mounted\n");
|
||||
path_put(&path);
|
||||
return -EINVAL;
|
||||
}
|
||||
struct super_block *sb = path.dentry->d_inode->i_sb;
|
||||
const char *name = sb->s_type->name;
|
||||
if (strcmp(name, "ext4") != 0) {
|
||||
pr_info("nuke but module aren't mounted\n");
|
||||
path_put(&path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ext4_unregister_sysfs(sb);
|
||||
path_put(&path);
|
||||
ext4_unregister_sysfs(sb);
|
||||
path_put(&path);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void on_module_mounted(void){
|
||||
pr_info("on_module_mounted!\n");
|
||||
ksu_module_mounted = true;
|
||||
pr_info("on_module_mounted!\n");
|
||||
ksu_module_mounted = true;
|
||||
}
|
||||
|
||||
void on_boot_completed(void){
|
||||
ksu_boot_completed = true;
|
||||
pr_info("on_boot_completed!\n");
|
||||
track_throne(true);
|
||||
ksu_boot_completed = true;
|
||||
pr_info("on_boot_completed!\n");
|
||||
track_throne(true);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_KSU_SUSFS
|
||||
#define MAX_ARG_STRINGS 0x7FFFFFFF
|
||||
struct user_arg_ptr {
|
||||
#ifdef CONFIG_COMPAT
|
||||
bool is_compat;
|
||||
bool is_compat;
|
||||
#endif
|
||||
union {
|
||||
const char __user *const __user *native;
|
||||
union {
|
||||
const char __user *const __user *native;
|
||||
#ifdef CONFIG_COMPAT
|
||||
const compat_uptr_t __user *compat;
|
||||
const compat_uptr_t __user *compat;
|
||||
#endif
|
||||
} ptr;
|
||||
} ptr;
|
||||
};
|
||||
#endif // #ifndef CONFIG_KSU_SUSFS
|
||||
|
||||
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
|
||||
{
|
||||
const char __user *native;
|
||||
const char __user *native;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (unlikely(argv.is_compat)) {
|
||||
compat_uptr_t compat;
|
||||
if (unlikely(argv.is_compat)) {
|
||||
compat_uptr_t compat;
|
||||
|
||||
if (get_user(compat, argv.ptr.compat + nr))
|
||||
return ERR_PTR(-EFAULT);
|
||||
if (get_user(compat, argv.ptr.compat + nr))
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
return compat_ptr(compat);
|
||||
}
|
||||
return compat_ptr(compat);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (get_user(native, argv.ptr.native + nr))
|
||||
return ERR_PTR(-EFAULT);
|
||||
if (get_user(native, argv.ptr.native + nr))
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
return native;
|
||||
return native;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -186,160 +186,160 @@ static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
|
||||
|
||||
static int __maybe_unused count(struct user_arg_ptr argv, int max)
|
||||
{
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
|
||||
if (argv.ptr.native != NULL) {
|
||||
for (;;) {
|
||||
const char __user *p = get_user_arg_ptr(argv, i);
|
||||
if (argv.ptr.native != NULL) {
|
||||
for (;;) {
|
||||
const char __user *p = get_user_arg_ptr(argv, i);
|
||||
|
||||
if (!p)
|
||||
break;
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
if (IS_ERR(p))
|
||||
return -EFAULT;
|
||||
if (IS_ERR(p))
|
||||
return -EFAULT;
|
||||
|
||||
if (i >= max)
|
||||
return -E2BIG;
|
||||
++i;
|
||||
if (i >= max)
|
||||
return -E2BIG;
|
||||
++i;
|
||||
|
||||
if (fatal_signal_pending(current))
|
||||
return -ERESTARTNOHAND;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
if (fatal_signal_pending(current))
|
||||
return -ERESTARTNOHAND;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static void on_post_fs_data_cbfun(struct callback_head *cb)
|
||||
{
|
||||
on_post_fs_data();
|
||||
on_post_fs_data();
|
||||
}
|
||||
|
||||
static struct callback_head on_post_fs_data_cb = { .func =
|
||||
on_post_fs_data_cbfun };
|
||||
on_post_fs_data_cbfun };
|
||||
|
||||
// IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version
|
||||
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||
struct user_arg_ptr *argv,
|
||||
struct user_arg_ptr *envp, int *flags)
|
||||
struct user_arg_ptr *argv,
|
||||
struct user_arg_ptr *envp, int *flags)
|
||||
{
|
||||
#ifndef KSU_KPROBES_HOOK
|
||||
if (!ksu_execveat_hook) {
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_execveat_hook) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
struct filename *filename;
|
||||
struct filename *filename;
|
||||
|
||||
static const char app_process[] = "/system/bin/app_process";
|
||||
static bool first_app_process = true;
|
||||
static const char app_process[] = "/system/bin/app_process";
|
||||
static bool first_app_process = true;
|
||||
|
||||
/* This applies to versions Android 10+ */
|
||||
static const char system_bin_init[] = "/system/bin/init";
|
||||
/* This applies to versions between Android 6 ~ 9 */
|
||||
static const char old_system_init[] = "/init";
|
||||
static bool init_second_stage_executed = false;
|
||||
/* This applies to versions Android 10+ */
|
||||
static const char system_bin_init[] = "/system/bin/init";
|
||||
/* This applies to versions between Android 6 ~ 9 */
|
||||
static const char old_system_init[] = "/init";
|
||||
static bool init_second_stage_executed = false;
|
||||
|
||||
if (!filename_ptr)
|
||||
return 0;
|
||||
if (!filename_ptr)
|
||||
return 0;
|
||||
|
||||
filename = *filename_ptr;
|
||||
if (IS_ERR(filename)) {
|
||||
return 0;
|
||||
}
|
||||
filename = *filename_ptr;
|
||||
if (IS_ERR(filename)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(!memcmp(filename->name, system_bin_init,
|
||||
sizeof(system_bin_init) - 1) &&
|
||||
argv)) {
|
||||
// /system/bin/init executed
|
||||
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||
pr_info("/system/bin/init argc: %d\n", argc);
|
||||
if (argc > 1 && !init_second_stage_executed) {
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
|
||||
pr_info("/system/bin/init first arg: %s\n", first_arg);
|
||||
if (!strcmp(first_arg, "second_stage")) {
|
||||
pr_info("/system/bin/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
}
|
||||
} else {
|
||||
pr_err("/system/bin/init parse args err!\n");
|
||||
}
|
||||
}
|
||||
} else if (unlikely(!memcmp(filename->name, old_system_init,
|
||||
sizeof(old_system_init) - 1) &&
|
||||
argv)) {
|
||||
// /init executed
|
||||
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||
pr_info("/init argc: %d\n", argc);
|
||||
if (argc > 1 && !init_second_stage_executed) {
|
||||
/* This applies to versions between Android 6 ~ 7 */
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
|
||||
pr_info("/init first arg: %s\n", first_arg);
|
||||
if (!strcmp(first_arg, "--second-stage")) {
|
||||
pr_info("/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
}
|
||||
} else {
|
||||
pr_err("/init parse args err!\n");
|
||||
}
|
||||
} else if (argc == 1 && !init_second_stage_executed && envp) {
|
||||
/* This applies to versions between Android 8 ~ 9 */
|
||||
int envc = count(*envp, MAX_ARG_STRINGS);
|
||||
if (envc > 0) {
|
||||
int n;
|
||||
for (n = 1; n <= envc; n++) {
|
||||
const char __user *p = get_user_arg_ptr(*envp, n);
|
||||
if (!p || IS_ERR(p)) {
|
||||
continue;
|
||||
}
|
||||
char env[256];
|
||||
// Reading environment variable strings from user space
|
||||
if (ksu_strncpy_from_user_nofault(env, p, sizeof(env)) < 0)
|
||||
continue;
|
||||
// Parsing environment variable names and values
|
||||
char *env_name = env;
|
||||
char *env_value = strchr(env, '=');
|
||||
if (env_value == NULL)
|
||||
continue;
|
||||
// Replace equal sign with string terminator
|
||||
*env_value = '\0';
|
||||
env_value++;
|
||||
// Check if the environment variable name and value are matching
|
||||
if (!strcmp(env_name, "INIT_SECOND_STAGE") &&
|
||||
(!strcmp(env_value, "1") ||
|
||||
!strcmp(env_value, "true"))) {
|
||||
pr_info("/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unlikely(!memcmp(filename->name, system_bin_init,
|
||||
sizeof(system_bin_init) - 1) &&
|
||||
argv)) {
|
||||
// /system/bin/init executed
|
||||
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||
pr_info("/system/bin/init argc: %d\n", argc);
|
||||
if (argc > 1 && !init_second_stage_executed) {
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
|
||||
pr_info("/system/bin/init first arg: %s\n", first_arg);
|
||||
if (!strcmp(first_arg, "second_stage")) {
|
||||
pr_info("/system/bin/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
}
|
||||
} else {
|
||||
pr_err("/system/bin/init parse args err!\n");
|
||||
}
|
||||
}
|
||||
} else if (unlikely(!memcmp(filename->name, old_system_init,
|
||||
sizeof(old_system_init) - 1) &&
|
||||
argv)) {
|
||||
// /init executed
|
||||
int argc = count(*argv, MAX_ARG_STRINGS);
|
||||
pr_info("/init argc: %d\n", argc);
|
||||
if (argc > 1 && !init_second_stage_executed) {
|
||||
/* This applies to versions between Android 6 ~ 7 */
|
||||
const char __user *p = get_user_arg_ptr(*argv, 1);
|
||||
if (p && !IS_ERR(p)) {
|
||||
char first_arg[16];
|
||||
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
|
||||
pr_info("/init first arg: %s\n", first_arg);
|
||||
if (!strcmp(first_arg, "--second-stage")) {
|
||||
pr_info("/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
}
|
||||
} else {
|
||||
pr_err("/init parse args err!\n");
|
||||
}
|
||||
} else if (argc == 1 && !init_second_stage_executed && envp) {
|
||||
/* This applies to versions between Android 8 ~ 9 */
|
||||
int envc = count(*envp, MAX_ARG_STRINGS);
|
||||
if (envc > 0) {
|
||||
int n;
|
||||
for (n = 1; n <= envc; n++) {
|
||||
const char __user *p = get_user_arg_ptr(*envp, n);
|
||||
if (!p || IS_ERR(p)) {
|
||||
continue;
|
||||
}
|
||||
char env[256];
|
||||
// Reading environment variable strings from user space
|
||||
if (ksu_strncpy_from_user_nofault(env, p, sizeof(env)) < 0)
|
||||
continue;
|
||||
// Parsing environment variable names and values
|
||||
char *env_name = env;
|
||||
char *env_value = strchr(env, '=');
|
||||
if (env_value == NULL)
|
||||
continue;
|
||||
// Replace equal sign with string terminator
|
||||
*env_value = '\0';
|
||||
env_value++;
|
||||
// Check if the environment variable name and value are matching
|
||||
if (!strcmp(env_name, "INIT_SECOND_STAGE") &&
|
||||
(!strcmp(env_value, "1") ||
|
||||
!strcmp(env_value, "true"))) {
|
||||
pr_info("/init second_stage executed\n");
|
||||
apply_kernelsu_rules();
|
||||
init_second_stage_executed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(first_app_process && !memcmp(filename->name, app_process,
|
||||
sizeof(app_process) - 1))) {
|
||||
first_app_process = false;
|
||||
pr_info("exec app_process, /data prepared, second_stage: %d\n",
|
||||
init_second_stage_executed);
|
||||
struct task_struct *init_task;
|
||||
rcu_read_lock();
|
||||
init_task = rcu_dereference(current->real_parent);
|
||||
if (init_task) {
|
||||
task_work_add(init_task, &on_post_fs_data_cb, TWA_RESUME);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (unlikely(first_app_process && !memcmp(filename->name, app_process,
|
||||
sizeof(app_process) - 1))) {
|
||||
first_app_process = false;
|
||||
pr_info("exec app_process, /data prepared, second_stage: %d\n",
|
||||
init_second_stage_executed);
|
||||
struct task_struct *init_task;
|
||||
rcu_read_lock();
|
||||
init_task = rcu_dereference(current->real_parent);
|
||||
if (init_task) {
|
||||
task_work_add(init_task, &on_post_fs_data_cb, TWA_RESUME);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
stop_execve_hook();
|
||||
}
|
||||
stop_execve_hook();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *);
|
||||
@@ -348,295 +348,295 @@ static struct file_operations fops_proxy;
|
||||
static ssize_t read_count_append = 0;
|
||||
|
||||
static ssize_t read_proxy(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *pos)
|
||||
loff_t *pos)
|
||||
{
|
||||
bool first_read = file->f_pos == 0;
|
||||
ssize_t ret = orig_read(file, buf, count, pos);
|
||||
if (first_read) {
|
||||
pr_info("read_proxy append %ld + %ld\n", ret, read_count_append);
|
||||
ret += read_count_append;
|
||||
}
|
||||
return ret;
|
||||
bool first_read = file->f_pos == 0;
|
||||
ssize_t ret = orig_read(file, buf, count, pos);
|
||||
if (first_read) {
|
||||
pr_info("read_proxy append %ld + %ld\n", ret, read_count_append);
|
||||
ret += read_count_append;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
bool first_read = iocb->ki_pos == 0;
|
||||
ssize_t ret = orig_read_iter(iocb, to);
|
||||
if (first_read) {
|
||||
pr_info("read_iter_proxy append %ld + %ld\n", ret, read_count_append);
|
||||
ret += read_count_append;
|
||||
}
|
||||
return ret;
|
||||
bool first_read = iocb->ki_pos == 0;
|
||||
ssize_t ret = orig_read_iter(iocb, to);
|
||||
if (first_read) {
|
||||
pr_info("read_iter_proxy append %ld + %ld\n", ret, read_count_append);
|
||||
ret += read_count_append;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||
size_t *count_ptr, loff_t **pos)
|
||||
size_t *count_ptr, loff_t **pos)
|
||||
{
|
||||
#ifndef KSU_KPROBES_HOOK
|
||||
if (!ksu_vfs_read_hook) {
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_vfs_read_hook) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
struct file *file;
|
||||
char __user *buf;
|
||||
size_t count;
|
||||
struct file *file;
|
||||
char __user *buf;
|
||||
size_t count;
|
||||
|
||||
if (strcmp(current->comm, "init")) {
|
||||
// we are only interest in `init` process
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(current->comm, "init")) {
|
||||
// we are only interest in `init` process
|
||||
return 0;
|
||||
}
|
||||
|
||||
file = *file_ptr;
|
||||
if (IS_ERR(file)) {
|
||||
return 0;
|
||||
}
|
||||
file = *file_ptr;
|
||||
if (IS_ERR(file)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!d_is_reg(file->f_path.dentry)) {
|
||||
return 0;
|
||||
}
|
||||
if (!d_is_reg(file->f_path.dentry)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *short_name = file->f_path.dentry->d_name.name;
|
||||
if (strcmp(short_name, "atrace.rc")) {
|
||||
// we are only interest `atrace.rc` file name file
|
||||
return 0;
|
||||
}
|
||||
char path[256];
|
||||
char *dpath = d_path(&file->f_path, path, sizeof(path));
|
||||
const char *short_name = file->f_path.dentry->d_name.name;
|
||||
if (strcmp(short_name, "atrace.rc")) {
|
||||
// we are only interest `atrace.rc` file name file
|
||||
return 0;
|
||||
}
|
||||
char path[256];
|
||||
char *dpath = d_path(&file->f_path, path, sizeof(path));
|
||||
|
||||
if (IS_ERR(dpath)) {
|
||||
return 0;
|
||||
}
|
||||
if (IS_ERR(dpath)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(dpath, "/system/etc/init/atrace.rc")) {
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(dpath, "/system/etc/init/atrace.rc")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we only process the first read
|
||||
static bool rc_inserted = false;
|
||||
if (rc_inserted) {
|
||||
// we don't need this kprobe, unregister it!
|
||||
stop_vfs_read_hook();
|
||||
return 0;
|
||||
}
|
||||
rc_inserted = true;
|
||||
// we only process the first read
|
||||
static bool rc_inserted = false;
|
||||
if (rc_inserted) {
|
||||
// we don't need this kprobe, unregister it!
|
||||
stop_vfs_read_hook();
|
||||
return 0;
|
||||
}
|
||||
rc_inserted = true;
|
||||
|
||||
// now we can sure that the init process is reading
|
||||
// `/system/etc/init/atrace.rc`
|
||||
buf = *buf_ptr;
|
||||
count = *count_ptr;
|
||||
// now we can sure that the init process is reading
|
||||
// `/system/etc/init/atrace.rc`
|
||||
buf = *buf_ptr;
|
||||
count = *count_ptr;
|
||||
|
||||
size_t rc_count = strlen(KERNEL_SU_RC);
|
||||
size_t rc_count = strlen(KERNEL_SU_RC);
|
||||
|
||||
pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath,
|
||||
current->comm, count, rc_count);
|
||||
pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath,
|
||||
current->comm, count, rc_count);
|
||||
|
||||
if (count < rc_count) {
|
||||
pr_err("count: %zu < rc_count: %zu\n", count, rc_count);
|
||||
return 0;
|
||||
}
|
||||
if (count < rc_count) {
|
||||
pr_err("count: %zu < rc_count: %zu\n", count, rc_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count);
|
||||
if (ret) {
|
||||
pr_err("copy ksud.rc failed: %zu\n", ret);
|
||||
return 0;
|
||||
}
|
||||
size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count);
|
||||
if (ret) {
|
||||
pr_err("copy ksud.rc failed: %zu\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we've succeed to insert ksud.rc, now we need to proxy the read and modify the result!
|
||||
// But, we can not modify the file_operations directly, because it's in read-only memory.
|
||||
// We just replace the whole file_operations with a proxy one.
|
||||
memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations));
|
||||
orig_read = file->f_op->read;
|
||||
if (orig_read) {
|
||||
fops_proxy.read = read_proxy;
|
||||
}
|
||||
orig_read_iter = file->f_op->read_iter;
|
||||
if (orig_read_iter) {
|
||||
fops_proxy.read_iter = read_iter_proxy;
|
||||
}
|
||||
// replace the file_operations
|
||||
file->f_op = &fops_proxy;
|
||||
read_count_append = rc_count;
|
||||
// we've succeed to insert ksud.rc, now we need to proxy the read and modify the result!
|
||||
// But, we can not modify the file_operations directly, because it's in read-only memory.
|
||||
// We just replace the whole file_operations with a proxy one.
|
||||
memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations));
|
||||
orig_read = file->f_op->read;
|
||||
if (orig_read) {
|
||||
fops_proxy.read = read_proxy;
|
||||
}
|
||||
orig_read_iter = file->f_op->read_iter;
|
||||
if (orig_read_iter) {
|
||||
fops_proxy.read_iter = read_iter_proxy;
|
||||
}
|
||||
// replace the file_operations
|
||||
file->f_op = &fops_proxy;
|
||||
read_count_append = rc_count;
|
||||
|
||||
*buf_ptr = buf + rc_count;
|
||||
*count_ptr = count - rc_count;
|
||||
*buf_ptr = buf + rc_count;
|
||||
*count_ptr = count - rc_count;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr,
|
||||
size_t *count_ptr)
|
||||
size_t *count_ptr)
|
||||
{
|
||||
struct file *file = fget(fd);
|
||||
if (!file) {
|
||||
return 0;
|
||||
}
|
||||
int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL);
|
||||
fput(file);
|
||||
return result;
|
||||
struct file *file = fget(fd);
|
||||
if (!file) {
|
||||
return 0;
|
||||
}
|
||||
int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL);
|
||||
fput(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned int volumedown_pressed_count = 0;
|
||||
|
||||
static bool is_volumedown_enough(unsigned int count)
|
||||
{
|
||||
return count >= 3;
|
||||
return count >= 3;
|
||||
}
|
||||
|
||||
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||
int *value)
|
||||
int *value)
|
||||
{
|
||||
#ifndef KSU_KPROBES_HOOK
|
||||
if (!ksu_input_hook) {
|
||||
return 0;
|
||||
}
|
||||
if (!ksu_input_hook) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) {
|
||||
int val = *value;
|
||||
pr_info("KEY_VOLUMEDOWN val: %d\n", val);
|
||||
if (val && is_boot_phase) {
|
||||
// key pressed, count it
|
||||
volumedown_pressed_count += 1;
|
||||
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||
stop_input_hook();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) {
|
||||
int val = *value;
|
||||
pr_info("KEY_VOLUMEDOWN val: %d\n", val);
|
||||
if (val && is_boot_phase) {
|
||||
// key pressed, count it
|
||||
volumedown_pressed_count += 1;
|
||||
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||
stop_input_hook();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ksu_is_safe_mode()
|
||||
{
|
||||
static bool safe_mode = false;
|
||||
if (safe_mode) {
|
||||
// don't need to check again, userspace may call multiple times
|
||||
return true;
|
||||
}
|
||||
static bool safe_mode = false;
|
||||
if (safe_mode) {
|
||||
// don't need to check again, userspace may call multiple times
|
||||
return true;
|
||||
}
|
||||
|
||||
// stop hook first!
|
||||
stop_input_hook();
|
||||
// stop hook first!
|
||||
stop_input_hook();
|
||||
|
||||
pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count);
|
||||
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||
// pressed over 3 times
|
||||
pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n");
|
||||
safe_mode = true;
|
||||
return true;
|
||||
}
|
||||
pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count);
|
||||
if (is_volumedown_enough(volumedown_pressed_count)) {
|
||||
// pressed over 3 times
|
||||
pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n");
|
||||
safe_mode = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
|
||||
|
||||
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||
const char __user **filename_user =
|
||||
(const char **)&PT_REGS_PARM1(real_regs);
|
||||
const char __user *const __user *__argv =
|
||||
(const char __user *const __user *)PT_REGS_PARM2(real_regs);
|
||||
struct user_arg_ptr argv = { .ptr.native = __argv };
|
||||
struct filename filename_in, *filename_p;
|
||||
char path[32];
|
||||
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||
const char __user **filename_user =
|
||||
(const char **)&PT_REGS_PARM1(real_regs);
|
||||
const char __user *const __user *__argv =
|
||||
(const char __user *const __user *)PT_REGS_PARM2(real_regs);
|
||||
struct user_arg_ptr argv = { .ptr.native = __argv };
|
||||
struct filename filename_in, *filename_p;
|
||||
char path[32];
|
||||
|
||||
if (!filename_user)
|
||||
return 0;
|
||||
if (!filename_user)
|
||||
return 0;
|
||||
|
||||
memset(path, 0, sizeof(path));
|
||||
ksu_strncpy_from_user_nofault(path, *filename_user, 32);
|
||||
filename_in.name = path;
|
||||
memset(path, 0, sizeof(path));
|
||||
ksu_strncpy_from_user_nofault(path, *filename_user, 32);
|
||||
filename_in.name = path;
|
||||
|
||||
filename_p = &filename_in;
|
||||
return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL, NULL);
|
||||
filename_p = &filename_in;
|
||||
return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL, NULL);
|
||||
}
|
||||
|
||||
static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||
unsigned int fd = PT_REGS_PARM1(real_regs);
|
||||
char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs);
|
||||
size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_regs);
|
||||
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||
unsigned int fd = PT_REGS_PARM1(real_regs);
|
||||
char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs);
|
||||
size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_regs);
|
||||
|
||||
return ksu_handle_sys_read(fd, buf_ptr, count_ptr);
|
||||
return ksu_handle_sys_read(fd, buf_ptr, count_ptr);
|
||||
}
|
||||
|
||||
static int input_handle_event_handler_pre(struct kprobe *p,
|
||||
struct pt_regs *regs)
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs);
|
||||
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs);
|
||||
int *value = (int *)&PT_REGS_CCALL_PARM4(regs);
|
||||
return ksu_handle_input_handle_event(type, code, value);
|
||||
unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs);
|
||||
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs);
|
||||
int *value = (int *)&PT_REGS_CCALL_PARM4(regs);
|
||||
return ksu_handle_input_handle_event(type, code, value);
|
||||
}
|
||||
|
||||
static struct kprobe execve_kp = {
|
||||
.symbol_name = SYS_EXECVE_SYMBOL,
|
||||
.pre_handler = sys_execve_handler_pre,
|
||||
.symbol_name = SYS_EXECVE_SYMBOL,
|
||||
.pre_handler = sys_execve_handler_pre,
|
||||
};
|
||||
|
||||
static struct kprobe vfs_read_kp = {
|
||||
.symbol_name = SYS_READ_SYMBOL,
|
||||
.pre_handler = sys_read_handler_pre,
|
||||
.symbol_name = SYS_READ_SYMBOL,
|
||||
.pre_handler = sys_read_handler_pre,
|
||||
};
|
||||
|
||||
static struct kprobe input_event_kp = {
|
||||
.symbol_name = "input_event",
|
||||
.pre_handler = input_handle_event_handler_pre,
|
||||
.symbol_name = "input_event",
|
||||
.pre_handler = input_handle_event_handler_pre,
|
||||
};
|
||||
|
||||
static void do_stop_vfs_read_hook(struct work_struct *work)
|
||||
{
|
||||
unregister_kprobe(&vfs_read_kp);
|
||||
unregister_kprobe(&vfs_read_kp);
|
||||
}
|
||||
|
||||
static void do_stop_execve_hook(struct work_struct *work)
|
||||
{
|
||||
unregister_kprobe(&execve_kp);
|
||||
unregister_kprobe(&execve_kp);
|
||||
}
|
||||
|
||||
static void do_stop_input_hook(struct work_struct *work)
|
||||
{
|
||||
unregister_kprobe(&input_event_kp);
|
||||
unregister_kprobe(&input_event_kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void stop_vfs_read_hook(void)
|
||||
{
|
||||
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
|
||||
bool ret = schedule_work(&stop_vfs_read_work);
|
||||
pr_info("unregister vfs_read kprobe: %d!\n", ret);
|
||||
bool ret = schedule_work(&stop_vfs_read_work);
|
||||
pr_info("unregister vfs_read kprobe: %d!\n", ret);
|
||||
#else
|
||||
ksu_vfs_read_hook = false;
|
||||
pr_info("stop vfs_read_hook\n");
|
||||
ksu_vfs_read_hook = false;
|
||||
pr_info("stop vfs_read_hook\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void stop_execve_hook(void)
|
||||
{
|
||||
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
|
||||
bool ret = schedule_work(&stop_execve_hook_work);
|
||||
pr_info("unregister execve kprobe: %d!\n", ret);
|
||||
bool ret = schedule_work(&stop_execve_hook_work);
|
||||
pr_info("unregister execve kprobe: %d!\n", ret);
|
||||
#else
|
||||
ksu_execveat_hook = false;
|
||||
pr_info("stop execve_hook\n");
|
||||
ksu_execveat_hook = false;
|
||||
pr_info("stop execve_hook\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void stop_input_hook(void)
|
||||
{
|
||||
static bool input_hook_stopped = false;
|
||||
if (input_hook_stopped) {
|
||||
return;
|
||||
}
|
||||
input_hook_stopped = true;
|
||||
static bool input_hook_stopped = false;
|
||||
if (input_hook_stopped) {
|
||||
return;
|
||||
}
|
||||
input_hook_stopped = true;
|
||||
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
|
||||
bool ret = schedule_work(&stop_input_hook_work);
|
||||
pr_info("unregister input kprobe: %d!\n", ret);
|
||||
bool ret = schedule_work(&stop_input_hook_work);
|
||||
pr_info("unregister input kprobe: %d!\n", ret);
|
||||
#else
|
||||
ksu_input_hook = false;
|
||||
pr_info("stop input_hook\n");
|
||||
ksu_input_hook = false;
|
||||
pr_info("stop input_hook\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -644,31 +644,31 @@ static void stop_input_hook(void)
|
||||
void ksu_ksud_init(void)
|
||||
{
|
||||
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
|
||||
int ret;
|
||||
int ret;
|
||||
|
||||
ret = register_kprobe(&execve_kp);
|
||||
pr_info("ksud: execve_kp: %d\n", ret);
|
||||
ret = register_kprobe(&execve_kp);
|
||||
pr_info("ksud: execve_kp: %d\n", ret);
|
||||
|
||||
ret = register_kprobe(&vfs_read_kp);
|
||||
pr_info("ksud: vfs_read_kp: %d\n", ret);
|
||||
ret = register_kprobe(&vfs_read_kp);
|
||||
pr_info("ksud: vfs_read_kp: %d\n", ret);
|
||||
|
||||
ret = register_kprobe(&input_event_kp);
|
||||
pr_info("ksud: input_event_kp: %d\n", ret);
|
||||
ret = register_kprobe(&input_event_kp);
|
||||
pr_info("ksud: input_event_kp: %d\n", ret);
|
||||
|
||||
INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
|
||||
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
|
||||
INIT_WORK(&stop_input_hook_work, do_stop_input_hook);
|
||||
INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
|
||||
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
|
||||
INIT_WORK(&stop_input_hook_work, do_stop_input_hook);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ksu_ksud_exit(void)
|
||||
{
|
||||
#if defined(KSU_KPROBES_HOOK) && !defined(CONFIG_KSU_SUSFS)
|
||||
unregister_kprobe(&execve_kp);
|
||||
// this should be done before unregister vfs_read_kp
|
||||
// unregister_kprobe(&vfs_read_kp);
|
||||
unregister_kprobe(&input_event_kp);
|
||||
unregister_kprobe(&execve_kp);
|
||||
// this should be done before unregister vfs_read_kp
|
||||
// unregister_kprobe(&vfs_read_kp);
|
||||
unregister_kprobe(&input_event_kp);
|
||||
#endif
|
||||
is_boot_phase = false;
|
||||
volumedown_pressed_count = 0;
|
||||
is_boot_phase = false;
|
||||
volumedown_pressed_count = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user