kernel: Reworking Dynamic Manager Index Configuration

This commit is contained in:
ShirkNeko
2025-09-06 15:06:10 +08:00
parent c520e57f9b
commit fc5cd9e9ed
5 changed files with 79 additions and 17 deletions

View File

@@ -30,7 +30,6 @@ static struct apk_sign_key {
const char *sha256; const char *sha256;
} apk_sign_keys[] = { } apk_sign_keys[] = {
{EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // SukiSU {EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // SukiSU
{EXPECTED_SIZE_OTHER, EXPECTED_HASH_OTHER}, // Dynamic Sign
#ifdef CONFIG_KSU_MULTI_MANAGER_SUPPORT #ifdef CONFIG_KSU_MULTI_MANAGER_SUPPORT
{EXPECTED_SIZE_WEISHU, EXPECTED_HASH_WEISHU}, // Official {EXPECTED_SIZE_WEISHU, EXPECTED_HASH_WEISHU}, // Official
{EXPECTED_SIZE_5EC1CFF, EXPECTED_HASH_5EC1CFF}, // 5ec1cff/KernelSU {EXPECTED_SIZE_5EC1CFF, EXPECTED_HASH_5EC1CFF}, // 5ec1cff/KernelSU
@@ -88,6 +87,54 @@ static int ksu_sha256(const unsigned char *data, unsigned int datalen,
crypto_free_shash(alg); crypto_free_shash(alg);
return ret; return ret;
} }
static struct dynamic_sign_key dynamic_sign = DYNAMIC_SIGN_DEFAULT_CONFIG;
static bool check_dynamic_sign(struct file *fp, u32 size4, loff_t *pos, int *matched_index)
{
struct dynamic_sign_key current_dynamic_key = dynamic_sign;
if (ksu_get_dynamic_manager_config(&current_dynamic_key.size, &current_dynamic_key.hash)) {
pr_debug("Using dynamic manager config: size=0x%x, hash=%.16s...\n",
current_dynamic_key.size, current_dynamic_key.hash);
}
if (size4 != current_dynamic_key.size) {
return false;
}
#define CERT_MAX_LENGTH 1024
char cert[CERT_MAX_LENGTH];
if (size4 > CERT_MAX_LENGTH) {
pr_info("cert length overlimit\n");
return false;
}
ksu_kernel_read_compat(fp, cert, size4, pos);
unsigned char digest[SHA256_DIGEST_SIZE];
if (ksu_sha256(cert, size4, digest) < 0) {
pr_info("sha256 error\n");
return false;
}
char hash_str[SHA256_DIGEST_SIZE * 2 + 1];
hash_str[SHA256_DIGEST_SIZE * 2] = '\0';
bin2hex(hash_str, digest, SHA256_DIGEST_SIZE);
pr_info("sha256: %s, expected: %s, index: dynamic\n", hash_str, current_dynamic_key.hash);
if (strcmp(current_dynamic_key.hash, hash_str) == 0) {
if (matched_index) {
*matched_index = DYNAMIC_SIGN_INDEX;
}
return true;
}
return false;
}
static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, int *matched_index) static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, int *matched_index)
{ {
int i; int i;
@@ -109,18 +156,18 @@ static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, i
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length
*offset += 0x4 * 2; *offset += 0x4 * 2;
if (ksu_is_dynamic_manager_enabled()) {
loff_t temp_pos = *pos;
if (check_dynamic_sign(fp, *size4, &temp_pos, matched_index)) {
*pos = temp_pos;
*offset += *size4;
return true;
}
}
for (i = 0; i < ARRAY_SIZE(apk_sign_keys); i++) { for (i = 0; i < ARRAY_SIZE(apk_sign_keys); i++) {
sign_key = apk_sign_keys[i]; sign_key = apk_sign_keys[i];
if (i == 1) { // Dynamic Sign indexing
unsigned int size;
const char *hash;
if (ksu_get_dynamic_manager_config(&size, &hash)) {
sign_key.size = size;
sign_key.sha256 = hash;
}
}
if (*size4 != sign_key.size) if (*size4 != sign_key.size)
continue; continue;
*offset += *size4; *offset += *size4;
@@ -335,8 +382,8 @@ clean:
} }
if (check_multi_manager) { if (check_multi_manager) {
// 0: ShirkNeko/SukiSU, 1: Dynamic Sign // 0: ShirkNeko/SukiSU, DYNAMIC_SIGN_INDEX : Dynamic Sign
if (matched_index == 0 || matched_index == 1) { if (matched_index == 0 || matched_index == DYNAMIC_SIGN_INDEX) {
pr_info("Multi-manager APK detected (dynamic_manager enabled): signature_index=%d\n", matched_index); pr_info("Multi-manager APK detected (dynamic_manager enabled): signature_index=%d\n", matched_index);
return true; return true;
} }

View File

@@ -142,7 +142,7 @@ int ksu_get_manager_signature_index(uid_t uid)
// Check traditional manager first // Check traditional manager first
if (ksu_manager_uid != KSU_INVALID_UID && uid == ksu_manager_uid) { if (ksu_manager_uid != KSU_INVALID_UID && uid == ksu_manager_uid) {
return 1; return DYNAMIC_SIGN_INDEX;
} }
if (!ksu_is_dynamic_manager_enabled()) { if (!ksu_is_dynamic_manager_enabled()) {

View File

@@ -7,6 +7,17 @@
#define DYNAMIC_MANAGER_FILE_MAGIC 0x7f445347 // 'DSG', u32 #define DYNAMIC_MANAGER_FILE_MAGIC 0x7f445347 // 'DSG', u32
#define DYNAMIC_MANAGER_FILE_VERSION 1 // u32 #define DYNAMIC_MANAGER_FILE_VERSION 1 // u32
#define KERNEL_SU_DYNAMIC_MANAGER "/data/adb/ksu/.dynamic_manager" #define KERNEL_SU_DYNAMIC_MANAGER "/data/adb/ksu/.dynamic_manager"
#define DYNAMIC_SIGN_INDEX 100
struct dynamic_sign_key {
unsigned int size;
const char *hash;
};
#define DYNAMIC_SIGN_DEFAULT_CONFIG { \
.size = 0x300, \
.hash = "0000000000000000000000000000000000000000000000000000000000000000" \
}
struct dynamic_manager_config { struct dynamic_manager_config {
unsigned int size; unsigned int size;

View File

@@ -20,7 +20,8 @@ static inline bool ksu_is_manager_uid_valid(void)
static inline bool is_manager(void) static inline bool is_manager(void)
{ {
return unlikely(ksu_is_any_manager(current_uid().val) || ksu_manager_uid == current_uid().val); return unlikely(ksu_is_any_manager(current_uid().val) ||
(ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val));
} }
static inline uid_t ksu_get_manager_uid(void) static inline uid_t ksu_get_manager_uid(void)

View File

@@ -88,7 +88,8 @@ static void crown_manager(const char *apk, struct list_head *uid_data, int signa
if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) { if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) {
pr_info("Crowning manager: %s(uid=%d, signature_index=%d)\n", pkg, np->uid, signature_index); pr_info("Crowning manager: %s(uid=%d, signature_index=%d)\n", pkg, np->uid, signature_index);
if (signature_index == 1 || signature_index == 2) { // Dynamic Sign index (1) or multi-manager signatures (2+)
if (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2) {
ksu_add_manager(np->uid, signature_index); ksu_add_manager(np->uid, signature_index);
if (!ksu_is_manager_uid_valid()) { if (!ksu_is_manager_uid_valid()) {
@@ -205,7 +206,8 @@ FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
pr_info("Found new base.apk at path: %s, is_multi_manager: %d, signature_index: %d\n", pr_info("Found new base.apk at path: %s, is_multi_manager: %d, signature_index: %d\n",
dirpath, is_multi_manager, signature_index); dirpath, is_multi_manager, signature_index);
if (is_multi_manager && (signature_index == 1 || signature_index == 2)) { // Check for dynamic sign or multi-manager signatures
if (is_multi_manager && (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2)) {
crown_manager(dirpath, my_ctx->private_data, signature_index); crown_manager(dirpath, my_ctx->private_data, signature_index);
struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC); struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC);
@@ -406,7 +408,8 @@ void track_throne(void)
// Check for dynamic managers // Check for dynamic managers
if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) { if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) {
list_for_each_entry (np, &uid_list, list) { list_for_each_entry (np, &uid_list, list) {
if (ksu_is_any_manager(np->uid)) { // Check if this uid is a dynamic manager (not the traditional manager)
if (ksu_is_any_manager(np->uid) && np->uid != ksu_get_manager_uid()) {
dynamic_manager_exist = true; dynamic_manager_exist = true;
break; break;
} }