From 730d58f18b9377ab82f5dcc8548917d9bdd16193 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Sun, 15 Jun 2025 17:17:19 +0800 Subject: [PATCH] dec++-ify jni part - Refactoring to c Co-authored-by: lamadaemon Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> --- manager/app/src/main/cpp/CMakeLists.txt | 10 +- manager/app/src/main/cpp/jni.c | 302 +++++++++++++++++ manager/app/src/main/cpp/jni.cc | 319 ------------------ manager/app/src/main/cpp/{ksu.cc => ksu.c} | 55 +-- manager/app/src/main/cpp/ksu.h | 9 +- manager/app/src/main/cpp/prelude.h | 17 + .../java/com/sukisu/ultra/ui/screen/Home.kt | 2 + .../src/main/res/values-zh-rTW/strings.xml | 6 - 8 files changed, 360 insertions(+), 360 deletions(-) create mode 100644 manager/app/src/main/cpp/jni.c delete mode 100644 manager/app/src/main/cpp/jni.cc rename manager/app/src/main/cpp/{ksu.cc => ksu.c} (58%) create mode 100644 manager/app/src/main/cpp/prelude.h diff --git a/manager/app/src/main/cpp/CMakeLists.txt b/manager/app/src/main/cpp/CMakeLists.txt index 759af3c8..a351e6b7 100644 --- a/manager/app/src/main/cpp/CMakeLists.txt +++ b/manager/app/src/main/cpp/CMakeLists.txt @@ -1,4 +1,3 @@ - # For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html @@ -7,14 +6,11 @@ cmake_minimum_required(VERSION 3.18.1) project("kernelsu") -find_package(cxx REQUIRED CONFIG) -link_libraries(cxx::cxx) - add_library(zako SHARED - jni.cc - ksu.cc - ) + jni.c + ksu.c +) find_library(log-lib log) diff --git a/manager/app/src/main/cpp/jni.c b/manager/app/src/main/cpp/jni.c new file mode 100644 index 00000000..7b10e069 --- /dev/null +++ b/manager/app/src/main/cpp/jni.c @@ -0,0 +1,302 @@ +#include "prelude.h" +#include "ksu.h" + +#include +#include +#include +#include + + +NativeBridge(becomeManager, jboolean, jstring pkg) { + const char* cpkg = GetEnvironment()->GetStringUTFChars(env, pkg, JNI_FALSE); + bool result = become_manager(cpkg); + + GetEnvironment()->ReleaseStringUTFChars(env, pkg, cpkg); + return result; +} + +NativeBridgeNP(getVersion, jint) { + return get_version(); +} + +NativeBridgeNP(getAllowList, jintArray) { + int uids[1024]; + int size = 0; + bool result = get_allow_list(uids, &size); + + LogDebug("getAllowList: %d, size: %d", result, size); + + if (result) { + jintArray array = GetEnvironment()->NewIntArray(env, size); + GetEnvironment()->SetIntArrayRegion(env, array, 0, size, uids); + + return array; + } + + return GetEnvironment()->NewIntArray(env, 0); +} + +NativeBridgeNP(isSafeMode, jboolean) { + return is_safe_mode(); +} + +NativeBridgeNP(isLkmMode, jboolean) { + return is_lkm_mode(); +} + +static void fillIntArray(JNIEnv *env, jobject list, int *data, int count) { + jclass cls = GetEnvironment()->GetObjectClass(env, list); + jmethodID add = GetEnvironment()->GetMethodID(env, cls, "add", "(Ljava/lang/Object;)Z"); + jclass integerCls = GetEnvironment()->FindClass(env, "java/lang/Integer"); + jmethodID constructor = GetEnvironment()->GetMethodID(env, integerCls, "", "(I)V"); + for (int i = 0; i < count; ++i) { + jobject integer = GetEnvironment()->NewObject(env, integerCls, constructor, data[i]); + GetEnvironment()->CallBooleanMethod(env, list, add, integer); + } +} + +static void addIntToList(JNIEnv *env, jobject list, int ele) { + jclass cls = GetEnvironment()->GetObjectClass(env, list); + jmethodID add = GetEnvironment()->GetMethodID(env, cls, "add", "(Ljava/lang/Object;)Z"); + jclass integerCls = GetEnvironment()->FindClass(env, "java/lang/Integer"); + jmethodID constructor = GetEnvironment()->GetMethodID(env, integerCls, "", "(I)V"); + jobject integer = GetEnvironment()->NewObject(env, integerCls, constructor, ele); + GetEnvironment()->CallBooleanMethod(env, list, add, integer); +} + +static uint64_t capListToBits(JNIEnv *env, jobject list) { + jclass cls = GetEnvironment()->GetObjectClass(env, list); + jmethodID get = GetEnvironment()->GetMethodID(env, cls, "get", "(I)Ljava/lang/Object;"); + jmethodID size = GetEnvironment()->GetMethodID(env, cls, "size", "()I"); + jint listSize = GetEnvironment()->CallIntMethod(env, list, size); + jclass integerCls = GetEnvironment()->FindClass(env, "java/lang/Integer"); + jmethodID intValue = GetEnvironment()->GetMethodID(env, integerCls, "intValue", "()I"); + uint64_t result = 0; + for (int i = 0; i < listSize; ++i) { + jobject integer = GetEnvironment()->CallObjectMethod(env, list, get, i); + int data = GetEnvironment()->CallIntMethod(env, integer, intValue); + + if (cap_valid(data)) { + result |= (1ULL << data); + } + } + + return result; +} + +static int getListSize(JNIEnv *env, jobject list) { + jclass cls = GetEnvironment()->GetObjectClass(env, list); + jmethodID size = GetEnvironment()->GetMethodID(env, cls, "size", "()I"); + return GetEnvironment()->CallIntMethod(env, list, size); +} + +static void fillArrayWithList(JNIEnv *env, jobject list, int *data, int count) { + jclass cls = GetEnvironment()->GetObjectClass(env, list); + jmethodID get = GetEnvironment()->GetMethodID(env, cls, "get", "(I)Ljava/lang/Object;"); + jclass integerCls = GetEnvironment()->FindClass(env, "java/lang/Integer"); + jmethodID intValue = GetEnvironment()->GetMethodID(env, integerCls, "intValue", "()I"); + for (int i = 0; i < count; ++i) { + jobject integer = GetEnvironment()->CallObjectMethod(env, list, get, i); + data[i] = GetEnvironment()->CallIntMethod(env, integer, intValue); + } +} + +NativeBridge(getAppProfile, jobject, jstring pkg, jint uid) { + if (GetEnvironment()->GetStringLength(env, pkg) > KSU_MAX_PACKAGE_NAME) { + return NULL; + } + + char key[KSU_MAX_PACKAGE_NAME] = { 0 }; + const char* cpkg = GetEnvironment()->GetStringUTFChars(env, pkg, nullptr); + strcpy(key, cpkg); + GetEnvironment()->ReleaseStringUTFChars(env, pkg, cpkg); + + struct app_profile profile = { 0 }; + profile.version = KSU_APP_PROFILE_VER; + + strcpy(profile.key, key); + profile.current_uid = uid; + + bool useDefaultProfile = !get_app_profile(key, &profile); + + jclass cls = GetEnvironment()->FindClass(env, "com/sukisu/ultra/Natives$Profile"); + jmethodID constructor = GetEnvironment()->GetMethodID(env, cls, "", "()V"); + jobject obj = GetEnvironment()->NewObject(env, cls, constructor); + jfieldID keyField = GetEnvironment()->GetFieldID(env, cls, "name", "Ljava/lang/String;"); + jfieldID currentUidField = GetEnvironment()->GetFieldID(env, cls, "currentUid", "I"); + jfieldID allowSuField = GetEnvironment()->GetFieldID(env, cls, "allowSu", "Z"); + + jfieldID rootUseDefaultField = GetEnvironment()->GetFieldID(env, cls, "rootUseDefault", "Z"); + jfieldID rootTemplateField = GetEnvironment()->GetFieldID(env, cls, "rootTemplate", "Ljava/lang/String;"); + + jfieldID uidField = GetEnvironment()->GetFieldID(env, cls, "uid", "I"); + jfieldID gidField = GetEnvironment()->GetFieldID(env, cls, "gid", "I"); + jfieldID groupsField = GetEnvironment()->GetFieldID(env, cls, "groups", "Ljava/util/List;"); + jfieldID capabilitiesField = GetEnvironment()->GetFieldID(env, cls, "capabilities", "Ljava/util/List;"); + jfieldID domainField = GetEnvironment()->GetFieldID(env, cls, "context", "Ljava/lang/String;"); + jfieldID namespacesField = GetEnvironment()->GetFieldID(env, cls, "namespace", "I"); + + jfieldID nonRootUseDefaultField = GetEnvironment()->GetFieldID(env, cls, "nonRootUseDefault", "Z"); + jfieldID umountModulesField = GetEnvironment()->GetFieldID(env, cls, "umountModules", "Z"); + + GetEnvironment()->SetObjectField(env, obj, keyField, GetEnvironment()->NewStringUTF(env, profile.key)); + GetEnvironment()->SetIntField(env, obj, currentUidField, profile.current_uid); + + if (useDefaultProfile) { + // no profile found, so just use default profile: + // don't allow root and use default profile! + LogDebug("use default profile for: %s, %d", key, uid); + + // allow_su = false + // non root use default = true + GetEnvironment()->SetBooleanField(env, obj, allowSuField, false); + GetEnvironment()->SetBooleanField(env, obj, nonRootUseDefaultField, true); + + return obj; + } + + bool allowSu = profile.allow_su; + + if (allowSu) { + GetEnvironment()->SetBooleanField(env, obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default); + if (strlen(profile.rp_config.template_name) > 0) { + GetEnvironment()->SetObjectField(env, obj, rootTemplateField, + GetEnvironment()->NewStringUTF(env, profile.rp_config.template_name)); + } + + GetEnvironment()->SetIntField(env, obj, uidField, profile.rp_config.profile.uid); + GetEnvironment()->SetIntField(env, obj, gidField, profile.rp_config.profile.gid); + + jobject groupList = GetEnvironment()->GetObjectField(env, obj, groupsField); + int groupCount = profile.rp_config.profile.groups_count; + if (groupCount > KSU_MAX_GROUPS) { + LogDebug("kernel group count too large: %d???", groupCount); + groupCount = KSU_MAX_GROUPS; + } + fillIntArray(env, groupList, profile.rp_config.profile.groups, groupCount); + + jobject capList = GetEnvironment()->GetObjectField(env, obj, capabilitiesField); + for (int i = 0; i <= CAP_LAST_CAP; i++) { + if (profile.rp_config.profile.capabilities.effective & (1ULL << i)) { + addIntToList(env, capList, i); + } + } + + GetEnvironment()->SetObjectField(env, obj, domainField, + GetEnvironment()->NewStringUTF(env, profile.rp_config.profile.selinux_domain)); + GetEnvironment()->SetIntField(env, obj, namespacesField, profile.rp_config.profile.namespaces); + GetEnvironment()->SetBooleanField(env, obj, allowSuField, profile.allow_su); + } else { + GetEnvironment()->SetBooleanField(env, obj, nonRootUseDefaultField, profile.nrp_config.use_default); + GetEnvironment()->SetBooleanField(env, obj, umountModulesField, profile.nrp_config.profile.umount_modules); + } + + return obj; +} + +NativeBridge(setAppProfile, jboolean, jobject profile) { + jclass cls = GetEnvironment()->FindClass(env, "com/sukisu/ultra/Natives$Profile"); + + jfieldID keyField = GetEnvironment()->GetFieldID(env, cls, "name", "Ljava/lang/String;"); + jfieldID currentUidField = GetEnvironment()->GetFieldID(env, cls, "currentUid", "I"); + jfieldID allowSuField = GetEnvironment()->GetFieldID(env, cls, "allowSu", "Z"); + + jfieldID rootUseDefaultField = GetEnvironment()->GetFieldID(env, cls, "rootUseDefault", "Z"); + jfieldID rootTemplateField = GetEnvironment()->GetFieldID(env, cls, "rootTemplate", "Ljava/lang/String;"); + + jfieldID uidField = GetEnvironment()->GetFieldID(env, cls, "uid", "I"); + jfieldID gidField = GetEnvironment()->GetFieldID(env, cls, "gid", "I"); + jfieldID groupsField = GetEnvironment()->GetFieldID(env, cls, "groups", "Ljava/util/List;"); + jfieldID capabilitiesField = GetEnvironment()->GetFieldID(env, cls, "capabilities", "Ljava/util/List;"); + jfieldID domainField = GetEnvironment()->GetFieldID(env, cls, "context", "Ljava/lang/String;"); + jfieldID namespacesField = GetEnvironment()->GetFieldID(env, cls, "namespace", "I"); + + jfieldID nonRootUseDefaultField = GetEnvironment()->GetFieldID(env, cls, "nonRootUseDefault", "Z"); + jfieldID umountModulesField = GetEnvironment()->GetFieldID(env, cls, "umountModules", "Z"); + + jobject key = GetEnvironment()->GetObjectField(env, profile, keyField); + if (!key) { + return false; + } + if (GetEnvironment()->GetStringLength(env, (jstring) key) > KSU_MAX_PACKAGE_NAME) { + return false; + } + + const char* cpkg = GetEnvironment()->GetStringUTFChars(env, (jstring) key, nullptr); + char p_key[KSU_MAX_PACKAGE_NAME] = { 0 }; + strcpy(p_key, cpkg); + GetEnvironment()->ReleaseStringUTFChars(env, (jstring) key, cpkg); + + jint currentUid = GetEnvironment()->GetIntField(env, profile, currentUidField); + + jint uid = GetEnvironment()->GetIntField(env, profile, uidField); + jint gid = GetEnvironment()->GetIntField(env, profile, gidField); + jobject groups = GetEnvironment()->GetObjectField(env, profile, groupsField); + jobject capabilities = GetEnvironment()->GetObjectField(env, profile, capabilitiesField); + jobject domain = GetEnvironment()->GetObjectField(env, profile, domainField); + jboolean allowSu = GetEnvironment()->GetBooleanField(env, profile, allowSuField); + jboolean umountModules = GetEnvironment()->GetBooleanField(env, profile, umountModulesField); + + struct app_profile p = { 0 }; + p.version = KSU_APP_PROFILE_VER; + + strcpy(p.key, p_key); + p.allow_su = allowSu; + p.current_uid = currentUid; + + if (allowSu) { + p.rp_config.use_default = GetEnvironment()->GetBooleanField(env, profile, rootUseDefaultField); + jobject templateName = GetEnvironment()->GetObjectField(env, profile, rootTemplateField); + if (templateName) { + const char* ctemplateName = GetEnvironment()->GetStringUTFChars(env, (jstring) templateName, nullptr); + strcpy(p.rp_config.template_name, ctemplateName); + GetEnvironment()->ReleaseStringUTFChars(env, (jstring) templateName, ctemplateName); + } + + p.rp_config.profile.uid = uid; + p.rp_config.profile.gid = gid; + + int groups_count = getListSize(env, groups); + if (groups_count > KSU_MAX_GROUPS) { + LogDebug("groups count too large: %d", groups_count); + return false; + } + p.rp_config.profile.groups_count = groups_count; + fillArrayWithList(env, groups, p.rp_config.profile.groups, groups_count); + + p.rp_config.profile.capabilities.effective = capListToBits(env, capabilities); + + const char* cdomain = GetEnvironment()->GetStringUTFChars(env, (jstring) domain, nullptr); + strcpy(p.rp_config.profile.selinux_domain, cdomain); + GetEnvironment()->ReleaseStringUTFChars(env, (jstring) domain, cdomain); + + p.rp_config.profile.namespaces = GetEnvironment()->GetIntField(env, profile, namespacesField); + } else { + p.nrp_config.use_default = GetEnvironment()->GetBooleanField(env, profile, nonRootUseDefaultField); + p.nrp_config.profile.umount_modules = umountModules; + } + + return set_app_profile(&p); +} + +NativeBridge(uidShouldUmount, jboolean, jint uid) { + return uid_should_umount(uid); +} + +NativeBridgeNP(isSuEnabled, jboolean) { + return is_su_enabled(); +} + +NativeBridge(setSuEnabled, jboolean, jboolean enabled) { + return set_su_enabled(enabled); +} + +NativeBridgeNP(isKPMEnabled, jboolean) { + return is_KPM_enable(); +} + +NativeBridgeNP(getHookType, jstring) { + char hook_type[16]; + get_hook_type(hook_type, sizeof(hook_type)); + return GetEnvironment()->NewStringUTF(env, hook_type); +} \ No newline at end of file diff --git a/manager/app/src/main/cpp/jni.cc b/manager/app/src/main/cpp/jni.cc deleted file mode 100644 index 65e37638..00000000 --- a/manager/app/src/main/cpp/jni.cc +++ /dev/null @@ -1,319 +0,0 @@ -#include - -#include - -#include -#include - -#include "ksu.h" - -#define LOG_TAG "KernelSU" -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) - -extern "C" -JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_becomeManager(JNIEnv *env, jobject, jstring pkg) { - auto cpkg = env->GetStringUTFChars(pkg, nullptr); - auto result = become_manager(cpkg); - env->ReleaseStringUTFChars(pkg, cpkg); - return result; -} - -extern "C" -JNIEXPORT jint JNICALL -Java_com_sukisu_ultra_Natives_getVersion(JNIEnv *env, jobject) { - return get_version(); -} - -extern "C" -JNIEXPORT jintArray JNICALL -Java_com_sukisu_ultra_Natives_getAllowList(JNIEnv *env, jobject) { - int uids[1024]; - int size = 0; - bool result = get_allow_list(uids, &size); - LOGD("getAllowList: %d, size: %d", result, size); - if (result) { - auto array = env->NewIntArray(size); - env->SetIntArrayRegion(array, 0, size, uids); - return array; - } - return env->NewIntArray(0); -} - -extern "C" -JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_isSafeMode(JNIEnv *env, jclass clazz) { - return is_safe_mode(); -} - -extern "C" -JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_isLkmMode(JNIEnv *env, jclass clazz) { - return is_lkm_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, "", "(I)V"); - for (int i = 0; i < count; ++i) { - auto integer = env->NewObject(integerCls, constructor, data[i]); - env->CallBooleanMethod(list, add, integer); - } -} - -static void addIntToList(JNIEnv *env, jobject list, int ele) { - 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, "", "(I)V"); - auto integer = env->NewObject(integerCls, constructor, ele); - env->CallBooleanMethod(list, add, integer); -} - -static uint64_t capListToBits(JNIEnv *env, jobject list) { - auto cls = env->GetObjectClass(list); - auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;"); - auto size = env->GetMethodID(cls, "size", "()I"); - auto listSize = env->CallIntMethod(list, size); - auto integerCls = env->FindClass("java/lang/Integer"); - auto intValue = env->GetMethodID(integerCls, "intValue", "()I"); - uint64_t result = 0; - for (int i = 0; i < listSize; ++i) { - auto integer = env->CallObjectMethod(list, get, i); - int data = env->CallIntMethod(integer, intValue); - - if (cap_valid(data)) { - result |= (1ULL << data); - } - } - - return result; -} - -static int getListSize(JNIEnv *env, jobject list) { - auto cls = env->GetObjectClass(list); - auto size = env->GetMethodID(cls, "size", "()I"); - return env->CallIntMethod(list, size); -} - -static void fillArrayWithList(JNIEnv *env, jobject list, int *data, int count) { - auto cls = env->GetObjectClass(list); - auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;"); - auto integerCls = env->FindClass("java/lang/Integer"); - auto intValue = env->GetMethodID(integerCls, "intValue", "()I"); - for (int i = 0; i < count; ++i) { - auto integer = env->CallObjectMethod(list, get, i); - data[i] = env->CallIntMethod(integer, intValue); - } -} - -extern "C" -JNIEXPORT jobject JNICALL -Java_com_sukisu_ultra_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 = {}; - profile.version = KSU_APP_PROFILE_VER; - - strcpy(profile.key, key); - profile.current_uid = uid; - - bool useDefaultProfile = !get_app_profile(key, &profile); - - auto cls = env->FindClass("com/sukisu/ultra/Natives$Profile"); - auto constructor = env->GetMethodID(cls, "", "()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); - - if (useDefaultProfile) { - // no profile found, so just use default profile: - // don't allow root and use default profile! - LOGD("use default profile for: %s, %d", key, uid); - - // allow_su = false - // non root use default = true - env->SetBooleanField(obj, allowSuField, false); - env->SetBooleanField(obj, nonRootUseDefaultField, true); - - return obj; - } - - auto allowSu = profile.allow_su; - - if (allowSu) { - env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default); - if (strlen(profile.rp_config.template_name) > 0) { - env->SetObjectField(obj, rootTemplateField, - env->NewStringUTF(profile.rp_config.template_name)); - } - - env->SetIntField(obj, uidField, profile.rp_config.profile.uid); - env->SetIntField(obj, gidField, profile.rp_config.profile.gid); - - jobject groupList = env->GetObjectField(obj, groupsField); - int groupCount = profile.rp_config.profile.groups_count; - if (groupCount > KSU_MAX_GROUPS) { - LOGD("kernel group count too large: %d???", groupCount); - groupCount = KSU_MAX_GROUPS; - } - fillIntArray(env, groupList, profile.rp_config.profile.groups, groupCount); - - jobject capList = env->GetObjectField(obj, capabilitiesField); - for (int i = 0; i <= CAP_LAST_CAP; i++) { - if (profile.rp_config.profile.capabilities.effective & (1ULL << i)) { - addIntToList(env, capList, i); - } - } - - env->SetObjectField(obj, domainField, - env->NewStringUTF(profile.rp_config.profile.selinux_domain)); - env->SetIntField(obj, namespacesField, profile.rp_config.profile.namespaces); - env->SetBooleanField(obj, allowSuField, profile.allow_su); - } else { - env->SetBooleanField(obj, nonRootUseDefaultField, - (jboolean) profile.nrp_config.use_default); - env->SetBooleanField(obj, umountModulesField, profile.nrp_config.profile.umount_modules); - } - - return obj; -} - -extern "C" -JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobject profile) { - auto cls = env->FindClass("com/sukisu/ultra/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, "namespace", "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 = {}; - p.version = KSU_APP_PROFILE_VER; - - strcpy(p.key, p_key); - p.allow_su = allowSu; - p.current_uid = currentUid; - - if (allowSu) { - p.rp_config.use_default = env->GetBooleanField(profile, rootUseDefaultField); - auto templateName = env->GetObjectField(profile, rootTemplateField); - if (templateName) { - auto ctemplateName = env->GetStringUTFChars((jstring) templateName, nullptr); - strcpy(p.rp_config.template_name, ctemplateName); - env->ReleaseStringUTFChars((jstring) templateName, ctemplateName); - } - - p.rp_config.profile.uid = uid; - p.rp_config.profile.gid = gid; - - int groups_count = getListSize(env, groups); - if (groups_count > KSU_MAX_GROUPS) { - LOGD("groups count too large: %d", groups_count); - return false; - } - p.rp_config.profile.groups_count = groups_count; - fillArrayWithList(env, groups, p.rp_config.profile.groups, groups_count); - - p.rp_config.profile.capabilities.effective = capListToBits(env, capabilities); - - auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr); - strcpy(p.rp_config.profile.selinux_domain, cdomain); - env->ReleaseStringUTFChars((jstring) domain, cdomain); - - p.rp_config.profile.namespaces = env->GetIntField(profile, namespacesField); - } else { - p.nrp_config.use_default = env->GetBooleanField(profile, nonRootUseDefaultField); - p.nrp_config.profile.umount_modules = umountModules; - } - - return set_app_profile(&p); -} -extern "C" -JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_uidShouldUmount(JNIEnv *env, jobject thiz, jint uid) { - return uid_should_umount(uid); -} -extern "C" -JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_isSuEnabled(JNIEnv *env, jobject thiz) { - return is_su_enabled(); -} -extern "C" -JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_setSuEnabled(JNIEnv *env, jobject thiz, jboolean enabled) { - return set_su_enabled(enabled); -} - -extern "C" JNIEXPORT jboolean JNICALL -Java_com_sukisu_ultra_Natives_isKPMEnabled(JNIEnv *env, jobject) { - return is_KPM_enable(); -} - -extern "C" JNIEXPORT jstring JNICALL -Java_com_sukisu_ultra_Natives_getHookType(JNIEnv *env, jobject) { - const char* hook_type = get_hook_type(); - return env->NewStringUTF(hook_type); -} \ No newline at end of file diff --git a/manager/app/src/main/cpp/ksu.cc b/manager/app/src/main/cpp/ksu.c similarity index 58% rename from manager/app/src/main/cpp/ksu.cc rename to manager/app/src/main/cpp/ksu.c index ab9069e4..710edd6c 100644 --- a/manager/app/src/main/cpp/ksu.cc +++ b/manager/app/src/main/cpp/ksu.c @@ -8,6 +8,7 @@ #include #include +#include "prelude.h" #include "ksu.h" #define KERNEL_SU_OPTION 0xDEADBEEF @@ -34,8 +35,9 @@ static bool ksuctl(int cmd, void* arg1, void* arg2) { int32_t result = 0; - prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result); - return result == KERNEL_SU_OPTION; + int32_t rtn = prctl(KERNEL_SU_OPTION, cmd, arg1, arg2, &result); + + return result == KERNEL_SU_OPTION && rtn == -1; } bool become_manager(const char* pkg) { @@ -48,7 +50,7 @@ bool become_manager(const char* pkg) { snprintf(param, sizeof(param), "/data/user/%d/%s", userId, pkg); } - return ksuctl(CMD_BECOME_MANAGER, param, nullptr); + return ksuctl(CMD_BECOME_MANAGER, param, NULL); } // cache the result to avoid unnecessary syscall @@ -68,7 +70,7 @@ bool get_allow_list(int *uids, int *size) { } bool is_safe_mode() { - return ksuctl(CMD_CHECK_SAFEMODE, nullptr, nullptr); + return ksuctl(CMD_CHECK_SAFEMODE, NULL, NULL); } bool is_lkm_mode() { @@ -77,41 +79,48 @@ bool is_lkm_mode() { } bool uid_should_umount(int uid) { - bool should; - return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, reinterpret_cast(uid), &should) && should; + int should; + return ksuctl(CMD_IS_UID_SHOULD_UMOUNT, (void*) ((size_t) uid), &should) && should; } -bool set_app_profile(const app_profile *profile) { - return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, nullptr); +bool set_app_profile(const struct app_profile* profile) { + return ksuctl(CMD_SET_APP_PROFILE, (void*) profile, NULL); } -bool get_app_profile(p_key_t key, app_profile *profile) { - return ksuctl(CMD_GET_APP_PROFILE, (void*) profile, nullptr); +bool get_app_profile(char* key, struct app_profile* profile) { + return ksuctl(CMD_GET_APP_PROFILE, profile, NULL); } bool set_su_enabled(bool enabled) { - return ksuctl(CMD_ENABLE_SU, (void*) enabled, nullptr); + return ksuctl(CMD_ENABLE_SU, (void*) enabled, NULL); } bool is_su_enabled() { - bool enabled = true; + int enabled = true; // if ksuctl failed, we assume su is enabled, and it cannot be disabled. - ksuctl(CMD_IS_SU_ENABLED, &enabled, nullptr); + ksuctl(CMD_IS_SU_ENABLED, &enabled, NULL); return enabled; } bool is_KPM_enable() { - bool enabled = false; - return ksuctl(CMD_ENABLE_KPM, &enabled, nullptr), enabled; + int enabled = false; + ksuctl(CMD_ENABLE_KPM, &enabled, NULL); + return enabled; } -const char* get_hook_type() { - static char hook_type[16] = {0}; - if (hook_type[0] == '\0') { - if (ksuctl(CMD_HOOK_TYPE, hook_type, nullptr)) { - return hook_type; - } - strcpy(hook_type, "Unknown"); +bool get_hook_type(char* hook_type, size_t size) { + if (hook_type == NULL || size == 0) { + return false; } - return hook_type; + + static char cached_hook_type[16] = {0}; + if (cached_hook_type[0] == '\0') { + if (!ksuctl(CMD_HOOK_TYPE, cached_hook_type, NULL)) { + strcpy(cached_hook_type, "Unknown"); + } + } + + strncpy(hook_type, cached_hook_type, size); + hook_type[size - 1] = '\0'; + return true; } \ No newline at end of file diff --git a/manager/app/src/main/cpp/ksu.h b/manager/app/src/main/cpp/ksu.h index 715c5aef..e894286b 100644 --- a/manager/app/src/main/cpp/ksu.h +++ b/manager/app/src/main/cpp/ksu.h @@ -5,6 +5,7 @@ #ifndef KERNELSU_KSU_H #define KERNELSU_KSU_H +#include "prelude.h" #include bool become_manager(const char *); @@ -25,8 +26,6 @@ bool is_lkm_mode(); #define KSU_MAX_GROUPS 32 #define KSU_SELINUX_DOMAIN 64 -using p_key_t = char[KSU_MAX_PACKAGE_NAME]; - struct root_profile { int32_t uid; int32_t gid; @@ -75,9 +74,9 @@ struct app_profile { }; }; -bool set_app_profile(const app_profile *profile); +bool set_app_profile(const struct app_profile* profile); -bool get_app_profile(p_key_t key, app_profile *profile); +bool get_app_profile(char* key, struct app_profile* profile); bool set_su_enabled(bool enabled); @@ -85,6 +84,6 @@ bool is_su_enabled(); bool is_KPM_enable(); -const char* get_hook_type(); +bool get_hook_type(char* hook_type, size_t size); #endif //KERNELSU_KSU_H \ No newline at end of file diff --git a/manager/app/src/main/cpp/prelude.h b/manager/app/src/main/cpp/prelude.h new file mode 100644 index 00000000..16a4a2b5 --- /dev/null +++ b/manager/app/src/main/cpp/prelude.h @@ -0,0 +1,17 @@ + +#ifndef KERNELSU_PRELUDE_H +#define KERNELSU_PRELUDE_H + +#include +#include +#include +#include +#include + +#define GetEnvironment() (*env) +#define NativeBridge(fn, rtn, ...) JNIEXPORT rtn JNICALL Java_com_sukisu_ultra_Natives_##fn(JNIEnv* env, jclass clazz, __VA_ARGS__) +#define NativeBridgeNP(fn, rtn) JNIEXPORT rtn JNICALL Java_com_sukisu_ultra_Natives_##fn(JNIEnv* env, jclass clazz) + +#define LogDebug(...) __android_log_print(ANDROID_LOG_DEBUG, "KernelSU", __VA_ARGS__) + +#endif diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt index 2fe5a973..83a500a9 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt @@ -1,5 +1,6 @@ package com.sukisu.ultra.ui.screen +import android.annotation.SuppressLint import android.content.Context import android.os.Build import android.os.PowerManager @@ -741,6 +742,7 @@ private fun InfoCard( } } +@SuppressLint("ComposableNaming") @Composable private fun SuSFSInfoText(systemInfo: HomeViewModel.SystemInfo): String = buildString { append(systemInfo.suSFSVersion) diff --git a/manager/app/src/main/res/values-zh-rTW/strings.xml b/manager/app/src/main/res/values-zh-rTW/strings.xml index 5d90fd82..70dffa13 100644 --- a/manager/app/src/main/res/values-zh-rTW/strings.xml +++ b/manager/app/src/main/res/values-zh-rTW/strings.xml @@ -503,12 +503,6 @@ 魔法掛載支援 OverlayFS 自動核心統計支援 SUS 核心統計支援 - - 新增項目 - 執行卸載操作 - 删除項目 - 重設此區段 - 重新整理功能狀態 SuSFS 配置 可配置的 SuSFS 功能