diff --git a/.github/workflows/build-lkm.yml b/.github/workflows/build-lkm.yml index 2da532cc0659..e5ed7eac475e 100644 --- a/.github/workflows/build-lkm.yml +++ b/.github/workflows/build-lkm.yml @@ -5,6 +5,7 @@ on: jobs: build-lkm: strategy: + fail-fast: false matrix: kmi: - android12-5.10 diff --git a/.github/workflows/build-manager.yml b/.github/workflows/build-manager.yml index 9031b92da45d..e3cd051d5e77 100644 --- a/.github/workflows/build-manager.yml +++ b/.github/workflows/build-manager.yml @@ -7,19 +7,24 @@ on: - '.github/workflows/build-manager.yml' - '.github/workflows/build-lkm.yml' - '.github/workflows/ksud.yml' + - '.github/workflows/ddl-lkm.yml' - 'manager/**' - 'kernel/**' - 'userspace/**' + - 'scripts/ksubot.py' pull_request: branches: [ "main", "dev" ] paths: - '.github/workflows/build-manager.yml' - '.github/workflows/build-lkm.yml' - '.github/workflows/ksud.yml' + - '.github/workflows/ddl-lkm.yml' - 'manager/**' - 'kernel/**' - 'userspace/**' + - 'scripts/ksubot.py' workflow_call: + workflow_dispatch: jobs: build-lkm: @@ -79,14 +84,14 @@ jobs: - name: Setup need_upload id: need_upload run: | - if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then + if [ ! -z "${{ secrets.BOT_TOKEN }}" ] && [ "${{ github.event_name }}" != "workflow_dispatch" ]; then echo "UPLOAD=true" >> $GITHUB_OUTPUT else echo "UPLOAD=false" >> $GITHUB_OUTPUT fi - name: Write key - if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }} + if: ${{ github.event_name != 'pull_request' || github.ref_type == 'tag' }} run: | if [ ! -z "${{ secrets.KEYSTORE }}" ]; then { @@ -95,7 +100,7 @@ jobs: echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' echo KEYSTORE_FILE='key.jks' } >> gradle.properties - echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks + echo "${{ secrets.KEYSTORE }}" | base64 -d > key.jks fi - name: Setup Java @@ -157,11 +162,10 @@ jobs: - name: Upload to telegram if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true' env: - CHAT_ID: ${{ secrets.CHAT_ID }} + CHAT_ID: ${{ vars.CHAT_ID }} BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }} - COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - COMMIT_URL: ${{ github.event.head_commit.url }} + MESSAGE_THREAD_ID: ${{ vars.MESSAGE_THREAD_ID }} + GITHUB_EVENT: ${{ toJson(github.event) }} RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} TITLE: Manager BRANCH: ${{ github.ref_name }} diff --git a/.github/workflows/ddk-lkm.yml b/.github/workflows/ddk-lkm.yml index 4e8e041b39ff..b51722720d91 100644 --- a/.github/workflows/ddk-lkm.yml +++ b/.github/workflows/ddk-lkm.yml @@ -31,6 +31,21 @@ jobs: cd kernel + if [[ "${{ inputs.kmi }}" == *"5.1"* ]]; then + echo "=== fix modpost ===" + sed -i '/s->module = exp->module;/s/^/\/\//' /opt/ddk/src/*/scripts/mod/modpost.c + pushd /opt/ddk/kdir/* + CMD_O=$(grep 'cmd_scripts/mod/modpost.o := ' scripts/mod/.modpost.o.cmd | sed 's/cmd_scripts\/mod\/modpost.o := //g') + CMD_2=$(grep 'cmd_scripts/mod/file2alias.o := ' scripts/mod/.file2alias.o.cmd | sed 's/cmd_scripts\/mod\/file2alias.o := //g') + CMD_3=$(grep 'cmd_scripts/mod/sumversion.o := ' scripts/mod/.sumversion.o.cmd | sed 's/cmd_scripts\/mod\/sumversion.o := //g') + CMD_L=$(grep 'cmd_scripts/mod/modpost := ' scripts/mod/.modpost.cmd | sed 's/cmd_scripts\/mod\/modpost := //g') + $CMD_O + $CMD_2 + $CMD_3 + $CMD_L + popd + fi + echo "=== Building kernelsu.ko for KMI: ${{ inputs.kmi }} ===" CONFIG_KSU=m CC=clang make diff --git a/.gitignore b/.gitignore index 9e7e95876351..79d923791aec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .idea -.vscode +/.vscode CLAUDE.md AGENTS.md \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 03a9346ea904..87d081a804e1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,10 @@ **English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_IW.md) | [हिंदी](README_IN.md) | [Italiano](README_IT.md) -# KernelSU +# My KernelSU logo -A kernel-based root solution for Android devices. +A [KernelSU](https://github.com/tiann/KernelSU/commit/6bac4b1bd1825a7902502425cdfb07ca6d6256a6)-based root solution for Android devices. [![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest) [![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu) diff --git a/kernel/.gitignore b/kernel/.gitignore index 15547df1c7de..85fecbf8cdb4 100644 --- a/kernel/.gitignore +++ b/kernel/.gitignore @@ -12,7 +12,7 @@ compile_commands.json *.mod.c *.symvers* *.order -.*.ko.cmd +.*.cmd .tmp_versions/ libs/ obj/ diff --git a/kernel/.vscode/generate_compdb.py b/kernel/.vscode/generate_compdb.py index 8866913868f4..22c5a0007d8c 100755 --- a/kernel/.vscode/generate_compdb.py +++ b/kernel/.vscode/generate_compdb.py @@ -44,6 +44,8 @@ def gen_compile_commands(cmd_file_search_path, out_dir): if not cmd_file_search_path: cmd_file_search_path = [out_dir] + else: + cmd_file_search_path += [out_dir] cmd_files = [] for search_path in cmd_file_search_path: diff --git a/kernel/Kbuild b/kernel/Kbuild index 70511859bd85..5f7157e62ce0 100644 --- a/kernel/Kbuild +++ b/kernel/Kbuild @@ -14,7 +14,10 @@ kernelsu-objs += feature.o kernelsu-objs += ksud.o kernelsu-objs += seccomp_cache.o kernelsu-objs += file_wrapper.o -kernelsu-objs += util.o +kernelsu-objs += pte.o +kernelsu-objs += patch.o +kernelsu-objs += inline_hook.o +kernelsu-objs += trampoline.o kernelsu-objs += selinux/selinux.o kernelsu-objs += selinux/sepolicy.o @@ -60,12 +63,35 @@ $(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU a git repo ccflags-y += -DKSU_VERSION=16 endif +KSU_NEW_DCACHE_FLUSH := $(shell grep -q __flush_dcache_area $(srctree)/arch/arm64/include/asm/cacheflush.h ; echo $$?) +$(info -- KSU_NEW_DCACHE_FLUSH: $(KSU_NEW_DCACHE_FLUSH)) + +KSU_MTE_SYNC_TAGS_DEF := $(shell grep 'void mte_sync_tags' $(srctree)/arch/arm64/include/asm/mte.h | grep -v 'static inline') +# 6.6 +KSU_MTE_SYNC_TAGS_NR_PAGES := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q 'nr_pages' && echo 1 || echo 0) +# 6.1 +KSU_MTE_SYNC_TAGS_NORMAL := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q '(pte_t pte)' && echo 1 || echo 0) +# 13-5.10 +KSU_MTE_SYNC_TAGS_OLD_PTE := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q 'old_pte' && echo 1 || echo 0) +# 12-5.10 +KSU_MTE_SYNC_TAGS_PTEP := $(shell echo '$(KSU_MTE_SYNC_TAGS_DEF)' | grep -q '*ptep' && echo 1 || echo 0) +KSU_DEF_MTE_SYNC_TAGS := 'extern $(KSU_MTE_SYNC_TAGS_DEF)' + +$(info -- KSU_DEF_MTE_SYNC_TAGS: $(KSU_DEF_MTE_SYNC_TAGS)) +$(info -- KSU_MTE_SYNC_TAGS_NR_PAGES: $(KSU_MTE_SYNC_TAGS_NR_PAGES)) +$(info -- KSU_MTE_SYNC_TAGS_PTEP: $(KSU_MTE_SYNC_TAGS_PTEP)) +$(info -- KSU_MTE_SYNC_TAGS_OLD_PTE: $(KSU_MTE_SYNC_TAGS_OLD_PTE)) +$(info -- KSU_MTE_SYNC_TAGS_NORMAL: $(KSU_MTE_SYNC_TAGS_NORMAL)) + +OFFICIAL_EXPECTED_SIZE := 0x033b +OFFICIAL_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6 + ifndef KSU_EXPECTED_SIZE -KSU_EXPECTED_SIZE := 0x033b +KSU_EXPECTED_SIZE := 384 endif ifndef KSU_EXPECTED_HASH -KSU_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6 +KSU_EXPECTED_HASH := 7e0c6d7278a3bb8e364e0fcba95afaf3666cf5ff3c245a3b63c8833bd0445cc4 endif ifdef KSU_MANAGER_PACKAGE @@ -78,6 +104,16 @@ $(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH)) ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE) ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\" +ccflags-y += -DOFFICIAL_EXPECTED_SIZE=$(OFFICIAL_EXPECTED_SIZE) +ccflags-y += -DOFFICIAL_EXPECTED_HASH=\"$(OFFICIAL_EXPECTED_HASH)\" + +ccflags-y += -DKSU_NEW_DCACHE_FLUSH=$(KSU_NEW_DCACHE_FLUSH) + +ccflags-y += -DKSU_DEF_MTE_SYNC_TAGS=$(KSU_DEF_MTE_SYNC_TAGS) +ccflags-y += -DKSU_MTE_SYNC_TAGS_NR_PAGES=$(KSU_MTE_SYNC_TAGS_NR_PAGES) +ccflags-y += -DKSU_MTE_SYNC_TAGS_PTEP=$(KSU_MTE_SYNC_TAGS_PTEP) +ccflags-y += -DKSU_MTE_SYNC_TAGS_OLD_PTE=$(KSU_MTE_SYNC_TAGS_OLD_PTE) +ccflags-y += -DKSU_MTE_SYNC_TAGS_NORMAL=$(KSU_MTE_SYNC_TAGS_NORMAL) ccflags-y += -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat -Wno-missing-prototypes ccflags-y += -Wno-declaration-after-statement -Wno-unused-function diff --git a/kernel/Makefile b/kernel/Makefile index 28e5a3a802d6..4cda37033424 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -7,7 +7,7 @@ $(info -- MDIR: $(MDIR)) .PHONY: all compdb clean format check-format all: check_symbol - make -C $(KDIR) M=$(MDIR) modules + CONFIG_KSU=m make -C $(KDIR) M=$(MDIR) modules ./check_symbol kernelsu.ko $(KDIR)/vmlinux compdb: python3 $(MDIR)/.vscode/generate_compdb.py -O $(KDIR) $(MDIR) diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 25de2a7ffd9a..cd1a6eb978dd 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -284,6 +284,10 @@ bool __ksu_is_allow_uid(uid_t uid) return true; } + if (unlikely(allow_shell) && uid == 2000) { + return true; + } + if (likely(uid <= BITMAP_UID_MAX)) { return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE))); @@ -340,6 +344,10 @@ void ksu_get_root_profile(uid_t uid, struct root_profile *profile) goto use_default; } + if (unlikely(allow_shell && uid == SHELL_UID)) { + goto use_default; + } + rcu_read_lock(); list_for_each_entry_rcu (p, &allow_list, list) { if (uid == p->profile.current_uid && p->profile.allow_su) { diff --git a/kernel/allowlist.h b/kernel/allowlist.h index 2afc303836c2..d8d122e9a74b 100644 --- a/kernel/allowlist.h +++ b/kernel/allowlist.h @@ -53,3 +53,5 @@ static inline bool is_isolated_process(uid_t uid) return appid >= FIRST_ISOLATED_UID && appid <= LAST_ISOLATED_UID; } #endif + +extern bool allow_shell; diff --git a/kernel/apk_sign.c b/kernel/apk_sign.c index 1c84127bd367..65a2f3fe26db 100644 --- a/kernel/apk_sign.c +++ b/kernel/apk_sign.c @@ -360,5 +360,7 @@ bool is_manager_apk(char *path) return false; } #endif - return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH); + return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH) || + check_v2_signature(path, OFFICIAL_EXPECTED_SIZE, + OFFICIAL_EXPECTED_HASH); } \ No newline at end of file diff --git a/kernel/app_profile.c b/kernel/app_profile.c index f544dd8de4a3..befe352b5fd4 100644 --- a/kernel/app_profile.c +++ b/kernel/app_profile.c @@ -66,7 +66,7 @@ static void disable_seccomp(void) { struct task_struct *fake; - fake = kmalloc(sizeof(*fake), GFP_ATOMIC); + fake = kmalloc(sizeof(*fake), GFP_KERNEL); if (!fake) { pr_warn("failed to alloc fake task_struct\n"); return; diff --git a/kernel/hook.h b/kernel/hook.h new file mode 100644 index 000000000000..fab52d5a77ea --- /dev/null +++ b/kernel/hook.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 bmax121. All Rights Reserved. + */ + +#ifndef __KSU_H_HOOK_ +#define __KSU_H_HOOK_ +#include "linux/types.h" // IWYU pragma: keep +#include "linux/version.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#include "asm/patching.h" // IWYU pragma: keep +#else +#include "asm/insn.h" // IWYU pragma: keep +#endif + +// https://github.com/bmax121/KernelPatch/blob/94e5be9cc3f8a6fbd9574155e3e9753200ab9bfb/kernel/include/hook.h#L54 + +#define HOOK_INTO_BRANCH_FUNC + +typedef enum { + HOOK_NO_ERR = 0, + HOOK_BAD_ADDRESS = 4095, + HOOK_DUPLICATED = 4094, + HOOK_NO_MEM = 4093, + HOOK_BAD_RELO = 4092, + HOOK_TRANSIT_NO_MEM = 4091, + HOOK_CHAIN_FULL = 4090, +} hook_err_t; + +#define HOOK_MEM_REGION_NUM 4 +#define TRAMPOLINE_MAX_NUM 6 +#define RELOCATE_INST_NUM (4 * 8 + 8 - 4) + +#define HOOK_CHAIN_NUM 0x10 + +#define ARM64_NOP 0xd503201f +#define ARM64_BTI_C 0xd503245f +#define ARM64_BTI_J 0xd503249f +#define ARM64_BTI_JC 0xd50324df +#define ARM64_PACIASP 0xd503233f +#define ARM64_PACIBSP 0xd503237f + +typedef struct { + // in + uint64_t func_addr; + uint64_t origin_addr; + uint64_t replace_addr; + uint64_t relo_addr; + // out + int32_t tramp_insts_num; + int32_t relo_insts_num; + uint32_t origin_insts[TRAMPOLINE_MAX_NUM] __attribute__((aligned(8))); + uint32_t tramp_insts[TRAMPOLINE_MAX_NUM] __attribute__((aligned(8))); + uint32_t relo_insts[RELOCATE_INST_NUM] __attribute__((aligned(8))); +} hook_t __attribute__((aligned(8))); + +static inline int is_bad_address(void *addr) +{ + return ((uint64_t)addr & 0x8000000000000000) != 0x8000000000000000; +} + +int32_t branch_from_to(uint32_t *tramp_buf, uint64_t src_addr, + uint64_t dst_addr); +int32_t branch_relative(uint32_t *buf, uint64_t src_addr, uint64_t dst_addr); +int32_t branch_absolute(uint32_t *buf, uint64_t addr); +int32_t ret_absolute(uint32_t *buf, uint64_t addr); + +hook_err_t hook_prepare(hook_t *hook); +int hook_install(hook_t *hook); + +/** + * @brief Inline-hook function which address is @param func with function @param replace, + * after hook, original @param func is backuped in @param backup. + * + * @note If multiple modules hook this function simultaneously, + * it will cause abnormality when unload the modules. Please use hook_wrap instead + * + * @see hook_wrap + * + * @param func + * @param replace + * @param backup + * @return hook_err_t + */ +hook_err_t hook(void *func, void *replace, void **backup); + +#define KSU_PATCH_TEXT_FLUSH_DCACHE 1 +#define KSU_PATCH_TEXT_FLUSH_ICACHE 2 + +int ksu_patch_text(void *dst, void *src, size_t len, int flags); + +#endif diff --git a/kernel/inline_hook.c b/kernel/inline_hook.c new file mode 100644 index 000000000000..9a991db17799 --- /dev/null +++ b/kernel/inline_hook.c @@ -0,0 +1,607 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 bmax121. All Rights Reserved. + */ +#include "hook.h" +#include "klog.h" // IWYU pragma: keep +#include "linux/compiler.h" +#include "linux/cpumask.h" +#include "linux/gfp.h" // IWYU pragma: keep +#include "linux/uaccess.h" +#include "linux/vmalloc.h" +#include "linux/stop_machine.h" +#include "asm/cacheflush.h" +#include "asm-generic/fixmap.h" +#include "asm/pgtable.h" + +#include "pte.h" + +// https://github.com/bmax121/KernelPatch/blob/94e5be9cc3f8a6fbd9574155e3e9753200ab9bfb/kernel/base/hook.c#L562-L603 + +#define bits32(n, high, low) \ + ((uint32_t)((n) << (31u - (high))) >> (31u - (high) + (low))) +#define bit(n, st) (((n) >> (st)) & 1) +#define sign64_extend(n, len) \ + (((uint64_t)((n) << (63u - (len - 1))) >> 63u) ? \ + ((n) | (0xFFFFFFFFFFFFFFFF << (len))) : \ + n) +#define align_ceil(x, align) \ + (((u64)(x) + (u64)(align) - 1) & ~((u64)(align) - 1)) + +typedef uint32_t inst_type_t; +typedef uint32_t inst_mask_t; + +#define INST_B 0x14000000 +#define INST_BC 0x54000000 +#define INST_BL 0x94000000 +#define INST_ADR 0x10000000 +#define INST_ADRP 0x90000000 +#define INST_LDR_32 0x18000000 +#define INST_LDR_64 0x58000000 +#define INST_LDRSW_LIT 0x98000000 +#define INST_PRFM_LIT 0xD8000000 +#define INST_LDR_SIMD_32 0x1C000000 +#define INST_LDR_SIMD_64 0x5C000000 +#define INST_LDR_SIMD_128 0x9C000000 +#define INST_CBZ 0x34000000 +#define INST_CBNZ 0x35000000 +#define INST_TBZ 0x36000000 +#define INST_TBNZ 0x37000000 +#define INST_HINT 0xD503201F +#define INST_IGNORE 0x0 + +#define MASK_B 0xFC000000 +#define MASK_BC 0xFF000010 +#define MASK_BL 0xFC000000 +#define MASK_ADR 0x9F000000 +#define MASK_ADRP 0x9F000000 +#define MASK_LDR_32 0xFF000000 +#define MASK_LDR_64 0xFF000000 +#define MASK_LDRSW_LIT 0xFF000000 +#define MASK_PRFM_LIT 0xFF000000 +#define MASK_LDR_SIMD_32 0xFF000000 +#define MASK_LDR_SIMD_64 0xFF000000 +#define MASK_LDR_SIMD_128 0xFF000000 +#define MASK_CBZ 0x7F000000u +#define MASK_CBNZ 0x7F000000u +#define MASK_TBZ 0x7F000000u +#define MASK_TBNZ 0x7F000000u +#define MASK_HINT 0xFFFFF01F +#define MASK_IGNORE 0x0 + +static inst_mask_t masks[] = { + MASK_B, MASK_BC, MASK_BL, MASK_ADR, + MASK_ADRP, MASK_LDR_32, MASK_LDR_64, MASK_LDRSW_LIT, + MASK_PRFM_LIT, MASK_LDR_SIMD_32, MASK_LDR_SIMD_64, MASK_LDR_SIMD_128, + MASK_CBZ, MASK_CBNZ, MASK_TBZ, MASK_TBNZ, + MASK_IGNORE, +}; +static inst_type_t types[] = { + INST_B, INST_BC, INST_BL, INST_ADR, + INST_ADRP, INST_LDR_32, INST_LDR_64, INST_LDRSW_LIT, + INST_PRFM_LIT, INST_LDR_SIMD_32, INST_LDR_SIMD_64, INST_LDR_SIMD_128, + INST_CBZ, INST_CBNZ, INST_TBZ, INST_TBNZ, + INST_IGNORE, +}; + +static int32_t relo_len[] = { + 6, 8, 8, 4, 4, 6, 6, 6, 8, 8, 8, 8, 6, 6, 6, 6, 2 +}; + +// static uint64_t sign_extend(uint64_t x, uint32_t len) +// { +// char sign_bit = bit(x, len - 1); +// unsigned long sign_mask = 0 - sign_bit; +// x |= ((sign_mask >> len) << len); +// return x; +// } + +static int is_in_tramp(hook_t *hook, uint64_t addr) +{ + uint64_t tramp_start = hook->origin_addr; + uint64_t tramp_end = tramp_start + hook->tramp_insts_num * 4; + if (addr >= tramp_start && addr < tramp_end) { + return 1; + } + return 0; +} + +static uint64_t relo_in_tramp(hook_t *hook, uint64_t addr) +{ + uint64_t tramp_start = hook->origin_addr; + uint64_t tramp_end = tramp_start + hook->tramp_insts_num * 4; + if (!(addr >= tramp_start && addr < tramp_end)) + return addr; + uint32_t addr_inst_index = (addr - tramp_start) / 4; + uint64_t fix_addr = hook->relo_addr; + for (int i = 0; i < addr_inst_index; i++) { + inst_type_t inst = hook->origin_insts[i]; + for (int j = 0; j < sizeof(relo_len) / sizeof(relo_len[0]); j++) { + if ((inst & masks[j]) == types[j]) { + fix_addr += relo_len[j] * 4; + break; + } + } + } + return fix_addr; +} + +#ifdef HOOK_INTO_BRANCH_FUNC + +#endif + +static hook_err_t relo_b(hook_t *hook, uint64_t inst_addr, uint32_t inst, + inst_type_t type) +{ + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; + uint64_t imm64; + if (type == INST_BC) { + uint64_t imm19 = bits32(inst, 23, 5); + imm64 = sign64_extend(imm19 << 2u, 21u); + } else { + uint64_t imm26 = bits32(inst, 25, 0); + imm64 = sign64_extend(imm26 << 2u, 28u); + } + uint64_t addr = inst_addr + imm64; + addr = relo_in_tramp(hook, addr); + + uint32_t idx = 0; + if (type == INST_BC) { + buf[idx++] = (inst & 0xFF00001F) | 0x40u; // B. #8 + buf[idx++] = 0x14000006; // B #24 + } + buf[idx++] = 0x58000051; // LDR X17, #8 + buf[idx++] = 0x14000003; // B #12 + buf[idx++] = addr & 0xFFFFFFFF; + buf[idx++] = addr >> 32u; + if (type == INST_BL) { + buf[idx++] = 0x1000001E; // ADR X30, . + buf[idx++] = 0x910033DE; // ADD X30, X30, #12 + buf[idx++] = 0xD65F0220; // RET X17 + } else { + buf[idx++] = 0xD65F0220; // RET X17 + } + buf[idx++] = ARM64_NOP; + return HOOK_NO_ERR; +} + +static hook_err_t relo_adr(hook_t *hook, uint64_t inst_addr, uint32_t inst, + inst_type_t type) +{ + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; + + uint32_t xd = bits32(inst, 4, 0); + uint64_t immlo = bits32(inst, 30, 29); + uint64_t immhi = bits32(inst, 23, 5); + uint64_t addr; + + if (type == INST_ADR) { + addr = inst_addr + sign64_extend((immhi << 2u) | immlo, 21u); + } else { + addr = + (inst_addr + sign64_extend((immhi << 14u) | (immlo << 12u), 33u)) & + 0xFFFFFFFFFFFFF000; + if (is_in_tramp(hook, addr)) + return -HOOK_BAD_RELO; + } + buf[0] = 0x58000040u | xd; // LDR Xd, #8 + buf[1] = 0x14000003; // B #12 + buf[2] = addr & 0xFFFFFFFF; + buf[3] = addr >> 32u; + return HOOK_NO_ERR; +} + +static hook_err_t relo_ldr(hook_t *hook, uint64_t inst_addr, uint32_t inst, + inst_type_t type) +{ + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; + + uint32_t rt = bits32(inst, 4, 0); + uint64_t imm19 = bits32(inst, 23, 5); + uint64_t offset = sign64_extend((imm19 << 2u), 21u); + uint64_t addr = inst_addr + offset; + + if (is_in_tramp(hook, addr) && type != INST_PRFM_LIT) + return -HOOK_BAD_RELO; + + addr = relo_in_tramp(hook, addr); + + if (type == INST_LDR_32 || type == INST_LDR_64 || type == INST_LDRSW_LIT) { + buf[0] = 0x58000060u | rt; // LDR Xt, #12 + if (type == INST_LDR_32) { + buf[1] = 0xB9400000 | rt | (rt << 5u); // LDR Wt, [Xt] + } else if (type == INST_LDR_64) { + buf[1] = 0xF9400000 | rt | (rt << 5u); // LDR Xt, [Xt] + } else { + // LDRSW_LIT + buf[1] = 0xB9800000 | rt | (rt << 5u); // LDRSW Xt, [Xt] + } + buf[2] = 0x14000004; // B #16 + buf[3] = ARM64_NOP; + buf[4] = addr & 0xFFFFFFFF; + buf[5] = addr >> 32u; + } else { + buf[0] = 0xA93F47F0; // STP X16, X17, [SP, -0x10] + buf[1] = 0x58000091; // LDR X17, #16 + if (type == INST_PRFM_LIT) { + buf[2] = 0xF9800220 | rt; // PRFM Rt, [X17] + } else if (type == INST_LDR_SIMD_32) { + buf[2] = 0xBD400220 | rt; // LDR St, [X17] + } else if (type == INST_LDR_SIMD_64) { + buf[2] = 0xFD400220 | rt; // LDR Dt, [X17] + } else { + // LDR_SIMD_128 + buf[2] = 0x3DC00220u | rt; // LDR Qt, [X17] + } + buf[3] = 0xF85F83F1; // LDR X17, [SP, -0x8] + buf[4] = 0x14000004; // B #16 + buf[5] = ARM64_NOP; + buf[6] = addr & 0xFFFFFFFF; + buf[7] = addr >> 32u; + } + return HOOK_NO_ERR; +} + +static hook_err_t relo_cb(hook_t *hook, uint64_t inst_addr, uint32_t inst, + inst_type_t type) +{ + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; + + uint64_t imm19 = bits32(inst, 23, 5); + uint64_t offset = sign64_extend((imm19 << 2u), 21u); + uint64_t addr = inst_addr + offset; + addr = relo_in_tramp(hook, addr); + + buf[0] = (inst & 0xFF00001F) | 0x40u; // CB(N)Z Rt, #8 + buf[1] = 0x14000005; // B #20 + buf[2] = 0x58000051; // LDR X17, #8 + buf[3] = 0xD65F0220; // RET X17 + buf[4] = addr & 0xFFFFFFFF; + buf[5] = addr >> 32u; + return HOOK_NO_ERR; +} + +static hook_err_t relo_tb(hook_t *hook, uint64_t inst_addr, uint32_t inst, + inst_type_t type) +{ + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; + + uint64_t imm14 = bits32(inst, 18, 5); + uint64_t offset = sign64_extend((imm14 << 2u), 16u); + uint64_t addr = inst_addr + offset; + addr = relo_in_tramp(hook, addr); + + buf[0] = (inst & 0xFFF8001F) | 0x40u; // TB(N)Z Rt, #, #8 + buf[1] = 0x14000005; // B #20 + buf[2] = 0x58000051; // LDR X17, #8 + buf[3] = 0xd65f0220; // RET X17 + buf[4] = addr & 0xFFFFFFFF; + buf[5] = addr >> 32u; + return HOOK_NO_ERR; +} + +static hook_err_t relo_ignore(hook_t *hook, uint64_t inst_addr, uint32_t inst, + inst_type_t type) +{ + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; + buf[0] = inst; + buf[1] = ARM64_NOP; + return HOOK_NO_ERR; +} + +static uint32_t can_b_rel(uint64_t src_addr, uint64_t dst_addr) +{ +#define B_REL_RANGE ((1 << 25) << 2) + return ((dst_addr >= src_addr) && (dst_addr - src_addr <= B_REL_RANGE)) || + ((src_addr >= dst_addr) && (src_addr - dst_addr <= B_REL_RANGE)); +} + +int32_t branch_relative(uint32_t *buf, uint64_t src_addr, uint64_t dst_addr) +{ + if (can_b_rel(src_addr, dst_addr)) { + buf[0] = 0x14000000u | + (((dst_addr - src_addr) & 0x0FFFFFFFu) >> 2u); // B