manager: implement app profile api call
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user