manager: implement app profile api call

This commit is contained in:
weishu
2023-05-17 11:23:46 +08:00
parent f2cb841b8a
commit 41265b0203
16 changed files with 395 additions and 267 deletions

View File

@@ -3,15 +3,16 @@
#include <sys/prctl.h>
#include <android/log.h>
#include <cstring>
#include "ksu.h"
#define LOG_TAG "KernelSu"
#define LOG_TAG "KernelSU"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jclass clazz, jstring pkg) {
Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jobject, jstring pkg) {
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
auto result = become_manager(cpkg);
env->ReleaseStringUTFChars(pkg, cpkg);
@@ -20,13 +21,13 @@ Java_me_weishu_kernelsu_Natives_becomeManager(JNIEnv *env, jclass clazz, jstring
extern "C"
JNIEXPORT jint JNICALL
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jclass clazz) {
Java_me_weishu_kernelsu_Natives_getVersion(JNIEnv *env, jobject) {
return get_version();
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jclass clazz) {
Java_me_weishu_kernelsu_Natives_getAllowList(JNIEnv *env, jobject) {
int uids[1024];
int size = 0;
bool result = get_allow_list(uids, &size);
@@ -56,7 +57,7 @@ Java_me_weishu_kernelsu_Natives_getDenyList(JNIEnv *env, jclass clazz) {
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_allowRoot(JNIEnv *env, jclass clazz, jint uid, jboolean allow) {
Java_me_weishu_kernelsu_Natives_allowRoot(JNIEnv *env, jobject clazz, jint uid, jboolean allow) {
return allow_su(uid, allow);
}
@@ -66,43 +67,173 @@ Java_me_weishu_kernelsu_Natives_isSafeMode(JNIEnv *env, jclass clazz) {
return is_safe_mode();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_isAllowlistMode(JNIEnv *env, jclass clazz) {
return is_allowlist_mode();
static void fillIntArray(JNIEnv* env, jobject list, int *data, int count) {
auto cls = env->GetObjectClass(list);
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
auto integerCls = env->FindClass("java/lang/Integer");
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
for (int i = 0; i < count; ++i) {
auto integer = env->NewObject(integerCls, constructor, data[i]);
env->CallBooleanMethod(list, add, integer);
}
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_setAllowlistMode(JNIEnv *env, jclass clazz, jboolean is_allowlist) {
return set_allowlist_mode(is_allowlist);
static int getListSize(JNIEnv *env, jobject list) {
auto cls = env->GetObjectClass(list);
auto size = env->GetMethodID(cls, "size", "()I");
return env->CallIntMethod(list, size);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_addUidToAllowlist(JNIEnv *env, jclass clazz, jint uid) {
return add_to_allow_list(uid);
JNIEXPORT jobject JNICALL
Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg, jint uid) {
if (env->GetStringLength(pkg) > KSU_MAX_PACKAGE_NAME) {
return nullptr;
}
p_key_t key = {};
auto cpkg = env->GetStringUTFChars(pkg, nullptr);
strcpy(key, cpkg);
env->ReleaseStringUTFChars(pkg, cpkg);
app_profile profile = {};
strcpy(profile.key, key);
profile.current_uid = uid;
if (!get_app_profile(key, &profile)) {
return nullptr;
}
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
auto constructor = env->GetMethodID(cls, "<init>", "()V");
auto obj = env->NewObject(cls, constructor);
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
auto uidField = env->GetFieldID(cls, "uid", "I");
auto gidField = env->GetFieldID(cls, "gid", "I");
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
// auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
env->SetObjectField(obj, keyField, env->NewStringUTF(profile.key));
env->SetIntField(obj, currentUidField, profile.current_uid);
auto allowSu = profile.allow_su;
if (allowSu) {
env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.root_profile.use_default);
if (strlen(profile.root_profile.template_name) > 0) {
env->SetObjectField(obj, rootTemplateField,
env->NewStringUTF(profile.root_profile.template_name));
}
env->SetIntField(obj, uidField, profile.root_profile.uid);
env->SetIntField(obj, gidField, profile.root_profile.gid);
jobject groupList = env->GetObjectField(obj, groupsField);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
}
fillIntArray(env, groupList, profile.root_profile.groups, profile.root_profile.groups_count);
jobject capList = env->GetObjectField(obj, capabilitiesField);
fillIntArray(env, capList, profile.root_profile.capabilities, 2);
env->SetObjectField(obj, domainField,
env->NewStringUTF(profile.root_profile.selinux_domain));
// env->SetIntField(obj, namespacesField, profile.root_profile.namespaces);
env->SetBooleanField(obj, allowSuField, profile.allow_su);
} else {
env->SetBooleanField(obj, nonRootUseDefaultField,
(jboolean) profile.non_root_profile.use_default);
env->SetBooleanField(obj, umountModulesField, profile.non_root_profile.umount_modules);
}
return obj;
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_removeUidFromAllowlist(JNIEnv *env, jclass clazz, jint uid) {
return remove_from_allow_list(uid);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_addUidToDenylist(JNIEnv *env, jclass clazz, jint uid) {
return add_to_deny_list(uid);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_removeUidFromDenylist(JNIEnv *env, jclass clazz, jint uid) {
return remove_from_deny_list(uid);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_isUidInAllowlist(JNIEnv *env, jclass clazz, jint uid) {
return is_in_allow_list(uid);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_isUidInDenylist(JNIEnv *env, jclass clazz, jint uid) {
return is_in_deny_list(uid);
Java_me_weishu_kernelsu_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobject profile) {
auto cls = env->FindClass("me/weishu/kernelsu/Natives$Profile");
auto keyField = env->GetFieldID(cls, "name", "Ljava/lang/String;");
auto currentUidField = env->GetFieldID(cls, "currentUid", "I");
auto allowSuField = env->GetFieldID(cls, "allowSu", "Z");
auto rootUseDefaultField = env->GetFieldID(cls, "rootUseDefault", "Z");
auto rootTemplateField = env->GetFieldID(cls, "rootTemplate", "Ljava/lang/String;");
auto uidField = env->GetFieldID(cls, "uid", "I");
auto gidField = env->GetFieldID(cls, "gid", "I");
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
// auto namespacesField = env->GetFieldID(cls, "namespaces", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
auto key = env->GetObjectField(profile, keyField);
if (!key) {
return false;
}
if (env->GetStringLength((jstring) key) > KSU_MAX_PACKAGE_NAME) {
return false;
}
auto cpkg = env->GetStringUTFChars((jstring) key, nullptr);
p_key_t p_key = {};
strcpy(p_key, cpkg);
env->ReleaseStringUTFChars((jstring) key, cpkg);
auto currentUid = env->GetIntField(profile, currentUidField);
auto uid = env->GetIntField(profile, uidField);
auto gid = env->GetIntField(profile, gidField);
auto groups = env->GetObjectField(profile, groupsField);
auto capabilities = env->GetObjectField(profile, capabilitiesField);
auto domain = env->GetObjectField(profile, domainField);
auto allowSu = env->GetBooleanField(profile, allowSuField);
auto umountModules = env->GetBooleanField(profile, umountModulesField);
app_profile p = {};
strcpy(p.key, p_key);
p.allow_su = allowSu;
p.current_uid = currentUid;
if (allowSu) {
p.root_profile.use_default = env->GetBooleanField(profile, rootUseDefaultField);
auto templateName = env->GetObjectField(profile, rootTemplateField);
if (templateName) {
auto ctemplateName = env->GetStringUTFChars((jstring) templateName, nullptr);
strcpy(p.root_profile.template_name, ctemplateName);
env->ReleaseStringUTFChars((jstring) templateName, ctemplateName);
}
p.root_profile.uid = uid;
p.root_profile.gid = gid;
p.root_profile.groups_count = getListSize(env, groups);
auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr);
strcpy(p.root_profile.selinux_domain, cdomain);
env->ReleaseStringUTFChars((jstring) domain, cdomain);
// p.root_profile.namespaces = env->GetIntField(profile, namespacesField);
} else {
p.non_root_profile.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
p.non_root_profile.umount_modules = umountModules;
}
return set_app_profile(&p);
}

View File

@@ -22,17 +22,8 @@
#define CMD_GET_DENY_LIST 6
#define CMD_CHECK_SAFEMODE 9
#define CMD_GET_WORK_MODE 10
#define CMD_SET_WORK_MODE 11
#define CMD_IN_ALLOW_LIST 12
#define CMD_IN_DENY_LIST 13
#define CMD_ADD_ALLOW_LIST 14
#define CMD_REMOVE_ALLOW_LIST 15
#define CMD_ADD_DENY_LIST 16
#define CMD_REMOVE_DENY_LIST 17
#define CMD_GET_APP_PROFILE 18
#define CMD_SET_APP_PROFILE 19
#define CMD_GET_APP_PROFILE 10
#define CMD_SET_APP_PROFILE 11
static bool ksuctl(int cmd, void* arg1, void* arg2) {
int32_t result = 0;
@@ -82,50 +73,6 @@ bool set_app_profile(const app_profile *profile) {
return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, nullptr);
}
bool get_app_profile(int32_t key, app_profile *profile) {
bool get_app_profile(p_key_t key, app_profile *profile) {
return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr);
}
bool get_default_non_root_app_profile(app_profile *profile) {
return get_app_profile(DEFAULT_NON_ROOT_PROFILE_KEY, profile);
}
bool get_default_root_app_profile(app_profile *profile) {
return get_app_profile(DEFAULT_ROOT_PROFILE_KEY, profile);
}
bool is_allowlist_mode() {
int32_t mode = -1;
ksuctl(CMD_GET_WORK_MODE, &mode, nullptr);
// for kernel that doesn't support allowlist mode, return -1 and it is always allowlist mode
return mode <= 0;
}
bool set_allowlist_mode(bool allowlist_mode) {
int32_t mode = allowlist_mode ? 0 : 1;
return ksuctl(CMD_SET_WORK_MODE, &mode, nullptr);
}
bool is_in_allow_list(int uid) {
return ksuctl(CMD_IN_ALLOW_LIST, &uid, nullptr);
}
bool is_in_deny_list(int uid) {
return ksuctl(CMD_IN_DENY_LIST, &uid, nullptr);
}
bool add_to_allow_list(int uid) {
return ksuctl(CMD_ADD_ALLOW_LIST, &uid, nullptr);
}
bool remove_from_allow_list(int uid) {
return ksuctl(CMD_REMOVE_ALLOW_LIST, &uid, nullptr);
}
bool add_to_deny_list(int uid) {
return ksuctl(CMD_ADD_DENY_LIST, &uid, nullptr);
}
bool remove_from_deny_list(int uid) {
return ksuctl(CMD_REMOVE_DENY_LIST, &uid, nullptr);
}

View File

@@ -5,7 +5,7 @@
#ifndef KERNELSU_KSU_H
#define KERNELSU_KSU_H
bool become_manager(const char*);
bool become_manager(const char *);
int get_version();
@@ -17,49 +17,46 @@ bool get_deny_list(int *uids, int *size);
bool is_safe_mode();
bool is_allowlist_mode();
bool set_allowlist_mode(bool allowlist_mode);
bool is_in_allow_list(int uid);
bool is_in_deny_list(int uid);
bool add_to_allow_list(int uid);
bool remove_from_allow_list(int uid);
bool add_to_deny_list(int uid);
bool remove_from_deny_list(int uid);
#define KSU_MAX_PACKAGE_NAME 256
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
#define KSU_MAX_GROUPS 32
#define KSU_SELINUX_DOMAIN 64
#define DEFAULT_ROOT_PROFILE_KEY 0
#define DEFAULT_NON_ROOT_PROFILE_KEY 9999 // This UID means NOBODY in Android
using p_key_t = char[KSU_MAX_PACKAGE_NAME];
struct app_profile {
int32_t key; // this is usually the uid of the app, but can be other value for special apps
int32_t uid;
int32_t gid;
int32_t groups[KSU_MAX_GROUPS];
int32_t groups_count;
// kernel_cap_t is u32[2]
uint64_t capabilities;
char selinux_domain[KSU_SELINUX_DOMAIN];
// this is usually the package of the app, but can be other value for special apps
p_key_t key;
int32_t current_uid;
bool allow_su;
bool mount_module;
union {
struct {
bool use_default;
char template_name[KSU_MAX_PACKAGE_NAME];
int32_t uid;
int32_t gid;
int32_t groups[KSU_MAX_GROUPS];
int32_t groups_count;
// kernel_cap_t is u32[2]
int32_t capabilities[2];
char selinux_domain[KSU_SELINUX_DOMAIN];
int32_t namespaces;
} root_profile;
struct {
bool use_default;
bool umount_modules;
} non_root_profile;
};
};
bool set_app_profile(const app_profile *profile);
bool get_app_profile(int32_t key, app_profile *profile);
bool get_app_profile(p_key_t key, app_profile *profile);
#endif //KERNELSU_KSU_H