Skip to content
Merged
Show file tree
Hide file tree
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
13 changes: 3 additions & 10 deletions kernel/base/hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,16 +328,9 @@ KP_EXPORT_SYMBOL(ret_absolute);

int32_t branch_from_to(uint32_t *tramp_buf, uint64_t src_addr, uint64_t dst_addr)
{
#if 0
uint32_t len = branch_relative(tramp_buf, src_addr, dst_addr);
int32_t len = branch_relative(tramp_buf, src_addr, dst_addr);
if (len) return len;
#else
#if 0
return branch_absolute(tramp_buf, dst_addr);
#else
return ret_absolute(tramp_buf, dst_addr);
#endif
#endif
}

// transit0
Expand Down Expand Up @@ -558,11 +551,11 @@ hook_err_t hook_prepare(hook_t *hook)
}
// trampline to replace_addr
if (hook->origin_insts[0] == ARM64_PACIASP || hook->origin_insts[0] == ARM64_PACIBSP) {
hook->tramp_insts_num = branch_from_to(&hook->tramp_insts[1], hook->origin_addr, hook->replace_addr);
hook->tramp_insts_num = branch_absolute(&hook->tramp_insts[1], hook->replace_addr);
hook->tramp_insts[0] = ARM64_BTI_JC;
hook->tramp_insts_num++;
} else {
hook->tramp_insts_num = branch_from_to(hook->tramp_insts, hook->origin_addr, hook->replace_addr);
hook->tramp_insts_num = branch_absolute(hook->tramp_insts, hook->replace_addr);
}

// relocate
Expand Down
8 changes: 6 additions & 2 deletions kernel/patch/android/userd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,8 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen
hook_local->data0 = 0;
}

if (current_uid() != 0 && !hook_local->data0) return;

static char app_process[] = "/system/bin/app_process";
static char app_process64[] = "/system/bin/app_process64";
static int first_app_process_execed = 0;
Expand Down Expand Up @@ -1521,13 +1523,15 @@ static void before_openat(hook_fargs4_t *args, void *udata)
args->local.data3 = 0;
static int replaced = 0;

if (replaced) return;

if (current_uid() != 0) return;

const char __user *filename = (typeof(filename))syscall_argn(args, 1);
char buf[256];
long rc = compat_strncpy_from_user(buf, filename, sizeof(buf));
if (rc <= 0) return;

if (replaced) return;

