diff --git a/kernel/.gitignore b/kernel/.gitignore index 33132a55..91ab46aa 100644 --- a/kernel/.gitignore +++ b/kernel/.gitignore @@ -19,4 +19,9 @@ # kernel patch module *.kpm -kpimg \ No newline at end of file +kpimg + +*.img +kernel +kernel-b +*.bat \ No newline at end of file diff --git a/kernel/linux/include/linux/fs.h b/kernel/linux/include/linux/fs.h index 896915fb..d566df3d 100644 --- a/kernel/linux/include/linux/fs.h +++ b/kernel/linux/include/linux/fs.h @@ -357,6 +357,24 @@ static inline loff_t vfs_llseek(struct file *file, loff_t offset, int whence) kfunc_direct_call(vfs_llseek, file, offset, whence); } +/* Directory iteration context (kernel 3.11+). + * Actor signature: int return (4.x) or bool return (5.0+) — both are ABI-compatible + * on arm64 for 0/1 values, so we use the 5.0+ bool form to satisfy the compiler. + */ +struct dir_context { + bool (*actor)(struct dir_context *, const char *, int, loff_t, u64, unsigned int); + loff_t pos; +}; + +extern int kfunc_def(iterate_dir)(struct file *, struct dir_context *); + +static inline int iterate_dir(struct file *file, struct dir_context *ctx) +{ + kfunc_call(iterate_dir, file, ctx); + kfunc_not_found(); + return 0; /* symbol not resolved; caller checks result via its context */ +} + static inline void putname(struct filename *name) { kfunc_direct_call_void(putname, name); diff --git a/kernel/patch/android/userd.c b/kernel/patch/android/userd.c index 5a27538a..4133bc2a 100644 --- a/kernel/patch/android/userd.c +++ b/kernel/patch/android/userd.c @@ -29,12 +29,17 @@ #include #include #include -#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include #define REPLACE_RC_FILE "/dev/user_init.rc" @@ -48,7 +53,46 @@ #define APD_PATH "/data/adb/apd" #define MAGISK_POLICY_PATH "/data/adb/ap/bin/magiskpolicy" #define AP_PACKAGE_CONFIG_PATH "/data/adb/ap/package_config" +#define ANDROID_PACKAGES_LIST_PATH "/data/system/packages.list" +#define APK_SIG_BLOCK_MAGIC "APK Sig Block 42" +#define APK_SIG_BLOCK_MAGIC_LEN 16 +#define APK_SIG_SCHEME_V2_BLOCK_ID 0x7109871au +#define APK_SIG_SCHEME_V3_BLOCK_ID 0xf05368c0u +#define APK_SIG_SCHEME_V31_BLOCK_ID 0x1b93ad61u +#define APK_CERT_MAX_LENGTH 4096 + +#define TRUSTED_MANAGER_DIGEST_LEN SHA256_BLOCK_SIZE +#define TRUSTED_MANAGER_UID_INVALID ((uid_t)-1) + +struct trusted_manager_entry { + const char package[64]; + const uint8_t digest[TRUSTED_MANAGER_DIGEST_LEN]; +}; +static const struct trusted_manager_entry trusted_managers[] = { + { + "me.bmax.apatch", + { + 0xd7, 0x1d, 0xad, 0xc0, 0xca, 0x07, 0xbd, 0xf5, + 0x94, 0x38, 0x3b, 0xfb, 0x2a, 0x44, 0x51, 0x34, + 0xa0, 0x73, 0x39, 0xf1, 0x2a, 0x27, 0x04, 0x4a, + 0x1b, 0x32, 0x69, 0x81, 0xac, 0xf5, 0xf3, 0x19 + } + }, + { + "com.example.apatch", + { + 0xe5, 0x11, 0x33, 0x12, 0x5f, 0xef, 0x56, 0xaa, + 0x52, 0x83, 0x91, 0xfc, 0xc2, 0x04, 0x94, 0xeb, + 0xb5, 0x38, 0xbd, 0x8e, 0x09, 0x3d, 0x6c, 0x47, + 0x5d, 0x6d, 0x00, 0x2a, 0x7a, 0x12, 0x1a, 0x8f + } + }, + { "", { 0 } } +}; + +static uid_t trusted_manager_uid = TRUSTED_MANAGER_UID_INVALID; +static int global_pkg_pos = 0; static const char ORIGIN_RC_FILES[][64] = { @@ -93,9 +137,14 @@ static const void *kernel_read_file(const char *path, loff_t *len) } *len = vfs_llseek(filp, 0, SEEK_END); vfs_llseek(filp, 0, SEEK_SET); - data = vmalloc(*len); + data = vmalloc(*len + 1); + if (!data) { + filp_close(filp, 0); + goto out; + } loff_t pos = 0; kernel_read(filp, data, *len, &pos); + ((char *)data)[*len] = '\0'; filp_close(filp, 0); out: @@ -103,30 +152,683 @@ static const void *kernel_read_file(const char *path, loff_t *len) return data; } -static loff_t kernel_write_file(const char *path, const void *data, loff_t len, umode_t mode) +static int path_has_suffix(const char *path, const char *suffix) { - loff_t off = 0; - set_priv_sel_allow(current, true); + size_t path_len; + size_t suffix_len; + if (!path || !suffix) return 0; + path_len = strlen(path); + suffix_len = strlen(suffix); + if (path_len < suffix_len) return 0; + return strcmp(path + path_len - suffix_len, suffix) == 0; +} + +static int path_is_exact(const char *path, const char *target) +{ + return path && target && strcmp(path, target) == 0; +} + +static int read_le32(struct file *fp, loff_t *pos, uint32_t *out) +{ + return kernel_read(fp, out, sizeof(*out), pos) == sizeof(*out) ? 0 : -EIO; +} + +static int read_le64(struct file *fp, loff_t *pos, uint64_t *out) +{ + return kernel_read(fp, out, sizeof(*out), pos) == sizeof(*out) ? 0 : -EIO; +} + +static int skip_bytes(loff_t *pos, uint64_t len) +{ + *pos += (loff_t)len; + return 0; +} + +static int cert_der_matches_trusted_digest(const uint8_t *cert_der, size_t cert_len, const uint8_t *expected_digest) +{ + uint8_t digest[SHA256_BLOCK_SIZE]; + SHA256_CTX ctx; + + sha256_init(&ctx); + sha256_update(&ctx, cert_der, cert_len); + sha256_final(&ctx, digest); + + + + return lib_memcmp(digest, expected_digest, TRUSTED_MANAGER_DIGEST_LEN) == 0 ? 0 : -EPERM; +} + +struct zip_entry_header +{ + uint32_t signature; + uint16_t version; + uint16_t flags; + uint16_t compression; + uint16_t mod_time; + uint16_t mod_date; + uint32_t crc32; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t file_name_length; + uint16_t extra_field_length; +} __attribute__((packed)); + +static int apk_sig_block_matches_trusted_digest(struct file *fp, uint32_t *size4, loff_t *pos, uint32_t *offset, const uint8_t *expected_digest) +{ + uint8_t *cert_buf; + + if (read_le32(fp, pos, size4)) return 0; // signer-sequence length + if (read_le32(fp, pos, size4)) return 0; // signer length + if (read_le32(fp, pos, size4)) return 0; // signed data length + *offset += sizeof(*size4) * 3; + + if (read_le32(fp, pos, size4)) return 0; // digests-sequence length + if (skip_bytes(pos, *size4)) return 0; + *offset += sizeof(*size4) + *size4; + + if (read_le32(fp, pos, size4)) return 0; // certificates length + if (read_le32(fp, pos, size4)) return 0; // certificate length + *offset += sizeof(*size4) * 2; + + if (*size4 == 0 || *size4 > APK_CERT_MAX_LENGTH) { + log_boot("trusted manager apk cert length invalid: %u\n", *size4); + return 0; + } + + *offset += *size4; + cert_buf = vmalloc(*size4); + if (!cert_buf) { + return 0; + } + + if (kernel_read(fp, cert_buf, *size4, pos) != *size4) { + kvfree(cert_buf); + return 0; + } + + if (!cert_der_matches_trusted_digest(cert_buf, *size4, expected_digest)) { + kvfree(cert_buf); + return 2; + } + + kvfree(cert_buf); + return 1; +} + +static int apk_has_v1_signature_file(struct file *fp) +{ + static const char manifest[] = "META-INF/MANIFEST.MF"; + struct zip_entry_header header; + loff_t pos = 0; - struct file *fp = filp_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); + while (kernel_read(fp, &header, sizeof(header), &pos) == sizeof(header)) { + if (header.signature != 0x04034b50u) { + return 0; + } + + if (header.file_name_length == sizeof(manifest) - 1) { + char file_name[sizeof(manifest)]; + if (kernel_read(fp, file_name, header.file_name_length, &pos) != header.file_name_length) { + return 0; + } + file_name[header.file_name_length] = '\0'; + if (strncmp(file_name, manifest, sizeof(manifest) - 1) == 0) { + return 1; + } + } else if (skip_bytes(&pos, header.file_name_length)) { + return 0; + } + + if (skip_bytes(&pos, (uint64_t)header.extra_field_length + header.compressed_size)) { + return 0; + } + } + + return 0; +} + +static int apk_matches_trusted_signature(const char *path, const uint8_t *expected_digest) +{ + int i; + int rc = 0; + int v2_blocks = 0; + int v2_valid = 0; + int v3_present = 0; + int v31_present = 0; + uint8_t magic[APK_SIG_BLOCK_MAGIC_LEN + 1] = { 0 }; + uint32_t size4; + uint64_t size8; + uint64_t size_of_block; + loff_t pos; + struct file *fp; + + if (!path || !path[0]) return 0; + + set_priv_sel_allow(current, true); + fp = filp_open(path, O_RDONLY, 0); if (!fp || IS_ERR(fp)) { - log_boot("create file %s error: %d\n", path, PTR_ERR(fp)); + log_boot("trusted manager apk open failed: %s rc=%ld\n", path, PTR_ERR(fp)); + set_priv_sel_allow(current, false); + return 0; + } + + for (i = 0; i <= 0xffff; i++) { + unsigned short n = 0; + pos = vfs_llseek(fp, -i - 2, SEEK_END); + if (pos < 0) { + continue; + } + if (kernel_read(fp, &n, sizeof(n), &pos) != sizeof(n)) { + continue; + } + if (n == i) { + pos -= 22; + if (!read_le32(fp, &pos, &size4) && size4 == 0x06054b50u) { + break; + } + } + } + + if (i > 0xffff) { goto out; } - kernel_write(fp, data, len, &off); - if (off != len) { - log_boot("write file %s error: %x\n", path, off); - goto free; + + pos += 12; + if (read_le32(fp, &pos, &size4)) { + goto out; } + pos = (loff_t)size4 - 0x18; -free: + if (read_le64(fp, &pos, &size8)) { + goto out; + } + if (kernel_read(fp, magic, APK_SIG_BLOCK_MAGIC_LEN, &pos) != APK_SIG_BLOCK_MAGIC_LEN) { + goto out; + } + if (strncmp((char *)magic, APK_SIG_BLOCK_MAGIC, APK_SIG_BLOCK_MAGIC_LEN) != 0) { + goto out; + } + + pos = (loff_t)size4 - (loff_t)(size8 + 0x8); + if (read_le64(fp, &pos, &size_of_block)) { + goto out; + } + if (size_of_block != size8) { + goto out; + } + + for (i = 0; i < 16; i++) { + uint32_t id; + uint32_t offset = sizeof(id); + if (read_le64(fp, &pos, &size8)) { + goto out; + } + if (size8 == size_of_block) { + break; + } + if (read_le32(fp, &pos, &id)) { + goto out; + } + + if (id == APK_SIG_SCHEME_V2_BLOCK_ID) { + int match; + v2_blocks++; + match = apk_sig_block_matches_trusted_digest(fp, &size4, &pos, &offset, expected_digest); + if (match == 2) { + v2_valid = 1; + } + } else if (id == APK_SIG_SCHEME_V3_BLOCK_ID) { + v3_present = 1; + } else if (id == APK_SIG_SCHEME_V31_BLOCK_ID) { + v31_present = 1; + } + + if (size8 < offset) { + log_boot("trusted manager apk sig block size invalid: %llu offset: %u\n", size8, offset); + goto out; + } + if (skip_bytes(&pos, size8 - offset)) { + log_boot("trusted manager apk sig block skip failed\n"); + goto out; + } + } + + if (!v2_valid) { + log_boot("trusted manager apk sig block invalid: v2_blocks=%d v2_valid=%d v3_present=%d v31_present=%d\n", + v2_blocks, v2_valid, v3_present, v31_present); + goto out; + } + + // if (apk_has_v1_signature_file(fp)) { + // log_boot("trusted manager apk has v1 signature file, which is not allowed\n"); + // goto out; + // } + + rc = 1; + +out: filp_close(fp, 0); + set_priv_sel_allow(current, false); + return rc; +} + +static int lookup_package_list_uid(const char *package_name, uid_t *trusted_uid_out) +{ + loff_t len = 0; + char *content = (char *)kernel_read_file(ANDROID_PACKAGES_LIST_PATH, &len); + char *cursor; + char *end; + + if (!trusted_uid_out) return -EINVAL; + if (!content || len <= 0) { + log_boot("trusted manager: failed to read %s\n", ANDROID_PACKAGES_LIST_PATH); + return -ENOENT; + } + + cursor = content; + end = content + len; + while (cursor < end) { + char *line = cursor; + char *line_end = cursor; + char *pkg; + char *uid_str; + unsigned long long uid_raw = 0; + + while (line_end < end && *line_end != '\n' && *line_end != '\r') { + line_end++; + } + if (line_end < end) { + *line_end = '\0'; + cursor = line_end + 1; + } else { + cursor = end; + } + + while (*line && isspace(*line)) { + line++; + } + if (!*line) { + continue; + } + + pkg = line; + while (*line && !isspace(*line)) { + line++; + } + if (!*line) { + continue; + } + *line++ = '\0'; + + while (*line && isspace(*line)) { + line++; + } + if (!*line) { + continue; + } + + uid_str = line; + while (*line && !isspace(*line)) { + line++; + } + *line = '\0'; + + if (strcmp(pkg, package_name) != 0) { + continue; + } + if (kstrtoull(uid_str, 10, &uid_raw) || uid_raw > UINT_MAX) { + kvfree(content); + return -EINVAL; + } + + *trusted_uid_out = (uid_t)uid_raw; + kvfree(content); + return 0; + } + + kvfree(content); + return -ENOENT; +} + +/* + * Kernel-space APK path discovery using iterate_dir. + * Avoids shell/usermodehelper SELinux restrictions and packages.xml (binary + * protobuf on Android 11+). + * + * Android 11+ layout: /data/app/~~/me.bmax.apatch-/base.apk + * Pre-Android-11: /data/app/me.bmax.apatch-/base.apk + * + * We try both layouts: first a shallow scan of /data/app/ (pre-11), then a + * two-level scan through the tilde-scramble directories (11+). + */ + +/* Inner callback: scan one directory for a subdir starting with + * TRUSTED_MANAGER_PACKAGE_TARGET "-". + */ +struct apk_inner_ctx { + struct dir_context dctx; /* MUST be first member for safe cast */ + const char *outer_dir; /* parent path, e.g. "/data/app/~~abc/" */ + char *result; + size_t result_len; + int found; + const char *package; +}; + +static bool apk_inner_actor(struct dir_context *dctx, + const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct apk_inner_ctx *ctx = + container_of(dctx, struct apk_inner_ctx, dctx); + + const char *pkg; + size_t len, outer_len, path_len; + static const char base_apk[] = "/base.apk"; + + if (!ctx || !ctx->result) + return false; + + if (ctx->found) + return false; + + pkg = ctx->package; + + + if (!pkg || !pkg[0]) + return true; + + len = strnlen(pkg, 128); + + if ((size_t)namelen <= len) + return true; + + if (memcmp(name, pkg, len) != 0) + return true; + + if (name[len] != '-') + return true; + + outer_len = strlen(ctx->outer_dir); + path_len = outer_len + namelen + sizeof(base_apk); + + if (path_len >= ctx->result_len) + return true; + + memcpy(ctx->result, ctx->outer_dir, outer_len); + memcpy(ctx->result + outer_len, name, namelen); + memcpy(ctx->result + outer_len + namelen, + base_apk, sizeof(base_apk)); + + ctx->found = 1; + return false; +} + +/* Outer callback: scan /data/app/ for ~~* scramble directories, then descend */ +struct apk_outer_ctx { + struct dir_context dctx; /* MUST be first member */ + char *result; + size_t result_len; + int found; + char *inner_path; /* heap-allocated: "/data/app/~~/" */ + size_t inner_path_len; + const char *package; +}; + +static bool apk_outer_actor(struct dir_context *dctx, + const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ + struct apk_outer_ctx *ctx = container_of(dctx, struct apk_outer_ctx, dctx); + struct apk_inner_ctx *inner; + struct file *inner_dir; + int len; + + if (!ctx) + return false; + + if (ctx->found) + return false; + + if (namelen < 2 || name[0] != '~' || name[1] != '~') + return true; + + len = snprintf(ctx->inner_path, ctx->inner_path_len, + "/data/app/%.*s/", namelen, name); + + if (len <= 0 || len >= (int)ctx->inner_path_len) + return true; + + inner_dir = filp_open(ctx->inner_path, O_RDONLY, 0); + if (IS_ERR(inner_dir)) + return true; + + inner = vmalloc(sizeof(*inner)); + if (!inner) { + filp_close(inner_dir, 0); + return true; + } + memset(inner, 0, sizeof(*inner)); + + inner->dctx.actor = apk_inner_actor; + inner->dctx.pos = 0; + inner->outer_dir = ctx->inner_path; + inner->result = ctx->result; + inner->result_len = ctx->result_len; + inner->package = ctx->package; + + iterate_dir(inner_dir, &inner->dctx); + filp_close(inner_dir, 0); + + if (inner->found) { + ctx->found = 1; + vfree(inner); + return false; + } + + vfree(inner); + return true; +} + +static int find_trusted_manager_apk_path(char *apk_path, + size_t apk_path_len, + int index) +{ + + log_boot("finding apk path for package: %s\n", trusted_managers[index].package); + struct apk_outer_ctx *outer = NULL; + struct apk_inner_ctx *flat = NULL; + struct file *app_dir; + int rc = -ENOENT; + + char *pkg_buf = NULL; + + if (!apk_path || apk_path_len == 0) + return -EINVAL; + + if (index < 0) + return -EINVAL; + + if (trusted_managers[index].package[0] == '\0') + return -EINVAL; + pkg_buf = vmalloc(64); + if (!pkg_buf) return -ENOMEM; + size_t len = strnlen(trusted_managers[index].package, 63); + memcpy(pkg_buf, trusted_managers[index].package, len); + pkg_buf[len] = '\0'; + apk_path[0] = '\0'; + + flat = vmalloc(sizeof(*flat)); + if (!flat) { rc = -ENOMEM; goto out_free; } + + outer = vmalloc(sizeof(*outer)); + if (!outer) { rc = -ENOMEM; goto out_free; } + + memset(flat, 0, sizeof(*flat)); + memset(outer, 0, sizeof(*outer)); + + outer->inner_path = vmalloc(256); + if (!outer->inner_path) { rc = -ENOMEM; goto out_free; } + outer->inner_path_len = 256; + + set_priv_sel_allow(current, true); + + app_dir = filp_open("/data/app/", O_RDONLY, 0); + if (IS_ERR(app_dir)) { + log_boot("open /data/app failed rc=%ld\n", PTR_ERR(app_dir)); + set_priv_sel_allow(current, false); + rc = -ENOENT; + goto out_free; + } + + /* ===== Pass1 ===== */ + flat->dctx.actor = apk_inner_actor; + flat->dctx.pos = 0; + flat->outer_dir = "/data/app/"; + flat->result = apk_path; + flat->result_len = apk_path_len; + flat->package = pkg_buf; + + iterate_dir(app_dir, &flat->dctx); + + if (flat->found) { + log_boot("apk found (flat): %s\n", apk_path); + rc = 0; + goto out; + } + + /* ===== Pass2 ===== */ + vfs_llseek(app_dir, 0, SEEK_SET); + + outer->dctx.actor = apk_outer_actor; + outer->dctx.pos = 0; + outer->result = apk_path; + outer->result_len = apk_path_len; + outer->package = pkg_buf; + + iterate_dir(app_dir, &outer->dctx); + + if (outer->found) { + log_boot("apk found (scramble): %s\n", apk_path); + rc = 0; + goto out; + } + + log_boot("apk not found: %s\n", pkg_buf); out: + filp_close(app_dir, 0); set_priv_sel_allow(current, false); - return off; +out_free: + if (outer) { + if (outer->inner_path) vfree(outer->inner_path); + vfree(outer); + } + if (flat) vfree(flat); + if (pkg_buf) vfree(pkg_buf); + return rc; } + +static int refresh_trusted_manager_uid_from_packages_list(uid_t *trusted_uid_out) +{ + uid_t last_uid = TRUSTED_MANAGER_UID_INVALID; + int i, any_success = 0; + + char *apk_path; + + if (!trusted_uid_out) + return -EINVAL; + + apk_path = vmalloc(PATH_MAX); + if (!apk_path) { + log_boot("failed to allocate memory for apk_path\n"); + return -ENOMEM; + } + + for (i = 0; trusted_managers[i].package[0] != '\0'; i++) { + int rc; + uid_t uid; + + rc = find_trusted_manager_apk_path( + apk_path, PATH_MAX, + i); + if (rc) { + log_boot("no apk for %s rc=%d\n", + trusted_managers[i].package, rc); + continue; + } + + if (!apk_matches_trusted_signature( + apk_path, trusted_managers[i].digest)) { + log_boot("apk signature invalid: %s\n", apk_path); + continue; + } + + + rc = lookup_package_list_uid( + trusted_managers[i].package, + &uid); + + if (rc == 0) { + last_uid = uid; + any_success = 1; + log_boot("uid ok pkg=%s uid=%u\n", + trusted_managers[i].package, uid); + } else { + log_boot("uid lookup fail pkg=%s rc=%d\n", + trusted_managers[i].package, rc); + } + } + + vfree(apk_path); + + if (!any_success) { + log_boot("no valid trusted manager found\n"); + return -ENOENT; + } + + *trusted_uid_out = last_uid; + return 0; +} + +int refresh_trusted_manager_uid(void) +{ + return refresh_trusted_manager_state(); +} + +int refresh_trusted_manager_state(void) +{ + uid_t uid = TRUSTED_MANAGER_UID_INVALID; + int rc = refresh_trusted_manager_uid_from_packages_list(&uid); + if (rc) { + trusted_manager_uid = TRUSTED_MANAGER_UID_INVALID; + log_boot("trusted manager refresh failed rc=%d\n", rc); + return rc; + } + + trusted_manager_uid = uid; + log_boot("trusted manager refresh success uid=%u\n", uid); + return 0; +} +KP_EXPORT_SYMBOL(refresh_trusted_manager_uid); +KP_EXPORT_SYMBOL(refresh_trusted_manager_state); + +int is_trusted_manager_uid_android(uid_t uid) +{ + uid_t trusted_uid = trusted_manager_uid; + if (trusted_uid == TRUSTED_MANAGER_UID_INVALID) { + return 0; + } + return uid == trusted_uid; +} +KP_EXPORT_SYMBOL(is_trusted_manager_uid_android); + +uid_t get_trusted_manager_uid(void) +{ + return trusted_manager_uid; +} +KP_EXPORT_SYMBOL(get_trusted_manager_uid); + // Simple CSV field parser helper function static char *parse_csv_field(char **line_ptr) { @@ -387,6 +1089,13 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen // unhook flag hook_local->data7 = 0; + // Check if current process is trusted manager, set auto-su flag + if (is_trusted_manager_uid(current_uid())) { + hook_local->data0 = 1; + } else { + hook_local->data0 = 0; + } + static char app_process[] = "/system/bin/app_process"; static char app_process64[] = "/system/bin/app_process64"; static int first_app_process_execed = 0; @@ -462,8 +1171,13 @@ static void after_execve(hook_fargs3_t *args, void *udata); static void before_execveat(hook_fargs5_t *args, void *udata); static void after_execveat(hook_fargs5_t *args, void *udata); -static void handle_after_execve(hook_local_t *hook_local) +static void handle_after_execve(hook_local_t *hook_local, long ret) { + // Auto-su for processes executed by trusted manager + if (hook_local->data0 && ret >= 0) { + commit_su(0, all_allow_sctx); + } + int unhook = hook_local->data7; if (unhook) { unhook_syscalln(__NR_execve, before_execve, after_execve); @@ -484,7 +1198,7 @@ static void before_execve(hook_fargs3_t *args, void *udata) static void after_execve(hook_fargs3_t *args, void *udata) { - handle_after_execve(&args->local); + handle_after_execve(&args->local, args->ret); } // https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2095 @@ -500,7 +1214,7 @@ static void before_execveat(hook_fargs5_t *args, void *udata) static void after_execveat(hook_fargs5_t *args, void *udata) { - handle_after_execve(&args->local); + handle_after_execve(&args->local, args->ret); } // https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L1337 @@ -514,20 +1228,16 @@ static void before_openat(hook_fargs4_t *args, void *udata) args->local.data1 = 0; // unhook flag args->local.data2 = 0; - /* Meaning of args->local.data3 values: - * 0 = no match - * 1 = ORIGIN_RC_FILES[0] - * 2 = ORIGIN_RC_FILES[1] - */ args->local.data3 = 0; static int replaced = 0; - if (replaced) return; const char __user *filename = (typeof(filename))syscall_argn(args, 1); - char buf[64]; + char buf[256]; long rc = compat_strncpy_from_user(buf, filename, sizeof(buf)); if (rc <= 0) return; + if (replaced) return; + int file_count = sizeof(ORIGIN_RC_FILES) / sizeof(ORIGIN_RC_FILES[0]); for (int i = 0; i < file_count; i++) { if (ORIGIN_RC_FILES[i][0] == '\0') break; @@ -595,7 +1305,6 @@ static void before_openat(hook_fargs4_t *args, void *udata) static void after_openat(hook_fargs4_t *args, void *udata) { - if (args->local.data0 && args->local.data3 > 0) { const char *origin_rc = ORIGIN_RC_FILES[args->local.data3 - 1]; @@ -605,8 +1314,6 @@ static void after_openat(hook_fargs4_t *args, void *udata) sizeof(ORIGIN_RC_FILES[args->local.data3 - 1])); log_boot("restore rc file: %x\n", args->local.data0); } - - if (args->local.data2) { unhook_syscalln(__NR_openat, before_openat, after_openat); } diff --git a/kernel/patch/common/supercall.c b/kernel/patch/common/supercall.c index 21e46509..afb6d078 100644 --- a/kernel/patch/common/supercall.c +++ b/kernel/patch/common/supercall.c @@ -31,6 +31,9 @@ #include #include #include +#ifdef ANDROID +#include +#endif #define MAX_KEY_LEN 128 @@ -376,6 +379,16 @@ static long supercall(int is_key_auth, long cmd, long arg1, long arg2, long arg3 return -ENOSYS; } +int is_trusted_manager_uid(uid_t uid) +{ + #ifdef ANDROID + return is_trusted_manager_uid_android(uid); + #endif + return 1; +} + + + static void before(hook_fargs6_t *args, void *udata) { const char *__user ukey = (const char *__user)syscall_argn(args, 0); @@ -398,9 +411,9 @@ static void before(hook_fargs6_t *args, void *udata) is_key_auth = 1; } else if (!strcmp("su", key)) { uid_t uid = current_uid(); - if (!is_su_allow_uid(uid)) return; + if (!is_su_allow_uid(uid) && !is_trusted_manager_uid(uid)) return; } else { - return; + if (!is_trusted_manager_uid(current_uid())) return; } long a1 = (long)syscall_argn(args, 2); diff --git a/kernel/patch/common/supercmd.c b/kernel/patch/common/supercmd.c index c1e2718e..ba0f9b0d 100644 --- a/kernel/patch/common/supercmd.c +++ b/kernel/patch/common/supercmd.c @@ -16,6 +16,10 @@ #include #include #include +#include +#ifdef ANDROID +#include +#endif static char *__user supercmd_str_to_user_sp(const char *data, uintptr_t *sp) { @@ -227,6 +231,7 @@ static void handle_cmd_sumgr(char **__user u_filename_p, const char **carr, char } } + // superkey commands static void handle_cmd_key_auth(char **__user u_filename_p, const char *cmd, const char **carr, char *buffer, int buflen, struct cmd_res *cmd_res) @@ -339,10 +344,10 @@ void handle_supercmd(char **__user u_filename_p, char **__user uargv) is_key_auth = 1; } else if (!strcmp("su", arg1)) { uid_t uid = current_uid(); - if (!is_su_allow_uid(uid)) return; + if (!is_su_allow_uid(uid) && !is_trusted_manager_uid(uid)) return; su_allow_uid_profile(0, uid, &profile); } else { - return; + if (!is_trusted_manager_uid(current_uid())) return; } #define SUPERCMD_ARGS_NO 16 @@ -453,7 +458,9 @@ void handle_supercmd(char **__user u_filename_p, char **__user uargv) goto echo; #ifdef ANDROID } else if (!strcmp("reload-cfg", cmd)) { - load_ap_package_config(); + int trust_rc = refresh_trusted_manager_state(); + int config_rc = load_ap_package_config(); + log_boot("reload-cfg: refresh rc=%d package_config rc=%d\n", trust_rc, config_rc); cmd_res.msg = "reload package config success"; goto echo; #endif diff --git a/kernel/patch/common/user_event.c b/kernel/patch/common/user_event.c index 7fbcc5e9..5cae1cb0 100644 --- a/kernel/patch/common/user_event.c +++ b/kernel/patch/common/user_event.c @@ -15,10 +15,16 @@ int report_user_event(const char *event, const char *args) #ifdef ANDROID if (lib_strcmp(safe_event, "post-fs-data") == 0 && lib_strcmp(safe_args, "before") == 0) { - logki("post-fs-data before event received, loading ap package config ...\n"); + int trust_rc = refresh_trusted_manager_state(); + log_boot("post-fs-data before: trusted manager refresh rc=%d\n", trust_rc); + log_boot("post-fs-data before: loading ap package config ...\n"); load_ap_package_config(); } + if (lib_strcmp(safe_event, "boot-completed") == 0) { + int trust_rc = refresh_trusted_manager_state(); + log_boot("boot-completed: trusted manager refresh rc=%d\n", trust_rc); + } #endif logki("user report event: %s, args: %s\n", safe_event, safe_args); return 0; -} \ No newline at end of file +} diff --git a/kernel/patch/include/userd.h b/kernel/patch/include/userd.h index c9a4d85c..79ab70a3 100644 --- a/kernel/patch/include/userd.h +++ b/kernel/patch/include/userd.h @@ -6,6 +6,16 @@ #ifndef _KP_USERD_H_ #define _KP_USERD_H_ +#include + int load_ap_package_config(void); -#endif \ No newline at end of file +#ifdef ANDROID +int refresh_trusted_manager_uid(void); +int refresh_trusted_manager_state(void); +int is_trusted_manager_uid(uid_t uid); +uid_t get_trusted_manager_uid(void); + +#endif + +#endif diff --git a/kernel/patch/ksyms/misc.c b/kernel/patch/ksyms/misc.c index cc0a462d..20eeea72 100644 --- a/kernel/patch/ksyms/misc.c +++ b/kernel/patch/ksyms/misc.c @@ -450,6 +450,7 @@ void kfunc_def(putname)(struct filename *name) = 0; void kfunc_def(final_putname)(struct filename *name) = 0; loff_t kfunc_def(vfs_llseek)(struct file *file, loff_t offset, int whence) = 0; +int kfunc_def(iterate_dir)(struct file *, struct dir_context *) = 0; static void _linux_fs_sym_match(const char *name, unsigned long addr) { @@ -470,6 +471,7 @@ static void _linux_fs_sym_match(const char *name, unsigned long addr) // kfunc_match(putname, name, addr); // kfunc_match(final_putname, name, addr); kfunc_match(vfs_llseek, name, addr); + kfunc_match(iterate_dir, name, addr); } #include @@ -742,7 +744,7 @@ uint64_t kfunc_def(get_random_long)(void) = 0; static void _linux_misc_misc(const char *name, unsigned long addr) { kfunc_match(panic, name, addr); - // kfunc_match(call_usermodehelper, name, addr); + kfunc_match(call_usermodehelper, name, addr); // kfunc_match(get_random_bytes, name, addr); // kfunc_match(get_random_u64, name, addr); // kfunc_match(get_random_long, name, addr); diff --git a/tools/kptools.c b/tools/kptools.c index 2f0affbc..6a4071f9 100644 --- a/tools/kptools.c +++ b/tools/kptools.c @@ -203,6 +203,7 @@ int main(int argc, char *argv[]) else fprintf(stdout, "%x\n", version); } else if (cmd == 'p') { + if (!superkey) root_skey = true; ret = patch_update_img(kimg_path, kpimg_path, out_path, superkey, root_skey, additional, extra_configs, extra_config_num); } else if (cmd == 'd') { diff --git a/tools/patch.c b/tools/patch.c index c072b446..aecfcae9 100644 --- a/tools/patch.c +++ b/tools/patch.c @@ -407,7 +407,7 @@ int patch_update_img(const char *kimg_path, const char *kpimg_path, const char * if (!kpimg_path) tools_loge_exit("empty kpimg\n"); if (!out_path) tools_loge_exit("empty out image path\n"); - if (!superkey) tools_loge_exit("empty superkey\n"); + if (!superkey && !root_key) tools_loge_exit("empty superkey\n"); patched_kimg_t pimg = { 0 }; kernel_file_t kernel_file; @@ -429,7 +429,7 @@ int patch_update_img(const char *kimg_path, const char *kpimg_path, const char * int kver = 0; find_linux_banner(&kallsym, kallsym_kimg, pimg.ori_kimg_len, &kver); if (kver > 395008) { - if(!disable_pi_map(kernel_file.kimg, kernel_file.kimg_len)) //395008= (6<<16)+(7<<8) + if(disable_pi_map(kernel_file.kimg, kernel_file.kimg_len)) //395008= (6<<16)+(7<<8) { tools_logi("kernel have patched or not found\n"); }else{ @@ -626,7 +626,7 @@ int patch_update_img(const char *kimg_path, const char *kpimg_path, const char * if (!root_key) { tools_logi("superkey: %s\n", superkey); strncpy((char *)setup->superkey, superkey, SUPER_KEY_LEN - 1); - } else { + } else if (superkey && superkey[0] != '\0') { int len = SHA256_BLOCK_SIZE > ROOT_SUPER_KEY_HASH_LEN ? ROOT_SUPER_KEY_HASH_LEN : SHA256_BLOCK_SIZE; BYTE buf[SHA256_BLOCK_SIZE]; SHA256_CTX ctx; @@ -637,6 +637,9 @@ int patch_update_img(const char *kimg_path, const char *kpimg_path, const char * char *hexstr = bytes_to_hexstr(setup->root_superkey, len); tools_logi("root superkey hash: %s\n", hexstr); free(hexstr); + } else { + memset(setup->root_superkey, 0, ROOT_SUPER_KEY_HASH_LEN); + tools_logi("root_key mode with empty superkey: root_superkey zeroed\n"); } // modify kernel entry