CVE-2023-5521 (published 2023-10-11T12:15Z)

Incorrect Authorization in GitHub repository tiann/kernelsu prior to v0.6.9.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-863
cwe_name: Incorrect Authorization
description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are incorrectly applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         

Fix information:
repo_url: https://github.com/tiann/kernelsu
commit_details: repo_url: https://github.com/tiann/kernelsu
author: weishu
author_date: 2023-10-11 15:53:11+08:00
msg: kernel: harden the signature check (#1027)
repository: repo_url: https://github.com/tiann/kernelsu
repo_name: tiann/KernelSU
description: A Kernel based root solution for Android
repo_language: Kotlin
owner: tiann
file_changes: filename: Makefile
change_type: ModificationType.MODIFY
diff: @@ -29,13 +29,13 @@ KSU_EXPECTED_SIZE := 0x033b
 endif
 
 ifndef KSU_EXPECTED_HASH
-KSU_EXPECTED_HASH := 0xb0b91415
+KSU_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6
 endif
 
 $(info -- KernelSU Manager signature size: $(KSU_EXPECTED_SIZE))
 $(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
 
 ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
-ccflags-y += -DEXPECTED_HASH=$(KSU_EXPECTED_HASH)
+ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\"
 ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
 ccflags-y += -Wno-declaration-after-statement

programming_language: Shell
filename: apk_sign.c
change_type: ModificationType.MODIFY
diff: @@ -1,20 +1,136 @@
+#include "linux/err.h"
 #include "linux/fs.h"
+#include "linux/gfp.h"
+#include "linux/kernel.h"
 #include "linux/moduleparam.h"
 
 #include "apk_sign.h"
 #include "klog.h" // IWYU pragma: keep
 #include "kernel_compat.h"
+#include "crypto/hash.h"
+#include "linux/slab.h"
+#include "linux/version.h"
 
-static __always_inline int
-check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
+#include "crypto/sha2.h"
+#else
+#include "crypto/sha.h"
+#endif
+
+struct sdesc {
+	struct shash_desc shash;
+	char ctx[];
+};
+
+static struct sdesc *init_sdesc(struct crypto_shash *alg)
+{
+	struct sdesc *sdesc;
+	int size;
+
+	size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
+	sdesc = kmalloc(size, GFP_KERNEL);
+	if (!sdesc)
+		return ERR_PTR(-ENOMEM);
+	sdesc->shash.tfm = alg;
+	return sdesc;
+}
+
+static int calc_hash(struct crypto_shash *alg, const unsigned char *data,
+		     unsigned int datalen, unsigned char *digest)
+{
+	struct sdesc *sdesc;
+	int ret;
+
+	sdesc = init_sdesc(alg);
+	if (IS_ERR(sdesc)) {
+		pr_info("can't alloc sdesc\n");
+		return PTR_ERR(sdesc);
+	}
+
+	ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
+	kfree(sdesc);
+	return ret;
+}
+
+static int ksu_sha256(const unsigned char *data, unsigned int datalen,
+		unsigned char *digest)
+{
+	struct crypto_shash *alg;
+	char *hash_alg_name = "sha256";
+	int ret;
+
+	alg = crypto_alloc_shash(hash_alg_name, 0, 0);
+	if (IS_ERR(alg)) {
+		pr_info("can't alloc alg %s\n", hash_alg_name);
+		return PTR_ERR(alg);
+	}
+	ret = calc_hash(alg, data, datalen, digest);
+	crypto_free_shash(alg);
+	return ret;
+}
+
+static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset,
+			unsigned expected_size, const char* expected_sha256)
+{
+	ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length
+	ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length
+	ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length
+
+	*offset += 0x4 * 3;
+
+	ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length
+
+	*pos += *size4;
+	*offset += 0x4 + *size4;
+
+	ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length
+	ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length
+	*offset += 0x4 * 2;
+
+	if (*size4 == expected_size) {
+		*offset += *size4;
+
+		#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 (IS_ERR(ksu_sha256(cert, *size4, digest))) {
+			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\n", hash_str, expected_sha256);
+		if (strcmp(expected_sha256, hash_str) == 0) {
+			return true;
+		}
+	}
+	return false;
+}
+
+static __always_inline bool
+check_v2_signature(char *path, unsigned expected_size, const char *expected_sha256)
 {
 	unsigned char buffer[0x11] = { 0 };
 	u32 size4;
 	u64 size8, size_of_block;
 
 	loff_t pos;
+	bool block_valid;
+
+	const int NOT_EXIST = 0;
+	const int INVALID = 1;
+	const int VALID = 2;
+	int v2_signing_status = NOT_EXIST;
+	int v3_signing_status = NOT_EXIST;
 
-	int sign = -1;
 	int i;
 	struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
 	if (IS_ERR(fp)) {
@@ -25,7 +141,6 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
 	// disable inotify for this file
 	fp->f_mode |= FMODE_NONOTIFY;
 
-	sign = 1;
 	// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
 	for (i = 0;; ++i) {
 		unsigned short n;
@@ -64,59 +179,22 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
 	for (;;) {
 		uint32_t id;
 		uint32_t offset;
-		ksu_kernel_read_compat(fp, &size8, 0x8, &pos); // sequence length
+		ksu_kernel_read_compat(fp, &size8, 0x8,
+				       &pos); // sequence length
 		if (size8 == size_of_block) {
 			break;
 		}
 		ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id
 		offset = 4;
 		pr_info("id: 0x%08x\n", id);
-		if ((id ^ 0xdeadbeefu) == 0xafa439f5u ||
-		    (id ^ 0xdeadbeefu) == 0x2efed62f) {
-			ksu_kernel_read_compat(fp, &size4, 0x4,
-				    &pos); // signer-sequence length
-			ksu_kernel_read_compat(fp, &size4, 0x4, &pos); // signer length
-			ksu_kernel_read_compat(fp, &size4, 0x4,
-				    &pos); // signed data length
-			offset += 0x4 * 3;
-
-			ksu_kernel_read_compat(fp, &size4, 0x4,
-				    &pos); // digests-sequence length
-			pos += size4;
-			offset += 0x4 + size4;
-
-			ksu_kernel_read_compat(fp, &size4, 0x4,
-				    &pos); // certificates length
-			ksu_kernel_read_compat(fp, &size4, 0x4,
-				    &pos); // certificate length
-			offset += 0x4 * 2;
-#if 0
-			int hash = 1;
-			signed char c;
-			for (i = 0; i < size4; ++i) {
-				ksu_kernel_read_compat(fp, &c, 0x1, &pos);
-				hash = 31 * hash + c;
-			}
-			offset += size4;
-			pr_info("    size: 0x%04x, hash: 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
-#else
-			if (size4 == expected_size) {
-				int hash = 1;
-				signed char c;
-				for (i = 0; i < size4; ++i) {
-					ksu_kernel_read_compat(fp, &c, 0x1, &pos);
-					hash = 31 * hash + c;
-				}
-				offset += size4;
-				if ((((unsigned)hash) ^ 0x14131211u) ==
-				    expected_hash) {
-					sign = 0;
-					break;
-				}
-			}
-			// don't try again.
-			break;
-#endif
+		if (id == 0x7109871au) {
+			block_valid = check_block(fp, &size4, &pos, &offset,
+						  expected_size, expected_sha256);
+			v2_signing_status = block_valid ? VALID : INVALID;
+		} else if (id == 0xf05368c0u) {
+			block_valid = check_block(fp, &size4, &pos, &offset,
+						  expected_size, expected_sha256);
+			v3_signing_status = block_valid ? VALID : INVALID;
 		}
 		pos += (size8 - offset);
 	}
@@ -124,13 +202,15 @@ check_v2_signature(char *path, unsigned expected_size, unsigned expected_hash)
 clean:
 	filp_close(fp, 0);
 
-	return sign;
+	return (v2_signing_status == NOT_EXIST && v3_signing_status == VALID) ||
+	       (v2_signing_status == VALID && v3_signing_status == NOT_EXIST) ||
+	       (v2_signing_status == VALID && v3_signing_status == VALID);
 }
 
 #ifdef CONFIG_KSU_DEBUG
 
 unsigned ksu_expected_size = EXPECTED_SIZE;
-unsigned ksu_expected_hash = EXPECTED_HASH;
+const char *ksu_expected_hash = EXPECTED_HASH;
 
 #include "manager.h"
 
@@ -144,9 +224,10 @@ static int set_expected_size(const char *val, const struct kernel_param *kp)
 
 static int set_expected_hash(const char *val, const struct kernel_param *kp)
 {
-	int rv = param_set_uint(val, kp);
+	pr_info("set_expected_hash: %s\n", val);
+	int rv = param_set_charp(val, kp);
 	ksu_invalidate_manager_uid();
-	pr_info("ksu_expected_hash set to %x\n", ksu_expected_hash);
+	pr_info("ksu_expected_hash set to %s\n", ksu_expected_hash);
 	return rv;
 }
 
@@ -157,7 +238,8 @@ static struct kernel_param_ops expected_size_ops = {
 
 static struct kernel_param_ops expected_hash_ops = {
 	.set = set_expected_hash,
-	.get = param_get_uint,
+	.get = param_get_charp,
+	.free = param_free_charp,
 };
 
 module_param_cb(ksu_expected_size, &expected_size_ops, &ksu_expected_size,
@@ -165,14 +247,14 @@ module_param_cb(ksu_expected_size, &expected_size_ops, &ksu_expected_size,
 module_param_cb(ksu_expected_hash, &expected_hash_ops, &ksu_expected_hash,
 		S_IRUSR | S_IWUSR);
 
-int is_manager_apk(char *path)
+bool is_manager_apk(char *path)
 {
 	return check_v2_signature(path, ksu_expected_size, ksu_expected_hash);
 }
 
 #else
 
-int is_manager_apk(char *path)
+bool is_manager_apk(char *path)
 {
 	return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
 }

programming_language: C
filename: apk_sign.h
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,8 @@
 #ifndef __KSU_H_APK_V2_SIGN
 #define __KSU_H_APK_V2_SIGN
 
-// return 0 if signature match
-int is_manager_apk(char *path);
+#include "linux/types.h"
+
+bool is_manager_apk(char *path);
 
 #endif

programming_language: C
filename: manager.c
change_type: ModificationType.MODIFY
diff: @@ -70,7 +70,7 @@ bool become_manager(char *pkg)
 			pr_info("invalid pkg: %s\n", pkg);
 			continue;
 		}
-		if (is_manager_apk(cwd) == 0) {
+		if (is_manager_apk(cwd)) {
 			// check passed
 			uid_t uid = current_uid().val;
 			pr_info("manager uid: %d\n", uid);

programming_language: C
filename: check_v2.c
change_type: ModificationType.DELETE
diff: @@ -1,174 +0,0 @@
-//
-// Created by Thom on 2019/3/8.
-//
-
-// Credits: https://github.com/brevent/genuine/blob/master/src/main/jni/apk-sign-v2.c
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#define MAIN
-
-#ifdef MAIN
-#include <stdio.h>
-#else
-
-#include "common.h"
-#include "openat.h"
-
-#endif
-
-static bool isApkSigBlock42(const char *buffer) {
-    // APK Sig Block 42
-    return *buffer == 'A'
-           && *++buffer == 'P'
-           && *++buffer == 'K'
-           && *++buffer == ' '
-           && *++buffer == 'S'
-           && *++buffer == 'i'
-           && *++buffer == 'g'
-           && *++buffer == ' '
-           && *++buffer == 'B'
-           && *++buffer == 'l'
-           && *++buffer == 'o'
-           && *++buffer == 'c'
-           && *++buffer == 'k'
-           && *++buffer == ' '
-           && *++buffer == '4'
-           && *++buffer == '2';
-}
-
-int checkSignature(const char *path) {
-    unsigned char buffer[0x11] = {0};
-    uint32_t size4;
-    uint64_t size8, size_of_block;
-
-#ifdef DEBUG
-    LOGI("check signature for %s", path);
-#endif
-
-    int sign = -1;
-    int fd = (int) openat(AT_FDCWD, path, O_RDONLY);
-#ifdef DEBUG_OPENAT
-    LOGI("openat %s returns %d", path, fd);
-#endif
-    if (fd < 0) {
-        return sign;
-    }
-
-    sign = 1;
-    // https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
-    for (int i = 0;; ++i) {
-        unsigned short n;
-        lseek(fd, -i - 2, SEEK_END);
-        read(fd, &n, 2);
-        if (n == i) {
-            lseek(fd, -22, SEEK_CUR);
-            read(fd, &size4, 4);
-            if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
-#ifdef MAIN
-                if (i > 0) {
-                    printf("warning: comment length is %d\n", i);
-                }
-#endif
-                break;
-            }
-        }
-        if (i == 0xffff) {
-#ifdef MAIN
-            printf("error: cannot find eocd\n");
-#endif
-            goto clean;
-        }
-    }
-
-    lseek(fd, 12, SEEK_CUR);
-    // offset
-    read(fd, &size4, 0x4);
-    lseek(fd, (off_t) (size4 - 0x18), SEEK_SET);
-
-    read(fd, &size8, 0x8);
-    read(fd, buffer, 0x10);
-    if (!isApkSigBlock42((char *) buffer)) {
-        goto clean;
-    }
-
-    lseek(fd, (off_t) (size4 - (size8 + 0x8)), SEEK_SET);
-    read(fd, &size_of_block, 0x8);
-    if (size_of_block != size8) {
-        goto clean;
-    }
-
-    for (;;) {
-        uint32_t id;
-        uint32_t offset;
-        read(fd, &size8, 0x8); // sequence length
-        if (size8 == size_of_block) {
-            break;
-        }
-        read(fd, &id, 0x4); // id
-        offset = 4;
-#ifdef MAIN
-        // printf("id: 0x%08x\n", id);
-#endif
-        if ((id ^ 0xdeadbeefu) == 0xafa439f5u || (id ^ 0xdeadbeefu) == 0x2efed62f) {
-            read(fd, &size4, 0x4); // signer-sequence length
-            read(fd, &size4, 0x4); // signer length
-            read(fd, &size4, 0x4); // signed data length
-            offset += 0x4 * 3;
-
-            read(fd, &size4, 0x4); // digests-sequence length
-            lseek(fd, (off_t) (size4), SEEK_CUR);// skip digests
-            offset += 0x4 + size4;
-
-            read(fd, &size4, 0x4); // certificates length
-            read(fd, &size4, 0x4); // certificate length
-            offset += 0x4 * 2;
-#ifdef MAIN
-            int hash = 1;
-            signed char c;
-            for (unsigned i = 0; i < size4; ++i) {
-                read(fd, &c, 0x1);
-                hash = 31 * hash + c;
-            }
-            offset += size4;
-            // printf("    size: 0x%04x, hash: 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
-            printf("0x%04x 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
-#else
-#if defined(GENUINE_SIZE) && defined(GENUINE_HASH)
-            if (size4 == GENUINE_SIZE) {
-                int hash = 1;
-                signed char c;
-                for (unsigned i = 0; i < size4; ++i) {
-                    read(fd, &c, 0x1);
-                    hash = 31 * hash + c;
-                }
-                offset += size4;
-                if ((((unsigned) hash) ^ 0x14131211u) == GENUINE_HASH) {
-                    sign = 0;
-                    break;
-                }
-            }
-#else
-            sign = 0;
-            break;
-#endif
-#endif
-        }
-        lseek(fd, (off_t) (size8 - offset), SEEK_CUR);
-    }
-
-clean:
-    close(fd);
-
-    return sign;
-}
-
-#ifdef MAIN
-int main(int argc, char **argv) {
-    if (argc > 1) {
-        checkSignature(argv[1]);
-    }
-}
-#endif

programming_language: unknown
filename: Cargo.lock
change_type: ModificationType.MODIFY
diff: @@ -2,6 +2,15 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "addr2line"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
+dependencies = [
+ "gimli",
+]
+
 [[package]]
 name = "adler"
 version = "1.0.2"
@@ -74,12 +83,38 @@ version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
 
+[[package]]
+name = "async-trait"
+version = "0.1.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.38",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
+[[package]]
+name = "backtrace"
+version = "0.3.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
 [[package]]
 name = "base64ct"
 version = "1.6.0"
@@ -132,6 +167,12 @@ version = "1.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
+[[package]]
+name = "bytes"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+
 [[package]]
 name = "bzip2"
 version = "0.4.4"
@@ -234,7 +275,7 @@ dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -407,7 +448,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "scratch",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -424,7 +465,7 @@ checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -435,7 +476,7 @@ checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -604,6 +645,12 @@ dependencies = [
  "wasi 0.11.0+wasi-snapshot-preview1",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.27.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
+
 [[package]]
 name = "glob"
 version = "0.3.1"
@@ -700,7 +747,7 @@ dependencies = [
  "proc-macro-hack",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -816,6 +863,7 @@ dependencies = [
  "rust-embed",
  "serde",
  "serde_json",
+ "sha256",
  "sys-mount",
  "which",
  "zip 0.6.4",
@@ -979,6 +1027,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "object"
+version = "0.30.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.17.0"
@@ -1053,7 +1110,7 @@ dependencies = [
  "proc-macro-error-attr",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "version_check",
 ]
 
@@ -1076,9 +1133,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.50"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
 dependencies = [
  "unicode-ident",
 ]
@@ -1100,9 +1157,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.23"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -1212,7 +1269,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "rust-embed-utils",
- "syn",
+ "syn 1.0.107",
  "walkdir",
 ]
 
@@ -1226,6 +1283,12 @@ dependencies = [
  "walkdir",
 ]
 
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
 [[package]]
 name = "rustc-hash"
 version = "1.1.0"
@@ -1312,6 +1375,19 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "sha256"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "hex",
+ "sha2",
+ "tokio",
+]
+
 [[package]]
 name = "shlex"
 version = "1.1.0"
@@ -1326,7 +1402,7 @@ checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1352,6 +1428,17 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "syn"
+version = "2.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "sys-mount"
 version = "2.0.2"
@@ -1391,7 +1478,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1421,6 +1508,18 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
 
+[[package]]
+name = "tokio"
+version = "1.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
+dependencies = [
+ "autocfg",
+ "backtrace",
+ "bytes",
+ "pin-project-lite",
+]
+
 [[package]]
 name = "tracing"
 version = "0.1.37"
@@ -1441,7 +1540,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
 ]
 
 [[package]]
@@ -1527,7 +1626,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "wasm-bindgen-shared",
 ]
 
@@ -1549,7 +1648,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.107",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]

programming_language: PowerShell
filename: Cargo.toml
change_type: ModificationType.MODIFY
diff: @@ -33,6 +33,7 @@ rust-embed = { version = "6.4.2", features = [
 ] }
 which = "4.2.2"
 getopts = "0.2.21"
+sha256 = "1.4.0"
 
 [target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies]
 sys-mount = { git = "https://github.com/tiann/sys-mount", branch = "loopfix" }

programming_language: Lua
filename: apk_sign.rs
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 use anyhow::{ensure, Result};
 use std::io::{Read, Seek, SeekFrom};
 
-pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
+pub fn get_apk_signature(apk: &str) -> Result<(u32, String)> {
     let mut buffer = [0u8; 0x10];
     let mut size4 = [0u8; 4];
     let mut size8 = [0u8; 8];
@@ -49,9 +49,11 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
 
     ensure!(size_of_block == size8, "not a signed apk");
 
+    let mut v2_signing: Option<(u32, String)> = None;
+    let mut v3_signing: Option<(u32, String)> = None;
     loop {
         let mut id = [0u8; 4];
-        let offset = 4u32;
+        let mut offset = 4u32;
 
         f.read_exact(&mut size8)?; // sequence length
         if size8 == size_of_block {
@@ -61,36 +63,10 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
         f.read_exact(&mut id)?; // id
 
         let id = u32::from_le_bytes(id);
-        if (id ^ 0xdead_beef_u32) == 0xafa4_39f5_u32 || (id ^ 0xdead_beef_u32) == 0x2efe_d62f_u32 {
-            f.read_exact(&mut size4)?; // signer-sequence length
-            f.read_exact(&mut size4)?; // signer length
-            f.read_exact(&mut size4)?; // signed data length
-                                       // offset += 0x4 * 3;
-
-            f.read_exact(&mut size4)?; // digests-sequcence length
-            let pos = u32::from_le_bytes(size4);
-            f.seek(SeekFrom::Current(i64::from(pos)))?;
-            // offset += 0x4 + pos;
-
-            f.read_exact(&mut size4)?; // certificates length
-            f.read_exact(&mut size4)?; // certificate length
-                                       // offset += 0x4 * 2;
-
-            let mut hash = 1i32;
-            let mut c = [0u8; 1];
-
-            let j = u32::from_le_bytes(size4);
-            for _ in 0..j {
-                f.read_exact(&mut c)?;
-                hash = hash.wrapping_mul(31).wrapping_add(i32::from(c[0] as i8));
-            }
-
-            // offset += j;
-
-            let out_size = j;
-            let out_hash = (hash as u32) ^ 0x1413_1211_u32;
-
-            return Ok((out_size, out_hash));
+        if id == 0x7109_871a_u32 {
+            v2_signing = Some(calc_cert_sha256(&mut f, &mut size4, &mut offset)?);
+        } else if id == 0xf053_68c0_u32 {
+            v3_signing = Some(calc_cert_sha256(&mut f, &mut size4, &mut offset)?);
         }
 
         f.seek(SeekFrom::Current(
@@ -98,5 +74,47 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, u32)> {
         ))?;
     }
 
-    Err(anyhow::anyhow!("Unknown error"))
+    match (v2_signing, v3_signing) {
+        (None, Some(s)) => Ok(s),
+        (Some(s), None) => Ok(s),
+        (Some(s1), Some(s2)) => {
+            if s1 == s2 {
+                Ok(s1)
+            } else {
+                Err(anyhow::anyhow!(
+                    "Inconsisent signature, v2: {}, v3: {}!",
+                    s1.1,
+                    s2.1
+                ))
+            }
+        }
+        _ => Err(anyhow::anyhow!("Unknown signature!")),
+    }
+}
+
+fn calc_cert_sha256(
+    f: &mut std::fs::File,
+    size4: &mut [u8; 4],
+    offset: &mut u32,
+) -> Result<(u32, String)> {
+    f.read_exact(size4)?; // signer-sequence length
+    f.read_exact(size4)?; // signer length
+    f.read_exact(size4)?; // signed data length
+    *offset += 0x4 * 3;
+
+    f.read_exact(size4)?; // digests-sequence length
+    let pos = u32::from_le_bytes(*size4); // skip digests
+    f.seek(SeekFrom::Current(i64::from(pos)))?;
+    *offset += 0x4 + pos;
+
+    f.read_exact(size4)?; // certificates length
+    f.read_exact(size4)?; // certificate length
+    *offset += 0x4 * 2;
+
+    let cert_len = u32::from_le_bytes(*size4);
+    let mut cert: Vec<u8> = vec![0; cert_len as usize];
+    f.read_exact(&mut cert)?;
+    *offset += cert_len;
+
+    Ok((cert_len, sha256::digest(&cert)))
 }

programming_language: Rust
filename: cli.rs
change_type: ModificationType.MODIFY
diff: @@ -228,7 +228,7 @@ pub fn run() -> Result<()> {
             Debug::SetManager { apk } => debug::set_manager(&apk),
             Debug::GetSign { apk } => {
                 let sign = apk_sign::get_apk_signature(&apk)?;
-                println!("size: {:#x}, hash: {:#x}", sign.0, sign.1);
+                println!("size: {:#x}, hash: {}", sign.0, sign.1);
                 Ok(())
             }
             Debug::Version => {

programming_language: Rust
filename: debug.rs
change_type: ModificationType.MODIFY
diff: @@ -15,24 +15,25 @@ fn read_u32(path: &PathBuf) -> Result<u32> {
     Ok(content)
 }
 
-fn set_kernel_param(size: u32, hash: u32) -> Result<()> {
+fn set_kernel_param(size: u32, hash: String) -> Result<()> {
     let kernel_param_path = Path::new(KERNEL_PARAM_PATH).join("parameters");
+
     let expeced_size_path = kernel_param_path.join("ksu_expected_size");
     let expeced_hash_path = kernel_param_path.join("ksu_expected_hash");
 
     println!(
-        "before size: {:#x} hash: {:#x}",
+        "before size: {:#x} hash: {}",
         read_u32(&expeced_size_path)?,
-        read_u32(&expeced_hash_path)?
+        std::fs::read_to_string(&expeced_hash_path)?
     );
 
     std::fs::write(&expeced_size_path, size.to_string())?;
-    std::fs::write(&expeced_hash_path, hash.to_string())?;
+    std::fs::write(&expeced_hash_path, hash)?;
 
     println!(
-        "after size: {:#x} hash: {:#x}",
+        "after size: {:#x} hash: {}",
         read_u32(&expeced_size_path)?,
-        read_u32(&expeced_hash_path)?
+        std::fs::read_to_string(&expeced_hash_path)?
     );
 
     Ok(())

programming_language: Rust