int file_count = sizeof(ORIGIN_RC_FILES) / sizeof(ORIGIN_RC_FILES[0]);
for (int i = 0; i < file_count; i++) {
if (ORIGIN_RC_FILES[i][0] == '\0') break;
Expand Down
76 changes: 46 additions & 30 deletions kernel/patch/common/kstorage.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@

#define KSTRORAGE_MAX_GROUP_NUM 4

#define KSTORAGE_HASH_BITS 8
#define KSTORAGE_NBUCKETS (1 << KSTORAGE_HASH_BITS)

// static atomic64_t used_max_group = ATOMIC_INIT(0);
static int used_max_group = -1;
static struct list_head kstorage_groups[KSTRORAGE_MAX_GROUP_NUM];
static struct hlist_head kstorage_groups[KSTRORAGE_MAX_GROUP_NUM][KSTORAGE_NBUCKETS];
static spinlock_t kstorage_glocks[KSTRORAGE_MAX_GROUP_NUM];
static int group_sizes[KSTRORAGE_MAX_GROUP_NUM] = { 0 };
static spinlock_t used_max_group_lock;

static inline struct hlist_head *kstorage_bucket(int gid, long did)
{
unsigned long h = (unsigned long)did * 0x9e3779b97f4a7c15UL;
return &kstorage_groups[gid][h >> (64 - KSTORAGE_HASH_BITS)];
}

static void reclaim_callback(struct rcu_head *rcu)
{
struct kstorage *ks = container_of(rcu, struct kstorage, rcu);
Expand Down Expand Up @@ -54,21 +63,21 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data
int rc = -ENOENT;
if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return rc;

struct list_head *head = &kstorage_groups[gid];
struct hlist_head *bucket = kstorage_bucket(gid, did);
spinlock_t *lock = &kstorage_glocks[gid];
struct kstorage *pos = 0, *old = 0;

rcu_read_lock();

list_for_each_entry(pos, head, list)
hlist_for_each_entry_rcu(pos, bucket, hnode)
{
if (pos->did == did) {
Comment on lines 70 to 74
old = pos;
break;
}
}

struct kstorage *new = (struct kstorage *)vmalloc(sizeof(struct kstorage) + len);
struct kstorage *new = (struct kstorage *)vmalloc(sizeof(struct kstorage) + len);
if (!new) {
rcu_read_unlock();
return -ENOMEM;
Expand All @@ -80,6 +89,7 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data
void *drc = memdup_user(data + offset, len);
if (IS_ERR(drc)) {
rcu_read_unlock();
kvfree(new);
return PTR_ERR(drc);
}
memcpy(new->data, drc, len);
Expand All @@ -91,9 +101,9 @@ int write_kstorage(int gid, long did, void *data, int offset, int len, bool data

spin_lock(lock);
if (old) { // update
list_replace_rcu(&old->list, &new->list);
hlist_replace_rcu(&old->hnode, &new->hnode);
} else { // add new one
list_add_rcu(&new->list, head);
hlist_add_head_rcu(&new->hnode, bucket);
group_sizes[gid]++;
}
spin_unlock(lock);
Expand All @@ -117,10 +127,10 @@ const struct kstorage *get_kstorage(int gid, long did)
{
if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return ERR_PTR(-ENOENT);

struct list_head *head = &kstorage_groups[gid];
struct hlist_head *bucket = kstorage_bucket(gid, did);
struct kstorage *pos = 0;

list_for_each_entry(pos, head, list)
hlist_for_each_entry_rcu(pos, bucket, hnode)
{
if (pos->did == did) {
return pos;
Expand All @@ -137,17 +147,19 @@ int on_each_kstorage_elem(int gid, on_kstorage_cb cb, void *udata)

int rc = 0;

struct list_head *head = &kstorage_groups[gid];
struct kstorage *pos = 0;

rcu_read_lock();

list_for_each_entry(pos, head, list)
{
int rc = cb(pos, udata);
if (rc) break;
for (int b = 0; b < KSTORAGE_NBUCKETS; b++) {
hlist_for_each_entry_rcu(pos, &kstorage_groups[gid][b], hnode)
{
rc = cb(pos, udata);
if (rc) goto out;
}
}

out:
rcu_read_unlock();

return rc;
Expand Down Expand Up @@ -189,27 +201,29 @@ int list_kstorage_ids(int gid, long *ids, int idslen, bool data_is_user)

int cnt = 0;

struct list_head *head = &kstorage_groups[gid];
struct kstorage *pos = 0;

rcu_read_lock();

list_for_each_entry(pos, head, list)
{
if (cnt >= idslen) break;

if (data_is_user) {
int cplen = compat_copy_to_user(ids + cnt, &pos->did, sizeof(pos->did));
if (cplen <= 0) {
logkfe("compat_copy_to_user error: %d", cplen);
cnt = cplen;
for (int b = 0; b < KSTORAGE_NBUCKETS; b++) {
hlist_for_each_entry_rcu(pos, &kstorage_groups[gid][b], hnode)
{
if (cnt >= idslen) goto out;

if (data_is_user) {
int cplen = compat_copy_to_user(ids + cnt, &pos->did, sizeof(pos->did));
if (cplen <= 0) {
logkfe("compat_copy_to_user error: %d", cplen);
cnt = cplen;
Comment on lines +213 to +217
}
} else {
memcpy(ids + cnt, &pos->did, sizeof(pos->did));
}
} else {
memcpy(ids + cnt, &pos->did, sizeof(pos->did));
cnt++;
}
cnt++;
}

out:
rcu_read_unlock();

return cnt;
Expand All @@ -221,16 +235,16 @@ int remove_kstorage(int gid, long did)
int rc = -ENOENT;
if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return rc;

struct list_head *head = &kstorage_groups[gid];
struct hlist_head *bucket = kstorage_bucket(gid, did);
spinlock_t *lock = &kstorage_glocks[gid];
struct kstorage *pos = 0;

spin_lock(lock);

list_for_each_entry(pos, head, list)
hlist_for_each_entry_rcu(pos, bucket, hnode)
{
if (pos->did == did) {
list_del_rcu(&pos->list);
hlist_del_rcu(&pos->hnode);
spin_unlock(lock);

group_sizes[gid]--;
Expand All @@ -255,7 +269,9 @@ KP_EXPORT_SYMBOL(remove_kstorage);
int kstorage_init()
{
for (int i = 0; i < KSTRORAGE_MAX_GROUP_NUM; i++) {
INIT_LIST_HEAD(&kstorage_groups[i]);
for (int b = 0; b < KSTORAGE_NBUCKETS; b++) {
INIT_HLIST_HEAD(&kstorage_groups[i][b]);
}
spin_lock_init(&kstorage_glocks[i]);
}
spin_lock_init(&used_max_group_lock);
Expand Down
51 changes: 37 additions & 14 deletions kernel/patch/common/sucompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/vmalloc.h>
#include <sucompat.h>
#include <symbol.h>
#include <kallsyms.h>
#include <uapi/linux/limits.h>
#include <predata.h>
#include <kstorage.h>
Expand Down Expand Up @@ -310,7 +311,7 @@ __maybe_unused static void before_execveat(hook_fargs5_t *args, void *udata)
// int, dfd, const char __user *, filename, unsigned, flags,
// unsigned int, mask,
// struct statx __user *, buffer)
static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata)
__maybe_unused static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata)
{
uid_t uid = current_uid();
if (!is_su_allow_uid(uid) && !is_trusted_manager_uid(uid)) return;
Expand All @@ -331,6 +332,34 @@ static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata)
}
}

static void after_getname_flags(hook_fargs3_t *args, void *udata)
{
struct filename *fn = (struct filename *)args->ret;
if (IS_ERR_OR_NULL(fn)) return;

uid_t uid = current_uid();
if (!is_su_allow_uid(uid) && !is_trusted_manager_uid(uid)) return;

const char *name = fn->name;
if (!name || strcmp(name, su_get_path())) return;

if (strlen(sh_path) <= strlen(name)) {
strcpy((char *)name, sh_path);
return;
}

if (kfunc(getname_kernel) && kfunc(putname)) {
struct filename *nf = kfunc(getname_kernel)(sh_path);
if (!IS_ERR_OR_NULL(nf)) {
kfunc(putname)(fn);
args->ret = (uint64_t)nf;
return;
}
}

logkfi("uid: %d, cannot redirect su path to %s\n", uid, sh_path);
}

int set_ap_mod_exclude(uid_t uid, int exclude)
{
int rc = 0;
Expand Down Expand Up @@ -394,23 +423,17 @@ int su_compat_init()
rc = hook_syscalln(__NR_execve, 3, before_execve, 0, (void *)0);
log_boot("hook __NR_execve rc: %d\n", rc);

rc = hook_syscalln(__NR3264_fstatat, 4, su_handler_arg1_ufilename_before, 0, (void *)0);
log_boot("hook __NR3264_fstatat rc: %d\n", rc);

rc = hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, 0, (void *)0);
log_boot("hook __NR_faccessat rc: %d\n", rc);

// __NR_execve 11
rc = hook_compat_syscalln(11, 3, before_execve, 0, (void *)1);
log_boot("hook 32 __NR_execve rc: %d\n", rc);

// __NR_fstatat64 327
rc = hook_compat_syscalln(327, 4, su_handler_arg1_ufilename_before, 0, (void *)0);
log_boot("hook 32 __NR_fstatat64 rc: %d\n", rc);

// __NR_faccessat 334
rc = hook_compat_syscalln(334, 3, su_handler_arg1_ufilename_before, 0, (void *)0);
log_boot("hook 32 __NR_faccessat rc: %d\n", rc);
unsigned long getname_flags_addr = kallsyms_lookup_name("getname_flags");
if (getname_flags_addr) {
rc = hook_wrap3((void *)getname_flags_addr, 0, after_getname_flags, (void *)0);
log_boot("hook getname_flags rc: %d\n", rc);
} else {
log_boot("getname_flags not found\n");
}

return 0;
}
2 changes: 1 addition & 1 deletion kernel/patch/include/kstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

struct kstorage
{
struct list_head list;
struct hlist_node hnode;
struct rcu_head rcu;

int gid;
Expand Down
4 changes: 2 additions & 2 deletions kernel/patch/ksyms/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,8 @@ static void _linux_fs_sym_match(const char *name, unsigned long addr)
// kfunc_match(dentry_open, name, addr);
kfunc_match(filp_close, name, addr);
// kfunc_match(getname, name, addr);
// kfunc_match(getname_kernel, name, addr);
// kfunc_match(putname, name, addr);
kfunc_match(getname_kernel, name, addr);
kfunc_match(putname, name, addr);
// kfunc_match(final_putname, name, addr);
kfunc_match(vfs_llseek, name, addr);
kfunc_match(iterate_dir, name, addr);
Expand Down