diff --git a/kernel/kpm/compact.c b/kernel/kpm/compact.c index d6f69705..61e99a35 100644 --- a/kernel/kpm/compact.c +++ b/kernel/kpm/compact.c @@ -31,7 +31,7 @@ unsigned long sukisu_compact_find_symbol(const char* name); // ====================================================================== -const char* kver = "0.10"; +const char* kpver = "0.10"; struct CompactAddressSymbol { const char* symbol_name; @@ -46,17 +46,17 @@ struct CompactAliasSymbol { struct CompactAddressSymbol address_symbol [] = { { "kallsyms_lookup_name", &kallsyms_lookup_name }, { "compact_find_symbol", &sukisu_compact_find_symbol }, - { "compact_copy_to_user", ©_to_user }, - { "compact_strncpy_from_user", &strncpy_from_user }, - { "kver", &kver }, + { "compat_copy_to_user", ©_to_user }, + { "compat_strncpy_from_user", &strncpy_from_user }, + { "kpver", &kpver }, { "is_run_in_sukisu_ultra", (void*)1 } }; struct CompactAliasSymbol alias_symbol[] = { - {"kf__strncat", "strncat"}, - {"kf__strlen", "strlen" }, - {"kf__strcpy", "strcpy"}, - {"compact_copy_to_user", "__arch_copy_to_user"} + {"kf_strncat", "strncat"}, + {"kf_strlen", "strlen" }, + {"kf_strcpy", "strcpy"}, + {"compat_copy_to_user", "__arch_copy_to_user"} }; unsigned long sukisu_compact_find_symbol(const char* name) { diff --git a/kernel/kpm/kpm.c b/kernel/kpm/kpm.c index 1b84cbf6..b4b8fb11 100644 --- a/kernel/kpm/kpm.c +++ b/kernel/kpm/kpm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "kpm.h" #include "compact.h" @@ -361,19 +362,21 @@ static int kpm_simplify_symbols(struct kpm_module *mod, const struct kpm_load_in return ret; } -/* ARM64 重定位处理:支持 R_AARCH64_RELATIVE 与 R_AARCH64_ABS64 */ +/* ARM64 重定位处理:支持 R_AARCH64_RELATIVE、R_AARCH64_ABS64、R_AARCH64_GLOB_DAT、R_AARCH64_JUMP_SLOT */ static int kpm_apply_relocate_arm64(Elf64_Shdr *sechdrs, const char *strtab, int sym_idx, int rel_idx, struct kpm_module *mod) { Elf64_Shdr *relsec = &sechdrs[rel_idx]; int num = relsec->sh_size / sizeof(Elf64_Rel); - Elf64_Rela *rel = (Elf64_Rela *)((char *)mod->start + relsec->sh_entsize); + Elf64_Rel *rel = (Elf64_Rel *)((char *)mod->start + relsec->sh_offset); // 修正为 sh_offset int i; + for (i = 0; i < num; i++) { unsigned long type = ELF64_R_TYPE(rel[i].r_info); unsigned long *addr = (unsigned long *)(mod->start + rel[i].r_offset); + switch (type) { case R_AARCH64_RELATIVE: - *addr = (unsigned long)mod->start + rel[i].r_addend; + *addr = (unsigned long)mod->start + *(unsigned long *)addr; break; default: printk(KERN_ERR "ARM64 KPM Loader: Unsupported REL relocation type %lu\n", type); @@ -383,34 +386,238 @@ static int kpm_apply_relocate_arm64(Elf64_Shdr *sechdrs, const char *strtab, int return 0; } -static int kpm_apply_relocate_add_arm64(Elf64_Shdr *sechdrs, const char *strtab, int sym_idx, int rela_idx, struct kpm_module *mod) +#ifndef R_AARCH64_GLOB_DAT +#define R_AARCH64_GLOB_DAT 1025 /* Set GOT entry to data address */ +#endif +#ifndef R_AARCH64_JUMP_SLOT +#define R_AARCH64_JUMP_SLOT 1026 /* Set GOT entry to code address */ +#endif +#ifndef R_ARM_NONE +#define R_ARM_NONE 0 +#endif +#ifndef R_AARCH64_NONE +#define R_AARCH64_NONE 256 +#endif + +/* 重定位操作类型 */ +typedef enum { + RELOC_OP_ABS, + RELOC_OP_PREL, + RELOC_OP_PAGE +} reloc_op_t; + +/* 指令编码辅助函数 */ +static int reloc_data(reloc_op_t op, void *loc, u64 val, int len) +{ + u64 imm = val; + int shift = 0; + + switch (op) { + case RELOC_OP_ABS: + break; + case RELOC_OP_PREL: + imm -= (u64)loc; + break; + case RELOC_OP_PAGE: + imm = (imm >> 12) - ((u64)loc >> 12); + shift = 12; + break; + default: + return -EINVAL; + } + + switch (len) { + case 16: + *(u16 *)loc = cpu_to_le16(imm >> shift); + break; + case 32: + *(u32 *)loc = cpu_to_le32(imm >> shift); + break; + case 64: + *(u64 *)loc = cpu_to_le64(imm >> shift); + break; + default: + return -EINVAL; + } + + /* 检查溢出 */ + if (imm > (BIT_ULL(len) - 1) << shift) + return -ERANGE; + return 0; +} + +/* MOVW 指令重定位 */ +static int reloc_insn_movw(reloc_op_t op, void *loc, u64 val, int shift, aarch64_insn_imm_type imm_type) +{ + u64 imm = val; + s64 sval; + + switch (op) { + case RELOC_OP_ABS: + break; + case RELOC_OP_PREL: + imm -= (u64)loc; + break; + default: + return -EINVAL; + } + + sval = (s64)imm; + return aarch64_insn_patch_imm(loc, imm_type, sval >> shift); +} + +/* 立即数指令重定位 */ +static int reloc_insn_imm(reloc_op_t op, void *loc, u64 val, int shift, int len, aarch64_insn_imm_type imm_type) +{ + u64 imm = val; + s64 sval; + + switch (op) { + case RELOC_OP_ABS: + break; + case RELOC_OP_PREL: + imm -= (u64)loc; + break; + case RELOC_OP_PAGE: + imm = (imm >> 12) - ((u64)loc >> 12); + shift = 0; + break; + default: + return -EINVAL; + } + + sval = (s64)imm; + return aarch64_insn_patch_imm(loc, imm_type, sval >> shift); +} + +/* 完整的 ARM64 重定位适配 */ +static int kpm_apply_relocate_add_arm64(Elf64_Shdr *sechdrs, const char *strtab, + int sym_idx, int rela_idx, struct kpm_module *mod) { Elf64_Shdr *relasec = &sechdrs[rela_idx]; int num = relasec->sh_size / sizeof(Elf64_Rela); - Elf64_Rela *rela = (Elf64_Rela *)((char *)mod->start + relasec->sh_entsize); - int i; + Elf64_Rela *rela = (Elf64_Rela *)((char *)mod->start + relasec->sh_offset); + int i, ovf; + bool overflow_check; + for (i = 0; i < num; i++) { unsigned long type = ELF64_R_TYPE(rela[i].r_info); unsigned long sym_index = ELF64_R_SYM(rela[i].r_info); - unsigned long *addr = (unsigned long *)(mod->start + rela[i].r_offset); - switch (type) { - case R_AARCH64_RELATIVE: - *addr = (unsigned long)mod->start + rela[i].r_addend; - break; - case R_AARCH64_ABS64: - if (sym_index) { - Elf64_Sym *sym = (Elf64_Sym *)((char *)mod->start + sechdrs[sym_idx].sh_offset) + sym_index; - *addr = sym->st_value + rela[i].r_addend; + void *loc = (void *)(mod->start + rela[i].r_offset); + u64 val; + Elf64_Sym *sym; + + /* 处理特殊重定位类型 */ + if (type == R_AARCH64_NONE || type == R_ARM_NONE) + continue; + + /* 解析符号值 */ + if (sym_index) { + sym = (Elf64_Sym *)((char *)mod->start + sechdrs[sym_idx].sh_offset) + sym_index; + val = sym->st_value + rela[i].r_addend; + + /* 全局符号需通过内核解析 */ + if (ELF64_ST_BIND(sym->st_info) == STB_GLOBAL) { + const char *name = strtab + sym->st_name; + unsigned long addr = kallsyms_lookup_name(name); + if (!addr) { + printk(KERN_ERR "KPM: Symbol %s not found!\n", name); + return -ENOENT; + } + val = addr + rela[i].r_addend; } else { - printk(KERN_ERR "ARM64 KPM Loader: R_AARCH64_ABS64 with zero symbol\n"); - return -EINVAL; + val += (u64)mod->start; // 转换为模块内绝对地址 } + } else { + val = rela[i].r_addend; + } + + overflow_check = true; + + /* 处理所有重定位类型 */ + switch (type) { + /* 数据重定位 */ + case R_AARCH64_ABS64: + overflow_check = false; + ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); break; + case R_AARCH64_ABS32: + ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); + break; + case R_AARCH64_ABS16: + ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); + break; + case R_AARCH64_PREL64: + overflow_check = false; + ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); + break; + case R_AARCH64_PREL32: + ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); + break; + case R_AARCH64_PREL16: + ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); + break; + + /* MOVW 指令 */ + case R_AARCH64_MOVW_UABS_G0_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G0: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G1_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G1: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G2_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G2: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G3: + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, AARCH64_INSN_IMM_16); + break; + + /* 立即数指令 */ + case R_AARCH64_ADR_PREL_LO21: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, AARCH64_INSN_IMM_ADR); + break; + case R_AARCH64_ADR_PREL_PG_HI21_NC: + overflow_check = false; + case R_AARCH64_ADR_PREL_PG_HI21: + ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, AARCH64_INSN_IMM_ADR); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, AARCH64_INSN_IMM_12); + break; + + /* 跳转指令 */ + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, AARCH64_INSN_IMM_26); + break; + + /* GOT 相关 */ + case R_AARCH64_GLOB_DAT: + case R_AARCH64_JUMP_SLOT: + *((u64 *)loc) = val; + ovf = 0; + break; + default: - printk(KERN_ERR "ARM64 KPM Loader: Unsupported RELA relocation type %lu\n", type); - return -EINVAL; + printk(KERN_ERR "KPM: Unsupported relocation type %lu\n", type); + return -ENOEXEC; + } + + if (overflow_check && ovf == -ERANGE) { + printk(KERN_ERR "KPM: Relocation overflow (type %lu val 0x%llx)\n", type, val); + return -ENOEXEC; + } else if (ovf) { + return ovf; } } + return 0; } @@ -418,22 +625,36 @@ static int kpm_apply_relocations(struct kpm_module *mod, const struct kpm_load_i { int rc = 0; int i; + for (i = 1; i < info->ehdr->e_shnum; i++) { unsigned int target = info->sechdrs[i].sh_info; - if (target >= info->ehdr->e_shnum) + + if (target >= info->ehdr->e_shnum) { + printk(KERN_ERR "ARM64 KPM Loader: Invalid target section index %u\n", target); + return -EINVAL; + } + + if (!(info->sechdrs[target].sh_flags & SHF_ALLOC)) { + printk(KERN_INFO "ARM64 KPM Loader: Skipping non-allocated section %d\n", i); continue; - if (!(info->sechdrs[target].sh_flags & SHF_ALLOC)) - continue; - if (info->sechdrs[i].sh_type == SHT_REL) + } + + if (info->sechdrs[i].sh_type == SHT_REL) { rc = kpm_apply_relocate_arm64(info->sechdrs, info->strtab, info->index.sym, i, mod); - else if (info->sechdrs[i].sh_type == SHT_RELA) + } else if (info->sechdrs[i].sh_type == SHT_RELA) { rc = kpm_apply_relocate_add_arm64(info->sechdrs, info->strtab, info->index.sym, i, mod); - if (rc < 0) + } + + if (rc < 0) { + printk(KERN_ERR "ARM64 KPM Loader: Relocation failed at section %d, error %d\n", i, rc); break; + } } + return rc; } + /*----------------------------------------------------------- * 符号表与字符串表布局 *----------------------------------------------------------*/ @@ -481,45 +702,83 @@ static int kpm_rewrite_section_headers(struct kpm_load_info *info) /*----------------------------------------------------------- * 将各段复制到连续内存区域中 *----------------------------------------------------------*/ +/*----------------------------------------------------------- + * 将各段复制到连续内存区域(修复版) + * 关键修复点: + * 1. 段地址按对齐要求正确计算 + * 2. 显式设置可执行内存权限 + * 3. 刷新指令缓存保证一致性 + *----------------------------------------------------------*/ static int kpm_move_module(struct kpm_module *mod, struct kpm_load_info *info) { int i; + unsigned long curr_offset = 0; + Elf64_Shdr *shdr; + void *dest; + const char *secname; - printk(KERN_INFO "ARM64 KPM Loader: Allocating module memory: size=0x%x\n", mod->size); - mod->start = kpm_malloc_exec(mod->size); - if (!mod->start) + /* 分配连续内存(按页对齐) */ + mod->size = ALIGN(mod->size, PAGE_SIZE); + mod->start = module_alloc(mod->size); // 使用内核的 module_alloc 接口 + if (!mod->start) { + printk(KERN_ERR "ARM64 KPM Loader: Failed to allocate module memory\n"); return -ENOMEM; + } memset(mod->start, 0, mod->size); - printk(KERN_INFO "ARM64 KPM Loader: Final section addresses:\n"); - for (i = 1; i < info->ehdr->e_shnum; i++) { - void *dest; - Elf64_Shdr *shdr = &info->sechdrs[i]; + /* 设置内存可执行权限(关键修复) */ + set_memory_x((unsigned long)mod->start, mod->size >> PAGE_SHIFT); + + printk(KERN_INFO "ARM64 KPM Loader: Final section addresses (aligned base=0x%px):\n", mod->start); + + /* 遍历所有段并按对齐要求布局 */ + for (i = 0; i < info->ehdr->e_shnum; i++) { + shdr = &info->sechdrs[i]; if (!(shdr->sh_flags & SHF_ALLOC)) continue; - dest = mod->start + shdr->sh_entsize; - if (shdr->sh_type != SHT_NOBITS) + + /* 按段对齐要求调整偏移 */ + curr_offset = ALIGN(curr_offset, shdr->sh_addralign); + dest = mod->start + curr_offset; + + /* 复制段内容(NOBITS 段不复制) */ + if (shdr->sh_type != SHT_NOBITS) { memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size); + + /* 刷新指令缓存(针对可执行段) */ + if (shdr->sh_flags & SHF_EXECINSTR) { + flush_icache_range((unsigned long)dest, + (unsigned long)dest + shdr->sh_size); + } + } + + /* 更新段头中的虚拟地址 */ shdr->sh_addr = (unsigned long)dest; - if (!mod->init && !strcmp(".kpm.init", info->secstrings + shdr->sh_name)) + curr_offset += shdr->sh_size; + + /* 定位关键函数指针 */ + secname = info->secstrings + shdr->sh_name; + if (!mod->init && !strcmp(".kpm.init", secname)) { mod->init = (int (*)(const char *, const char *, void *__user))dest; - if (!strcmp(".kpm.exit", info->secstrings + shdr->sh_name)) + printk(KERN_DEBUG "Found .kpm.init at 0x%px\n", dest); + } else if (!strcmp(".kpm.exit", secname)) { mod->exit = (void (*)(void *__user))dest; - if (!strcmp(".kpm.ctl0", info->secstrings + shdr->sh_name)) - mod->ctl0 = (int (*)(const char *, char *__user, int))dest; - if (!strcmp(".kpm.ctl1", info->secstrings + shdr->sh_name)) - mod->ctl1 = (int (*)(void *, void *, void *))dest; - if (!mod->info.base && !strcmp(".kpm.info", info->secstrings + shdr->sh_name)) - mod->info.base = (const char *)dest; + } } - mod->info.name = info->info.name - info->info.base + mod->info.base; - mod->info.version = info->info.version - info->info.base + mod->info.base; - if (info->info.license) - mod->info.license = info->info.license - info->info.base + mod->info.base; - if (info->info.author) - mod->info.author = info->info.author - info->info.base + mod->info.base; - if (info->info.description) - mod->info.description = info->info.description - info->info.base + mod->info.base; + + /* 调整元数据指针(基于新基址) */ + if (info->info.base) { + unsigned long delta = (unsigned long)mod->start - (unsigned long)info->hdr; + mod->info.name = (const char *)((unsigned long)info->info.name + delta); + mod->info.version = (const char *)((unsigned long)info->info.version + delta); + if (info->info.license) + mod->info.license = (const char *)((unsigned long)info->info.license + delta); + if (info->info.author) + mod->info.author = (const char *)((unsigned long)info->info.author + delta); + if (info->info.description) + mod->info.description = (const char *)((unsigned long)info->info.description + delta); + } + return 0; } @@ -944,5 +1203,4 @@ int sukisu_is_kpm_control_code(unsigned long arg2) { return (arg2 >= CMD_KPM_CONTROL && arg2 <= CMD_KPM_CONTROL_MAX) ? 1 : 0; } -EXPORT_SYMBOL(sukisu_handle_kpm); - +EXPORT_SYMBOL(sukisu_handle_kpm); \ No newline at end of file