Skip to content

Commit

Permalink
sucompat: su profile struct
Browse files Browse the repository at this point in the history
  • Loading branch information
bmax committed Dec 17, 2023
1 parent 09e2708 commit fac770e
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 80 deletions.
3 changes: 0 additions & 3 deletions kernel/base/start.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ uint64_t _kp_rw_end = 0;
uint64_t _kp_region_start = 0;
uint64_t _kp_region_end = 0;

uint64_t ttbr1_el1 = 0;
uint64_t kernel_va = 0;
uint64_t kernel_stext_va = 0;
uint64_t kernel_pa = 0;
Expand Down Expand Up @@ -309,8 +308,6 @@ static void restore_map()

static void pgtable_init()
{
asm volatile("mrs %0, ttbr1_el1" : "=r"(ttbr1_el1));

uint64_t addr = kallsyms_lookup_name("memstart_addr");
if (addr) memstart_addr = *(int64_t *)addr;

Expand Down
93 changes: 60 additions & 33 deletions kernel/patch/android/sucompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <syscall.h>
#include <predata.h>
#include <uapi/scdefs.h>

/*
Modified from KernelSU, GPLv2
Expand All @@ -38,14 +39,6 @@ static const char *current_su_path = 0;
static const char apd_path[] = APD_PATH;
static const char kpatch_path[] = KPATCH_PATH;
static const char kpatch_shadow_path[] = KPATCH_SHADOW_PATH;
static const char bypass_via_hook_sctx[] = "bypass_via_hook";

struct su_profile
{
uid_t uid;
uid_t to_uid;
char scontext[SUPERCALL_SCONTEXT_LEN];
};

struct allow_uid
{
Expand Down Expand Up @@ -97,7 +90,7 @@ static int is_allow_uid(uid_t uid)
return 0;
}

int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *sctx, int async)
int su_add_allow_uid(uid_t uid, struct su_profile *profile, int async)
{
rcu_read_lock();
struct allow_uid *pos, *old = 0;
Expand All @@ -109,22 +102,18 @@ int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *sctx, int async)
}
}
struct allow_uid *new = (struct allow_uid *)kmalloc(sizeof(struct allow_uid), GFP_ATOMIC);
memset(new, 0, sizeof(struct allow_uid));
new->uid = uid;
new->profile.uid = uid;
new->profile.to_uid = to_uid;
memset(new->profile.scontext, 0, sizeof(new->profile.scontext));
if (sctx && strcmp(sctx, bypass_via_hook_sctx)) {
strlcpy(new->profile.scontext, sctx, sizeof(new->profile.scontext));
}
new->uid = profile->uid;
memcpy(&new->profile, profile, sizeof(struct su_profile));
new->profile.scontext[sizeof(new->profile.scontext) - 1] = '\0';
kvfree(profile);

spin_lock(&list_lock);
if (old) { // update
list_replace_rcu(&old->list, &new->list);
logkfi("update uid: %d, to_uid: %d, sctx: %s\n", uid, to_uid, sctx);
logkfi("update uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext);
} else { // add new one
list_add_rcu(&new->list, &allow_uid_list);
logkfi("new uid: %d, to_uid: %d, sctx: %s\n", uid, to_uid, sctx);
logkfi("new uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext);
}
spin_unlock(&list_lock);

Expand Down Expand Up @@ -173,42 +162,76 @@ int su_allow_uid_nums()
num++;
}
rcu_read_unlock();
logkd("allow uid num: %d\n", num);
return num;
}

int su_list_allow_uids(char *__user ubuf, int ubuf_len)
int su_allow_uids(uid_t *__user uuids, int unum)
{
int uoff = 0;
char line[SUPERCALL_SCONTEXT_LEN + 32];
int rc = 0;
int num = 0;
rcu_read_lock();
struct allow_uid *pos;
list_for_each_entry(pos, &allow_uid_list, list)
{
int lline = snprintf(line, sizeof(line), "%d,%d,%s\n", pos->uid, pos->profile.to_uid, pos->profile.scontext);
int left = ubuf_len - uoff;
if (left < lline) return -ENOMEM;
uoff += seq_copy_to_user(ubuf + uoff, line, lline);
if (num >= unum) {
goto out;
}
uid_t uid = pos->profile.uid;
int cplen = seq_copy_to_user(uuids + num, &uid, sizeof(uid));
logkd("copy_to_user allow uid: %d\n", uid);
if (cplen <= 0) {
logkfd("seq_copy_to_user error: %d", cplen);
rc = cplen;
goto out;
}
num++;
}
rc = num;
out:
rcu_read_unlock();
return uoff;
return rc;
}

int su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile)
{
int rc = -ENOENT;
rcu_read_lock();
struct allow_uid *pos;
list_for_each_entry(pos, &allow_uid_list, list)
{
if (pos->profile.uid != uid) continue;
int cplen = seq_copy_to_user(uprofile, &pos->profile, sizeof(struct su_profile));
logkd("copy_to_user allow uid profile: %d %d %s\n", uid, pos->profile.to_uid, pos->profile.scontext);
if (cplen <= 0) {
logkfd("seq_copy_to_user error: %d", cplen);
rc = cplen;
goto out;
}
rc = 0;
goto out;
}
out:
rcu_read_unlock();
return rc;
}

// todo:
// no free, no lock
int su_reset_path(const char *path)
{
char *new_su_path = kstrdup(path, GFP_ATOMIC);
current_su_path = new_su_path;
dsb(ish);
logkfi("%s\n", current_su_path);
dsb(ishst);
logki(": %s\n", current_su_path);
return 0;
}

int su_get_path(char *__user ubuf, int buf_len)
{
int len = strnlen(current_su_path, SU_PATH_MAX_LEN);
if (buf_len <= len) return -ENOMEM;
return seq_copy_to_user(ubuf, su_path, len);
if (buf_len < len) return -ENOMEM;
logkfi(": %s\n", current_su_path);
return seq_copy_to_user(ubuf, current_su_path, len + 1);
}

// todo: rcu_dereference_protected
Expand Down Expand Up @@ -414,7 +437,11 @@ int su_compat_init()
spin_lock_init(&list_lock);

// default shell
su_add_allow_uid(2000, 0, 0, 0);
struct su_profile default_shell_profile = {
.uid = 2000,
.to_uid = 0,
};
su_add_allow_uid(default_shell_profile.uid, &default_shell_profile, 1);

// state
unsigned long vfs_stat_addr = kallsyms_lookup_name("vfs_statx");
Expand Down
34 changes: 20 additions & 14 deletions kernel/patch/android/supercall.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <ktypes.h>
#include <uapi/scdefs.h>
#include <hook.h>
#include <common.h>
Expand All @@ -10,17 +11,15 @@
#include <linux/security.h>
#include <accctl.h>
#include <linux/string.h>
#include <linux/err.h>
#include <uapi/asm-generic/errno.h>

static long call_grant_uid(uid_t uid, uid_t to_uid, const char *__user usctx)
static long call_grant_uid(uid_t uid, struct su_profile *__user uprofile)
{
const char *sctx = 0;
if (usctx) {
char buf[SUPERCALL_SCONTEXT_LEN];
int slen = strncpy_from_user_nofault(buf, usctx, sizeof(buf));
if (slen > 0) sctx = buf;
}
return su_add_allow_uid(uid, to_uid, sctx, 1);
struct su_profile *profile = memdup_user(uprofile, sizeof(struct su_profile));
if (IS_ERR(profile)) return PTR_ERR(profile);

return su_add_allow_uid(uid, profile, 1);
}

static long call_revoke_uid(uid_t uid)
Expand All @@ -33,9 +32,14 @@ static long call_su_allow_uid_nums()
return su_allow_uid_nums();
}

static long call_su_list_allow_uid(char *__user buf, int buf_len)
static long call_su_list_allow_uid(uid_t *__user uids, int num)
{
return su_allow_uids(uids, num);
}

static long call_su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile)
{
return su_list_allow_uids(buf, buf_len);
return su_allow_uid_profile(uid, uprofile);
}

static long call_reset_su_path(const char *__user upath)
Expand All @@ -55,13 +59,15 @@ long supercall_android(long cmd, long arg1, long arg2, long arg3)
{
switch (cmd) {
case SUPERCALL_SU_GRANT_UID:
return call_grant_uid((uid_t)arg1, (uid_t)arg2, (const char *__user)arg3);
return call_grant_uid((uid_t)arg1, (struct su_profile * __user) arg2);
case SUPERCALL_SU_REVOKE_UID:
return call_revoke_uid((uid_t)arg1);
case SUPERCALL_SU_ALLOW_UID_NUM:
case SUPERCALL_SU_NUMS:
return call_su_allow_uid_nums();
case SUPERCALL_SU_LIST_ALLOW_UID:
return call_su_list_allow_uid((char *__user)arg1, (int)arg2);
case SUPERCALL_SU_LIST:
return call_su_list_allow_uid((uid_t *)arg1, (int)arg2);
case SUPERCALL_SU_PROFILE:
return call_su_allow_uid_profile((uid_t)arg1, (struct su_profile * __user) arg2);
case SUPERCALL_SU_RESET_PATH:
return call_reset_su_path((const char *)arg1);
case SUPERCALL_SU_GET_PATH:
Expand Down
1 change: 1 addition & 0 deletions kernel/patch/common/supercall.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <ktypes.h>
#include <uapi/scdefs.h>
#include <hook.h>
#include <common.h>
Expand Down
6 changes: 4 additions & 2 deletions kernel/patch/include/accctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/cred.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <uapi/scdefs.h>

int set_priv_selinx_allow(struct task_struct *task, int val);
int commit_kernel_cred();
Expand All @@ -17,10 +18,11 @@ int supercall_install();
#ifdef ANDROID
int kpuserd_init();
int su_compat_init();
int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *sctx, int async);
int su_add_allow_uid(uid_t uid, struct su_profile *profile, int async);
int su_remove_allow_uid(uid_t uid, int async);
int su_allow_uid_nums();
int su_list_allow_uids(char *__user buf, int buf_len);
int su_allow_uids(uid_t *__user uuids, int unum);
int su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile);
int su_reset_path(const char *path);
int su_get_path(char *__user ubuf, int buf_len);
long supercall_android(long cmd, long arg1, long arg2, long arg3);
Expand Down
16 changes: 12 additions & 4 deletions kernel/patch/include/uapi/scdefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ static inline long hash_key(const char *key)
#define KPATCH_PATH "/data/adb/kpatch"
#define KPATCH_SHADOW_PATH "/system/bin/truncate"

struct su_profile
{
uid_t uid;
uid_t to_uid;
char scontext[SUPERCALL_SCONTEXT_LEN];
};

#define SUPERCALL_SU_GRANT_UID 0x1100
#define SUPERCALL_SU_REVOKE_UID 0x1101
#define SUPERCALL_SU_ALLOW_UID_NUM 0x1102
#define SUPERCALL_SU_LIST_ALLOW_UID 0x1103
#define SUPERCALL_SU_GET_PATH 0x1104
#define SUPERCALL_SU_RESET_PATH 0x1105
#define SUPERCALL_SU_NUMS 0x1102
#define SUPERCALL_SU_LIST 0x1103
#define SUPERCALL_SU_PROFILE 0x1104
#define SUPERCALL_SU_GET_PATH 0x1110
#define SUPERCALL_SU_RESET_PATH 0x1111

#endif

Expand Down
65 changes: 59 additions & 6 deletions user/apjni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,52 @@ extern "C" JNIEXPORT jlong JNICALL Java_me_bmax_apatch_Natives_nativeThreadSu(JN
return rc;
}

extern "C" JNIEXPORT jstring JNICALL Java_me_bmax_apatch_Natives_nativeListSu(JNIEnv *env, jclass clz, jstring superKey)
extern "C" JNIEXPORT jint JNICALL Java_me_bmax_apatch_Natives_nativeSuNums(JNIEnv *env, jclass clz, jstring superKey)
{
const char *skey = env->GetStringUTFChars(superKey, NULL);
char buf[1024] = { '\0' };
long rc = sc_su_list_allow_uids(skey, buf, sizeof(buf));
long rc = sc_su_uid_nums(skey);
env->ReleaseStringUTFChars(superKey, skey);
jstring result = env->NewStringUTF(buf);
return result;
return rc;
}

extern "C" JNIEXPORT jintArray JNICALL Java_me_bmax_apatch_Natives_nativeSuUids(JNIEnv *env, jclass clz,
jstring superKey)
{
const char *skey = env->GetStringUTFChars(superKey, NULL);
int num = sc_su_uid_nums(skey);
int uids[num];
long n = sc_su_allow_uids(skey, (uid_t *)uids, num);
if (n > 0) {
jintArray array = env->NewIntArray(num);
env->SetIntArrayRegion(array, 0, n, uids);
return array;
}
env->ReleaseStringUTFChars(superKey, skey);
return env->NewIntArray(0);
}

extern "C" JNIEXPORT jobject JNICALL Java_me_bmax_apatch_Natives_nativeSuProfile(JNIEnv *env, jclass clz,
jstring superKey, jint uid)
{
const char *skey = env->GetStringUTFChars(superKey, NULL);
struct su_profile profile = { 0 };
long rc = sc_su_uid_profile(skey, (uid_t)uid, &profile);
if (rc) {
env->ReleaseStringUTFChars(superKey, skey);
return nullptr;
}
jclass cls = env->FindClass("me/bmax/apatch/Natives$Profile");
jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
jfieldID uidField = env->GetFieldID(cls, "uid", "I");
jfieldID toUidField = env->GetFieldID(cls, "toUid", "I");
jfieldID scontextFild = env->GetFieldID(cls, "scontext", "Ljava/lang/String;");

jobject obj = env->NewObject(cls, constructor);
env->SetIntField(obj, uidField, profile.uid);
env->SetIntField(obj, toUidField, profile.to_uid);
env->SetObjectField(obj, scontextFild, env->NewStringUTF(profile.scontext));

return obj;
}

extern "C" JNIEXPORT jlong JNICALL Java_me_bmax_apatch_Natives_nativeLoadKernelPatchModule(JNIEnv *env, jclass clz,
Expand Down Expand Up @@ -123,7 +161,11 @@ extern "C" JNIEXPORT jlong JNICALL Java_me_bmax_apatch_Natives_nativeGrantSu(JNI
{
const char *skey = env->GetStringUTFChars(superKey, NULL);
const char *sctx = env->GetStringUTFChars(scontext, NULL);
long rc = sc_su_grant_uid(skey, (uid_t)uid, (uid_t)to_uid, sctx);
struct su_profile profile = { 0 };
profile.uid = uid;
profile.to_uid = to_uid;
if (sctx) strncpy(profile.scontext, sctx, sizeof(profile.scontext) - 1);
long rc = sc_su_grant_uid(skey, uid, &profile);
env->ReleaseStringUTFChars(superKey, skey);
env->ReleaseStringUTFChars(scontext, sctx);
return rc;
Expand All @@ -146,3 +188,14 @@ extern "C" JNIEXPORT jstring JNICALL Java_me_bmax_apatch_Natives_nativeSuPath(JN
env->ReleaseStringUTFChars(superKey, skey);
return env->NewStringUTF(buf);
}

extern "C" JNIEXPORT jboolean JNICALL Java_me_bmax_apatch_Natives_nativeResetSuPath(JNIEnv *env, jclass clz,
jstring superKey, jstring jpath)
{
const char *skey = env->GetStringUTFChars(superKey, NULL);
const char *path = env->GetStringUTFChars(jpath, NULL);
long rc = sc_su_reset_path(skey, path);
env->ReleaseStringUTFChars(superKey, skey);
env->ReleaseStringUTFChars(jpath, path);
return rc == 0;
}
Loading

0 comments on commit fac770e

Please sign in to comment.