manager: Add the ability to get a list of active managers
This commit is contained in:
@@ -139,6 +139,10 @@ int ksu_get_manager_signature_index(uid_t uid)
|
|||||||
int signature_index = -1;
|
int signature_index = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (ksu_manager_uid != KSU_INVALID_UID && uid == ksu_manager_uid) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_dynamic_sign_enabled()) {
|
if (!is_dynamic_sign_enabled()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -156,6 +160,7 @@ int ksu_get_manager_signature_index(uid_t uid)
|
|||||||
return signature_index;
|
return signature_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void clear_all_managers(void)
|
static void clear_all_managers(void)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -442,6 +447,40 @@ void ksu_dynamic_sign_exit(void)
|
|||||||
pr_info("Dynamic sign exited with persistent storage\n");
|
pr_info("Dynamic sign exited with persistent storage\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get active managers for multi-manager APKs
|
||||||
|
int ksu_get_active_managers(struct manager_list_info *info)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int i, count = 0;
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ksu_manager_uid != KSU_INVALID_UID && count < 2) {
|
||||||
|
info->managers[count].uid = ksu_manager_uid;
|
||||||
|
info->managers[count].signature_index = 1;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_dynamic_sign_enabled()) {
|
||||||
|
spin_lock_irqsave(&managers_lock, flags);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_MANAGERS && count < 2; i++) {
|
||||||
|
if (active_managers[i].is_active) {
|
||||||
|
info->managers[count].uid = active_managers[i].uid;
|
||||||
|
info->managers[count].signature_index = active_managers[i].signature_index;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&managers_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->count = count;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct sdesc {
|
struct sdesc {
|
||||||
struct shash_desc shash;
|
struct shash_desc shash;
|
||||||
char ctx[];
|
char ctx[];
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include "ksu.h"
|
#include "ksu.h"
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
bool is_manager_apk(char *path);
|
bool is_manager_apk(char *path);
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ void ksu_add_manager(uid_t uid, int signature_index);
|
|||||||
void ksu_remove_manager(uid_t uid);
|
void ksu_remove_manager(uid_t uid);
|
||||||
bool ksu_is_any_manager(uid_t uid);
|
bool ksu_is_any_manager(uid_t uid);
|
||||||
int ksu_get_manager_signature_index(uid_t uid);
|
int ksu_get_manager_signature_index(uid_t uid);
|
||||||
|
int ksu_get_active_managers(struct manager_list_info *info);
|
||||||
|
|
||||||
int ksu_handle_dynamic_sign(struct dynamic_sign_user_config *config);
|
int ksu_handle_dynamic_sign(struct dynamic_sign_user_config *config);
|
||||||
void ksu_dynamic_sign_init(void);
|
void ksu_dynamic_sign_init(void);
|
||||||
|
|||||||
@@ -364,6 +364,27 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow root manager to get active managers
|
||||||
|
if (arg2 == CMD_GET_MANAGERS) {
|
||||||
|
if (!from_root && !from_manager) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct manager_list_info manager_info;
|
||||||
|
int ret = ksu_get_active_managers(&manager_info);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (copy_to_user((void __user *)arg3, &manager_info, sizeof(manager_info))) {
|
||||||
|
pr_err("copy manager list failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
|
||||||
|
pr_err("get_managers: prctl reply error\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg2 == CMD_REPORT_EVENT) {
|
if (arg2 == CMD_REPORT_EVENT) {
|
||||||
if (!from_root) {
|
if (!from_root) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#define CMD_ENABLE_KPM 100
|
#define CMD_ENABLE_KPM 100
|
||||||
#define CMD_DYNAMIC_SIGN 103
|
#define CMD_DYNAMIC_SIGN 103
|
||||||
|
#define CMD_GET_MANAGERS 104
|
||||||
|
|
||||||
#define EVENT_POST_FS_DATA 1
|
#define EVENT_POST_FS_DATA 1
|
||||||
#define EVENT_BOOT_COMPLETED 2
|
#define EVENT_BOOT_COMPLETED 2
|
||||||
@@ -55,6 +56,14 @@ struct dynamic_sign_user_config {
|
|||||||
char hash[65];
|
char hash[65];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct manager_list_info {
|
||||||
|
int count;
|
||||||
|
struct {
|
||||||
|
uid_t uid;
|
||||||
|
int signature_index;
|
||||||
|
} managers[2];
|
||||||
|
};
|
||||||
|
|
||||||
struct root_profile {
|
struct root_profile {
|
||||||
int32_t uid;
|
int32_t uid;
|
||||||
int32_t gid;
|
int32_t gid;
|
||||||
|
|||||||
@@ -394,4 +394,43 @@ NativeBridgeNP(clearDynamicSign, jboolean) {
|
|||||||
bool result = clear_dynamic_sign();
|
bool result = clear_dynamic_sign();
|
||||||
LogDebug("clearDynamicSign: result=%d", result);
|
LogDebug("clearDynamicSign: result=%d", result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeBridgeNP(getManagersList, jobject) {
|
||||||
|
struct manager_list_info info;
|
||||||
|
bool result = get_managers_list(&info);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
LogDebug("getManagersList: failed to get managers list");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass cls = GetEnvironment()->FindClass(env, "com/sukisu/ultra/Natives$ManagersList");
|
||||||
|
jmethodID constructor = GetEnvironment()->GetMethodID(env, cls, "<init>", "()V");
|
||||||
|
jobject obj = GetEnvironment()->NewObject(env, cls, constructor);
|
||||||
|
|
||||||
|
jfieldID countField = GetEnvironment()->GetFieldID(env, cls, "count", "I");
|
||||||
|
jfieldID managersField = GetEnvironment()->GetFieldID(env, cls, "managers", "Ljava/util/List;");
|
||||||
|
|
||||||
|
GetEnvironment()->SetIntField(env, obj, countField, (jint)info.count);
|
||||||
|
|
||||||
|
jclass arrayListCls = GetEnvironment()->FindClass(env, "java/util/ArrayList");
|
||||||
|
jmethodID arrayListConstructor = GetEnvironment()->GetMethodID(env, arrayListCls, "<init>", "()V");
|
||||||
|
jobject managersList = GetEnvironment()->NewObject(env, arrayListCls, arrayListConstructor);
|
||||||
|
jmethodID addMethod = GetEnvironment()->GetMethodID(env, arrayListCls, "add", "(Ljava/lang/Object;)Z");
|
||||||
|
|
||||||
|
jclass managerInfoCls = GetEnvironment()->FindClass(env, "com/sukisu/ultra/Natives$ManagerInfo");
|
||||||
|
jmethodID managerInfoConstructor = GetEnvironment()->GetMethodID(env, managerInfoCls, "<init>", "(II)V");
|
||||||
|
|
||||||
|
for (int i = 0; i < info.count; i++) {
|
||||||
|
jobject managerInfo = GetEnvironment()->NewObject(env, managerInfoCls, managerInfoConstructor,
|
||||||
|
(jint)info.managers[i].uid,
|
||||||
|
(jint)info.managers[i].signature_index);
|
||||||
|
GetEnvironment()->CallBooleanMethod(env, managersList, addMethod, managerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetEnvironment()->SetObjectField(env, obj, managersField, managersList);
|
||||||
|
|
||||||
|
LogDebug("getManagersList: count=%d", info.count);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#define CMD_HOOK_TYPE 101
|
#define CMD_HOOK_TYPE 101
|
||||||
#define CMD_GET_SUSFS_FEATURE_STATUS 102
|
#define CMD_GET_SUSFS_FEATURE_STATUS 102
|
||||||
#define CMD_DYNAMIC_SIGN 103
|
#define CMD_DYNAMIC_SIGN 103
|
||||||
|
#define CMD_GET_MANAGERS 104
|
||||||
|
|
||||||
#define DYNAMIC_SIGN_OP_SET 0
|
#define DYNAMIC_SIGN_OP_SET 0
|
||||||
#define DYNAMIC_SIGN_OP_GET 1
|
#define DYNAMIC_SIGN_OP_GET 1
|
||||||
@@ -173,4 +174,12 @@ bool clear_dynamic_sign() {
|
|||||||
struct dynamic_sign_user_config config;
|
struct dynamic_sign_user_config config;
|
||||||
config.operation = DYNAMIC_SIGN_OP_CLEAR;
|
config.operation = DYNAMIC_SIGN_OP_CLEAR;
|
||||||
return ksuctl(CMD_DYNAMIC_SIGN, &config, NULL);
|
return ksuctl(CMD_DYNAMIC_SIGN, &config, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_managers_list(struct manager_list_info* info) {
|
||||||
|
if (info == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ksuctl(CMD_GET_MANAGERS, info, NULL);
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "prelude.h"
|
#include "prelude.h"
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
bool become_manager(const char *);
|
bool become_manager(const char *);
|
||||||
|
|
||||||
@@ -105,6 +106,14 @@ struct app_profile {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct manager_list_info {
|
||||||
|
int count;
|
||||||
|
struct {
|
||||||
|
uid_t uid;
|
||||||
|
int signature_index;
|
||||||
|
} managers[2];
|
||||||
|
};
|
||||||
|
|
||||||
bool set_app_profile(const struct app_profile* profile);
|
bool set_app_profile(const struct app_profile* profile);
|
||||||
|
|
||||||
bool get_app_profile(char* key, struct app_profile* profile);
|
bool get_app_profile(char* key, struct app_profile* profile);
|
||||||
@@ -125,4 +134,6 @@ bool get_dynamic_sign(struct dynamic_sign_user_config* config);
|
|||||||
|
|
||||||
bool clear_dynamic_sign();
|
bool clear_dynamic_sign();
|
||||||
|
|
||||||
|
bool get_managers_list(struct manager_list_info* info);
|
||||||
|
|
||||||
#endif //KERNELSU_KSU_H
|
#endif //KERNELSU_KSU_H
|
||||||
@@ -118,6 +118,12 @@ object Natives {
|
|||||||
*/
|
*/
|
||||||
external fun clearDynamicSign(): Boolean
|
external fun clearDynamicSign(): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get active managers list when dynamic sign is enabled
|
||||||
|
* @return ManagersList object containing active managers, or null if failed or not enabled
|
||||||
|
*/
|
||||||
|
external fun getManagersList(): ManagersList?
|
||||||
|
|
||||||
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
|
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
|
||||||
private const val NOBODY_UID = 9999
|
private const val NOBODY_UID = 9999
|
||||||
|
|
||||||
@@ -177,7 +183,6 @@ object Natives {
|
|||||||
val size: Int = 0,
|
val size: Int = 0,
|
||||||
val hash: String = ""
|
val hash: String = ""
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
constructor() : this(0, "")
|
|
||||||
|
|
||||||
fun isValid(): Boolean {
|
fun isValid(): Boolean {
|
||||||
return size > 0 && hash.length == 64 && hash.all {
|
return size > 0 && hash.length == 64 && hash.all {
|
||||||
@@ -186,6 +191,22 @@ object Natives {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@Parcelize
|
||||||
|
@Keep
|
||||||
|
data class ManagersList(
|
||||||
|
val count: Int = 0,
|
||||||
|
val managers: List<ManagerInfo> = emptyList()
|
||||||
|
) : Parcelable
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@Parcelize
|
||||||
|
@Keep
|
||||||
|
data class ManagerInfo(
|
||||||
|
val uid: Int = 0,
|
||||||
|
val signatureIndex: Int = 0
|
||||||
|
) : Parcelable
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Keep
|
@Keep
|
||||||
|
|||||||
@@ -719,6 +719,32 @@ private fun InfoCard(
|
|||||||
icon = Icons.Default.SettingsSuggest,
|
icon = Icons.Default.SettingsSuggest,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 活跃管理器
|
||||||
|
if (systemInfo.isDynamicSignEnabled && systemInfo.managersList != null) {
|
||||||
|
val signatureMap = systemInfo.managersList.managers.groupBy { it.signatureIndex }
|
||||||
|
|
||||||
|
val managersText = buildString {
|
||||||
|
signatureMap.toSortedMap().forEach { (signatureIndex, managers) ->
|
||||||
|
append(managers.joinToString(", ") { "UID:${it.uid}" })
|
||||||
|
append(" ")
|
||||||
|
append(
|
||||||
|
when (signatureIndex) {
|
||||||
|
1 -> "(${stringResource(R.string.default_signature)})"
|
||||||
|
2 -> "(${stringResource(R.string.dynamic_signature)})"
|
||||||
|
else -> if (signatureIndex >= 0) "(${stringResource(R.string.signature_index, signatureIndex)})" else "(${stringResource(R.string.unknown_signature)})"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
append("; ")
|
||||||
|
}
|
||||||
|
}.trimEnd(' ', ';')
|
||||||
|
|
||||||
|
InfoCardItem(
|
||||||
|
stringResource(R.string.multi_manager_list),
|
||||||
|
managersText.ifEmpty { stringResource(R.string.no_active_manager) },
|
||||||
|
icon = Icons.Default.Group,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
InfoCardItem(
|
InfoCardItem(
|
||||||
stringResource(R.string.home_selinux_status),
|
stringResource(R.string.home_selinux_status),
|
||||||
systemInfo.seLinuxStatus,
|
systemInfo.seLinuxStatus,
|
||||||
|
|||||||
@@ -60,7 +60,9 @@ class HomeViewModel : ViewModel() {
|
|||||||
val susSUMode: String = "",
|
val susSUMode: String = "",
|
||||||
val superuserCount: Int = 0,
|
val superuserCount: Int = 0,
|
||||||
val moduleCount: Int = 0,
|
val moduleCount: Int = 0,
|
||||||
val kpmModuleCount: Int = 0
|
val kpmModuleCount: Int = 0,
|
||||||
|
val managersList: Natives.ManagersList? = null,
|
||||||
|
val isDynamicSignEnabled: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
private val gson = Gson()
|
private val gson = Gson()
|
||||||
@@ -242,6 +244,26 @@ class HomeViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取动态签名状态和管理器列表
|
||||||
|
val dynamicSignConfig = try {
|
||||||
|
Natives.getDynamicSign()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Failed to get dynamic sign config", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val isDynamicSignEnabled = dynamicSignConfig?.isValid() == true
|
||||||
|
val managersList = if (isDynamicSignEnabled) {
|
||||||
|
try {
|
||||||
|
Natives.getManagersList()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Failed to get managers list", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
systemInfo = SystemInfo(
|
systemInfo = SystemInfo(
|
||||||
kernelRelease = uname.release,
|
kernelRelease = uname.release,
|
||||||
androidVersion = Build.VERSION.RELEASE,
|
androidVersion = Build.VERSION.RELEASE,
|
||||||
@@ -256,7 +278,9 @@ class HomeViewModel : ViewModel() {
|
|||||||
susSUMode = susSUMode,
|
susSUMode = susSUMode,
|
||||||
superuserCount = getSuperuserCount(),
|
superuserCount = getSuperuserCount(),
|
||||||
moduleCount = getModuleCount(),
|
moduleCount = getModuleCount(),
|
||||||
kpmModuleCount = getKpmModuleCount()
|
kpmModuleCount = getKpmModuleCount(),
|
||||||
|
managersList = managersList,
|
||||||
|
isDynamicSignEnabled = isDynamicSignEnabled
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error fetching system info", e)
|
Log.e(TAG, "Error fetching system info", e)
|
||||||
|
|||||||
@@ -578,4 +578,9 @@
|
|||||||
<string name="invalid_sign_config">无效的签名配置</string>
|
<string name="invalid_sign_config">无效的签名配置</string>
|
||||||
<string name="dynamic_sign_disabled_success">动态签名已禁用</string>
|
<string name="dynamic_sign_disabled_success">动态签名已禁用</string>
|
||||||
<string name="dynamic_sign_clear_failed">清除动态签名错误</string>
|
<string name="dynamic_sign_clear_failed">清除动态签名错误</string>
|
||||||
|
<string name="dynamic_signature">动态</string>
|
||||||
|
<string name="signature_index">签名%1$d</string>
|
||||||
|
<string name="unknown_signature">未知</string>
|
||||||
|
<string name="multi_manager_list">活跃管理器</string>
|
||||||
|
<string name="no_active_manager">无活跃管理器</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -580,4 +580,10 @@
|
|||||||
<string name="invalid_sign_config">Invalid signature configuration</string>
|
<string name="invalid_sign_config">Invalid signature configuration</string>
|
||||||
<string name="dynamic_sign_disabled_success">Dynamic signature disabled</string>
|
<string name="dynamic_sign_disabled_success">Dynamic signature disabled</string>
|
||||||
<string name="dynamic_sign_clear_failed">Failed to clear dynamic signature</string>
|
<string name="dynamic_sign_clear_failed">Failed to clear dynamic signature</string>
|
||||||
|
<string name="dynamic_signature">Dynamic</string>
|
||||||
|
<string name="signature_index">Signature %1$d</string>
|
||||||
|
<string name="unknown_signature">Unknown</string>
|
||||||
|
<string name="multi_manager_list">Active Manager</string>
|
||||||
|
<string name="no_active_manager">No active manager</string>
|
||||||
|
<string name="default_signature">SukiSU</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user