From 221a3d550c4b6e542b452fc7c7408a027d3d600e Mon Sep 17 00:00:00 2001 From: bmax121 Date: Thu, 16 May 2024 19:02:08 +0800 Subject: [PATCH] 1. kpatch is deprecated, instead is supercmd 2. hook imporvoed 3. add thread local interface for module 4. doc (#91) Co-authored-by: bmax --- .github/workflows/build.yml | 29 +- .github/workflows/build_dev.yml | 28 +- doc/.gitignore | 1 + doxyfile | 18 + kernel/base/fphook.c | 11 +- kernel/base/hook.c | 84 ++- kernel/{patch/common => base}/hotpatch.c | 4 + kernel/base/map.c | 2 +- kernel/base/setup.h | 1 + kernel/base/start.c | 46 +- kernel/base/symbol.c | 7 +- kernel/include/hook.h | 116 ++- kernel/include/hotpatch.h | 13 + kernel/include/predata.h | 2 +- kernel/include/preset.h | 9 - kernel/include/stdbool.h | 3 +- kernel/include/symbol.h | 8 +- .../linux/arch/arm64/include/asm/processor.h | 2 - kernel/linux/include/linux/cred.h | 7 +- kernel/linux/include/linux/fs.h | 1 - kernel/linux/include/linux/security.h | 11 +- kernel/linux/include/linux/string.h | 24 +- kernel/linux/include/linux/uaccess.h | 2 - kernel/patch/android/supercall.c | 85 --- kernel/patch/android/userd.c | 82 +- kernel/patch/common/accctl.c | 173 ++++- .../{selinuxhook.c => selinuxhook.c.bak} | 24 +- kernel/patch/{android => common}/sucompat.c | 411 +++------- kernel/patch/common/supercall.c | 140 +++- kernel/patch/common/supercmd.c | 405 ++++++++++ kernel/patch/common/syscall.c | 79 +- kernel/patch/common/sysname.c | 712 ++++++++++++++++++ kernel/patch/common/taskob.c | 57 +- kernel/patch/common/test.c | 17 + kernel/patch/common/utils.c | 23 +- kernel/patch/include/accctl.h | 41 +- kernel/patch/include/kputils.h | 4 +- kernel/patch/include/module.h | 2 - kernel/patch/include/sucompat.h | 8 + kernel/patch/include/syscall.h | 71 +- kernel/patch/include/taskext.h | 83 +- kernel/patch/include/uapi/scdefs.h | 46 +- kernel/patch/ksyms/execv.c | 10 +- kernel/patch/ksyms/libs.c | 13 +- kernel/patch/ksyms/misc.c | 19 +- kernel/patch/module/module.c | 11 +- kernel/patch/patch.c | 82 +- kernel/patch/patch.h | 6 - kpms/demo-syscallhook/syscallhook.c | 7 +- tools/kptools.c | 11 +- tools/patch.c | 15 +- tools/patch.h | 3 +- tools/symbol.c | 21 - user/.gitignore | 40 +- user/supercall.h | 335 ++++++-- user_deprecated/.gitignore | 39 + {user => user_deprecated}/CMakeLists.txt | 0 {user => user_deprecated}/Makefile | 0 .../android/android_user.c | 8 +- .../android/android_user.h | 0 {user => user_deprecated}/android/apjni.cpp | 0 {user => user_deprecated}/android/sumgr.c | 2 +- {user => user_deprecated}/android/sumgr.h | 0 {user => user_deprecated}/kpatch.c | 0 {user => user_deprecated}/kpatch.h | 0 {user => user_deprecated}/kpm.c | 0 {user => user_deprecated}/kpm.h | 0 {user => user_deprecated}/main.c | 0 {user => user_deprecated}/su.c | 4 +- {user => user_deprecated}/su.h | 0 user_deprecated/supercall.h | 411 ++++++++++ {user => user_deprecated}/supercall_ge0a04.h | 17 +- version | 4 +- 73 files changed, 2905 insertions(+), 1045 deletions(-) create mode 100644 doc/.gitignore create mode 100644 doxyfile rename kernel/{patch/common => base}/hotpatch.c (97%) create mode 100644 kernel/include/hotpatch.h delete mode 100644 kernel/patch/android/supercall.c rename kernel/patch/common/{selinuxhook.c => selinuxhook.c.bak} (94%) rename kernel/patch/{android => common}/sucompat.c (50%) create mode 100644 kernel/patch/common/supercmd.c create mode 100644 kernel/patch/common/sysname.c create mode 100644 kernel/patch/common/test.c delete mode 100644 kernel/patch/patch.h create mode 100644 user_deprecated/.gitignore rename {user => user_deprecated}/CMakeLists.txt (100%) rename {user => user_deprecated}/Makefile (100%) rename {user => user_deprecated}/android/android_user.c (97%) rename {user => user_deprecated}/android/android_user.h (100%) rename {user => user_deprecated}/android/apjni.cpp (100%) rename {user => user_deprecated}/android/sumgr.c (98%) rename {user => user_deprecated}/android/sumgr.h (100%) rename {user => user_deprecated}/kpatch.c (100%) rename {user => user_deprecated}/kpatch.h (100%) rename {user => user_deprecated}/kpm.c (100%) rename {user => user_deprecated}/kpm.h (100%) rename {user => user_deprecated}/main.c (100%) rename {user => user_deprecated}/su.c (99%) rename {user => user_deprecated}/su.h (100%) create mode 100644 user_deprecated/supercall.h rename {user => user_deprecated}/supercall_ge0a04.h (95%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 54be42af..2de32c87 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,17 +38,19 @@ jobs: - name: Build kpimg run: | export TARGET_COMPILE=`pwd`/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf/bin/aarch64-none-elf- - cd kernel - make - mv kpimg kpimg-linux - mv kpimg.elf kpimg.elf-linux - make clean + export ANDROID=1 make mv kpimg kpimg-android mv kpimg.elf kpimg.elf-android + unset ANDROID + make + mv kpimg kpimg-linux + mv kpimg.elf kpimg.elf-linux + make clean + cd .. cd kpms @@ -125,7 +127,7 @@ jobs: replacesArtifacts: true omitBodyDuringUpdate: true - Build-android-kpatch-kptools: + Build-android-kptools: runs-on: ubuntu-latest permissions: contents: write @@ -158,21 +160,6 @@ jobs: cd kernel make hdr - - name: Build kpatch-android - run: | - cd user - export ANDROID=1 - mkdir -p build/android && cd build/android - echo ${{ steps.setup-ndk.outputs.ndk-path }} - cmake \ - -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup-ndk.outputs.ndk-path }}/build/cmake/android.toolchain.cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DANDROID_PLATFORM=android-33 \ - -DANDROID_ABI=arm64-v8a ../.. - cmake --build . - unset ANDROID - mv kpatch kpatch-android - - name: Build kptools-android run: | cd tools diff --git a/.github/workflows/build_dev.yml b/.github/workflows/build_dev.yml index 725be0df..c99057c7 100644 --- a/.github/workflows/build_dev.yml +++ b/.github/workflows/build_dev.yml @@ -48,15 +48,18 @@ jobs: run: | export TARGET_COMPILE=`pwd`/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf/bin/aarch64-none-elf- cd kernel - make - mv kpimg kpimg-linux - mv kpimg.elf kpimg.elf-linux - make clean + export ANDROID=1 make mv kpimg kpimg-android mv kpimg.elf kpimg.elf-android + unset ANDROID + make + mv kpimg kpimg-linux + mv kpimg.elf kpimg.elf-linux + make clean + cd .. cd kpms @@ -134,7 +137,7 @@ jobs: replacesArtifacts: true prerelease: true - Build-android-kpatch-kptools: + Build-android-kptools: runs-on: ubuntu-latest permissions: contents: write @@ -167,21 +170,6 @@ jobs: cd kernel make hdr - - name: Build kpatch-android - run: | - cd user - export ANDROID=1 - mkdir -p build/android && cd build/android - echo ${{ steps.setup-ndk.outputs.ndk-path }} - cmake \ - -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup-ndk.outputs.ndk-path }}/build/cmake/android.toolchain.cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DANDROID_PLATFORM=android-33 \ - -DANDROID_ABI=arm64-v8a ../.. - cmake --build . - unset ANDROID - mv kpatch kpatch-android - - name: Build kptools-android run: | cd tools diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 00000000..9e5bfb42 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +api \ No newline at end of file diff --git a/doxyfile b/doxyfile new file mode 100644 index 00000000..af3a3966 --- /dev/null +++ b/doxyfile @@ -0,0 +1,18 @@ +PROJECT_NAME = "KernelPatch Document" +OUTPUT_DIRECTORY = ./doc/api + +INPUT = \ + ./user/supercall.h \ + ./kernel/include/hook.h \ + ./kernel/patch/include/accctl.h \ + ./kernel/patch/include/taskext.h \ + ./kernel/patch/include/uapi/scdefs.h \ + +FILE_PATTERNS = *.h *.md + +RECURSIVE = YES +GENERATE_LATEX = NO +SOURCE_BROWSER = YES +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES diff --git a/kernel/base/fphook.c b/kernel/base/fphook.c index 6f8bba4d..620bdf29 100644 --- a/kernel/base/fphook.c +++ b/kernel/base/fphook.c @@ -19,6 +19,7 @@ uint64_t __attribute__((section(".fp.transit0.text"))) __attribute__((__noinline uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); hook_fargs0_t fargs; fargs.skip_origin = 0; @@ -52,6 +53,7 @@ _fp_transit4(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); hook_fargs4_t fargs; fargs.skip_origin = 0; @@ -91,6 +93,7 @@ _fp_transit8(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_ uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); hook_fargs8_t fargs; fargs.skip_origin = 0; @@ -136,6 +139,7 @@ _fp_transit12(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64 uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); hook_fargs12_t fargs; fargs.skip_origin = 0; @@ -205,9 +209,10 @@ static hook_err_t hook_chain_prepare(uint32_t *transit, int32_t argno) // todo: assert if (transit_num >= TRANSIT_INST_NUM) return -HOOK_TRANSIT_NO_MEM; - transit[0] = ARM64_NOP; + transit[0] = ARM64_BTI_JC; + transit[1] = ARM64_NOP; for (int i = 0; i < transit_num; i++) { - transit[i + 1] = ((uint32_t *)transit_start)[i]; + transit[i + 2] = ((uint32_t *)transit_start)[i]; } return HOOK_NO_ERR; } @@ -258,6 +263,8 @@ hook_err_t fp_hook_wrap(uintptr_t fp_addr, int32_t argno, void *before, void *af } for (int i = 0; i < FP_HOOK_CHAIN_NUM; i++) { + if ((before && chain->befores[i] == before) || (after && chain->afters[i] == after)) return -HOOK_DUPLICATED; + // todo: atomic or lock if (chain->states[i] == CHAIN_ITEM_STATE_EMPTY) { chain->states[i] = CHAIN_ITEM_STATE_BUSY; diff --git a/kernel/base/hook.c b/kernel/base/hook.c index 049a6931..3bf0cab4 100644 --- a/kernel/base/hook.c +++ b/kernel/base/hook.c @@ -82,7 +82,7 @@ static int32_t relo_len[] = { 6, 8, 6, 4, 4, 6, 6, 6, 8, 8, 8, 8, 6, 6, 6, 6, 2 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_len * 4; + uint64_t tramp_end = tramp_start + hook->tramp_insts_num * 4; if (addr >= tramp_start && addr < tramp_end) { return 1; } @@ -92,7 +92,7 @@ static int is_in_tramp(hook_t *hook, uint64_t addr) 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_len * 4; + 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; @@ -118,14 +118,9 @@ static uint64_t branch_func_addr_once(uint64_t addr) uint64_t imm26 = bits32(inst, 25, 0); uint64_t imm64 = sign64_extend(imm26 << 2u, 28u); ret = addr + imm64; + } else if (inst == ARM64_BTI_C || inst == ARM64_BTI_J || inst == ARM64_BTI_JC) { + ret = addr + 4; } else { - addr += 4; - uint32_t inst1 = *(uint32_t *)addr; - if (((inst & MASK_HINT) == INST_HINT) && ((inst1 & MASK_B) == INST_B)) { - uint64_t imm26 = bits32(inst1, 25, 0); - uint64_t imm64 = sign64_extend(imm26 << 2u, 28u); - ret = addr + imm64; - } } return ret; } @@ -143,9 +138,9 @@ uint64_t branch_func_addr(uint64_t addr) #endif -hook_err_t relo_b(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t type) +static __noinline 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_len; + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; uint64_t imm64; if (type == INST_BC) { uint64_t imm19 = bits32(inst, 23, 5); @@ -175,9 +170,9 @@ hook_err_t relo_b(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t t return HOOK_NO_ERR; } -hook_err_t relo_adr(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t type) +static __noinline 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_len; + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; uint32_t xd = bits32(inst, 4, 0); uint64_t immlo = bits32(inst, 30, 29); @@ -197,9 +192,9 @@ hook_err_t relo_adr(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t return HOOK_NO_ERR; } -hook_err_t relo_ldr(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t type) +static __noinline 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_len; + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; uint32_t rt = bits32(inst, 4, 0); uint64_t imm19 = bits32(inst, 23, 5); @@ -246,9 +241,9 @@ hook_err_t relo_ldr(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t return HOOK_NO_ERR; } -hook_err_t relo_cb(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t type) +static __noinline 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_len; + 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); @@ -264,9 +259,9 @@ hook_err_t relo_cb(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t return HOOK_NO_ERR; } -hook_err_t relo_tb(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t type) +static __noinline 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_len; + 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); @@ -282,9 +277,9 @@ hook_err_t relo_tb(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t return HOOK_NO_ERR; } -hook_err_t relo_ignore(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t type) +static __noinline 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_len; + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; buf[0] = inst; buf[1] = ARM64_NOP; return HOOK_NO_ERR; @@ -333,11 +328,14 @@ int32_t branch_from_to(uint32_t *tramp_buf, uint64_t src_addr, uint64_t dst_addr #if 0 uint32_t len = branch_relative(tramp_buf, src_addr, dst_addr); if (len) return len; -#endif - // return branch_absolute(tramp_buf, dst_addr); +#else +#if 0 + return branch_absolute(tramp_buf, dst_addr); +#else return ret_absolute(tramp_buf, dst_addr); +#endif +#endif } -KP_EXPORT_SYMBOL(branch_from_to); // transit0 typedef uint64_t (*transit0_func_t)(); @@ -349,6 +347,7 @@ uint64_t __attribute__((section(".transit0.text"))) __attribute__((__noinline__) uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, hook_chain_t, transit); hook_fargs0_t fargs; fargs.skip_origin = 0; @@ -382,6 +381,7 @@ _transit4(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, hook_chain_t, transit); hook_fargs4_t fargs; fargs.skip_origin = 0; @@ -421,6 +421,7 @@ _transit8(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t a uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, hook_chain_t, transit); hook_fargs8_t fargs; fargs.skip_origin = 0; @@ -466,6 +467,7 @@ _transit12(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t uint32_t *vptr = (uint32_t *)this_va; while (*--vptr != ARM64_NOP) { }; + vptr--; hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, hook_chain_t, transit); hook_fargs12_t fargs; fargs.skip_origin = 0; @@ -549,7 +551,7 @@ static __noinline hook_err_t relocate_inst(hook_t *hook, uint64_t inst_addr, uin break; } - hook->relo_insts_len += len; + hook->relo_insts_num += len; return rc; } @@ -566,14 +568,19 @@ hook_err_t hook_prepare(hook_t *hook) hook->origin_insts[i] = *((uint32_t *)hook->origin_addr + i); } // trampline to replace_addr - hook->tramp_insts_len = branch_from_to(hook->tramp_insts, hook->origin_addr, hook->replace_addr); + hook->tramp_insts_num = branch_from_to(hook->tramp_insts, hook->origin_addr, hook->replace_addr); // relocate for (int i = 0; i < sizeof(hook->relo_insts) / sizeof(hook->relo_insts[0]); i++) { hook->relo_insts[i] = ARM64_NOP; } - for (int i = 0; i < hook->tramp_insts_len; i++) { + uint32_t *bti = hook->relo_insts + hook->relo_insts_num; + bti[0] = ARM64_BTI_JC; + bti[1] = ARM64_NOP; + hook->relo_insts_num += 2; + + for (int i = 0; i < hook->tramp_insts_num; i++) { uint64_t inst_addr = hook->origin_addr + i * 4; uint32_t inst = hook->origin_insts[i]; hook_err_t relo_res = relocate_inst(hook, inst_addr, inst); @@ -583,10 +590,10 @@ hook_err_t hook_prepare(hook_t *hook) } // jump back - uint64_t back_src_addr = hook->relo_addr + hook->relo_insts_len * 4; - uint64_t back_dst_addr = hook->origin_addr + hook->tramp_insts_len * 4; - uint32_t *buf = hook->relo_insts + hook->relo_insts_len; - hook->relo_insts_len += branch_from_to(buf, back_src_addr, back_dst_addr); + uint64_t back_src_addr = hook->relo_addr + hook->relo_insts_num * 4; + uint64_t back_dst_addr = hook->origin_addr + hook->tramp_insts_num * 4; + uint32_t *buf = hook->relo_insts + hook->relo_insts_num; + hook->relo_insts_num += branch_from_to(buf, back_src_addr, back_dst_addr); return HOOK_NO_ERR; } KP_EXPORT_SYMBOL(hook_prepare); @@ -597,11 +604,11 @@ void hook_install(hook_t *hook) uint64_t va = hook->origin_addr; uint64_t *entry = pgtable_entry_kernel(va); uint64_t ori_prot = *entry; - *entry = (ori_prot | PTE_DBM) & ~PTE_RDONLY & 0xFFFBFFFFFFFFFFFF; + *entry = (ori_prot | PTE_DBM) & ~PTE_RDONLY; flush_tlb_kernel_page(va); - // todo: + // todo: cpu_stop_machine // todo: can use aarch64_insn_patch_text_nosync, aarch64_insn_patch_text directly? - for (int32_t i = 0; i < hook->tramp_insts_len; i++) { + for (int32_t i = 0; i < hook->tramp_insts_num; i++) { *((uint32_t *)hook->origin_addr + i) = hook->tramp_insts[i]; } flush_icache_all(); @@ -617,7 +624,7 @@ void hook_uninstall(hook_t *hook) uint64_t ori_prot = *entry; *entry = (ori_prot | PTE_DBM) & ~PTE_RDONLY; flush_tlb_kernel_page(va); - for (int32_t i = 0; i < hook->tramp_insts_len; i++) { + for (int32_t i = 0; i < hook->tramp_insts_num; i++) { *((uint32_t *)hook->origin_addr + i) = hook->origin_insts[i]; } flush_icache_all(); @@ -697,9 +704,10 @@ static hook_err_t hook_chain_prepare(uint32_t *transit, int32_t argno) // todo:assert if (transit_num >= TRANSIT_INST_NUM) return -HOOK_TRANSIT_NO_MEM; - transit[0] = ARM64_NOP; + transit[0] = ARM64_BTI_JC; + transit[1] = ARM64_NOP; for (int i = 0; i < transit_num; i++) { - transit[i + 1] = ((uint32_t *)transit_start)[i]; + transit[i + 2] = ((uint32_t *)transit_start)[i]; } return HOOK_NO_ERR; } @@ -707,6 +715,8 @@ static hook_err_t hook_chain_prepare(uint32_t *transit, int32_t argno) hook_err_t hook_chain_add(hook_chain_t *chain, void *before, void *after, void *udata) { for (int i = 0; i < HOOK_CHAIN_NUM; i++) { + if ((before && chain->befores[i] == before) || (after && chain->afters[i] == after)) return -HOOK_DUPLICATED; + // todo: atomic or lock if (chain->states[i] == CHAIN_ITEM_STATE_EMPTY) { chain->states[i] = CHAIN_ITEM_STATE_BUSY; diff --git a/kernel/patch/common/hotpatch.c b/kernel/base/hotpatch.c similarity index 97% rename from kernel/patch/common/hotpatch.c rename to kernel/base/hotpatch.c index 0cc30405..356b3901 100644 --- a/kernel/patch/common/hotpatch.c +++ b/kernel/base/hotpatch.c @@ -84,3 +84,7 @@ int hot_patch_text() // logkd("stop_machine rc: %d\n", rc); return 0; } + +int kp_insn_patch_text(void *addrs[], uint32_t insn[], int cnt) +{ +} \ No newline at end of file diff --git a/kernel/base/map.c b/kernel/base/map.c index 6e669a26..97898041 100644 --- a/kernel/base/map.c +++ b/kernel/base/map.c @@ -126,7 +126,7 @@ static uint64_t __noinline get_or_create_pte(map_data_t *data, uint64_t va, uint uint64_t baddr = ttbr1_el1 & 0xFFFFFFFFFFFE; uint64_t page_size = 1 << page_shift; uint64_t page_size_mask = ~(page_size - 1); - uint64_t attr_prot = 0xC0000000000703 | attr_indx; + uint64_t attr_prot = 0x40000000000703 | attr_indx; uint64_t pxd_pa = baddr & page_size_mask; uint64_t pxd_va = phys_to_lm(data, pxd_pa); diff --git a/kernel/base/setup.h b/kernel/base/setup.h index e17e1c79..c5de937e 100644 --- a/kernel/base/setup.h +++ b/kernel/base/setup.h @@ -17,6 +17,7 @@ #define __section(s) __attribute__((section(#s))) #define __noinline __attribute__((__noinline__)) #define __aligned(x) __attribute__((aligned(x))) +#define __bti_c __attribute__((target("branch-protection=bti"))) #endif diff --git a/kernel/base/start.c b/kernel/base/start.c index 4a901b84..cb03cfbc 100644 --- a/kernel/base/start.c +++ b/kernel/base/start.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -20,6 +19,7 @@ #include "hook.h" #include "tlsf.h" #include "hmem.h" +#include "setup.h" #define bits(n, high, low) (((n) << (63u - (high))) >> (63u - (high) + (low))) #define align_floor(x, align) ((uint64_t)(x) & ~((uint64_t)(align)-1)) @@ -41,7 +41,7 @@ KP_EXPORT_SYMBOL(lookup_symbol_attrs); void (*printk)(const char *fmt, ...) = 0; KP_EXPORT_SYMBOL(printk); -int (*vsprintf)(char *buf, const char *fmt, va_list args) = 0; +int (*vsnprintf)(char *buf, size_t size, const char *fmt, va_list args); static struct vm_struct { @@ -78,6 +78,9 @@ uint64_t _kp_rw_end = 0; uint64_t _kp_region_start = 0; uint64_t _kp_region_end = 0; +uint64_t link_base_addr = (uint64_t)_link_base; +uint64_t runtime_base_addr = 0; + uint64_t kimage_voffset = 0; uint64_t linear_voffset = 0; uint64_t kernel_va = 0; @@ -116,7 +119,7 @@ void log_boot(const char *fmt, ...) { va_list va; va_start(va, fmt); - int ret = vsprintf(boot_log + boot_log_offset, fmt, va); + int ret = vsnprintf(boot_log + boot_log_offset, sizeof(boot_log) - boot_log_offset, fmt, va); va_end(va); printk("KP %s", boot_log + boot_log_offset); boot_log_offset += ret; @@ -178,7 +181,8 @@ static void prot_myself() log_boot("Kernel stext prot: %llx\n", *kpte); _kp_region_start = (uint64_t)_kp_text_start; - _kp_region_end = (uint64_t)_kp_end + HOOK_ALLOC_SIZE + MEMORY_ROX_SIZE + MEMORY_RW_SIZE; + _kp_region_end = (uint64_t)_kp_end + align_ceil(start_preset.extra_size, page_size) + HOOK_ALLOC_SIZE + + MEMORY_ROX_SIZE + MEMORY_RW_SIZE; log_boot("Region: %llx, %llx\n", _kp_region_start, _kp_region_end); uint64_t *kppte = pgtable_entry_kernel(_kp_region_start); @@ -192,11 +196,9 @@ static void prot_myself() for (uint64_t i = text_start; i < align_text_end; i += page_size) { uint64_t *pte = pgtable_entry_kernel(i); - *pte |= PTE_SHARED; - *pte = *pte & ~PTE_PXN; + *pte = (*pte | PTE_SHARED) & ~PTE_PXN & ~PTE_GP; if (has_vmalloc_area()) { - *pte |= PTE_RDONLY; - *pte &= ~PTE_DBM; + *pte = (*pte | PTE_RDONLY) & ~PTE_DBM; } } flush_tlb_kernel_range(text_start, align_text_end); @@ -238,7 +240,7 @@ static void prot_myself() for (uint64_t i = _kp_hook_start; i < _kp_hook_end; i += page_size) { uint64_t *pte = pgtable_entry_kernel(i); - *pte = (*pte & ~PTE_PXN & ~PTE_RDONLY) | PTE_DBM | PTE_SHARED; + *pte = (*pte | PTE_DBM | PTE_SHARED) & ~PTE_PXN & ~PTE_RDONLY & ~PTE_GP; } flush_tlb_kernel_range(_kp_hook_start, _kp_hook_end); hook_mem_add(_kp_hook_start, HOOK_ALLOC_SIZE); @@ -270,8 +272,7 @@ static void prot_myself() for (uint64_t i = _kp_rox_start; i < _kp_rox_end; i += page_size) { uint64_t *pte = pgtable_entry_kernel(i); - *pte |= PTE_SHARED; - *pte = *pte & ~PTE_PXN; + *pte = (*pte | PTE_SHARED) & ~PTE_PXN & ~PTE_GP; // todo: tlsf malloc block_split will write to alloced memory // if (has_vmalloc_area()) { // *pte |= PTE_RDONLY; @@ -382,6 +383,7 @@ static void start_init(uint64_t kimage_voff, uint64_t linear_voff) kernel_pa = start_preset.kernel_pa; kernel_va = kimage_voff + kernel_pa; kernel_size = start_preset.kernel_size; + runtime_base_addr = (uint64_t)_link_base; uint64_t kallsym_addr = kernel_va + start_preset.kallsyms_lookup_name_offset; kallsyms_lookup_name = (typeof(kallsyms_lookup_name))(kallsym_addr); @@ -389,7 +391,7 @@ static void start_init(uint64_t kimage_voff, uint64_t linear_voff) printk = (typeof(printk))kallsyms_lookup_name("printk"); if (!printk) printk = (typeof(printk))kallsyms_lookup_name("_printk"); - vsprintf = (typeof(vsprintf))kallsyms_lookup_name("vsprintf"); + vsnprintf = (typeof(vsnprintf))kallsyms_lookup_name("vsnprintf"); log_boot(KERNEL_PATCH_BANNER); @@ -403,9 +405,11 @@ static void start_init(uint64_t kimage_voff, uint64_t linear_voff) log_boot("Kernel va: %llx\n", kernel_va); log_boot("Kernel Version: %x\n", kver); - log_boot("Kernel Patch Version: %x\n", kpver); - log_boot("Kernel Patch Config: %llx\n", header->config_flags); - log_boot("Kernel Patch Compile Time: %s\n", (uint64_t)header->compile_time); + log_boot("KernelPatch Version: %x\n", kpver); + log_boot("KernelPatch Config: %llx\n", header->config_flags); + log_boot("KernelPatch Compile Time: %s\n", (uint64_t)header->compile_time); + + log_boot("KernelPatch link base: %llx, runtime base: %llx\n", link_base_addr, runtime_base_addr); kallsyms_on_each_symbol = (typeof(kallsyms_on_each_symbol))kallsyms_lookup_name("kallsyms_on_each_symbol"); lookup_symbol_attrs = (typeof(lookup_symbol_attrs))kallsyms_lookup_name("lookup_symbol_attrs"); @@ -434,14 +438,8 @@ static void start_init(uint64_t kimage_voff, uint64_t linear_voff) pgd_va = phys_to_virt(pgd_pa); } -static int nice_zone() -{ - int err = 0; - - err = patch(); - - return err; -} +void symbol_init(); +int patch(); int __attribute__((section(".start.text"))) __noinline start(uint64_t kimage_voff, uint64_t linear_voff) { @@ -452,6 +450,6 @@ int __attribute__((section(".start.text"))) __noinline start(uint64_t kimage_vof log_regs(); predata_init(); symbol_init(); - rc = nice_zone(); + rc = patch(); return rc; } diff --git a/kernel/base/symbol.c b/kernel/base/symbol.c index 0f2c9ca5..e34b7dca 100644 --- a/kernel/base/symbol.c +++ b/kernel/base/symbol.c @@ -14,8 +14,6 @@ extern void _kp_symbol_start(); extern void _kp_symbol_end(); static uint64_t symbol_start = 0; static uint64_t symbol_end = 0; -static unsigned long link_base_addr = (unsigned long)_link_base; -static unsigned long runtime_base_addr = 0; // DJB2 static unsigned long sym_hash(const char *str) @@ -53,17 +51,14 @@ unsigned long symbol_lookup_name(const char *name) return 0; } -int symbol_init() +void symbol_init() { - runtime_base_addr = (unsigned long)_link_base; symbol_start = (uint64_t)_kp_symbol_start; symbol_end = (uint64_t)_kp_symbol_end; log_boot("Symbol: %llx, %llx\n", symbol_start, symbol_end); - log_boot("Symbol link: %llx, runtime: %llx\n", link_base_addr, runtime_base_addr); for (uint64_t addr = symbol_start; addr < symbol_end; addr += sizeof(kp_symbol_t)) { kp_symbol_t *symbol = (kp_symbol_t *)addr; symbol->addr = symbol->addr - link_base_addr + runtime_base_addr; symbol->hash = sym_hash(symbol->name); } - return 0; } \ No newline at end of file diff --git a/kernel/include/hook.h b/kernel/include/hook.h index 0d028c41..d29cbd87 100644 --- a/kernel/include/hook.h +++ b/kernel/include/hook.h @@ -14,13 +14,12 @@ typedef enum { HOOK_NO_ERR = 0, - HOOK_BAD_ADDRESS = 4089, - HOOK_NO_MEM = 4090, - HOOK_BAD_RELO = 4091, - HOOK_TRANSIT_NO_MEM = 4092, - HOOK_CHAIN_FULL = 4093, - HOOK_NOT_HOOK = 4094, - HOOK_INST_BUSY = 4095, + 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; enum hook_type @@ -50,6 +49,9 @@ typedef int8_t chain_item_state; #define FP_HOOK_CHAIN_NUM 0x20 #define ARM64_NOP 0xd503201f +#define ARM64_BTI_C 0xd503245f +#define ARM64_BTI_J 0xd503249f +#define ARM64_BTI_JC 0xd50324df typedef struct { @@ -59,8 +61,8 @@ typedef struct uint64_t replace_addr; uint64_t relo_addr; // out - int32_t tramp_insts_len; - int32_t relo_insts_len; + int32_t tramp_insts_num; + int32_t relo_insts_num; uint32_t origin_insts[TRAMPOLINE_NUM] __attribute__((aligned(8))); uint32_t tramp_insts[TRAMPOLINE_NUM] __attribute__((aligned(8))); uint32_t relo_insts[RELOCATE_INST_NUM] __attribute__((aligned(8))); @@ -242,13 +244,74 @@ int32_t ret_absolute(uint32_t *buf, uint64_t addr); hook_err_t hook_prepare(hook_t *hook); void hook_install(hook_t *hook); void hook_uninstall(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); + +/** + * @brief unhook of hooked function + * + * @param func + */ void unhook(void *func); -// todo: hook priority +/** + * @brief + * + * @param chain + * @param before + * @param after + * @param udata + * @return hook_err_t + */ hook_err_t hook_chain_add(hook_chain_t *chain, void *before, void *after, void *udata); +/** + * @brief + * + * @param chain + * @param before + * @param after + */ void hook_chain_remove(hook_chain_t *chain, void *before, void *after); + +/** + * @brief Wrap a function with before and after function. + * The same function can do hook and unhook multiple times + * + * @see hook_chain0_callback + * @see hook_fargs0_t + * + * @param func The address of function + * @param argno The number of method arguments + * @param before This function will be called before hooked function, + * the type of before is hook_chain{n}_callback which n is equal to argno. + * @param after The same as before but will be call after hooked function + * @param udata + * @return hook_err_t + */ hook_err_t hook_wrap(void *func, int32_t argno, void *before, void *after, void *udata); + +/** + * @brief + * + * @param func + * @param before + * @param after + * @param remove + */ void hook_unwrap_remove(void *func, void *before, void *after, int remove); static inline void hook_unwrap(void *func, void *before, void *after) @@ -263,9 +326,42 @@ static inline void *hook_chain_origin_func(void *hook_args) return (void *)chain->hook.relo_addr; } +/** + * @brief + * + * @param fp_addr + * @param replace + * @param backup + */ void fp_hook(uintptr_t fp_addr, void *replace, void **backup); + +/** + * @brief + * + * @param fp_addr + * @param backup + */ void fp_unhook(uintptr_t fp_addr, void *backup); + +/** + * @brief + * + * @param fp_addr + * @param argno + * @param before + * @param after + * @param udata + * @return hook_err_t + */ hook_err_t fp_hook_wrap(uintptr_t fp_addr, int32_t argno, void *before, void *after, void *udata); + +/** + * @brief + * + * @param fp_addr + * @param before + * @param after + */ void fp_hook_unwrap(uintptr_t fp_addr, void *before, void *after); static inline void hook_chain_install(hook_chain_t *chain) diff --git a/kernel/include/hotpatch.h b/kernel/include/hotpatch.h new file mode 100644 index 00000000..3a418f46 --- /dev/null +++ b/kernel/include/hotpatch.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 bmax121. All Rights Reserved. + */ + +#ifndef _KP_HOTPATCH_H_ +#define _KP_HOTPATCH_H_ + +#include + +int kp_insn_patch_text(void *addrs[], uint32_t insn[], int cnt); + +#endif \ No newline at end of file diff --git a/kernel/include/predata.h b/kernel/include/predata.h index 66e60ec1..56ae5bd4 100644 --- a/kernel/include/predata.h +++ b/kernel/include/predata.h @@ -11,7 +11,7 @@ int auth_superkey(const char *key); void reset_superkey(const char *key); -void enable_auth_root_key(int skip_hash); +void enable_auth_root_key(int enable); const char *get_superkey(); uint64_t rand_next(); diff --git a/kernel/include/preset.h b/kernel/include/preset.h index af5921f9..1970d33e 100644 --- a/kernel/include/preset.h +++ b/kernel/include/preset.h @@ -117,15 +117,6 @@ struct patch_symbol uint64_t __cfi_slowpath; uint64_t copy_process; uint64_t cgroup_post_fork; - uint64_t do_execveat_common; - uint64_t __do_execve_file; - uint64_t do_execve_common; - uint64_t do_faccessat; - uint64_t sys_faccessat; - uint64_t sys_faccessat2; - uint64_t sys_newfstatat; - uint64_t vfs_statx; - uint64_t vfs_fstatat; uint64_t avc_denied; uint64_t slow_avc_audit; uint64_t input_handle_event; diff --git a/kernel/include/stdbool.h b/kernel/include/stdbool.h index 488efdb1..b40bcdfa 100644 --- a/kernel/include/stdbool.h +++ b/kernel/include/stdbool.h @@ -1,7 +1,8 @@ #ifndef _KP_STDBOOL_H_ #define _KP_STDBOOL_H_ -typedef unsigned char bool; +#define bool _Bool + #define true ((bool)1) #define false ((bool)0) diff --git a/kernel/include/symbol.h b/kernel/include/symbol.h index 14a487ff..c9e620ca 100644 --- a/kernel/include/symbol.h +++ b/kernel/include/symbol.h @@ -22,8 +22,14 @@ typedef struct #define KP_EXPORT_SYMBOL(sym) _KP_EXPORT_SYMBOL(sym) +extern unsigned long link_base_addr; +extern unsigned long runtime_base_addr; + unsigned long symbol_lookup_name(const char *name); -int symbol_init(); +static inline unsigned long link2runtime(unsigned long addr) +{ + return addr - link_base_addr + runtime_base_addr; +} #endif \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/asm/processor.h b/kernel/linux/arch/arm64/include/asm/processor.h index ca39a61c..79dad534 100644 --- a/kernel/linux/arch/arm64/include/asm/processor.h +++ b/kernel/linux/arch/arm64/include/asm/processor.h @@ -17,8 +17,6 @@ // #define THREAD_START_SP (THREAD_SIZE - 16) // #define task_pt_regs(p) ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) -// implemented in utils - extern int16_t pt_regs_offset; struct pt_regs *_task_pt_reg(struct task_struct *task); diff --git a/kernel/linux/include/linux/cred.h b/kernel/linux/include/linux/cred.h index b425a0ee..6af545fa 100644 --- a/kernel/linux/include/linux/cred.h +++ b/kernel/linux/include/linux/cred.h @@ -163,36 +163,41 @@ static inline struct cred *prepare_kernel_cred(struct task_struct *daemon) kfunc_not_found(); return 0; } + static inline int change_create_files_as(struct cred *cred, struct inode *inode) { kfunc_call(change_create_files_as, cred, inode); kfunc_not_found(); return 0; } + static inline int set_security_override(struct cred *new, u32 secid) { kfunc_call(set_security_override, new, secid); - kfunc_not_found(); return 0; } + static inline int set_security_override_from_ctx(struct cred *new, const char *secctx) { kfunc_call(set_security_override_from_ctx, new, secctx); kfunc_not_found(); return 0; } + static inline int set_create_files_as(struct cred *new, struct inode *inode) { kfunc_call(set_create_files_as, new, inode); kfunc_not_found(); return 0; } + static inline int cred_fscmp(const struct cred *a, const struct cred *b) { kfunc_call(cred_fscmp, a, b); kfunc_not_found(); return 0; } + static inline void cred_init(void) { kfunc_call(cred_init); diff --git a/kernel/linux/include/linux/fs.h b/kernel/linux/include/linux/fs.h index 799980a8..896915fb 100644 --- a/kernel/linux/include/linux/fs.h +++ b/kernel/linux/include/linux/fs.h @@ -359,7 +359,6 @@ static inline loff_t vfs_llseek(struct file *file, loff_t offset, int whence) static inline void putname(struct filename *name) { - // logkd("aaaaaaaaaaa %llx\n", kfunc(putname)); kfunc_direct_call_void(putname, name); // kfunc_direct_call_void(final_putname, name); } diff --git a/kernel/linux/include/linux/security.h b/kernel/linux/include/linux/security.h index 51922cd8..18f3eb48 100644 --- a/kernel/linux/include/linux/security.h +++ b/kernel/linux/include/linux/security.h @@ -624,8 +624,6 @@ static inline int cap_vm_enough_memory(struct mm_struct *mm, long pages) return 0; } -// - static inline void security_task_getsecid(struct task_struct *task, u32 *secid) { kfunc_call(security_task_getsecid, task, secid); @@ -633,19 +631,14 @@ static inline void security_task_getsecid(struct task_struct *task, u32 *secid) kfunc_not_found(); } -// When we are uncertain whether secctx exists or is correct, we cannot rely on security_secctx_to_secid; otherwise, secid might be set to an unexpected value. static inline int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { - kfunc_call(security_secctx_to_secid, secdata, seclen, secid); - kfunc_not_found(); - return 0; + kfunc_direct_call(security_secctx_to_secid, secdata, seclen, secid); } static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { - kfunc_call(security_secid_to_secctx, secid, secdata, seclen); - kfunc_not_found(); - return 0; + kfunc_direct_call(security_secid_to_secctx, secid, secdata, seclen); } static inline void security_release_secctx(char *secdata, u32 seclen) diff --git a/kernel/linux/include/linux/string.h b/kernel/linux/include/linux/string.h index c52930b9..bec5fcd2 100644 --- a/kernel/linux/include/linux/string.h +++ b/kernel/linux/include/linux/string.h @@ -6,11 +6,15 @@ #include #include +extern char *kfunc_def(strndup_user)(const char __user *, long); +extern void *kfunc_def(memdup_user)(const void __user *, size_t); +extern void *kfunc_def(vmemdup_user)(const void __user *, size_t); +extern void *kfunc_def(memdup_user_nul)(const void __user *, size_t); + extern void kfunc_def(kfree_const)(const void *x); extern char *kfunc_def(kstrdup)(const char *s, gfp_t gfp); extern const char *kfunc_def(kstrdup_const)(const char *s, gfp_t gfp); extern char *kfunc_def(kstrndup)(const char *s, size_t len, gfp_t gfp); -extern void *kfunc_def(memdup_user)(const void __user *src, size_t len); extern void *kfunc_def(kmemdup)(const void *src, size_t len, gfp_t gfp); extern char *kfunc_def(kmemdup_nul)(const char *s, size_t len, gfp_t gfp); extern char **kfunc_def(argv_split)(gfp_t gfp, const char *str, int *argcp); @@ -62,6 +66,9 @@ extern void *kfunc_def(memchr_inv)(const void *start, int c, size_t bytes); extern char *kfunc_def(strreplace)(char *s, char old, char new); extern void kfunc_def(fortify_panic)(const char *name); +extern int __must_check kfunc_def(kstrtoull)(const char *s, unsigned int base, unsigned long long *res); +extern int __must_check kfunc_def(kstrtoll)(const char *s, unsigned int base, long long *res); + static inline void kfree_const(const void *x) { kfunc_direct_call(kfree_const, x); @@ -92,6 +99,11 @@ static inline char *kmemdup_nul(const char *s, size_t len, gfp_t gfp) kfunc_direct_call(kmemdup_nul, s, len, gfp); } +static inline char *strndup_user(const void __user *s, long len) +{ + kfunc_direct_call(strndup_user, s, len); +} + static inline void *memdup_user(const void __user *src, size_t len) { kfunc_direct_call(memdup_user, src, len); @@ -332,4 +344,14 @@ static inline void fortify_panic(const char *name) kfunc_direct_call(fortify_panic, name); } +static inline int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res) +{ + kfunc_direct_call(kstrtoull, s, base, res); +} + +static inline int __must_check kstrtoll(const char *s, unsigned int base, long long *res) +{ + kfunc_direct_call(kstrtoll, s, base, res); +} + #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/uaccess.h b/kernel/linux/include/linux/uaccess.h index 4400e034..22230dbb 100644 --- a/kernel/linux/include/linux/uaccess.h +++ b/kernel/linux/include/linux/uaccess.h @@ -60,6 +60,4 @@ extern long kfunc_def(strnlen_user_nofault)(const void __user *unsafe_addr, long extern long kfunc_def(strnlen_unsafe_user)(const void __user *unsafe_addr, long count); extern long kfunc_def(strnlen_user)(const char __user *str, long n); -long compat_strncpy_from_user(char *dest, const char __user *src, long count); - #endif \ No newline at end of file diff --git a/kernel/patch/android/supercall.c b/kernel/patch/android/supercall.c deleted file mode 100644 index 413a6876..00000000 --- a/kernel/patch/android/supercall.c +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2023 bmax121. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static long call_grant_uid(uid_t uid, struct su_profile *__user uprofile) -{ - struct su_profile *profile = memdup_user(uprofile, sizeof(struct su_profile)); - if (!profile || IS_ERR(profile)) return PTR_ERR(profile); - int rc = su_add_allow_uid(uid, profile, 1); - kvfree(profile); - return rc; -} - -static long call_revoke_uid(uid_t uid) -{ - return su_remove_allow_uid(uid, 1); -} - -static long call_su_allow_uid_nums() -{ - return su_allow_uid_nums(); -} - -static long call_su_list_allow_uid(uid_t *__user uids, int num) -{ - return su_allow_uids(uids, num); -} - -static long call_su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile) -{ - return su_allow_uid_profile(uid, uprofile); -} - -static long call_reset_su_path(const char *__user upath) -{ - char path[SU_PATH_MAX_LEN]; - compat_strncpy_from_user(path, upath, sizeof(path)); - return su_reset_path(path); -} - -static long call_su_get_path(char *__user ubuf, int buf_len) -{ - return su_get_path(ubuf, buf_len); -} - -long supercall_android(long cmd, long arg1, long arg2, long arg3) -{ - switch (cmd) { - case SUPERCALL_SU_GRANT_UID: - return call_grant_uid((uid_t)arg1, (struct su_profile * __user) arg2); - case SUPERCALL_SU_REVOKE_UID: - return call_revoke_uid((uid_t)arg1); - case SUPERCALL_SU_NUMS: - return call_su_allow_uid_nums(); - case SUPERCALL_SU_LIST: - return call_su_list_allow_uid((uid_t *)arg1, (int)arg2); - case SUPERCALL_SU_PROFILE: - return call_su_allow_uid_profile((uid_t)arg1, (struct su_profile * __user) arg2); - case SUPERCALL_SU_RESET_PATH: - return call_reset_su_path((const char *)arg1); - case SUPERCALL_SU_GET_PATH: - return call_su_get_path((char *__user)arg1, (int)arg2); - default: - break; - } - return -ENOSYS; -} diff --git a/kernel/patch/android/userd.c b/kernel/patch/android/userd.c index feb174c9..16c99253 100644 --- a/kernel/patch/android/userd.c +++ b/kernel/patch/android/userd.c @@ -35,7 +35,7 @@ static const void *kernel_read_file(const char *path, loff_t *len) { - set_priv_selinx_allow(current, 1); + set_priv_sel_allow(current, true); void *data = 0; struct file *filp = filp_open(path, O_RDONLY, 0); @@ -51,14 +51,14 @@ static const void *kernel_read_file(const char *path, loff_t *len) filp_close(filp, 0); out: - set_priv_selinx_allow(current, 0); + set_priv_sel_allow(current, false); return data; } static loff_t kernel_write_file(const char *path, const void *data, loff_t len, umode_t mode) { loff_t off = 0; - set_priv_selinx_allow(current, 1); + set_priv_sel_allow(current, true); struct file *fp = filp_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); if (!fp || IS_ERR(fp)) { @@ -75,48 +75,13 @@ static loff_t kernel_write_file(const char *path, const void *data, loff_t len, filp_close(fp, 0); out: - set_priv_selinx_allow(current, 0); + set_priv_sel_allow(current, false); return off; } -static loff_t kernel_write_exec(const char *path, const void *data, loff_t len) -{ - return kernel_write_file(path, data, len, 0744); -} - -static int extract_kpatch_call_back(const patch_extra_item_t *extra, const char *arg, const void *con, void *udata) -{ - const char *event = (const char *)udata; - if (extra->type == EXTRA_TYPE_EXEC && !strcmp("kpatch", extra->name)) { - loff_t size = kernel_write_exec(KPATCH_DEV_PATH, con, extra->con_size); - log_boot("%s extract kpatch size: %d\n", event, (long)size); - } - return 0; -} - -static void try_extract_kpatch(const char *event) -{ - set_priv_selinx_allow(current, 1); - struct file *fp = filp_open(KPATCH_DEV_PATH, O_RDONLY, 0); - if (!fp || IS_ERR(fp)) { - on_each_extra_item(extract_kpatch_call_back, (void *)event); - } else { - filp_close(fp, 0); - } - set_priv_selinx_allow(current, 0); -} - static void pre_user_exec_init() { log_boot("event: %s\n", EXTRA_EVENT_PRE_EXEC_INIT); - try_extract_kpatch(EXTRA_EVENT_PRE_EXEC_INIT); - - // struct file *work_dir = filp_open(KPATCH_DEV_WORK_DIR, O_DIRECTORY | O_CREAT, S_IRUSR); - // if (!work_dir || IS_ERR(work_dir)) { - // log_boot("creat work dir error: %s\n", KPATCH_DEV_WORK_DIR); - // return; - // } - // filp_close(work_dir, 0); } static void pre_init_second_stage() @@ -213,8 +178,8 @@ static void handle_after_execve(hook_local_t *hook_local) { int unhook = hook_local->data7; if (unhook) { - fp_unhook_syscall(__NR_execve, before_execve, after_execve); - fp_unhook_syscall(__NR_execveat, before_execveat, after_execveat); + unhook_syscalln(__NR_execve, before_execve, after_execve); + unhook_syscalln(__NR_execveat, before_execveat, after_execveat); } } @@ -253,30 +218,23 @@ static void after_execveat(hook_fargs5_t *args, void *udata) #define ORIGIN_RC_FILE "/system/etc/init/atrace.rc" #define REPLACE_RC_FILE "/dev/anduser.rc" +#define ADB_FLODER "/data/adb/" +#define AP_DIR "/data/adb/ap/" +#define AP_BIN_DIR AP_DIR "bin/" +#define AP_LOG_DIR AP_DIR "log/" + static const char user_rc_data[] = { // "\n" - "\n" - "on early-init\n" - " exec -- " SUPERCMD " %s " KPATCH_DEV_PATH " %s android_user early-init -k\n" - "on post-fs-data\n" - " exec -- " SUPERCMD " %s " KPATCH_DEV_PATH " %s android_user post-fs-data-init -k\n" - " exec -- " SUPERCMD " %s " KPATCH_DATA_PATH " %s android_user post-fs-data-init -k\n" - " exec -- " SUPERCMD " %s " KPATCH_DATA_PATH " %s android_user post-fs-data -k\n" - + " exec -- " SUPERCMD " %s exec " AP_BIN_DIR "magiskpolicy --live --magisk\n" + " exec -- " SUPERCMD " %s exec " APD_PATH " post-fs-data\n" "on nonencrypted\n" - " exec -- " SUPERCMD " %s " KPATCH_DATA_PATH " %s android_user services -k\n" - + " exec -- " SUPERCMD " %s exec " APD_PATH " services\n" "on property:vold.decrypt=trigger_restart_framework\n" - " exec -- " SUPERCMD " %s " KPATCH_DATA_PATH " %s android_user services -k\n" - + " exec -- " SUPERCMD " %s exec " APD_PATH " services\n" "on property:sys.boot_completed=1\n" - " rm " REPLACE_RC_FILE "\n" - " rm " KPATCH_DEV_PATH "\n" - " rm " EARLY_INIT_LOG_0 "\n" - " rm " EARLY_INIT_LOG_1 "\n" - " exec -- " SUPERCMD " %s " KPATCH_DATA_PATH " %s android_user boot-completed -k\n" - "\n\n" + " exec -- " SUPERCMD " %s exec " APD_PATH " boot-completed\n" + "\n" "" }; @@ -322,7 +280,7 @@ static void before_openat(hook_fargs4_t *args, void *udata) char added_rc_data[2048]; const char *sk = get_superkey(); - sprintf(added_rc_data, user_rc_data, sk, sk, sk, sk, sk, sk, sk, sk, sk, sk, sk, sk, sk, sk); + sprintf(added_rc_data, user_rc_data, sk, sk, sk, sk, sk, sk); kernel_write(newfp, added_rc_data, strlen(added_rc_data), &off); if (off != strlen(added_rc_data) + ori_len) { @@ -358,7 +316,7 @@ static void after_openat(hook_fargs4_t *args, void *udata) log_boot("restore rc file: %x\n", args->local.data0); } if (args->local.data2) { - fp_unhook_syscall(__NR_openat, before_openat, after_openat); + unhook_syscalln(__NR_openat, before_openat, after_openat); } } @@ -386,7 +344,7 @@ static void before_input_handle_event(hook_fargs4_t *args, void *udata) } } -int kpuserd_init() +int android_user_init() { hook_err_t ret = 0; hook_err_t rc = HOOK_NO_ERR; diff --git a/kernel/patch/common/accctl.c b/kernel/patch/common/accctl.c index e8b345d2..58e6a8cf 100644 --- a/kernel/patch/common/accctl.c +++ b/kernel/patch/common/accctl.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -15,18 +16,19 @@ #include #include #include -#include #include #include #include +#include +#include +#include +#include +#include +#include -int set_priv_selinx_allow(struct task_struct *task, int val) -{ - struct task_ext *ext = get_task_ext(task); - ext->priv_selinux_allow = val; - dsb(ish); - return 0; -} +char all_allow_sctx[SUPERCALL_SCONTEXT_LEN] = { '\0' }; +int allow_sid_enable = 0; +uint32_t all_allow_sid = 0; static void su_cred(struct cred *cred, uid_t uid) { @@ -47,26 +49,38 @@ static void su_cred(struct cred *cred, uid_t uid) *(uid_t *)((uintptr_t)cred + cred_offset.sgid_offset) = uid; } -// int commit_kernel_cred() -// { -// int rc = 0; -// struct task_struct *task = current; -// struct task_ext *ext = get_task_ext(task); -// if (!task_ext_valid(ext)) goto out; - -// const struct cred *old = get_task_cred(task); -// struct cred *new = prepare_kernel_cred(0); -// u32 secid; -// if (kfunc(security_cred_getsecid)) { -// kfunc(security_cred_getsecid)(old, &secid); -// set_security_override(new, secid); -// } -// commit_creds(new); -// out: -// return rc; -// } +int set_all_allow_sctx(const char *sctx) +{ + if (!sctx || !sctx[0]) { + all_allow_sctx[0] = 0; + all_allow_sid = 0; + dsb(ish); + allow_sid_enable = 0; + dsb(ish); + logkfd("clear all allow sconetxt\n"); + return 0; + } -int commit_su(uid_t to_uid, const char *sctx) + int rc = security_secctx_to_secid(sctx, strlen(sctx), &all_allow_sid); + if (!rc) { + strncpy(all_allow_sctx, sctx, sizeof(all_allow_sctx) - 1); + all_allow_sctx[sizeof(all_allow_sctx) - 1] = '\0'; + dsb(ish); + allow_sid_enable = 1; + dsb(ish); + logkfd("set all allow sconetxt: %s, sid: %d\n", all_allow_sctx, all_allow_sid); + } + return rc; +} + +int commit_kernel_su() +{ + struct cred *new = prepare_kernel_cred(0); + set_security_override(new, all_allow_sid); + return commit_creds(new); +} + +int commit_common_su(uid_t to_uid, const char *sctx) { int rc = 0; struct task_struct *task = current; @@ -88,22 +102,33 @@ int commit_su(uid_t to_uid, const char *sctx) // seccomp_filter_release(task); } - ext->selinux_allow = 1; + ext->sel_allow = 1; struct cred *new = prepare_creds(); su_cred(new, to_uid); struct group_info *group_info = groups_alloc(0); set_groups(new, group_info); - if (sctx && sctx[0]) ext->selinux_allow = !!set_security_override_from_ctx(new, sctx); + if (sctx && sctx[0]) { + ext->sel_allow = !!set_security_override_from_ctx(new, sctx); + } commit_creds(new); out: logkfi("pid: %d, tgid: %d, to_uid: %d, sctx: %s, via_hook: %d\n", ext->pid, ext->tgid, to_uid, sctx, - ext->selinux_allow); + ext->sel_allow); return rc; } +int commit_su(uid_t to_uid, const char *sctx) +{ + if (unlikely(allow_sid_enable) && !to_uid) { + return commit_kernel_su(); + } else { + return commit_common_su(to_uid, sctx); + } +} + // todo: rcu int task_su(pid_t pid, uid_t to_uid, const char *sctx) { @@ -142,10 +167,94 @@ int task_su(pid_t pid, uid_t to_uid, const char *sctx) su_cred(real_cred, to_uid); if (sctx && sctx[0]) scontext_changed = scontext_changed && !set_security_override_from_ctx(real_cred, sctx); } - ext->priv_selinux_allow = !scontext_changed; + ext->priv_sel_allow = !scontext_changed; logkfi("pid: %d, tgid: %d, to_uid: %d, sctx: %s, via_hook: %d\n", ext->pid, ext->tgid, to_uid, sctx, - ext->priv_selinux_allow); + ext->priv_sel_allow); out: return rc; } + +static int (*avc_denied_backup)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, void *requested, + void *driver, void *xperm, void *flags, struct av_decision *avd) = 0; + +static int avc_denied_replace(struct selinux_state *_state, void *_ssid, void *_tsid, void *_tclass, void *_requested, + void *_driver, void *_xperm, void *_flags, struct av_decision *_avd) +{ + if (unlikely(allow_sid_enable)) { + u32 ssid = (u32)(u64)_ssid; + if ((uint64_t)_state <= 0xffffffffL) { + ssid = (u32)(u64)_state; + } + if (ssid == all_allow_sid) { + goto allow; + } + } + + struct task_ext *ext = get_current_task_ext(); + if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { + goto allow; + } + + int rc = avc_denied_backup(_state, _ssid, _tsid, _tclass, _requested, _driver, _xperm, _flags, _avd); + return rc; + +allow: + struct av_decision *avd = (struct av_decision *)_avd; + if ((uint64_t)_state <= 0xffffffffL) { + avd = (struct av_decision *)_flags; + } + avd->allowed = 0xffffffff; + avd->auditallow = 0; + avd->auditdeny = 0; + return 0; +} + +static int (*slow_avc_audit_backup)(struct selinux_state *_state, void *_ssid, void *_tsid, void *_tclass, + void *_requested, void *_audited, void *_denied, void *_result, + struct common_audit_data *_a) = 0; + +static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, void *_tsid, void *_tclass, + void *_requested, void *_audited, void *_denied, void *_result, + struct common_audit_data *_a) +{ + if (allow_sid_enable) { + u32 ssid = (u64)_ssid; + if ((uint64_t)_state <= 0xffffffffL) { + ssid = (u64)_state; + } + if (ssid == all_allow_sid) { + return 0; + } + } + + struct task_ext *ext = get_current_task_ext(); + if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { + return 0; + } + + int rc = slow_avc_audit_backup(_state, _ssid, _tsid, _tclass, _requested, _audited, _denied, _result, _a); + return rc; +} + +int bypass_selinux() +{ + unsigned long avc_denied_addr = get_preset_patch_sym()->avc_denied; + if (avc_denied_addr) { + hook_err_t err = hook((void *)avc_denied_addr, (void *)avc_denied_replace, (void **)&avc_denied_backup); + if (err != HOOK_NO_ERR) { + log_boot("hook avc_denied_addr: %llx, error: %d\n", avc_denied_addr, err); + } + } + + unsigned long slow_avc_audit_addr = get_preset_patch_sym()->slow_avc_audit; + if (slow_avc_audit_addr) { + hook_err_t err = + hook((void *)slow_avc_audit_addr, (void *)slow_avc_audit_replace, (void **)&slow_avc_audit_backup); + if (err != HOOK_NO_ERR) { + log_boot("hook slow_avc_audit: %llx, error: %d\n", slow_avc_audit_addr, err); + } + } + + return 0; +} diff --git a/kernel/patch/common/selinuxhook.c b/kernel/patch/common/selinuxhook.c.bak similarity index 94% rename from kernel/patch/common/selinuxhook.c rename to kernel/patch/common/selinuxhook.c.bak index 2a0ca50e..2e2329c8 100644 --- a/kernel/patch/common/selinuxhook.c +++ b/kernel/patch/common/selinuxhook.c.bak @@ -63,10 +63,10 @@ static void _selinux_debug(u32 ssid, u32 tsid, u16 tclass, u32 requested) log_boot("no symbol %s\n", #func); \ } -#define HOOK_AVC_RET_ZERO_BEFORE() \ - struct task_ext *ext = get_current_task_ext(); \ - if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { \ - return 0; \ +#define HOOK_AVC_RET_ZERO_BEFORE() \ + struct task_ext *ext = get_current_task_ext(); \ + if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { \ + return 0; \ } static int (*avc_denied_backup)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, void *requested, @@ -76,7 +76,7 @@ static int avc_denied_replace(struct selinux_state *_state, void *_ssid, void *_ void *_driver, void *_xperm, void *_flags, struct av_decision *_avd) { struct task_ext *ext = get_current_task_ext(); - if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { + if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { struct av_decision *avd = (struct av_decision *)_avd; if ((uint64_t)_state <= 0xffffffffL) { avd = (struct av_decision *)_flags; @@ -99,7 +99,7 @@ static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, voi struct common_audit_data *_a) { struct task_ext *ext = get_current_task_ext(); - if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { + if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { return 0; } int rc = slow_avc_audit_backup(_state, _ssid, _tsid, _tclass, _requested, _audited, _denied, _result, _a); @@ -123,7 +123,7 @@ static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, voi // // HOOK_AVC_RET_ZERO_BEFORE(); // struct task_ext *ext = get_current_task_ext(); -// if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { +// if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { // struct av_decision *avd = (struct av_decision *)avd; // if (((uint64_t)state & 0xF000000000000000) != 0xF000000000000000) { // avd = (struct av_decision *)flags; @@ -197,7 +197,7 @@ static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, voi // if (!node) return node; // struct task_ext *ext = get_current_task_ext(); -// if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { +// if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { // make_avc_node_all_perm(node); // } // return node; @@ -212,7 +212,7 @@ static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, voi // { // struct avc_node *node = hook_call_backup(avc_compute_av, _state, _ssid, _tsid, _tclass, _avd, _xp_node); // struct task_ext *ext = get_current_task_ext(); -// if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { +// if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { // struct av_decision *avd = (struct av_decision *)_avd; // struct avc_xperms_node *xp_node = (struct avc_xperms_node *)_xp_node; // if ((uint64_t)_state <= 0xffffffffL) { @@ -241,7 +241,7 @@ static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, voi // hook_call_backup(security_compute_av, _state, _ssid, _tsid, _orig_tclass, _avd, _xperms); // struct task_ext *ext = get_current_task_ext(); -// if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { +// if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { // struct av_decision *avd = (struct av_decision *)_avd; // struct extended_perms *xperms = (struct extended_perms *)_xperms; // if ((uint64_t)_state <= 0xffffffffL) { @@ -266,7 +266,7 @@ static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, voi // { // hook_call_backup(security_compute_xperms_decision, _state, _ssid, _tsid, _orig_tclass, _driver, _xpermd); // struct task_ext *ext = get_current_task_ext(); -// if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { +// if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { // struct extended_perms_decision *xpermd = (struct extended_perms_decision *)_xpermd; // if ((uint64_t)_state <= 0xffffffffL) { // xpermd = (struct extended_perms_decision *)_driver; @@ -286,7 +286,7 @@ static int slow_avc_audit_replace(struct selinux_state *_state, void *_ssid, voi // hook_call_backup(security_compute_av_user, _state, _ssid, _tsid, _tclass, _avd); // struct task_ext *ext = get_current_task_ext(); -// if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { +// if (unlikely(task_ext_valid(ext) && (ext->sel_allow || ext->priv_sel_allow))) { // struct av_decision *avd = (struct av_decision *)_avd; // if ((uint64_t)_state <= 0xffffffffL) { // avd = (struct av_decision *)_tclass; diff --git a/kernel/patch/android/sucompat.c b/kernel/patch/common/sucompat.c similarity index 50% rename from kernel/patch/android/sucompat.c rename to kernel/patch/common/sucompat.c index 28dccbf6..06161c23 100644 --- a/kernel/patch/android/sucompat.c +++ b/kernel/patch/common/sucompat.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -39,11 +40,15 @@ #include #include -static const char sh_path[] = ANDROID_SH_PATH; -static const char default_su_path[] = ANDROID_SU_PATH; -static const char legacy_su_path[] = ANDROID_LEGACY_SU_PATH; +const char sh_path[] = SH_PATH; +const char default_su_path[] = SU_PATH; + +#ifdef ANDROID +const char legacy_su_path[] = LEGACY_SU_PATH; +const char apd_path[] = APD_PATH; +#endif + static const char *current_su_path = 0; -static const char apd_path[] = APD_PATH; static struct list_head allow_uid_list; static spinlock_t list_lock; @@ -88,8 +93,10 @@ int is_su_allow_uid(uid_t uid) } KP_EXPORT_SYMBOL(is_su_allow_uid); -int su_add_allow_uid(uid_t uid, struct su_profile *profile, int async) +int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext, int async) { + if (!scontext) scontext = ""; + rcu_read_lock(); struct allow_uid *pos, *old = 0; list_for_each_entry(pos, &allow_uid_list, list) @@ -99,9 +106,12 @@ int su_add_allow_uid(uid_t uid, struct su_profile *profile, int async) break; } } + // todo: vmalloc -> kmalloc, gfp struct allow_uid *new = (struct allow_uid *)vmalloc(sizeof(struct allow_uid)); - new->uid = profile->uid; - memcpy(&new->profile, profile, sizeof(struct su_profile)); + new->uid = uid; + new->profile.uid = uid; + new->profile.to_uid = to_uid; + strncpy(new->profile.scontext, scontext, sizeof(new->profile.scontext)); new->profile.scontext[sizeof(new->profile.scontext) - 1] = '\0'; spin_lock(&list_lock); @@ -125,6 +135,7 @@ int su_add_allow_uid(uid_t uid, struct su_profile *profile, int async) } return 0; } +KP_EXPORT_SYMBOL(su_add_allow_uid); int su_remove_allow_uid(uid_t uid, int async) { @@ -148,6 +159,7 @@ int su_remove_allow_uid(uid_t uid, int async) spin_unlock(&list_lock); return 0; } +KP_EXPORT_SYMBOL(su_remove_allow_uid); int su_allow_uid_nums() { @@ -162,8 +174,9 @@ int su_allow_uid_nums() logkfd("%d\n", num); return num; } +KP_EXPORT_SYMBOL(su_allow_uid_nums); -int su_allow_uids(uid_t *__user uuids, int unum) +int su_allow_uids(int is_user, uid_t *out_uids, int out_num) { int rc = 0; int num = 0; @@ -171,17 +184,21 @@ int su_allow_uids(uid_t *__user uuids, int unum) struct allow_uid *pos; list_for_each_entry(pos, &allow_uid_list, list) { - if (num >= unum) { - goto out; - } + if (num >= out_num) goto out; + uid_t uid = pos->profile.uid; - int cplen = compat_copy_to_user(uuids + num, &uid, sizeof(uid)); - logkfd("uid: %d\n", uid); - if (cplen <= 0) { - logkfd("compat_copy_to_user error: %d", cplen); - rc = cplen; - goto out; + if (is_user) { + int cplen = compat_copy_to_user(out_uids + num, &uid, sizeof(uid)); + logkfd("uid: %d\n", uid); + if (cplen <= 0) { + logkfd("compat_copy_to_user error: %d", cplen); + rc = cplen; + goto out; + } + } else { + out_uids[num] = uid; } + num++; } rc = num; @@ -189,8 +206,9 @@ int su_allow_uids(uid_t *__user uuids, int unum) rcu_read_unlock(); return rc; } +KP_EXPORT_SYMBOL(su_allow_uids); -int su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile) +int su_allow_uid_profile(int is_user, uid_t uid, struct su_profile *profile) { int rc = -ENOENT; rcu_read_lock(); @@ -198,12 +216,16 @@ int su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile) list_for_each_entry(pos, &allow_uid_list, list) { if (pos->profile.uid != uid) continue; - int cplen = compat_copy_to_user(uprofile, &pos->profile, sizeof(struct su_profile)); - logkfd("profile: %d %d %s\n", uid, pos->profile.to_uid, pos->profile.scontext); - if (cplen <= 0) { - logkfd("compat_copy_to_user error: %d", cplen); - rc = cplen; - goto out; + if (is_user) { + int cplen = compat_copy_to_user(profile, &pos->profile, sizeof(struct su_profile)); + logkfd("profile: %d %d %s\n", uid, pos->profile.to_uid, pos->profile.scontext); + if (cplen <= 0) { + logkfd("compat_copy_to_user error: %d", cplen); + rc = cplen; + goto out; + } + } else { + memcpy(profile, &pos->profile, sizeof(struct su_profile)); } rc = 0; goto out; @@ -212,190 +234,31 @@ int su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile) rcu_read_unlock(); return rc; } +KP_EXPORT_SYMBOL(su_allow_uid_profile); // no free, no lock int su_reset_path(const char *path) { if (!path) return -EINVAL; - int len = strlen(path); - if (len <= 0) return -EINVAL; - char *new_su_path = vmalloc(len + 1); - if (!new_su_path) return -ENOMEM; - strcpy(new_su_path, path); - new_su_path[len] = '\0'; - current_su_path = new_su_path; - dsb(ishst); - logkfi("%s\n", current_su_path); + if (IS_ERR(path)) return PTR_ERR(path); + current_su_path = path; + logkfd("%s\n", current_su_path); + dsb(ish); return 0; } +KP_EXPORT_SYMBOL(su_reset_path); -int su_get_path(char *__user ubuf, int buf_len) -{ - if (!current_su_path) { - logkfi("null su path\n"); - current_su_path = default_su_path; - } - int len = strnlen(current_su_path, SU_PATH_MAX_LEN); - if (len <= 0) return -EINVAL; - if (buf_len < len) return -ENOBUFS; - logkfi("%s\n", current_su_path); - return compat_copy_to_user(ubuf, current_su_path, len + 1); -} - -// todo: rcu_dereference_protected -static uid_t current_uid() -{ - struct cred *cred = *(struct cred **)((uintptr_t)current + task_struct_offset.cred_offset); - uid_t uid = *(uid_t *)((uintptr_t)cred + cred_offset.uid_offset); - return uid; -} - -// #define SU_COMPAT_INLINE_HOOK - -#ifdef SU_COMPAT_INLINE_HOOK - -// int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) -// int __do_execve_file(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags, -// struct file *file); -// static int do_execve_common(struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp) -static void before_do_execve(hook_fargs8_t *args, void *udata) -{ - struct filename *filename; - int filename_index = 1; - - if (udata && (((uintptr_t)args->arg0) & 0xF000000000000000) == 0xF000000000000000) { - // int, AT_FDCWD(ffffff9c) or fd - filename_index = 0; - } - - filename = (struct filename *)args->args[filename_index]; - if (!filename || IS_ERR(filename)) return; - - if (!strcmp(current_su_path, filename->name)) { - uid_t uid = current_uid(); - if (!is_su_allow_uid(uid)) return; - struct su_profile profile = profile_su_allow_uid(uid); - - uid_t to_uid = profile.to_uid; - const char *sctx = profile.scontext; - commit_su(to_uid, sctx); - - struct file *filp = filp_open(apd_path, O_RDONLY, 0); - if (!filp || IS_ERR(filp)) { - logkfi("call su uid: %d, to_uid: %d, sctx: %s\n", uid, to_uid, sctx); - strcpy((char *)filename->name, sh_path); - } else { - filp_close(filp, 0); - strcpy((char *)filename->name, apd_path); - int cplen = 0; - if (strcmp(legacy_su_path, filename->name)) { - const char *__user p0 = - get_user_arg_ptr((void *)args->args[filename_index + 1], (void *)args->args[filename_index + 2], 0); - cplen = compat_copy_to_user((char *__user)p0, legacy_su_path, sizeof(legacy_su_path)); - } - logkfi("call apd uid: %d, to_uid: %d, sctx: %s, cplen: %d\n", uid, to_uid, sctx, cplen); - } - } else if (!strcmp(SUPERCMD, filename->name)) { - void *ua0 = (void *)args->args[filename_index + 1]; - void *ua1 = (void *)args->args[filename_index + 2]; - - // key - const char __user *p1 = get_user_arg_ptr(ua0, ua1, 1); - if (IS_ERR(p1)) return; - - // auth skey - char arg1[SUPER_KEY_LEN]; - if (compat_strncpy_from_user(arg1, p1, sizeof(arg1)) <= 0) return; - if (auth_superkey(arg1)) return; - - commit_su(0, 0); - - // real command -#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(*filename) - 128) // enough - - const char __user *p2 = get_user_arg_ptr(ua0, ua1, 2); - if (!p2 || IS_ERR(p2)) { - strcpy((char *)filename->name, sh_path); - } else { - compat_strncpy_from_user((char *)filename->name, p2, EMBEDDED_NAME_MAX); - } - logkfi("supercmd %s\n", filename->name); - - // shift args - args->args[filename_index + (has_config_compat ? 2 : 1)] += 2 * ((has_config_compat && ua0) ? 4 : 8); - } - return; -} - -// SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) -// SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode, int, flags) -static void before_faccessat(hook_fargs4_t *args, void *udata) +const char *su_get_path() { - uid_t uid = current_uid(); - if (!is_su_allow_uid(uid)) return; - - char __user *filename = (char __user *)syscall_argn(args, 1); - - char buf[SU_PATH_MAX_LEN]; - compat_strncpy_from_user(buf, filename, sizeof(buf)); - if (strcmp(current_su_path, buf)) return; - - logkfd("uid: %d\n", uid); - args->ret = 0; - args->skip_origin = 1; -} - -// SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, struct stat __user *, statbuf, int, flag) -static void before_sysfstatat(hook_fargs4_t *args, void *udata) -{ - uid_t uid = current_uid(); - if (!is_su_allow_uid(uid)) return; - - char *__user filename = (char *__user)syscall_argn(args, 1); - - char buf[SU_PATH_MAX_LEN]; - compat_strncpy_from_user(buf, filename, sizeof(buf)); - if (!strcmp(current_su_path, buf)) { - void *__user uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); - if (uptr && !IS_ERR(uptr)) set_syscall_argn(args, 1, (uint64_t)uptr); - logkfd("uid: %d, %llx\n", uid, uptr); - } - return; + if (!current_su_path) current_su_path = default_su_path; + return current_su_path; } - -// int vfs_statx(int dfd, struct filename *filename, int flags, struct kstat *stat, u32 request_mask) -// int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, int flags) -// int vfs_statx(int dfd, const char __user *filename, int flags, struct kstat *stat, u32 request_mask) -// static void before_stat(hook_fargs8_t *args, void *udata) -// { -// uid_t uid = current_uid(); -// if (!is_su_allow_uid(uid)) return; - -// if ((args->arg1 & 0xF000000000000000) == 0xF000000000000000) { -// struct filename *filename = (struct filename *)args->arg1; -// if (IS_ERR(filename)) return; -// if (!strcmp(current_su_path, filename->name)) { -// logkfd("0 uid: %d\n", uid); -// strcpy((char *)filename->name, sh_path); -// return; -// } -// } else { -// char __user *filename = (char __user *)args->arg1; -// char buf[SU_PATH_MAX_LEN]; -// compat_strncpy_from_user(buf, filename, sizeof(buf)); -// if (!strcmp(current_su_path, buf)) { -// void *__user uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); -// args->arg1 = (uint64_t)uptr; -// logkfd("1 uid: %d, %llx\n", uid, uptr); -// } -// return; -// } -// } - -#else // SU_COMPAT_INLINE_HOOK +KP_EXPORT_SYMBOL(su_get_path); // #define TRY_DIRECT_MODIFY_USER +#define INLINE_HOOK_SYSCALL + static void handle_before_execve(hook_local_t *hook_local, char **__user u_filename_p, char **__user uargv, void *udata) { #ifdef TRY_DIRECT_MODIFY_USER @@ -403,8 +266,6 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen hook_local->data0 = 0; #endif - void *is_compact = udata; - char __user *ufilename = *u_filename_p; char filename[SU_PATH_MAX_LEN]; int flen = compat_strncpy_from_user(filename, ufilename, sizeof(filename)); @@ -419,8 +280,10 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen const char *sctx = profile.scontext; commit_su(to_uid, sctx); +#ifdef ANDROID struct file *filp = filp_open(apd_path, O_RDONLY, 0); if (!filp || IS_ERR(filp)) { +#endif int cplen = 0; #ifdef TRY_DIRECT_MODIFY_USER cplen = compat_copy_to_user(*u_filename_p, sh_path, sizeof(sh_path)); @@ -437,6 +300,8 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen } logkfi("call su uid: %d, to_uid: %d, sctx: %s, uptr: %llx\n", uid, to_uid, sctx, uptr); } + +#ifdef ANDROID } else { filp_close(filp, 0); @@ -464,7 +329,7 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen int argv_cplen = 0; if (strcmp(legacy_su_path, filename)) { #ifdef TRY_DIRECT_MODIFY_USER - const char __user *p1 = get_user_arg_ptr(is_compact, *uargv, 0); + const char __user *p1 = get_user_arg_ptr(0, *uargv, 0); argv_cplen = compat_copy_to_user((void *__user)p1, legacy_su_path, sizeof(legacy_su_path)); #endif if (argv_cplen <= 0) { @@ -473,7 +338,7 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen sp &= 0xFFFFFFFFFFFFFFF8; argv_cplen = compat_copy_to_user((void *)sp, legacy_su_path, sizeof(legacy_su_path)); if (argv_cplen > 0) { - int rc = set_user_arg_ptr(is_compact, *uargv, 0, sp); + int rc = set_user_arg_ptr(0, *uargv, 0, sp); if (rc < 0) { // todo: modify entire argv logkfi("call apd argv error, uid: %d, to_uid: %d, sctx: %s, rc: %d\n", uid, to_uid, sctx, rc); @@ -483,43 +348,10 @@ static void handle_before_execve(hook_local_t *hook_local, char **__user u_filen } logkfi("call apd uid: %d, to_uid: %d, sctx: %s, cplen: %d, %d\n", uid, to_uid, sctx, cplen, argv_cplen); } - +#endif // ANDROID } else if (!strcmp(SUPERCMD, filename)) { - // key - const char __user *p1 = get_user_arg_ptr(is_compact, *uargv, 1); - if (!p1 || IS_ERR(p1)) return; - - // auth key - char arg1[SUPER_KEY_LEN]; - if (compat_strncpy_from_user(arg1, p1, sizeof(arg1)) <= 0) return; - if (auth_superkey(arg1)) return; - - commit_su(0, 0); - - // real command -#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(*filename) - 128) // enough - - const char *exec = sh_path; - int exec_len = sizeof(sh_path); - const char __user *p2 = get_user_arg_ptr(is_compact, *uargv, 2); - - if (p1 && !IS_ERR(p2)) { - char buffer[EMBEDDED_NAME_MAX]; - int len = compat_strncpy_from_user(buffer, p2, EMBEDDED_NAME_MAX); - if (len >= 0) { - exec = buffer; - exec_len = len; - } - } - - int cplen = 0; -#ifdef TRY_DIRECT_MODIFY_USER - cplen = compat_copy_to_user(*u_filename_p, exec, exec_len); -#endif - if (cplen <= 0) *u_filename_p = copy_to_user_stack(exec, exec_len); - - // shift args - *uargv += 2 * (is_compact ? 4 : 8); + handle_supercmd(u_filename_p, uargv); + return; } } @@ -542,6 +374,7 @@ static void handle_after_execve(hook_local_t *hook_local) // https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2087 // SYSCALL_DEFINE3(execve, const char __user *, filename, const char __user *const __user *, argv, // const char __user *const __user *, envp) + static void before_execve(hook_fargs3_t *args, void *udata) { void *arg0p = syscall_argn_p(args, 0); @@ -568,7 +401,7 @@ static void after_execve(hook_fargs3_t *args, void *udata) // https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2095 // SYSCALL_DEFINE5(execveat, int, fd, const char __user *, filename, const char __user *const __user *, argv, // const char __user *const __user *, envp, int, flags) -static void before_execveat(hook_fargs5_t *args, void *udata) +__maybe_unused static void before_execveat(hook_fargs5_t *args, void *udata) { void *arg1p = syscall_argn_p(args, 1); void *arg2p = syscall_argn_p(args, 2); @@ -607,26 +440,28 @@ static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata) uid_t uid = current_uid(); if (!is_su_allow_uid(uid)) return; - char __user *ufilename = (char __user *)syscall_argn(args, 1); + char __user **u_filename_p = (char __user **)syscall_argn_p(args, 1); + char filename[SU_PATH_MAX_LEN]; - int flen = compat_strncpy_from_user(filename, ufilename, sizeof(filename)); + int flen = compat_strncpy_from_user(filename, *u_filename_p, sizeof(filename)); if (flen <= 0) return; if (!strcmp(current_su_path, filename)) { int cplen = 0; #ifdef TRY_DIRECT_MODIFY_USER - cplen = compat_copy_to_user(ufilename, sh_path, sizeof(sh_path)); + cplen = compat_copy_to_user(*u_filename_p, sh_path, sizeof(sh_path)); #endif if (cplen > 0) { args->local.data0 = cplen; - args->local.data1 = (uint64_t)ufilename; - // logkfi("su uid: %d, cp: %d\n", uid, cplen); + args->local.data1 = (uint64_t)*u_filename_p; + logkfi("su uid: %d, cp: %d\n", uid, cplen); } else { void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); if (uptr && !IS_ERR(uptr)) { - set_syscall_argn(args, 1, (uint64_t)uptr); + *u_filename_p = uptr; + } else { + logkfi("su uid: %d, cp stack error: %d\n", uid, uptr); } - // logkfi("su uid: %d, cp stack: %llx\n", uid, uptr); } } } @@ -643,8 +478,6 @@ static void su_handler_arg1_ufilename_after(hook_fargs6_t *args, void *udata) #define su_handler_arg1_ufilename_after 0 #endif -#endif // SU_COMPAT_INLINE_HOOK - int su_compat_init() { current_su_path = default_su_path; @@ -653,84 +486,44 @@ int su_compat_init() spin_lock_init(&list_lock); // default shell - struct su_profile default_allow_profile = { - .uid = 2000, - .to_uid = 0, - .scontext = ALL_ALLOW_SCONTEXT, - }; - su_add_allow_uid(default_allow_profile.uid, &default_allow_profile, 1); - - // default root - default_allow_profile.uid = 0; - su_add_allow_uid(default_allow_profile.uid, &default_allow_profile, 1); + su_add_allow_uid(2000, 0, all_allow_sctx, 1); + su_add_allow_uid(0, 0, all_allow_sctx, 1); hook_err_t rc = HOOK_NO_ERR; -#ifdef SU_COMPAT_INLINE_HOOK - - struct patch_symbol *symbol = get_preset_patch_sym(); - - if (symbol->do_execveat_common) { // [5.9.0, ) or [3.19, 4.19] - rc = hook_wrap8((void *)symbol->do_execveat_common, (void *)before_do_execve, 0, 0); - log_boot("hook do_execveat_common rc: %d\n", rc); - } else if (symbol->__do_execve_file) { // [4.19, 5.9) - rc = hook_wrap8((void *)symbol->__do_execve_file, (void *)before_do_execve, 0, 0); - log_boot("hook __do_execve_file rc: %d\n", rc); - } else if (symbol->do_execve_common) { // (, 3.19) - rc = hook_wrap8((void *)symbol->do_execve_common, (void *)before_do_execve, 0, (void *)1); - log_boot("hook do_execve_common rc: %d\n", rc); - } - - if (symbol->sys_faccessat) { - rc = hook_wrap4((void *)symbol->sys_faccessat, (void *)before_faccessat, 0, (void *)1); - log_boot("hook sys_faccessat rc: %d\n", rc); - } - if (symbol->sys_faccessat2) { - rc = hook_wrap4((void *)symbol->sys_faccessat2, (void *)before_faccessat, 0, (void *)1); - log_boot("hook sys_faccessat2 rc: %d\n", rc); - } - - if (symbol->sys_newfstatat) { - rc = hook_wrap4((void *)symbol->sys_newfstatat, (void *)before_sysfstatat, 0, (void *)1); - log_boot("hook sys_newfstatat rc: %d\n", rc); - } - -#else - - rc = fp_hook_syscalln(__NR_execve, 3, before_execve, after_execve, (void *)0); + rc = hook_syscalln(__NR_execve, 3, before_execve, after_execve, (void *)0); log_boot("hook __NR_execve rc: %d\n", rc); - rc = fp_hook_syscalln(__NR_execveat, 5, before_execveat, after_execveat, (void *)0); - log_boot("hook __NR_execveat rc: %d\n", rc); + // rc = hook_syscalln(__NR_execveat, 5, before_execveat, after_execveat, (void *)0); + // log_boot("hook __NR_execveat rc: %d\n", rc); - rc = fp_hook_syscalln(__NR3264_fstatat, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, - (void *)0); + rc = hook_syscalln(__NR3264_fstatat, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, + (void *)0); log_boot("hook __NR3264_fstatat rc: %d\n", rc); - rc = fp_hook_syscalln(__NR_statx, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); - log_boot("hook __NR_statx rc: %d\n", rc); + // rc = hook_syscalln(__NR_statx, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook __NR_statx rc: %d\n", rc); - rc = fp_hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, - (void *)0); + rc = hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); log_boot("hook __NR_faccessat rc: %d\n", rc); - rc = fp_hook_syscalln(__NR_faccessat2, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, - (void *)0); - log_boot("hook __NR_faccessat2 rc: %d\n", rc); + // rc = + // hook_syscalln(__NR_faccessat2, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook __NR_faccessat2 rc: %d\n", rc); // #include // __NR_execve 11 - rc = fp_hook_compat_syscalln(11, 3, before_execve, after_execve, (void *)1); + rc = hook_compat_syscalln(11, 3, before_execve, after_execve, (void *)1); log_boot("hook 32 __NR_execve rc: %d\n", rc); // __NR_execveat 387 - rc = fp_hook_compat_syscalln(387, 5, before_execveat, after_execveat, (void *)1); - log_boot("hook 32 __NR_execveat rc: %d\n", rc); + // rc = hook_compat_syscalln(387, 5, before_execveat, after_execveat, (void *)1); + // log_boot("hook 32 __NR_execveat rc: %d\n", rc); // __NR_statx 397 - rc = fp_hook_compat_syscalln(397, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); - log_boot("hook 32 __NR_statx rc: %d\n", rc); + // rc = hook_compat_syscalln(397, 5, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook 32 __NR_statx rc: %d\n", rc); // #define __NR_stat 106 // #define __NR_lstat 107 @@ -738,18 +531,16 @@ int su_compat_init() // #define __NR_lstat64 196 // __NR_fstatat64 327 - rc = fp_hook_compat_syscalln(327, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + rc = hook_compat_syscalln(327, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); log_boot("hook 32 __NR_fstatat64 rc: %d\n", rc); // __NR_faccessat 334 - rc = fp_hook_compat_syscalln(334, 3, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + rc = hook_compat_syscalln(334, 3, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); log_boot("hook 32 __NR_faccessat rc: %d\n", rc); // __NR_faccessat2 439 - rc = fp_hook_compat_syscalln(439, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); - log_boot("hook 32 __NR_faccessat2 rc: %d\n", rc); - -#endif + // rc = hook_compat_syscalln(439, 4, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, (void *)0); + // log_boot("hook 32 __NR_faccessat2 rc: %d\n", rc); - return rc; + return 0; } \ No newline at end of file diff --git a/kernel/patch/common/supercall.c b/kernel/patch/common/supercall.c index 3d3bd33f..d512fd09 100644 --- a/kernel/patch/common/supercall.c +++ b/kernel/patch/common/supercall.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #define MAX_KEY_LEN 128 @@ -178,7 +180,65 @@ static unsigned long call_pid_virt_to_phys(pid_t pid, uintptr_t vaddr) return pid_virt_to_phys(pid, vaddr); } -static long supercall(long cmd, long arg1, long arg2, long arg3, long arg4) +static long call_grant_uid(struct su_profile *__user uprofile) +{ + struct su_profile *profile = memdup_user(uprofile, sizeof(struct su_profile)); + if (!profile || IS_ERR(profile)) return PTR_ERR(profile); + int rc = su_add_allow_uid(profile->uid, profile->to_uid, profile->scontext, 1); + kvfree(profile); + return rc; +} + +static long call_revoke_uid(uid_t uid) +{ + return su_remove_allow_uid(uid, 1); +} + +static long call_su_allow_uid_nums() +{ + return su_allow_uid_nums(); +} + +static long call_su_list_allow_uid(uid_t *__user uids, int num) +{ + return su_allow_uids(1, uids, num); +} + +static long call_su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile) +{ + return su_allow_uid_profile(1, uid, uprofile); +} + +static long call_reset_su_path(const char *__user upath) +{ + return su_reset_path(strndup_user(upath, SU_PATH_MAX_LEN)); +} + +static long call_su_get_path(char *__user ubuf, int buf_len) +{ + const char *path = su_get_path(); + int len = strlen(path); + if (buf_len <= len) return -ENOBUFS; + return compat_copy_to_user(ubuf, path, len + 1); +} + +static long call_su_get_allow_sctx(char *__user usctx, int ulen) +{ + int len = strlen(all_allow_sctx); + if (ulen <= len) return -ENOBUFS; + return compat_copy_to_user(usctx, all_allow_sctx, len + 1); +} + +static long call_su_set_allow_sctx(char *__user usctx) +{ + char buf[SUPERCALL_SCONTEXT_LEN]; + buf[0] = '\0'; + int len = compat_strncpy_from_user(buf, usctx, sizeof(buf)); + if (len >= SUPERCALL_SCONTEXT_LEN && buf[SUPERCALL_SCONTEXT_LEN - 1]) return -E2BIG; + return set_all_allow_sctx(buf); +} + +static long supercall(int is_key_auth, long cmd, long arg1, long arg2, long arg3, long arg4) { switch (cmd) { case SUPERCALL_HELLO: @@ -192,6 +252,47 @@ static long supercall(long cmd, long arg1, long arg2, long arg3, long arg4) return kver; } + switch (cmd) { + case SUPERCALL_SU: + return call_su((struct su_profile * __user) arg1); + case SUPERCALL_SU_TASK: + return call_su_task((pid_t)arg1, (struct su_profile * __user) arg2); + + case SUPERCALL_SU_GRANT_UID: + return call_grant_uid((struct su_profile * __user) arg1); + case SUPERCALL_SU_REVOKE_UID: + return call_revoke_uid((uid_t)arg1); + case SUPERCALL_SU_NUMS: + return call_su_allow_uid_nums(); + case SUPERCALL_SU_LIST: + return call_su_list_allow_uid((uid_t *)arg1, (int)arg2); + case SUPERCALL_SU_PROFILE: + return call_su_allow_uid_profile((uid_t)arg1, (struct su_profile * __user) arg2); + case SUPERCALL_SU_RESET_PATH: + return call_reset_su_path((const char *)arg1); + case SUPERCALL_SU_GET_PATH: + return call_su_get_path((char *__user)arg1, (int)arg2); + case SUPERCALL_SU_GET_ALLOW_SCTX: + return call_su_get_allow_sctx((char *__user)arg1, (int)arg2); + case SUPERCALL_SU_SET_ALLOW_SCTX: + return call_su_set_allow_sctx((char *__user)arg1); + default: + break; + } + + switch (cmd) { + case SUPERCALL_BOOTLOG: + return call_bootlog(); + case SUPERCALL_PANIC: + return call_panic(); + case SUPERCALL_TEST: + return call_test(arg1, arg2, arg3); + default: + break; + } + + if (!is_key_auth) return -EPERM; + switch (cmd) { case SUPERCALL_SKEY_GET: return call_skey_get((char *__user)arg1, (int)arg2); @@ -203,10 +304,6 @@ static long supercall(long cmd, long arg1, long arg2, long arg3, long arg4) } switch (cmd) { - case SUPERCALL_SU: - return call_su((struct su_profile * __user) arg1); - case SUPERCALL_SU_TASK: - return call_su_task((pid_t)arg1, (struct su_profile * __user) arg2); case SUPERCALL_KPM_LOAD: return call_kpm_load((const char *__user)arg1, (const char *__user)arg2, (void *__user)arg3); case SUPERCALL_KPM_UNLOAD: @@ -219,21 +316,16 @@ static long supercall(long cmd, long arg1, long arg2, long arg3, long arg4) return call_kpm_list((char *__user)arg1, (int)arg2); case SUPERCALL_KPM_INFO: return call_kpm_info((const char *__user)arg1, (char *__user)arg2, (int)arg3); + } + + switch (cmd) { case SUPERCALL_MEM_PHYS: return call_pid_virt_to_phys((pid_t)arg1, (uintptr_t)arg2); - - case SUPERCALL_BOOTLOG: - return call_bootlog(); - case SUPERCALL_PANIC: - return call_panic(); - case SUPERCALL_TEST: - return call_test(arg1, arg2, arg3); + default: + break; } -#ifdef ANDROID - return supercall_android(cmd, arg1, arg2, arg3); -#endif - return NO_SYSCALL; + return -ENOSYS; } static void before(hook_fargs6_t *args, void *udata) @@ -251,7 +343,17 @@ static void before(hook_fargs6_t *args, void *udata) char key[MAX_KEY_LEN]; long len = compat_strncpy_from_user(key, ukey, MAX_KEY_LEN); if (len <= 0) return; - if (auth_superkey(key)) return; + + int is_key_auth = 0; + + if (auth_superkey(key)) { + is_key_auth = 1; + } else if (!strcmp("su", key)) { + uid_t uid = current_uid(); + if (!is_su_allow_uid(uid)) return; + } else { + return; + } long a1 = (long)syscall_argn(args, 2); long a2 = (long)syscall_argn(args, 3); @@ -259,14 +361,14 @@ static void before(hook_fargs6_t *args, void *udata) long a4 = (long)syscall_argn(args, 5); args->skip_origin = 1; - args->ret = supercall(cmd, a1, a2, a3, a4); + args->ret = supercall(is_key_auth, cmd, a1, a2, a3, a4); } int supercall_install() { int rc = 0; - hook_err_t err = fp_hook_syscalln(__NR_supercall, 6, before, 0, 0); + hook_err_t err = hook_syscalln(__NR_supercall, 6, before, 0, 0); if (err) { log_boot("install supercall hook error: %d\n", err); rc = err; diff --git a/kernel/patch/common/supercmd.c b/kernel/patch/common/supercmd.c new file mode 100644 index 00000000..090eb7ad --- /dev/null +++ b/kernel/patch/common/supercmd.c @@ -0,0 +1,405 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *__user supercmd_str_to_user_sp(const char *data, uintptr_t *sp) +{ + int len = strlen(data) + 1; + *sp -= len; + *sp &= 0xFFFFFFFFFFFFFFF8; + int cplen = compat_copy_to_user((void *)*sp, data, len); + if (cplen > 0) return (char *__user) * sp; + return 0; +} + +static void supercmd_exec(char **__user u_filename_p, const char *cmd, uintptr_t *sp) +{ + int cplen = 0; +#if 1 + cplen = compat_copy_to_user(*u_filename_p, cmd, strlen(cmd) + 1); +#endif + if (cplen <= 0) *u_filename_p = supercmd_str_to_user_sp(cmd, sp); +} + +static void supercmd_echo(char **__user u_filename_p, char **__user uargv, uintptr_t *sp, const char *fmt, ...) +{ + supercmd_exec(u_filename_p, ECHO_PATH, sp); + + char buffer[4096]; + va_list va; + va_start(va, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, va); + va_end(va); + + const char *__user cmd = supercmd_str_to_user_sp(ECHO_PATH, sp); + const char *__user argv1 = supercmd_str_to_user_sp(buffer, sp); + + set_user_arg_ptr(0, *uargv, 0, (uintptr_t)cmd); + set_user_arg_ptr(0, *uargv, 1, (uintptr_t)argv1); + set_user_arg_ptr(0, *uargv, 2, 0); +} + +static const char supercmd_help[] = + "" + "KernelPatch supercmd:\n" + "Usage: truncate [-uZc] [Command [[SubCommand]...]]\n" + "superkey|su: Authentication. For certain commands, if the current uid is allowed to use su,\n" + " the 'su' string can be used for authentication.\n" + "Options:\n" + " -u Change user id to UID.\n" + " -Z Change security context to SCONTEXT.\n" + "\n" + "Command:\n" + " help: Print this help message.\n" + " version: Print Kernel version and KernelPatch version,\n " + " eg: 50a0a,a06 means kernel version 5.10.10, KernelPatch version 0.10.6.\n" + " -c [...]: Pass a single COMMAND to the default shell.\n" + " exec [...]: Execute command with full PATH.\n" + " sumgr [...]: SU permission manager\n" + " The default command obtain a shell with the specified TO_UID and SCONTEXT is 'kp',\n" + " whose full PATH is '/system/bin/kp'. This can avoid conflicts with the existing 'su' command.\n" + " If you wish to modify this PATH, you can use the 'reset' command.\n" + " SubCommand:\n" + " grant [TO_UID] [SCONTEXT] Grant su permission to UID.\n" + " revoke Revoke su permission to UID.\n" + " num Get the number of uids with the aforementioned permissions.\n" + " list List all su allowed uids.\n" + " profile Get the profile of the uid configuration.\n" + " path [PATH] Get or Reset current su path. The length of PATH must 2-127.\n" + " sctx [SCONTEXT] Get or Reset current all allowed security context, \n" + "\n" + "The command below requires superkey authentication.\n" + " module [...]: KernelPatch Module manager\n" + " SubCommand:\n" + " load [KPM_ARGS] Load module with KPM_PATH and KPM_ARGS.\n" + " ctl0 Control module named KPM_PATH with CTL_ARGS.\n" + " unload Unload module named KPM_NAME.\n" + " num Get the number of modules that have been loaded.\n" + " list List names of all loaded modules.\n" + " info Get detailed information about module named KPM_NAME.\n" + " key [...]: Superkey manager\n" + " SubCommand:\n" + " key [SUPERKEY]: Get or Reset current superkey\n" + " hash [enable|disable]: Whether to use hash to verify the root superkey.\n" + ""; + +void handle_supercmd(char **__user u_filename_p, char **__user uargv) +{ + int is_key_auth = 0; + + // key + const char __user *p1 = get_user_arg_ptr(0, *uargv, 1); + if (!p1 || IS_ERR(p1)) return; + + struct su_profile profile = { .to_uid = 0, .scontext = "" }; + + // auth key + char arg1[SUPER_KEY_LEN]; + if (compat_strncpy_from_user(arg1, p1, sizeof(arg1)) <= 0) return; + + if (!auth_superkey(arg1)) { + is_key_auth = 1; + } else if (!strcmp("su", arg1)) { + uid_t uid = current_uid(); + if (!is_su_allow_uid(uid)) return; + profile = profile_su_allow_uid(uid); + } else { + return; + } + +#define SUPERCMD_ARGS_NO 16 + + // args + const char *parr[SUPERCMD_ARGS_NO + 4] = { 0 }; + + for (int i = 2; i < SUPERCMD_ARGS_NO; i++) { + const char __user *ua = get_user_arg_ptr(0, *uargv, i); + if (!ua || IS_ERR(ua)) break; + const char *a = strndup_user(ua, 512); + if (IS_ERR(a)) break; + // ignore after -c or exec + if (a[0] == '-' && a[1] == 'c') break; + if (!strcmp("exec", a)) break; + parr[i] = a; + } + + uint64_t sp = current_user_stack_pointer(); + + // if no any more + if (!parr[2]) { + supercmd_exec(u_filename_p, sh_path, &sp); + const char *__user argv1 = supercmd_str_to_user_sp(sh_path, &sp); + set_user_arg_ptr(0, *uargv, 1, (uintptr_t)argv1); + *uargv += 1 * 8; + commit_su(profile.to_uid, profile.scontext); + return; + } + + int pi = 2; + + // options, contiguous + while (pi < SUPERCMD_ARGS_NO) { + const char *arg = parr[pi]; + if (!arg || arg[0] != '-') break; + // ignore -c + if (arg[0] == '-' && arg[1] == 'c') break; + char o = arg[1]; + pi++; + switch (o) { + case 'u': + if (parr[pi]) { + unsigned long long to_uid = profile.to_uid; + kstrtoull(parr[pi++], 10, &to_uid); + profile.to_uid = to_uid; + } else { + supercmd_echo(u_filename_p, uargv, &sp, "supercmd error: invalid to_uid"); + goto free; + } + break; + case 'Z': + if (parr[pi]) { + strncpy(profile.scontext, parr[pi++], sizeof(profile.scontext) - 1); + profile.scontext[sizeof(profile.scontext) - 1] = '\0'; + } else { + supercmd_echo(u_filename_p, uargv, &sp, "supercmd error: invalid scontext"); + goto free; + } + break; + default: + goto out_opt; + } + } + +out_opt: + + commit_su(profile.to_uid, profile.scontext); + + int rc = 0; + const char *msg = 0; + const char *err_msg = 0; + char buffer[4096]; + + // command + const char **carr = parr + pi; + const char *cmd = 0; + if (pi < SUPERCMD_ARGS_NO - 1) cmd = carr[0]; + if (!cmd) { + supercmd_exec(u_filename_p, sh_path, &sp); + *uargv += pi * 8; + goto free; + } + + if (!strcmp("help", cmd)) { + msg = supercmd_help; + } else if (!strcmp("-c", cmd)) { + supercmd_exec(u_filename_p, sh_path, &sp); + *uargv += (carr - parr - 1) * 8; + } else if (!strcmp("exec", cmd)) { + if (!carr[1]) { + err_msg = "invalid commmand path"; + goto echo; + } + supercmd_exec(u_filename_p, carr[1], &sp); + *uargv += 3 * 8; + } else if (!strcmp("version", cmd)) { + supercmd_echo(u_filename_p, uargv, &sp, "%x,%x", kver, kpver); + } else if (!strcmp("sumgr", cmd)) { + const char *sub_cmd = carr[1]; + if (!sub_cmd) sub_cmd = ""; + if (!strcmp(sub_cmd, "grant")) { + unsigned long long uid = 0, to_uid = 0; + const char *scontext = ""; + if (!carr[2] || kstrtoull(carr[2], 10, &uid)) { + supercmd_echo(u_filename_p, uargv, &sp, "supercmd error: illegal uid"); + goto free; + } + if (carr[3]) kstrtoull(carr[3], 10, &to_uid); + if (carr[4]) scontext = carr[4]; + su_add_allow_uid(uid, to_uid, scontext, 1); + supercmd_echo(u_filename_p, uargv, &sp, "supercmd: grant %d, %d, %s", uid, to_uid, scontext); + } else if (!strcmp(sub_cmd, "revoke")) { + const char *suid = carr[2]; + unsigned long long uid; + if (!suid || kstrtoull(suid, 10, &uid)) { + supercmd_echo(u_filename_p, uargv, &sp, "supercmd error: illegal uid"); + goto free; + } + su_remove_allow_uid(uid, 1); + msg = suid; + } else if (!strcmp(sub_cmd, "num")) { + int num = su_allow_uid_nums(); + supercmd_echo(u_filename_p, uargv, &sp, "%d", num); + } else if (!strcmp(sub_cmd, "list")) { + int num = su_allow_uid_nums(); + uid_t *uids = (uid_t *)buffer; + int offset = 0; + su_allow_uids(0, uids, num); + + char *msg_buf = buffer + num * sizeof(uid_t); + msg_buf[0] = '\0'; + for (int i = 0; i < num; i++) { + offset += sprintf(msg_buf + offset, "%d\n", uids[i]); + }; + if (offset > 0) msg_buf[offset - 1] = '\0'; + msg = msg_buf; + } else if (!strcmp(sub_cmd, "profile")) { + unsigned long long uid; + if (!carr[2] || kstrtoull(carr[2], 10, &uid)) { + err_msg = "invalid uid"; + goto echo; + } + struct su_profile *profile = (struct su_profile *)buffer; + rc = su_allow_uid_profile(0, uid, profile); + char *msg = buffer + sizeof(struct su_profile); + msg[0] = '\0'; + if (!rc) + sprintf(msg, "uid: %d, to_uid: %d, scontext: %s", profile->uid, profile->to_uid, profile->scontext); + } else if (!strcmp(sub_cmd, "path")) { + if (carr[2]) { + rc = su_reset_path(carr[2]); + msg = carr[2]; + carr[2] = 0; // no free + } else { + msg = su_get_path(); + } + } else if (!strcmp(sub_cmd, "sctx")) { + if (carr[2]) { + rc = set_all_allow_sctx(carr[2]); + if (!rc) msg = carr[2]; + } else { + msg = all_allow_sctx; + } + } else { + err_msg = "invalid subcommand"; + } + } else if (!strcmp("bootlog", cmd)) { + msg = get_boot_log(); + } else if (!strcmp("test", cmd)) { + void test(); + test(); + msg = "test done..."; + } else { + // superkey authrication command + const char *not_key_auth_err_msg = "superkey(not su) is required"; + if (!strcmp("key", cmd)) { + if (!is_key_auth) { + err_msg = not_key_auth_err_msg; + goto echo; + } + const char *sub_cmd = carr[1]; + if (!sub_cmd) sub_cmd = ""; + if (!strcmp("get", sub_cmd)) { + msg = get_superkey(); + } else if (!strcmp("set", sub_cmd)) { + const char *key = carr[2]; + if (!key) { + err_msg = "invalid new key"; + goto echo; + } + msg = key; + reset_superkey(key); + } else if (!strcmp("hash", sub_cmd)) { + const char *able = carr[2]; + if (!strcmp("enable", able) || !strcmp("disable", able)) { + msg = able; + enable_auth_root_key(1); + } else if (!strcmp("disable", able)) { + msg = able; + enable_auth_root_key(0); + } else { + err_msg = "enable or disable"; + } + } else { + err_msg = "invalid subcommand"; + } + } else if (!strcmp("module", cmd)) { + if (!is_key_auth) { + err_msg = not_key_auth_err_msg; + goto echo; + } + const char *sub_cmd = carr[1]; + if (!sub_cmd) sub_cmd = ""; + if (!strcmp("num", sub_cmd)) { + int num = get_module_nums(); + supercmd_echo(u_filename_p, uargv, &sp, "%d", num); + } else if (!strcmp("list", sub_cmd)) { + buffer[0] = '\0'; + list_modules(buffer, sizeof(buffer)); + msg = buffer; + } else if (!strcmp("load", sub_cmd)) { + const char *path = carr[2]; + if (!path) { + err_msg = "invalid module path"; + goto echo; + } + rc = load_module_path(path, carr[3], 0); + if (!rc) msg = path; + } else if (!strcmp("ctl0", sub_cmd)) { + const char *name = carr[2]; + if (!name) { + err_msg = "invalid module name"; + goto echo; + } + const char *mod_args = carr[3]; + if (!mod_args) { + err_msg = "invalid control arguments"; + goto echo; + } + buffer[0] = '\0'; + rc = module_control0(name, mod_args, buffer, sizeof(buffer)); + msg = buffer; + } else if (!strcmp("ctl1", sub_cmd)) { + err_msg = "not implement"; + } else if (!strcmp("unload", sub_cmd)) { + const char *name = carr[2]; + if (!name) { + err_msg = "invalid module name"; + goto echo; + } + rc = unload_module(name, 0); + if (!rc) msg = name; + } else if (!strcmp("info", sub_cmd)) { + const char *name = carr[2]; + if (!name) { + err_msg = "invalid module name"; + goto echo; + } + buffer[0] = '\0'; + int sz = get_module_info(name, buffer, sizeof(buffer)); + if (sz <= 0) rc = sz; + msg = buffer; + } else { + err_msg = "invalid subcommand"; + } + } else { + err_msg = "invalid command"; + } + } + +echo: + if (msg) supercmd_echo(u_filename_p, uargv, &sp, msg); + if (rc) supercmd_echo(u_filename_p, uargv, &sp, "supercmd error code: %d", rc); + if (err_msg) supercmd_echo(u_filename_p, uargv, &sp, "supercmd error message: %s", err_msg); + +free: + // free args + for (int i = 2; i < sizeof(parr) / sizeof(parr[0]); i++) { + const char *a = parr[i]; + if (!a) break; + kfree(a); + } +} diff --git a/kernel/patch/common/syscall.c b/kernel/patch/common/syscall.c index c83130b0..d8a6b7ca 100644 --- a/kernel/patch/common/syscall.c +++ b/kernel/patch/common/syscall.c @@ -18,6 +18,7 @@ #include #include #include +#include uintptr_t *sys_call_table = 0; KP_EXPORT_SYMBOL(sys_call_table); @@ -68,7 +69,7 @@ const char __user *get_user_arg_ptr(void *a0, void *a1, int nr) } else { uptr = (char __user *)(unsigned long)*(int32_t *)upptr; } - kvfree(upptr); + kfree(upptr); return uptr; } @@ -103,7 +104,8 @@ long raw_syscall0(long nr) uintptr_t addr = sys_call_table[nr]; if (has_syscall_wrapper) { struct pt_regs regs; - memset(®s, 0, sizeof(regs)); + regs.syscallno = nr; + regs.regs[8] = nr; return ((warp_raw_syscall_f)addr)(®s); } return ((raw_syscall0_f)addr)(); @@ -115,7 +117,9 @@ long raw_syscall1(long nr, long arg0) uintptr_t addr = sys_call_table[nr]; if (has_syscall_wrapper) { struct pt_regs regs; - memset(®s, 0, sizeof(regs)); + regs.syscallno = nr; + regs.regs[8] = nr; + regs.regs[0] = arg0; return ((warp_raw_syscall_f)addr)(®s); } return ((raw_syscall1_f)addr)(arg0); @@ -126,7 +130,8 @@ long raw_syscall2(long nr, long arg0, long arg1) uintptr_t addr = sys_call_table[nr]; if (has_syscall_wrapper) { struct pt_regs regs; - memset(®s, 0, sizeof(regs)); + regs.syscallno = nr; + regs.regs[8] = nr; regs.regs[0] = arg0; regs.regs[1] = arg1; return ((warp_raw_syscall_f)addr)(®s); @@ -139,7 +144,8 @@ long raw_syscall3(long nr, long arg0, long arg1, long arg2) uintptr_t addr = sys_call_table[nr]; if (has_syscall_wrapper) { struct pt_regs regs; - memset(®s, 0, sizeof(regs)); + regs.syscallno = nr; + regs.regs[8] = nr; regs.regs[0] = arg0; regs.regs[1] = arg1; regs.regs[2] = arg2; @@ -153,7 +159,8 @@ long raw_syscall4(long nr, long arg0, long arg1, long arg2, long arg3) uintptr_t addr = sys_call_table[nr]; if (has_syscall_wrapper) { struct pt_regs regs; - memset(®s, 0, sizeof(regs)); + regs.syscallno = nr; + regs.regs[8] = nr; regs.regs[0] = arg0; regs.regs[1] = arg1; regs.regs[2] = arg2; @@ -168,7 +175,8 @@ long raw_syscall5(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 uintptr_t addr = sys_call_table[nr]; if (has_syscall_wrapper) { struct pt_regs regs; - memset(®s, 0, sizeof(regs)); + regs.syscallno = nr; + regs.regs[8] = nr; regs.regs[0] = arg0; regs.regs[1] = arg1; regs.regs[2] = arg2; @@ -184,7 +192,8 @@ long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 uintptr_t addr = sys_call_table[nr]; if (has_syscall_wrapper) { struct pt_regs regs; - memset(®s, 0, sizeof(regs)); + regs.syscallno = nr; + regs.regs[8] = nr; regs.regs[0] = arg0; regs.regs[1] = arg1; regs.regs[2] = arg2; @@ -196,6 +205,36 @@ long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 return ((raw_syscall6_f)addr)(arg0, arg1, arg2, arg3, arg4, arg5); } +uintptr_t syscalln_name_addr(int nr, int is_compat) +{ + const char *name = 0; + if (!is_compat) { + name = syscall_name_table[nr]; + } else { + name = compat_syscall_name_table[nr]; + } + if (!name) return 0; + char buffer[128] = "__arm64_"; + strlcat(buffer, name, 64); + uintptr_t addr = kallsyms_lookup_name(buffer); + if (!addr) addr = kallsyms_lookup_name(name); + return addr; +} + +hook_err_t __inline_hook_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata) +{ + uintptr_t addr = syscalln_name_addr(nr, is_compat); + if (!addr) return -HOOK_BAD_ADDRESS; + if (has_syscall_wrapper) narg = 1; + return hook_wrap((void *)addr, narg, before, after, udata); +} + +void __inline_unhook_syscalln(int nr, int is_compat, void *before, void *after) +{ + uintptr_t addr = syscalln_name_addr(nr, is_compat); + hook_unwrap((void *)addr, before, after); +} + static uint64_t search_sys_call_table_addr() { uint64_t addr = kernel_va; @@ -249,18 +288,20 @@ static uint64_t search_sys_call_table_addr() return 0; } -int syscall_init() +void syscall_init() { - int rc = 0; - sys_call_table = (typeof(sys_call_table))kallsyms_lookup_name("sys_call_table"); - if (!sys_call_table) { - sys_call_table = (typeof(sys_call_table))search_sys_call_table_addr(); + for (int i = 0; i < sizeof(syscall_name_table) / sizeof(syscall_name_table[0]); i++) { + uintptr_t *addr = (uintptr_t *)syscall_name_table + i; + *addr = link2runtime(*addr); } - if (!sys_call_table) { - rc = -ENOENT; - log_boot("no symbol sys_call_table\n"); - goto out; + + for (int i = 0; i < sizeof(compat_syscall_name_table) / sizeof(compat_syscall_name_table[0]); i++) { + uintptr_t *addr = (uintptr_t *)compat_syscall_name_table + i; + *addr = link2runtime(*addr); } + + sys_call_table = (typeof(sys_call_table))kallsyms_lookup_name("sys_call_table"); + if (!sys_call_table) sys_call_table = (typeof(sys_call_table))search_sys_call_table_addr(); log_boot("sys_call_table addr: %llx\n", sys_call_table); compat_sys_call_table = (typeof(compat_sys_call_table))kallsyms_lookup_name("compat_sys_call_table"); @@ -282,9 +323,5 @@ int syscall_init() } log_boot("syscall config_compat: %d\n", has_config_compat); - log_boot("syscall has_wrapper: %d\n", has_syscall_wrapper); - -out: - return rc; } diff --git a/kernel/patch/common/sysname.c b/kernel/patch/common/sysname.c new file mode 100644 index 00000000..21e28f01 --- /dev/null +++ b/kernel/patch/common/sysname.c @@ -0,0 +1,712 @@ +#include + +const char *syscall_name_table[460] = { + [0] = "sys_io_setup", + [1] = "sys_io_destroy", + [2] = "sys_io_submit", + [3] = "sys_io_cancel", + [4] = "sys_io_getevents", + [5] = "sys_setxattr", + [6] = "sys_lsetxattr", + [7] = "sys_fsetxattr", + [8] = "sys_getxattr", + [9] = "sys_lgetxattr", + [10] = "sys_fgetxattr", + [11] = "sys_listxattr", + [12] = "sys_llistxattr", + [13] = "sys_flistxattr", + [14] = "sys_removexattr", + [15] = "sys_lremovexattr", + [16] = "sys_fremovexattr", + [17] = "sys_getcwd", + [19] = "sys_eventfd2", + [20] = "sys_epoll_create1", + [21] = "sys_epoll_ctl", + [22] = "sys_epoll_pwait", + [23] = "sys_dup", + [24] = "sys_dup3", + [25] = "sys_fcntl", + [26] = "sys_inotify_init1", + [27] = "sys_inotify_add_watch", + [28] = "sys_inotify_rm_watch", + [29] = "sys_ioctl", + [30] = "sys_ioprio_set", + [31] = "sys_ioprio_get", + [32] = "sys_flock", + [33] = "sys_mknodat", + [34] = "sys_mkdirat", + [35] = "sys_unlinkat", + [36] = "sys_symlinkat", + [37] = "sys_linkat", + [38] = "sys_renameat", + [39] = "sys_umount", + [40] = "sys_mount", + [41] = "sys_pivot_root", + [43] = "sys_statfs", + [44] = "sys_fstatfs", + [45] = "sys_truncate", + [46] = "sys_ftruncate", + [47] = "sys_fallocate", + [48] = "sys_faccessat", + [49] = "sys_chdir", + [50] = "sys_fchdir", + [51] = "sys_chroot", + [52] = "sys_fchmod", + [53] = "sys_fchmodat", + [54] = "sys_fchownat", + [55] = "sys_fchown", + [56] = "sys_openat", + [57] = "sys_close", + [58] = "sys_vhangup", + [59] = "sys_pipe2", + [60] = "sys_quotactl", + [61] = "sys_getdents64", + [62] = "sys_lseek", + [63] = "sys_read", + [64] = "sys_write", + [65] = "sys_readv", + [66] = "sys_writev", + [67] = "sys_pread64", + [68] = "sys_pwrite64", + [69] = "sys_preadv", + [70] = "sys_pwritev", + [71] = "sys_sendfile64", + [72] = "sys_pselect6", + [73] = "sys_ppoll", + [74] = "sys_signalfd4", + [75] = "sys_vmsplice", + [76] = "sys_splice", + [77] = "sys_tee", + [78] = "sys_readlinkat", + [79] = "sys_newfstatat", + [80] = "sys_newfstat", + [81] = "sys_sync", + [82] = "sys_fsync", + [83] = "sys_fdatasync", + [84] = "sys_sync_file_range", + [85] = "sys_timerfd_create", + [86] = "sys_timerfd_settime", + [87] = "sys_timerfd_gettime", + [88] = "sys_utimensat", + [89] = "sys_acct", + [90] = "sys_capget", + [91] = "sys_capset", + [92] = "sys_arm64_personality", + [93] = "sys_exit", + [94] = "sys_exit_group", + [95] = "sys_waitid", + [96] = "sys_set_tid_address", + [97] = "sys_unshare", + [98] = "sys_futex", + [99] = "sys_set_robust_list", + [100] = "sys_get_robust_list", + [101] = "sys_nanosleep", + [102] = "sys_getitimer", + [103] = "sys_setitimer", + [104] = "sys_kexec_load", + [105] = "sys_init_module", + [106] = "sys_delete_module", + [107] = "sys_timer_create", + [108] = "sys_timer_gettime", + [109] = "sys_timer_getoverrun", + [110] = "sys_timer_settime", + [111] = "sys_timer_delete", + [112] = "sys_clock_settime", + [113] = "sys_clock_gettime", + [114] = "sys_clock_getres", + [115] = "sys_clock_nanosleep", + [116] = "sys_syslog", + [117] = "sys_ptrace", + [118] = "sys_sched_setparam", + [119] = "sys_sched_setscheduler", + [120] = "sys_sched_getscheduler", + [121] = "sys_sched_getparam", + [122] = "sys_sched_setaffinity", + [123] = "sys_sched_getaffinity", + [124] = "sys_sched_yield", + [125] = "sys_sched_get_priority_max", + [126] = "sys_sched_get_priority_min", + [127] = "sys_sched_rr_get_interval", + [128] = "sys_restart_syscall", + [129] = "sys_kill", + [130] = "sys_tkill", + [131] = "sys_tgkill", + [132] = "sys_sigaltstack", + [133] = "sys_rt_sigsuspend", + [134] = "sys_rt_sigaction", + [135] = "sys_rt_sigprocmask", + [136] = "sys_rt_sigpending", + [137] = "sys_rt_sigtimedwait", + [138] = "sys_rt_sigqueueinfo", + [139] = "sys_rt_sigreturn", + [140] = "sys_setpriority", + [141] = "sys_getpriority", + [142] = "sys_reboot", + [143] = "sys_setregid", + [144] = "sys_setgid", + [145] = "sys_setreuid", + [146] = "sys_setuid", + [147] = "sys_setresuid", + [148] = "sys_getresuid", + [149] = "sys_setresgid", + [150] = "sys_getresgid", + [151] = "sys_setfsuid", + [152] = "sys_setfsgid", + [153] = "sys_times", + [154] = "sys_setpgid", + [155] = "sys_getpgid", + [156] = "sys_getsid", + [157] = "sys_setsid", + [158] = "sys_getgroups", + [159] = "sys_setgroups", + [160] = "sys_newuname", + [161] = "sys_sethostname", + [162] = "sys_setdomainname", + [163] = "sys_getrlimit", + [164] = "sys_setrlimit", + [165] = "sys_getrusage", + [166] = "sys_umask", + [167] = "sys_prctl", + [168] = "sys_getcpu", + [169] = "sys_gettimeofday", + [170] = "sys_settimeofday", + [171] = "sys_adjtimex", + [172] = "sys_getpid", + [173] = "sys_getppid", + [174] = "sys_getuid", + [175] = "sys_geteuid", + [176] = "sys_getgid", + [177] = "sys_getegid", + [178] = "sys_gettid", + [179] = "sys_sysinfo", + [180] = "sys_mq_open", + [181] = "sys_mq_unlink", + [182] = "sys_mq_timedsend", + [183] = "sys_mq_timedreceive", + [184] = "sys_mq_notify", + [185] = "sys_mq_getsetattr", + [186] = "sys_msgget", + [187] = "sys_msgctl", + [188] = "sys_msgrcv", + [189] = "sys_msgsnd", + [190] = "sys_semget", + [191] = "sys_semctl", + [192] = "sys_semtimedop", + [193] = "sys_semop", + [194] = "sys_shmget", + [195] = "sys_shmctl", + [196] = "sys_shmat", + [197] = "sys_shmdt", + [198] = "sys_socket", + [199] = "sys_socketpair", + [200] = "sys_bind", + [201] = "sys_listen", + [202] = "sys_accept", + [203] = "sys_connect", + [204] = "sys_getsockname", + [205] = "sys_getpeername", + [206] = "sys_sendto", + [207] = "sys_recvfrom", + [208] = "sys_setsockopt", + [209] = "sys_getsockopt", + [210] = "sys_shutdown", + [211] = "sys_sendmsg", + [212] = "sys_recvmsg", + [213] = "sys_readahead", + [214] = "sys_brk", + [215] = "sys_munmap", + [216] = "sys_mremap", + [217] = "sys_add_key", + [218] = "sys_request_key", + [219] = "sys_keyctl", + [220] = "sys_clone", + [221] = "sys_execve", + [222] = "sys_mmap", + [223] = "sys_fadvise64_64", + [224] = "sys_swapon", + [225] = "sys_swapoff", + [226] = "sys_mprotect", + [227] = "sys_msync", + [228] = "sys_mlock", + [229] = "sys_munlock", + [230] = "sys_mlockall", + [231] = "sys_munlockall", + [232] = "sys_mincore", + [233] = "sys_madvise", + [234] = "sys_remap_file_pages", + [235] = "sys_mbind", + [236] = "sys_get_mempolicy", + [237] = "sys_set_mempolicy", + [238] = "sys_migrate_pages", + [239] = "sys_move_pages", + [240] = "sys_rt_tgsigqueueinfo", + [241] = "sys_perf_event_open", + [242] = "sys_accept4", + [243] = "sys_recvmmsg", + [260] = "sys_wait4", + [261] = "sys_prlimit64", + [262] = "sys_fanotify_init", + [263] = "sys_fanotify_mark", + [264] = "sys_name_to_handle_at", + [265] = "sys_open_by_handle_at", + [266] = "sys_clock_adjtime", + [267] = "sys_syncfs", + [268] = "sys_setns", + [269] = "sys_sendmmsg", + [270] = "sys_process_vm_readv", + [271] = "sys_process_vm_writev", + [272] = "sys_kcmp", + [273] = "sys_finit_module", + [274] = "sys_sched_setattr", + [275] = "sys_sched_getattr", + [276] = "sys_renameat2", + [277] = "sys_seccomp", + [278] = "sys_getrandom", + [279] = "sys_memfd_create", + [280] = "sys_bpf", + [281] = "sys_execveat", + [282] = "sys_userfaultfd", + [283] = "sys_membarrier", + [284] = "sys_mlock2", + [285] = "sys_copy_file_range", + [286] = "sys_preadv2", + [287] = "sys_pwritev2", + [288] = "sys_pkey_mprotect", + [289] = "sys_pkey_alloc", + [290] = "sys_pkey_free", + [291] = "sys_statx", + [292] = "sys_io_pgetevents", + [293] = "sys_rseq", + [294] = "sys_kexec_file_load", + [424] = "sys_pidfd_send_signal", + [425] = "sys_io_uring_setup", + [426] = "sys_io_uring_enter", + [427] = "sys_io_uring_register", + [428] = "sys_open_tree", + [429] = "sys_move_mount", + [430] = "sys_fsopen", + [431] = "sys_fsconfig", + [432] = "sys_fsmount", + [433] = "sys_fspick", + [434] = "sys_pidfd_open", + [435] = "sys_clone3", + [436] = "sys_close_range", + [437] = "sys_openat2", + [438] = "sys_pidfd_getfd", + [439] = "sys_faccessat2", + [440] = "sys_process_madvise", + [441] = "sys_epoll_pwait2", + [442] = "sys_mount_setattr", + [443] = "sys_quotactl_fd", + [444] = "sys_landlock_create_ruleset", + [445] = "sys_landlock_add_rule", + [446] = "sys_landlock_restrict_self", + [447] = "sys_memfd_secret", + [448] = "sys_process_mrelease", + [449] = "sys_futex_waitv", + [450] = "sys_set_mempolicy_home_node", + [451] = "sys_cachestat", +}; +KP_EXPORT_SYMBOL(syscall_name_table); + +const char *compat_syscall_name_table[460] = { + [0] = "sys_restart_syscall", + [1] = "sys_exit", + [2] = "sys_fork", + [3] = "sys_read", + [4] = "sys_write", + [5] = "sys_open", + [6] = "sys_close", + [8] = "sys_creat", + [9] = "sys_link", + [10] = "sys_unlink", + [11] = "sys_execve", + [12] = "sys_chdir", + [14] = "sys_mknod", + [15] = "sys_chmod", + [16] = "sys_lchown16", + [19] = "sys_lseek", + [20] = "sys_getpid", + [21] = "sys_mount", + [23] = "sys_setuid16", + [24] = "sys_getuid16", + [26] = "sys_ptrace", + [29] = "sys_pause", + [33] = "sys_access", + [34] = "sys_nice", + [36] = "sys_sync", + [37] = "sys_kill", + [38] = "sys_rename", + [39] = "sys_mkdir", + [40] = "sys_rmdir", + [41] = "sys_dup", + [42] = "sys_pipe", + [43] = "sys_times", + [45] = "sys_brk", + [46] = "sys_setgid16", + [47] = "sys_getgid16", + [49] = "sys_geteuid16", + [50] = "sys_getegid16", + [51] = "sys_acct", + [52] = "sys_umount", + [54] = "sys_ioctl", + [55] = "sys_fcntl", + [57] = "sys_setpgid", + [60] = "sys_umask", + [61] = "sys_chroot", + [62] = "sys_ustat", + [63] = "sys_dup2", + [64] = "sys_getppid", + [65] = "sys_getpgrp", + [66] = "sys_setsid", + [67] = "sys_sigaction", + [70] = "sys_setreuid16", + [71] = "sys_setregid16", + [72] = "sys_sigsuspend", + [73] = "sys_sigpending", + [74] = "sys_sethostname", + [75] = "sys_setrlimit", + [77] = "sys_getrusage", + [78] = "sys_gettimeofday", + [79] = "sys_settimeofday", + [80] = "sys_getgroups16", + [81] = "sys_setgroups16", + [83] = "sys_symlink", + [85] = "sys_readlink", + [86] = "sys_uselib", + [87] = "sys_swapon", + [88] = "sys_reboot", + [91] = "sys_munmap", + [92] = "sys_truncate", + [93] = "sys_ftruncate", + [94] = "sys_fchmod", + [95] = "sys_fchown16", + [96] = "sys_getpriority", + [97] = "sys_setpriority", + [99] = "sys_statfs", + [100] = "sys_fstatfs", + [103] = "sys_syslog", + [104] = "sys_setitimer", + [105] = "sys_getitimer", + [106] = "sys_newstat", + [107] = "sys_newlstat", + [108] = "sys_newfstat", + [111] = "sys_vhangup", + [114] = "sys_wait4", + [115] = "sys_swapoff", + [116] = "sys_sysinfo", + [118] = "sys_fsync", + [119] = "sys_sigreturn", + [120] = "sys_clone", + [121] = "sys_setdomainname", + [122] = "sys_newuname", + [124] = "sys_adjtimex_time32", + [125] = "sys_mprotect", + [126] = "sys_sigprocmask", + [128] = "sys_init_module", + [129] = "sys_delete_module", + [131] = "sys_quotactl", + [132] = "sys_getpgid", + [133] = "sys_fchdir", + [135] = "sys_sysfs", + [136] = "sys_personality", + [138] = "sys_setfsuid16", + [139] = "sys_setfsgid16", + [140] = "sys_llseek", + [141] = "sys_getdents", + [142] = "sys_select", + [143] = "sys_flock", + [144] = "sys_msync", + [145] = "sys_readv", + [146] = "sys_writev", + [147] = "sys_getsid", + [148] = "sys_fdatasync", + [150] = "sys_mlock", + [151] = "sys_munlock", + [152] = "sys_mlockall", + [153] = "sys_munlockall", + [154] = "sys_sched_setparam", + [155] = "sys_sched_getparam", + [156] = "sys_sched_setscheduler", + [157] = "sys_sched_getscheduler", + [158] = "sys_sched_yield", + [159] = "sys_sched_get_priority_max", + [160] = "sys_sched_get_priority_min", + [161] = "sys_sched_rr_get_interval_time32", + [162] = "sys_nanosleep_time32", + [163] = "sys_mremap", + [164] = "sys_setresuid16", + [165] = "sys_getresuid16", + [168] = "sys_poll", + [170] = "sys_setresgid16", + [171] = "sys_getresgid16", + [172] = "sys_prctl", + [173] = "sys_rt_sigreturn", + [174] = "sys_rt_sigaction", + [175] = "sys_rt_sigprocmask", + [176] = "sys_rt_sigpending", + [177] = "sys_rt_sigtimedwait_time32", + [178] = "sys_rt_sigqueueinfo", + [179] = "sys_rt_sigsuspend", + [180] = "sys_aarch32_pread64", + [181] = "sys_aarch32_pwrite64", + [182] = "sys_chown16", + [183] = "sys_getcwd", + [184] = "sys_capget", + [185] = "sys_capset", + [186] = "sys_sigaltstack", + [187] = "sys_sendfile", + [190] = "sys_vfork", + [191] = "sys_getrlimit", + [192] = "sys_aarch32_mmap2", + [193] = "sys_aarch32_truncate64", + [194] = "sys_aarch32_ftruncate64", + [195] = "sys_stat64", + [196] = "sys_lstat64", + [197] = "sys_fstat64", + [198] = "sys_lchown", + [199] = "sys_getuid", + [200] = "sys_getgid", + [201] = "sys_geteuid", + [202] = "sys_getegid", + [203] = "sys_setreuid", + [204] = "sys_setregid", + [205] = "sys_getgroups", + [206] = "sys_setgroups", + [207] = "sys_fchown", + [208] = "sys_setresuid", + [209] = "sys_getresuid", + [210] = "sys_setresgid", + [211] = "sys_getresgid", + [212] = "sys_chown", + [213] = "sys_setuid", + [214] = "sys_setgid", + [215] = "sys_setfsuid", + [216] = "sys_setfsgid", + [217] = "sys_getdents64", + [218] = "sys_pivot_root", + [219] = "sys_mincore", + [220] = "sys_madvise", + [221] = "sys_fcntl64", + [224] = "sys_gettid", + [225] = "sys_aarch32_readahead", + [226] = "sys_setxattr", + [227] = "sys_lsetxattr", + [228] = "sys_fsetxattr", + [229] = "sys_getxattr", + [230] = "sys_lgetxattr", + [231] = "sys_fgetxattr", + [232] = "sys_listxattr", + [233] = "sys_llistxattr", + [234] = "sys_flistxattr", + [235] = "sys_removexattr", + [236] = "sys_lremovexattr", + [237] = "sys_fremovexattr", + [238] = "sys_tkill", + [239] = "sys_sendfile64", + [240] = "sys_futex_time32", + [241] = "sys_sched_setaffinity", + [242] = "sys_sched_getaffinity", + [243] = "sys_io_setup", + [244] = "sys_io_destroy", + [245] = "sys_io_getevents_time32", + [246] = "sys_io_submit", + [247] = "sys_io_cancel", + [248] = "sys_exit_group", + [250] = "sys_epoll_create", + [251] = "sys_epoll_ctl", + [252] = "sys_epoll_wait", + [253] = "sys_remap_file_pages", + [256] = "sys_set_tid_address", + [257] = "sys_timer_create", + [258] = "sys_timer_settime32", + [259] = "sys_timer_gettime32", + [260] = "sys_timer_getoverrun", + [261] = "sys_timer_delete", + [262] = "sys_clock_settime32", + [263] = "sys_clock_gettime32", + [264] = "sys_clock_getres_time32", + [265] = "sys_clock_nanosleep_time32", + [266] = "sys_aarch32_statfs64", + [267] = "sys_aarch32_fstatfs64", + [268] = "sys_tgkill", + [269] = "sys_utimes_time32", + [270] = "sys_aarch32_fadvise64_64", + [272] = "sys_pciconfig_read", + [273] = "sys_pciconfig_write", + [274] = "sys_mq_open", + [275] = "sys_mq_unlink", + [276] = "sys_mq_timedsend_time32", + [277] = "sys_mq_timedreceive_time32", + [278] = "sys_mq_notify", + [279] = "sys_mq_getsetattr", + [280] = "sys_waitid", + [281] = "sys_socket", + [282] = "sys_bind", + [283] = "sys_connect", + [284] = "sys_listen", + [285] = "sys_accept", + [286] = "sys_getsockname", + [287] = "sys_getpeername", + [288] = "sys_socketpair", + [289] = "sys_send", + [290] = "sys_sendto", + [291] = "sys_recv", + [292] = "sys_recvfrom", + [293] = "sys_shutdown", + [294] = "sys_setsockopt", + [295] = "sys_getsockopt", + [296] = "sys_sendmsg", + [297] = "sys_recvmsg", + [298] = "sys_semop", + [299] = "sys_semget", + [300] = "sys_old_semctl", + [301] = "sys_msgsnd", + [302] = "sys_msgrcv", + [303] = "sys_msgget", + [304] = "sys_old_msgctl", + [305] = "sys_shmat", + [306] = "sys_shmdt", + [307] = "sys_shmget", + [308] = "sys_old_shmctl", + [309] = "sys_add_key", + [310] = "sys_request_key", + [311] = "sys_keyctl", + [312] = "sys_semtimedop_time32", + [314] = "sys_ioprio_set", + [315] = "sys_ioprio_get", + [316] = "sys_inotify_init", + [317] = "sys_inotify_add_watch", + [318] = "sys_inotify_rm_watch", + [319] = "sys_mbind", + [320] = "sys_get_mempolicy", + [321] = "sys_set_mempolicy", + [322] = "sys_openat", + [323] = "sys_mkdirat", + [324] = "sys_mknodat", + [325] = "sys_fchownat", + [326] = "sys_futimesat_time32", + [327] = "sys_fstatat64", + [328] = "sys_unlinkat", + [329] = "sys_renameat", + [330] = "sys_linkat", + [331] = "sys_symlinkat", + [332] = "sys_readlinkat", + [333] = "sys_fchmodat", + [334] = "sys_faccessat", + [335] = "sys_pselect6_time32", + [336] = "sys_ppoll_time32", + [337] = "sys_unshare", + [338] = "sys_set_robust_list", + [339] = "sys_get_robust_list", + [340] = "sys_splice", + [341] = "sys_aarch32_sync_file_range2", + [342] = "sys_tee", + [343] = "sys_vmsplice", + [344] = "sys_move_pages", + [345] = "sys_getcpu", + [346] = "sys_epoll_pwait", + [347] = "sys_kexec_load", + [348] = "sys_utimensat_time32", + [349] = "sys_signalfd", + [350] = "sys_timerfd_create", + [351] = "sys_eventfd", + [352] = "sys_aarch32_fallocate", + [353] = "sys_timerfd_settime32", + [354] = "sys_timerfd_gettime32", + [355] = "sys_signalfd4", + [356] = "sys_eventfd2", + [357] = "sys_epoll_create1", + [358] = "sys_dup3", + [359] = "sys_pipe2", + [360] = "sys_inotify_init1", + [361] = "sys_preadv", + [362] = "sys_pwritev", + [363] = "sys_rt_tgsigqueueinfo", + [364] = "sys_perf_event_open", + [365] = "sys_recvmmsg_time32", + [366] = "sys_accept4", + [367] = "sys_fanotify_init", + [368] = "sys_fanotify_mark", + [369] = "sys_prlimit64", + [370] = "sys_name_to_handle_at", + [371] = "sys_open_by_handle_at", + [372] = "sys_clock_adjtime32", + [373] = "sys_syncfs", + [374] = "sys_sendmmsg", + [375] = "sys_setns", + [376] = "sys_process_vm_readv", + [377] = "sys_process_vm_writev", + [378] = "sys_kcmp", + [379] = "sys_finit_module", + [380] = "sys_sched_setattr", + [381] = "sys_sched_getattr", + [382] = "sys_renameat2", + [383] = "sys_seccomp", + [384] = "sys_getrandom", + [385] = "sys_memfd_create", + [386] = "sys_bpf", + [387] = "sys_execveat", + [388] = "sys_userfaultfd", + [389] = "sys_membarrier", + [390] = "sys_mlock2", + [391] = "sys_copy_file_range", + [392] = "sys_preadv2", + [393] = "sys_pwritev2", + [394] = "sys_pkey_mprotect", + [395] = "sys_pkey_alloc", + [396] = "sys_pkey_free", + [397] = "sys_statx", + [398] = "sys_rseq", + [399] = "sys_io_pgetevents", + [400] = "sys_migrate_pages", + [401] = "sys_kexec_file_load", + [403] = "sys_clock_gettime", + [404] = "sys_clock_settime", + [405] = "sys_clock_adjtime", + [406] = "sys_clock_getres", + [407] = "sys_clock_nanosleep", + [408] = "sys_timer_gettime", + [409] = "sys_timer_settime", + [410] = "sys_timerfd_gettime", + [411] = "sys_timerfd_settime", + [412] = "sys_utimensat", + [413] = "sys_pselect6_time64", + [414] = "sys_ppoll_time64", + [416] = "sys_io_pgetevents", + [417] = "sys_recvmmsg_time64", + [418] = "sys_mq_timedsend", + [419] = "sys_mq_timedreceive", + [420] = "sys_semtimedop", + [421] = "sys_rt_sigtimedwait_time64", + [422] = "sys_futex", + [423] = "sys_sched_rr_get_interval", + [424] = "sys_pidfd_send_signal", + [425] = "sys_io_uring_setup", + [426] = "sys_io_uring_enter", + [427] = "sys_io_uring_register", + [428] = "sys_open_tree", + [429] = "sys_move_mount", + [430] = "sys_fsopen", + [431] = "sys_fsconfig", + [432] = "sys_fsmount", + [433] = "sys_fspick", + [434] = "sys_pidfd_open", + [435] = "sys_clone3", + [436] = "sys_close_range", + [437] = "sys_openat2", + [438] = "sys_pidfd_getfd", + [439] = "sys_faccessat2", + [440] = "sys_process_madvise", + [441] = "sys_epoll_pwait2", + [442] = "sys_mount_setattr", + [443] = "sys_quotactl_fd", + [444] = "sys_landlock_create_ruleset", + [445] = "sys_landlock_add_rule", + [446] = "sys_landlock_restrict_self", + [448] = "sys_process_mrelease", + [449] = "sys_futex_waitv", + [450] = "sys_set_mempolicy_home_node", + [451] = "sys_cachestat", +}; +KP_EXPORT_SYMBOL(compat_syscall_name_table); diff --git a/kernel/patch/common/taskob.c b/kernel/patch/common/taskob.c index b41f079d..e82fa8e4 100644 --- a/kernel/patch/common/taskob.c +++ b/kernel/patch/common/taskob.c @@ -20,6 +20,7 @@ #include #include #include +#include static inline void prepare_init_ext(struct task_struct *task) { @@ -27,7 +28,9 @@ static inline void prepare_init_ext(struct task_struct *task) for (uintptr_t i = (uintptr_t)ext; i < (uintptr_t)ext + sizeof(struct task_ext); i += 8) { *(uintptr_t *)i = 0; } - ext->magic = TASK_EXT_MAGIC; + ext->size = task_ext_size; + ext->_magic = TASK_EXT_MAGIC; + dsb(ish); } static void prepare_task_ext(struct task_struct *new, struct task_struct *old) @@ -41,32 +44,29 @@ static void prepare_task_ext(struct task_struct *new, struct task_struct *old) for (uintptr_t i = (uintptr_t)new_ext; i < (uintptr_t)new_ext + sizeof(struct task_ext); i += 8) { *(uintptr_t *)i = 0; } - new_ext->magic = TASK_EXT_MAGIC; + new_ext->size = task_ext_size; + new_ext->_magic = TASK_EXT_MAGIC; new_ext->pid = __task_pid_nr_ns(new, PIDTYPE_PID, 0); new_ext->tgid = __task_pid_nr_ns(new, PIDTYPE_TGID, 0); - new_ext->selinux_allow = old_ext->selinux_allow; + new_ext->sel_allow = old_ext->sel_allow; - dsb(ishst); + dsb(ish); } -static struct task_struct *(*backup_copy_process)(void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, - void *a7) = 0; +int task_ext_size = (sizeof(struct task_ext) - sizeof(int)); +KP_EXPORT_SYMBOL(task_ext_size); -struct task_struct *replace_copy_process(void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7) +static void after_copy_process(hook_fargs8_t *args, void *udata) { - struct task_struct *new = backup_copy_process(a0, a1, a2, a3, a4, a5, a6, a7); - if (unlikely(!new || IS_ERR(new))) return new; + struct task_struct *new = (struct task_struct *)args->ret; + if (unlikely(!new || IS_ERR(new))) return; prepare_task_ext(new, current); - return new; } -static void (*backup_cgroup_post_fork)(struct task_struct *p, void *a1) = 0; - -static void replace_cgroup_post_fork(struct task_struct *p, void *a1) +static void after_cgroup_post_fork(hook_fargs4_t *args, void *udata) { - struct task_struct *new = p; - backup_cgroup_post_fork(p, a1); + struct task_struct *new = (struct task_struct *)args->arg0; prepare_task_ext(new, current); } @@ -76,32 +76,19 @@ int task_observer() prepare_init_ext(init_task); - // __switch_to unsigned long copy_process_addr = get_preset_patch_sym()->copy_process; if (copy_process_addr) { - hook_err_t err = hook((void *)copy_process_addr, (void *)replace_copy_process, (void **)&backup_copy_process); - if (err) { - log_boot("hook copy_process: %llx, error: %d\n", copy_process_addr, err); - rc = err; - goto out; - } + rc |= hook_wrap8((void *)copy_process_addr, 0, after_copy_process, 0); + log_boot("hook copy_process: %llx, rc: %d\n", copy_process_addr, rc); } else { - log_boot("no symbol copy_process, try cgroup_post_fork\n"); unsigned long cgroup_post_fork_addr = get_preset_patch_sym()->cgroup_post_fork; - if (!cgroup_post_fork_addr) { - log_boot("no symbol cgroup_post_fork\n"); - rc = -ENOENT; - goto out; - } - hook_err_t err = - hook((void *)cgroup_post_fork_addr, (void *)replace_cgroup_post_fork, (void **)&backup_cgroup_post_fork); - if (err != HOOK_NO_ERR) { - log_boot("hook cgroup_post_fork: %llx, error: %d\n", cgroup_post_fork_addr, err); - rc = err; - goto out; + if (cgroup_post_fork_addr) { + rc |= hook_wrap4((void *)cgroup_post_fork_addr, 0, after_cgroup_post_fork, 0); + log_boot("hook cgroup_post_fork: %llx, rc: %d\n", cgroup_post_fork_addr, rc); + } else { + rc = HOOK_BAD_ADDRESS; } } -out: return rc; } \ No newline at end of file diff --git a/kernel/patch/common/test.c b/kernel/patch/common/test.c new file mode 100644 index 00000000..6b4c054d --- /dev/null +++ b/kernel/patch/common/test.c @@ -0,0 +1,17 @@ +#include +#include +#include + +void test() +{ + logkd("=== start test ==="); + + const char *sctx = "u:r:kernel:s0"; + + uint32_t secid = 0; + int rc = security_secctx_to_secid(sctx, strlen(sctx), &secid); + + logkd("secid: %d, rc: %d\n", secid, rc); + + logkd("=== end test ==="); +} \ No newline at end of file diff --git a/kernel/patch/common/utils.c b/kernel/patch/common/utils.c index beff9dde..5b09302c 100644 --- a/kernel/patch/common/utils.c +++ b/kernel/patch/common/utils.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include extern int kfunc_def(xt_data_to_user)(void __user *dst, const void *src, int usersize, int size, int aligned_size); @@ -96,8 +98,6 @@ KP_EXPORT_SYMBOL(compat_copy_to_user); long compat_strncpy_from_user(char *dest, const char __user *src, long count) { - kfunc_call(strncpy_from_user_nofault, dest, src, count); - kfunc_call(strncpy_from_unsafe_user, dest, src, count); if (kfunc(strncpy_from_user)) { long rc = kfunc(strncpy_from_user)(dest, src, count); if (rc >= count) { @@ -108,6 +108,8 @@ long compat_strncpy_from_user(char *dest, const char __user *src, long count) } return rc; } + kfunc_call(strncpy_from_user_nofault, dest, src, count); + kfunc_call(strncpy_from_unsafe_user, dest, src, count); return 0; } KP_EXPORT_SYMBOL(compat_strncpy_from_user); @@ -123,15 +125,15 @@ struct pt_regs *_task_pt_reg(struct task_struct *task) } else { #ifndef ANDROID if (kver < VERSION(4, 4, 19)) { - addr -= sizeof(struct pt_regs_lt4419); + addr -= sizeof(struct pt_regs_lt4419); // 0x120 } else if (kver < VERSION(4, 14, 0)) { - addr -= sizeof(struct pt_regs_lt4140); + addr -= sizeof(struct pt_regs_lt4140); // 0x130 } else #endif if (kver < VERSION(5, 10, 0)) { - addr -= sizeof(struct pt_regs_lt5100); + addr -= sizeof(struct pt_regs_lt5100); // 0x140 } else { - addr -= sizeof(struct pt_regs); + addr -= sizeof(struct pt_regs); // 0x150 } } @@ -156,3 +158,12 @@ uint64_t get_random_u64(void) return rand_next(); } KP_EXPORT_SYMBOL(get_random_u64); + +// todo: rcu_dereference_protected +uid_t current_uid() +{ + struct cred *cred = *(struct cred **)((uintptr_t)current + task_struct_offset.cred_offset); + uid_t uid = *(uid_t *)((uintptr_t)cred + cred_offset.uid_offset); + return uid; +} +KP_EXPORT_SYMBOL(current_uid); \ No newline at end of file diff --git a/kernel/patch/include/accctl.h b/kernel/patch/include/accctl.h index 8e6960a9..f2607478 100644 --- a/kernel/patch/include/accctl.h +++ b/kernel/patch/include/accctl.h @@ -11,26 +11,39 @@ #include #include #include +#include +#include +#include -int set_priv_selinx_allow(struct task_struct *task, int val); -int commit_kernel_cred(); +extern char all_allow_sctx[SUPERCALL_SCONTEXT_LEN]; +extern int allow_sid_enable; +extern uint32_t all_allow_sid; + +int set_all_allow_sctx(const char *sctx); +int commit_kernel_su(); +int commit_common_su(uid_t to_uid, const char *sctx); int commit_su(uid_t uid, const char *sctx); int task_su(pid_t pid, uid_t to_uid, const char *sctx); -int selinux_hook_install(); -int supercall_install(); - -#ifdef ANDROID -int kpuserd_init(); -int su_compat_init(); -int su_add_allow_uid(uid_t uid, struct su_profile *profile, int async); +int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext, int async); int su_remove_allow_uid(uid_t uid, int async); int su_allow_uid_nums(); -int su_allow_uids(uid_t *__user uuids, int unum); -int su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile); +int su_allow_uids(int is_user, uid_t *out_uids, int out_num); +int su_allow_uid_profile(int is_user, uid_t uid, struct su_profile *profile); int su_reset_path(const char *path); -int su_get_path(char *__user ubuf, int buf_len); -long supercall_android(long cmd, long arg1, long arg2, long arg3); -#endif +const char *su_get_path(); + +/** + * @brief Whether to make the current task bypass all selinux permission checks. + * + * @param task + * @param val + */ +static inline void set_priv_sel_allow(struct task_struct *task, bool val) +{ + struct task_ext *ext = get_task_ext(task); + ext->priv_sel_allow = val; + dsb(ish); +} #endif \ No newline at end of file diff --git a/kernel/patch/include/kputils.h b/kernel/patch/include/kputils.h index 9e847efb..bed8e2e5 100644 --- a/kernel/patch/include/kputils.h +++ b/kernel/patch/include/kputils.h @@ -10,9 +10,9 @@ #include int __must_check compat_copy_to_user(void __user *to, const void *from, int n); - +long compat_strncpy_from_user(char *dest, const char __user *src, long count); void *__user copy_to_user_stack(const void *data, int len); - +uid_t current_uid(); uint64_t get_random_u64(void); void print_bootlog(); diff --git a/kernel/patch/include/module.h b/kernel/patch/include/module.h index dff41462..08e87555 100644 --- a/kernel/patch/include/module.h +++ b/kernel/patch/include/module.h @@ -62,6 +62,4 @@ int get_module_nums(); int list_modules(char *out_names, int size); int get_module_info(const char *name, char *out_info, int size); -int module_init(); - #endif \ No newline at end of file diff --git a/kernel/patch/include/sucompat.h b/kernel/patch/include/sucompat.h index f2277871..03a00bbd 100644 --- a/kernel/patch/include/sucompat.h +++ b/kernel/patch/include/sucompat.h @@ -8,6 +8,12 @@ #include #include +#include + +extern const char sh_path[]; +extern const char default_su_path[]; +extern const char legacy_su_path[]; +extern const char apd_path[]; struct allow_uid { @@ -20,4 +26,6 @@ struct allow_uid struct su_profile profile_su_allow_uid(uid_t uid); int is_su_allow_uid(uid_t uid); +void handle_supercmd(char **__user u_filename_p, char **__user uargv); + #endif diff --git a/kernel/patch/include/syscall.h b/kernel/patch/include/syscall.h index af024ea7..efa733c3 100644 --- a/kernel/patch/include/syscall.h +++ b/kernel/patch/include/syscall.h @@ -15,6 +15,8 @@ extern uintptr_t *sys_call_table; extern uintptr_t *compat_sys_call_table; extern int has_syscall_wrapper; +extern const char *syscall_name_table[460]; +extern const char *compat_syscall_name_table[460]; const char __user *get_user_arg_ptr(void *a0, void *a1, int nr); int set_user_arg_ptr(void *a0, void *a1, int nr, uintptr_t val); @@ -58,13 +60,15 @@ static inline void *syscall_argn_p(void *fdata_args, int n) static inline hook_err_t fp_hook_syscalln(int nr, int narg, void *before, void *after, void *udata) { + if (!sys_call_table) return HOOK_BAD_ADDRESS; uintptr_t fp_addr = (uintptr_t)(sys_call_table + nr); if (has_syscall_wrapper) narg = 1; return fp_hook_wrap(fp_addr, narg, before, after, udata); } -static inline void fp_unhook_syscall(int nr, void *before, void *after) +static inline void fp_unhook_syscalln(int nr, void *before, void *after) { + if (!sys_call_table) return; uintptr_t fp_addr = (uintptr_t)(sys_call_table + nr); fp_hook_unwrap(fp_addr, before, after); } @@ -77,7 +81,7 @@ static inline hook_err_t fp_hook_compat_syscalln(int nr, int narg, void *before, return fp_hook_wrap(fp_addr, narg, before, after, udata); } -static inline void fp_unhook_compat_syscall(int nr, void *before, void *after) +static inline void fp_unhook_compat_syscalln(int nr, void *before, void *after) { if (!compat_sys_call_table) return; uintptr_t fp_addr = (uintptr_t)(compat_sys_call_table + nr); @@ -85,38 +89,67 @@ static inline void fp_unhook_compat_syscall(int nr, void *before, void *after) } /* -xxx.cfi_jt example: -hint #0x22 +syscall table element: +sys_xxx.cfi_jt +hint #0x22 # bti c b #0xfffffffffeb452f4 */ + +/** + * @brief + * + * @param nr + * @param narg + * @param is_compat + * @param before + * @param after + * @param udata + * @return hook_err_t + */ +hook_err_t __inline_hook_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata); + +/** + * @brief + * + * @param nr + * @param is_compat + * @param before + * @param after + */ +void __inline_unhook_syscalln(int nr, int is_compat, void *before, void *after); + static inline hook_err_t inline_hook_syscalln(int nr, int narg, void *before, void *after, void *udata) { - uintptr_t fp = sys_call_table[nr]; - if (has_syscall_wrapper) narg = 1; - return hook_wrap((void *)fp, narg, before, after, udata); + return __inline_hook_syscalln(nr, narg, 0, before, after, udata); } -static inline void inline_unhook_syscall(int nr, void *before, void *after) +static inline void inline_unhook_syscalln(int nr, void *before, void *after) { - uintptr_t fp = sys_call_table[nr]; - hook_unwrap((void *)fp, before, after); + __inline_unhook_syscalln(nr, 0, before, after); } static inline hook_err_t inline_hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata) { - if (!compat_sys_call_table) return HOOK_BAD_ADDRESS; - uintptr_t fp = compat_sys_call_table[nr]; - if (has_syscall_wrapper) narg = 1; - return hook_wrap((void *)fp, narg, before, after, udata); + return __inline_hook_syscalln(nr, narg, 1, before, after, udata); } -static inline void inline_unhook_compat_syscall(int nr, void *before, void *after) +static inline void inline_unhook_compat_syscalln(int nr, void *before, void *after) { - if (!compat_sys_call_table) return; - uintptr_t fp = compat_sys_call_table[nr]; - hook_unwrap((void *)fp, before, after); + __inline_unhook_syscalln(nr, 0, before, after); } -int syscall_init(); +// #define DEFAULT_INLINE_HOOK_SYSCALL + +#ifdef DEFAULT_INLINE_HOOK_SYSCALL +#define hook_syscalln inline_hook_syscalln +#define unhook_syscalln inline_unhook_syscalln +#define hook_compat_syscalln inline_hook_compat_syscalln +#define unhook_compat_syscalln inline_unhook_compat_syscalln +#else +#define hook_syscalln fp_hook_syscalln +#define unhook_syscalln fp_unhook_syscalln +#define hook_compat_syscalln fp_hook_compat_syscalln +#define unhook_compat_syscalln fp_unhook_compat_syscalln +#endif #endif \ No newline at end of file diff --git a/kernel/patch/include/taskext.h b/kernel/patch/include/taskext.h index 901a0e09..06240e24 100644 --- a/kernel/patch/include/taskext.h +++ b/kernel/patch/include/taskext.h @@ -9,26 +9,91 @@ #include #include #include +#include +#include -#define TASK_EXT_MAGIC 0x1158115811581158 +#define TASK_EXT_MAGIC 0x11581158 +/// @brief the size of current struct task_ext, not included _magic +extern int task_ext_size; + +/** + * @brief An extension of task_struct, stored in the kernel thread stack, + * can be used to store task-local(thread-local) variables. + * This can be very useful if you need to pass thread-local variables across multiple hook points. + * + * Task-local variables can be dynamically expanded. + * @see reg_task_local + * @see has_task_local + * @see task_local_ptr + */ struct task_ext { // first + int size; pid_t pid; pid_t tgid; - int super; - int _; - int selinux_allow; - int priv_selinux_allow; - void *__; + bool root; + bool sel_allow; + bool priv_sel_allow; // last - uint64_t magic; + int _magic; }; -static inline int task_ext_valid(struct task_ext *ext) +/** + * @brief Is task_ext dirty, and is it available? + * + * @param ext + * @return int + */ +static inline bool task_ext_valid(struct task_ext *ext) +{ + return !IS_ERR(ext) && (*(int *)(ext->size + (uintptr_t)ext) == TASK_EXT_MAGIC); +} + +/** + * @brief Register a new task-local varilable + * + * @param size The size of task-local varilable + * @return The offset of of task-local varilable, + * This value is needed when access this task-local variable. + * + * @see has_task_local + * @see task_local_ptr + */ +static inline int reg_task_local(int size) +{ + int offset = task_ext_size; + task_ext_size += size; + return offset; +} + +/** + * @brief Is there a task-local variable regiseted? + * + * @param ext + * @param offset Return value of reg_task_local + * @return true + * @return false + * + * @see reg_task_local + */ +static inline bool has_task_local(struct task_ext *ext, int offset) +{ + return offset >= ext->size; +} + +/** + * @brief Access task-local varilable, + * + * @param offset Return value of reg_task_local + * @return void* Task-local varilable pointer + * + * @see reg_task_local + */ +static inline void *task_local_ptr(struct task_ext *ext, int offset) { - return ext && (ext->magic == TASK_EXT_MAGIC); + return (void *)((uintptr_t)ext + offset); } #endif diff --git a/kernel/patch/include/uapi/scdefs.h b/kernel/patch/include/uapi/scdefs.h index 1126c79d..8db8ca88 100644 --- a/kernel/patch/include/uapi/scdefs.h +++ b/kernel/patch/include/uapi/scdefs.h @@ -6,15 +6,6 @@ #ifndef _KP_UAPI_SCDEF_H_ #define _KP_UAPI_SCDEF_H_ -static inline long hash_key(const char *key) -{ - long hash = 1000000007; - for (int i = 0; key[i]; i++) { - hash = hash * 31 + key[i]; - } - return hash; -} - #define SUPERCALL_HELLO_ECHO "hello1158" // #define __NR_supercall __NR3264_truncate // 45 @@ -63,40 +54,39 @@ struct su_profile }; #ifdef ANDROID - -#define ANDROID_SH_PATH "/system/bin/sh" -#define SU_PATH_MAX_LEN 128 - -#define ANDROID_SU_PATH "/system/bin/kp" -#define ANDROID_LEGACY_SU_PATH "/system/bin/su" -#define KPATCH_DATA_PATH "/data/adb/kpatch" -#define KPATCH_DEV_PATH "/dev/kpatch" -#define KPATCH_DEV_WORK_DIR "/dev/kp/" +#define SH_PATH "/system/bin/sh" +#define SU_PATH "/system/bin/kp" +#define LEGACY_SU_PATH "/system/bin/su" +#define ECHO_PATH "/system/bin/echo" #define KERNELPATCH_DATA_DIR "/data/adb/kp" #define KERNELPATCH_MODULE_DATA_DIR KERNELPATCH_DATA_DIR "/modules" #define APD_PATH "/data/adb/apd" +#define ALL_ALLOW_SCONTEXT "u:r:kp:s0" +#define ALL_ALLOW_SCONTEXT_MAGISK "u:r:magisk:s0" +#define ALL_ALLOW_SCONTEXT_KERNEL "u:r:kernel:s0" +#else +#define SH_PATH "/usr/bin/sh" +#define ECHO_PATH "/usr/bin/echo" +#define SU_PATH "/usr/bin/kp" +#define ALL_ALLOW_SCONTEXT "u:r:kernel:s0" +#endif + +#define SU_PATH_MAX_LEN 128 + #define SUPERCMD "/system/bin/truncate" -#define ADB_FLODER "/data/adb/" -#define APATCH_FLODER "/data/adb/ap/" -#define APATCH_BIN_FLODER APATCH_FLODER "bin/" -#define APATCH_LOG_FLODER APATCH_FLODER "log/" #define SAFE_MODE_FLAG_FILE "/dev/.safemode" -#define EARLY_INIT_LOG_0 "/dev/early_init_0.log" -#define EARLY_INIT_LOG_1 "/dev/early_init_1.log" - -#define ALL_ALLOW_SCONTEXT "u:r:magisk:s0" #define SUPERCALL_SU_GRANT_UID 0x1100 #define SUPERCALL_SU_REVOKE_UID 0x1101 #define SUPERCALL_SU_NUMS 0x1102 #define SUPERCALL_SU_LIST 0x1103 #define SUPERCALL_SU_PROFILE 0x1104 +#define SUPERCALL_SU_GET_ALLOW_SCTX 0x1105 +#define SUPERCALL_SU_SET_ALLOW_SCTX 0x1106 #define SUPERCALL_SU_GET_PATH 0x1110 #define SUPERCALL_SU_RESET_PATH 0x1111 -#endif - #define SUPERCALL_MAX 0x1200 #define SUPERCALL_RES_SUCCEED 0 diff --git a/kernel/patch/ksyms/execv.c b/kernel/patch/ksyms/execv.c index b58dfec1..7f32b54a 100644 --- a/kernel/patch/ksyms/execv.c +++ b/kernel/patch/ksyms/execv.c @@ -38,7 +38,7 @@ static void before_execve(hook_fargs3_t *args, void *udata) unsigned long stack = (unsigned long)get_stack(current); uintptr_t addr = (uintptr_t)(thread_size + stack); - for (uintptr_t i = addr - sizeof(struct pt_regs) - 0x40; i < addr - 31 * 8; i += 8) { + for (uintptr_t i = addr - sizeof(struct pt_regs) - 0x40; i < addr - 32 * 8; i += 0x10) { uintptr_t val0 = *(uintptr_t *)i; uintptr_t val1 = *(uintptr_t *)(i + 0x8); uintptr_t val2 = *(uintptr_t *)(i + 0x10); @@ -56,8 +56,8 @@ static void before_execve(hook_fargs3_t *args, void *udata) static void after_execv(hook_fargs5_t *args, void *udata) { - fp_unhook_syscall(__NR_execve, before_execve, after_execv); - fp_unhook_syscall(__NR_execveat, before_execve, after_execv); + unhook_syscalln(__NR_execve, before_execve, after_execv); + unhook_syscalln(__NR_execveat, before_execve, after_execv); } int resolve_pt_regs() @@ -65,11 +65,11 @@ int resolve_pt_regs() hook_err_t ret = 0; hook_err_t rc = HOOK_NO_ERR; - rc = fp_hook_syscalln(__NR_execve, 3, before_execve, after_execv, (void *)__NR_execve); + rc = hook_syscalln(__NR_execve, 3, before_execve, after_execv, (void *)__NR_execve); log_boot("hook __NR_execve rc: %d\n", rc); ret |= rc; - rc = fp_hook_syscalln(__NR_execveat, 5, before_execve, after_execv, (void *)__NR_execveat); + rc = hook_syscalln(__NR_execveat, 5, before_execve, after_execv, (void *)__NR_execveat); log_boot("hook __NR_execveat rc: %d\n", rc); ret |= rc; diff --git a/kernel/patch/ksyms/libs.c b/kernel/patch/ksyms/libs.c index 9e1c52e5..57bfd4c2 100644 --- a/kernel/patch/ksyms/libs.c +++ b/kernel/patch/ksyms/libs.c @@ -132,6 +132,11 @@ KP_EXPORT_SYMBOL(kfunc(strreplace)); void kfunc_def(fortify_panic)(const char *name) = 0; KP_EXPORT_SYMBOL(kfunc(fortify_panic)); +int __must_check kfunc_def(kstrtoull)(const char *s, unsigned int base, unsigned long long *res) = 0; +KP_EXPORT_SYMBOL(kfunc(kstrtoull)); +int __must_check kfunc_def(kstrtoll)(const char *s, unsigned int base, long long *res) = 0; +KP_EXPORT_SYMBOL(kfunc(kstrtoll)); + static void _linux_lib_string_sym_match(const char *name, unsigned long addr) { kfunc_match(strncasecmp, name, addr); @@ -178,6 +183,8 @@ static void _linux_lib_string_sym_match(const char *name, unsigned long addr) kfunc_match(memchr_inv, name, addr); kfunc_match(strreplace, name, addr); // kfunc_match(fortify_panic, name, addr); + kfunc_match(kstrtoull, name, addr); + kfunc_match(kstrtoll, name, addr); } // lib/argv_split.c @@ -246,7 +253,7 @@ static void _linux_include_kernel_sym_match(const char *name, unsigned long addr kfunc_match(vsscanf, name, addr); } -static int _linux_libs_symbol_init(void *data, const char *name, struct module *m, unsigned long addr) +static void _linux_libs_symbol_init(void *data, const char *name, struct module *m, unsigned long addr) { _linux_lib_misc(name, addr); _linux_lib_strncpy_from_user_sym_match(name, addr); @@ -254,15 +261,13 @@ static int _linux_libs_symbol_init(void *data, const char *name, struct module * _linux_lib_argv_split_sym_match(name, addr); _linux_lib_seq_buf_sym_match(name, addr); _linux_include_kernel_sym_match(name, addr); - return 0; } -int linux_libs_symbol_init(const char *name, unsigned long addr) +void linux_libs_symbol_init(const char *name, unsigned long addr) { #ifdef INIT_USE_KALLSYMS_LOOKUP_NAME _linux_libs_symbol_init(0, 0, 0, 0); #else kallsyms_on_each_symbol(_linux_libs_symbol_init, 0); #endif - return 0; } diff --git a/kernel/patch/ksyms/misc.c b/kernel/patch/ksyms/misc.c index ee759c15..6fa55e0e 100644 --- a/kernel/patch/ksyms/misc.c +++ b/kernel/patch/ksyms/misc.c @@ -274,16 +274,17 @@ struct page; struct address_space; struct task_struct; +char *kfunc_def(strndup_user)(const char __user *, long) = 0; +void *kfunc_def(memdup_user)(const void __user *, size_t) = 0; +void *kfunc_def(vmemdup_user)(const void __user *, size_t) = 0; +void *kfunc_def(memdup_user_nul)(const void __user *, size_t) = 0; + void kfunc_def(kfree_const)(const void *x) = 0; char *kfunc_def(kstrdup)(const char *s, gfp_t gfp) = 0; const char *kfunc_def(kstrdup_const)(const char *s, gfp_t gfp) = 0; char *kfunc_def(kstrndup)(const char *s, size_t max, gfp_t gfp) = 0; void *kfunc_def(kmemdup)(const void *src, size_t len, gfp_t gfp) = 0; char *kfunc_def(kmemdup_nul)(const char *s, size_t len, gfp_t gfp) = 0; -void *kfunc_def(memdup_user)(const void __user *src, size_t len) = 0; -void *kfunc_def(vmemdup_user)(const void __user *src, size_t len) = 0; -char *kfunc_def(strndup_user)(const char __user *s, long n) = 0; -void *kfunc_def(memdup_user_nul)(const void __user *src, size_t len) = 0; unsigned long kfunc_def(vm_mmap)(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flag, unsigned long offset) = 0; void *kfunc_def(kvmalloc_node)(size_t size, gfp_t flags, int node) = 0; @@ -311,7 +312,7 @@ static void _linux_mm_utils_sym_match(const char *name, unsigned long addr) kfunc_match(memdup_user, name, addr); // kfunc_match(vmemdup_user, name, addr); kfunc_match(strndup_user, name, addr); - kfunc_match(memdup_user_nul, name, addr); + // kfunc_match(memdup_user_nul, name, addr); // kfunc_match(vm_mmap, name, addr); // kfunc_match(kvmalloc_node, name, addr); kfunc_match(kvfree, name, addr); @@ -669,6 +670,8 @@ int kfunc_def(cap_task_setscheduler)(struct task_struct *p) = 0; int kfunc_def(cap_task_setioprio)(struct task_struct *p, int ioprio) = 0; int kfunc_def(cap_task_setnice)(struct task_struct *p, int nice) = 0; int kfunc_def(cap_vm_enough_memory)(struct mm_struct *mm, long pages) = 0; +// int kfunc_def(security_secid_to_secctx)(u32 secid, char **secdata, u32 *seclen) = 0; +int kfunc_def(security_secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid) = 0; kernel_cap_t full_cap = { 0 }; @@ -693,7 +696,8 @@ static void _linux_security_commoncap_sym_match(const char *name, unsigned long // kfunc_match(cap_task_setscheduler, name, addr); // kfunc_match(cap_task_setioprio, name, addr); // kfunc_match(cap_task_setnice, name, addr); - // kfunc_match(cap_vm_enough_memory, name, addr); + // kfunc_match(security_secid_to_secctx, name, addr); + kfunc_match(security_secctx_to_secid, name, addr); } #include @@ -855,12 +859,11 @@ static int _linux_misc_symbol_init(void *data, const char *name, struct module * return 0; } -int linux_misc_symbol_init() +void linux_misc_symbol_init() { #ifdef INIT_USE_KALLSYMS_LOOKUP_NAME _linux_misc_symbol_init(0, 0, 0, 0); #else kallsyms_on_each_symbol(_linux_misc_symbol_init, 0); #endif - return 0; } diff --git a/kernel/patch/module/module.c b/kernel/patch/module/module.c index ea1c2c1c..2c09fd2a 100644 --- a/kernel/patch/module/module.c +++ b/kernel/patch/module/module.c @@ -460,6 +460,7 @@ long load_module(const void *data, int len, const char *args, const char *event, // todo: lock long unload_module(const char *name, void *__user reserved) { + if (!name) return -EINVAL; logkfe("name: %s\n", name); rcu_read_lock(); @@ -490,6 +491,7 @@ long load_module_path(const char *path, const char *args, void *__user reserved) { long rc = 0; logkfd("%s\n", path); + if (!path) return -EINVAL; struct file *filp = filp_open(path, O_RDONLY, 0); if (unlikely(!filp || IS_ERR(filp))) { @@ -527,7 +529,7 @@ long load_module_path(const char *path, const char *args, void *__user reserved) long module_control0(const char *name, const char *ctl_args, char *__user out_msg, int outlen) { - if (!ctl_args) return -EINVAL; + if (!name || !ctl_args) return -EINVAL; int args_len = strlen(ctl_args); if (args_len <= 0) return -EINVAL; @@ -630,7 +632,7 @@ int list_modules(char *out_names, int size) { off += snprintf(out_names + off, size - 1 - off, "%s\n", pos->info.name); } - out_names[off] = '\0'; + if (off > 0) out_names[off - 1] = '\0'; rcu_read_unlock(); return off; @@ -653,15 +655,16 @@ int get_module_info(const char *name, char *out_info, int size) "args=%s\n", mod->info.name, mod->info.version, mod->info.license, mod->info.author, mod->info.description, mod->args); + + if (sz > 0) out_info[sz - 1] = '\0'; logkfd("%s", out_info); rcu_read_unlock(); return sz; } -int module_init() +void module_init() { INIT_LIST_HEAD(&modules.list); spin_lock_init(&module_lock); - return 0; } \ No newline at end of file diff --git a/kernel/patch/patch.c b/kernel/patch/patch.c index 6681566b..d4093dfe 100644 --- a/kernel/patch/patch.c +++ b/kernel/patch/patch.c @@ -1,5 +1,3 @@ -#include "patch.h" - #include #include #include @@ -14,14 +12,6 @@ #include #include -int linux_misc_symbol_init(); -int linux_libs_symbol_init(); - -int resolve_struct(); -int task_observer(); -int bypass_kcfi(); -int resolve_pt_regs(); - void print_bootlog() { const char *log = get_boot_log(); @@ -48,60 +38,59 @@ void before_panic(hook_fargs12_t *args, void *udata) printk("==== End KernelPatch for Kernel panic ====\n"); } +int resolve_struct(); +int task_observer(); +int bypass_kcfi(); +int bypass_selinux(); +int resolve_pt_regs(); +int supercall_install(); +int su_compat_init(); + +int android_user_init(); + static void before_rest_init(hook_fargs4_t *args, void *udata) { int rc = 0; log_boot("entering init ...\n"); - if ((rc = linux_libs_symbol_init())) goto out; - log_boot("linux_libs_symbol_init done: %d\n", rc); - - if ((rc = linux_misc_symbol_init())) goto out; - log_boot("linux_misc_symbol_init done: %d\n", rc); - if ((rc = bypass_kcfi())) goto out; log_boot("bypass_kcfi done: %d\n", rc); - if ((rc = syscall_init())) goto out; - log_boot("syscall_init done: %d\n", rc); - if ((rc = resolve_struct())) goto out; log_boot("resolve_struct done: %d\n", rc); - if ((rc = selinux_hook_install())) goto out; - log_boot("selinux_hook_install done: %d\n", rc); + if ((rc = bypass_selinux())) goto out; + log_boot("bypass_selinux done: %d\n", rc); if ((rc = task_observer())) goto out; log_boot("task_observer done: %d\n", rc); - if ((rc = module_init())) goto out; - log_boot("module_init done: %d\n", rc); - rc = supercall_install(); log_boot("supercall_install done: %d\n", rc); + rc = su_compat_init(); + log_boot("su_compat_init done: %d\n", rc); + rc = resolve_pt_regs(); log_boot("resolve_pt_regs done: %d\n", rc); #ifdef ANDROID - rc = su_compat_init(); - log_boot("su_compat_init done: %d\n", rc); - rc = kpuserd_init(); - log_boot("kpuserd_init done: %d\n", rc); + rc = android_user_init(); + log_boot("android_user_init done: %d\n", rc); + #endif out: return; } -static int pre_kernel_init(const patch_extra_item_t *extra, const char *args, const void *data, void *udata) +static int extra_event_pre_kernel_init(const patch_extra_item_t *extra, const char *args, const void *data, void *udata) { - const char *event = (const char *)udata; if (extra->type == EXTRA_TYPE_KPM) { if (!strcmp(EXTRA_EVENT_PRE_KERNEL_INIT, extra->event) || !extra->event[0]) { - int rc = load_module(data, extra->con_size, args, event, 0); - log_boot("%s loading extra kpm return: %d\n", event, rc); + int rc = load_module(data, extra->con_size, args, EXTRA_EVENT_PRE_KERNEL_INIT, 0); + log_boot("load kpm: %s, rc: %d\n", extra->name, rc); } } return 0; @@ -110,7 +99,7 @@ static int pre_kernel_init(const patch_extra_item_t *extra, const char *args, co static void before_kernel_init(hook_fargs4_t *args, void *udata) { log_boot("event: %s\n", EXTRA_EVENT_PRE_KERNEL_INIT); - on_each_extra_item(pre_kernel_init, 0); + on_each_extra_item(extra_event_pre_kernel_init, 0); } static void after_kernel_init(hook_fargs4_t *args, void *udata) @@ -118,33 +107,44 @@ static void after_kernel_init(hook_fargs4_t *args, void *udata) log_boot("event: %s\n", EXTRA_EVENT_POST_KERNEL_INIT); } +// internal header +void linux_misc_symbol_init(); +void linux_libs_symbol_init(); +void module_init(); +void syscall_init(); + int patch() { - hook_err_t ret = 0; + linux_libs_symbol_init(); + linux_misc_symbol_init(); + module_init(); + syscall_init(); + + hook_err_t rc = 0; unsigned long panic_addr = get_preset_patch_sym()->panic; + logkd("panic addr: %llx\n", panic_addr); if (panic_addr) { - hook_err_t rc = hook_wrap12((void *)panic_addr, before_panic, 0, 0); + rc = hook_wrap12((void *)panic_addr, before_panic, 0, 0); log_boot("hook panic rc: %d\n", rc); - ret |= rc; } + if (rc) return rc; // rest_init or cgroup_init unsigned long init_addr = get_preset_patch_sym()->rest_init; if (!init_addr) init_addr = get_preset_patch_sym()->cgroup_init; if (init_addr) { - hook_err_t rc = hook_wrap4((void *)init_addr, before_rest_init, 0, (void *)init_addr); + rc = hook_wrap4((void *)init_addr, before_rest_init, 0, (void *)init_addr); log_boot("hook rest_init rc: %d\n", rc); - ret |= rc; } + if (rc) return rc; // kernel_init unsigned long kernel_init_addr = get_preset_patch_sym()->kernel_init; if (kernel_init_addr) { - hook_err_t rc = hook_wrap4((void *)kernel_init_addr, before_kernel_init, after_kernel_init, 0); + rc = hook_wrap4((void *)kernel_init_addr, before_kernel_init, after_kernel_init, 0); log_boot("hook kernel_init rc: %d\n", rc); - ret |= rc; } - return ret; + return rc; } diff --git a/kernel/patch/patch.h b/kernel/patch/patch.h deleted file mode 100644 index 8b0adf6c..00000000 --- a/kernel/patch/patch.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _KP_PATCH_H_ -#define _KP_PATCH_H_ - -int patch(); - -#endif \ No newline at end of file diff --git a/kpms/demo-syscallhook/syscallhook.c b/kpms/demo-syscallhook/syscallhook.c index a4b78af5..2719f496 100644 --- a/kpms/demo-syscallhook/syscallhook.c +++ b/kpms/demo-syscallhook/syscallhook.c @@ -10,6 +10,7 @@ #include #include #include +#include #include KPM_NAME("kpm-syscall-hook-demo"); @@ -119,10 +120,10 @@ static long syscall_hook_demo_exit(void *__user reserved) pr_info("kpm-syscall-hook-demo exit ...\n"); if (hook_type == INLINE_CHAIN) { - inline_unhook_syscall(__NR_openat, before_openat_0, 0); + inline_unhook_syscalln(__NR_openat, before_openat_0, 0); } else if (hook_type == FUNCTION_POINTER_CHAIN) { - fp_unhook_syscall(__NR_openat, before_openat_0, 0); - fp_unhook_syscall(__NR_openat, before_openat_1, after_openat_1); + fp_unhook_syscalln(__NR_openat, before_openat_0, 0); + fp_unhook_syscalln(__NR_openat, before_openat_1, after_openat_1); } else { } return 0; diff --git a/tools/kptools.c b/tools/kptools.c index af14d8d2..99f60c2b 100644 --- a/tools/kptools.c +++ b/tools/kptools.c @@ -90,7 +90,6 @@ int main(int argc, char *argv[]) { "skey-hash", required_argument, NULL, 'S' }, { "out", required_argument, NULL, 'o' }, { "addition", required_argument, NULL, 'a' }, - { "kpatch", required_argument, NULL, 'K' }, { "embed-extra-path", required_argument, NULL, 'M' }, { "embeded-extra-name", required_argument, NULL, 'E' }, @@ -99,13 +98,12 @@ int main(int argc, char *argv[]) { "extra-event", required_argument, NULL, 'V' }, { "extra-args", required_argument, NULL, 'A' }, { 0, 0, 0, 0 } }; - char *optstr = "hvpurdli:s:S:k:o:a:K:M:E:T:N:V:A:"; + char *optstr = "hvpurdli:s:S:k:o:a:M:E:T:N:V:A:"; char *kimg_path = NULL; char *kpimg_path = NULL; char *out_path = NULL; char *superkey = NULL; - char *kpatch_path = NULL; bool root_skey = false; int additional_num = 0; @@ -148,9 +146,6 @@ int main(int argc, char *argv[]) case 'a': additional[additional_num++] = optarg; break; - case 'K': - kpatch_path = optarg; - break; case 'M': config = &extra_configs[extra_config_num++]; config->is_path = true; @@ -190,8 +185,8 @@ int main(int argc, char *argv[]) else fprintf(stdout, "%x\n", version); } else if (cmd == 'p') { - ret = patch_update_img(kimg_path, kpimg_path, out_path, superkey, root_skey, additional, kpatch_path, - extra_configs, extra_config_num); + ret = patch_update_img(kimg_path, kpimg_path, out_path, superkey, root_skey, additional, extra_configs, + extra_config_num); } else if (cmd == 'd') { ret = dump_kallsym(kimg_path); } else if (cmd == 'u') { diff --git a/tools/patch.c b/tools/patch.c index f9a5ba5f..bc981db6 100644 --- a/tools/patch.c +++ b/tools/patch.c @@ -337,8 +337,7 @@ static void extra_append(char *kimg, const void *data, int len, int *offset) } int patch_update_img(const char *kimg_path, const char *kpimg_path, const char *out_path, const char *superkey, - bool root_key, const char **additional, const char *kpatch_path, extra_config_t *extra_configs, - int extra_config_num) + bool root_key, const char **additional, extra_config_t *extra_configs, int extra_config_num) { set_log_enable(true); @@ -372,18 +371,6 @@ int patch_update_img(const char *kimg_path, const char *kpimg_path, const char * int kpimg_len = 0; read_file_align(kpimg_path, &kpimg, &kpimg_len, 0x10); - // embed kpatch executable - if (kpatch_path) { - // add new - extra_config_t *config = extra_configs + extra_config_num; - extra_config_num++; - config->extra_type = EXTRA_TYPE_EXEC; - config->is_path = true; - config->path = kpatch_path; - config->priority = __INT32_MAX__; - config->set_name = "kpatch"; - } - // extra int extra_size = 0; int extra_num = 0; diff --git a/tools/patch.h b/tools/patch.h index d2443e67..0882b457 100644 --- a/tools/patch.h +++ b/tools/patch.h @@ -69,8 +69,7 @@ uint32_t get_kpimg_version(const char *kpimg_path); int extra_str_type(const char *extra_str); const char *extra_type_str(extra_item_type extra_type); int patch_update_img(const char *kimg_path, const char *kpimg_path, const char *out_path, const char *superkey, - bool root_skey, const char **additional, const char *kpatch_path, extra_config_t *extra_configs, - int extra_config_num); + bool root_skey, const char **additional, extra_config_t *extra_configs, int extra_config_num); int unpatch_img(const char *kimg_path, const char *out_path); int reset_key(const char *kimg_path, const char *out_path, const char *key); int dump_kallsym(const char *kimg_path); diff --git a/tools/symbol.c b/tools/symbol.c index 4513a9cc..d3787b90 100644 --- a/tools/symbol.c +++ b/tools/symbol.c @@ -120,27 +120,6 @@ int fillin_patch_symbol(kallsym_t *kallsym, char *img_buf, int imglen, patch_sym if (!symbol->copy_process) symbol->cgroup_post_fork = get_symbol_offset_zero(kallsym, img_buf, "cgroup_post_fork"); if (!symbol->copy_process && !symbol->cgroup_post_fork) tools_loge_exit("no symbol copy_process"); - symbol->do_execveat_common = try_get_symbol_offset_zero(kallsym, img_buf, "do_execveat_common"); - symbol->__do_execve_file = try_get_symbol_offset_zero(kallsym, img_buf, "__do_execve_file"); - symbol->do_execve_common = try_get_symbol_offset_zero(kallsym, img_buf, "do_execve_common"); - if (!symbol->do_execveat_common && !symbol->__do_execve_file && !symbol->do_execve_common) - tools_loge_exit("no symbol do_execveat_common, __do_execve_file and do_execve_common"); - - symbol->do_faccessat = try_get_symbol_offset_zero(kallsym, img_buf, "do_faccessat"); - symbol->sys_faccessat = get_symbol_offset_zero(kallsym, img_buf, "__arm64_sys_faccessat"); - if (!symbol->sys_faccessat) symbol->sys_faccessat = get_symbol_offset_zero(kallsym, img_buf, "sys_faccessat"); - symbol->sys_faccessat2 = get_symbol_offset_zero(kallsym, img_buf, "__arm64_sys_faccessat2"); - if (!symbol->sys_faccessat2) symbol->sys_faccessat2 = get_symbol_offset_zero(kallsym, img_buf, "sys_faccessat2"); - if (!symbol->do_faccessat && !symbol->sys_faccessat && !symbol->sys_faccessat) - tools_loge_exit("no symbol do_faccessat, sys_faccessat and sys_faccessat2"); - - symbol->sys_newfstatat = get_symbol_offset_zero(kallsym, img_buf, "__arm64_sys_newfstatat"); - if (!symbol->sys_newfstatat) symbol->sys_newfstatat = get_symbol_offset_zero(kallsym, img_buf, "sys_newfstatat"); - symbol->vfs_statx = try_get_symbol_offset_zero(kallsym, img_buf, "vfs_statx"); - symbol->vfs_fstatat = try_get_symbol_offset_zero(kallsym, img_buf, "vfs_fstatat"); - if (!symbol->sys_newfstatat && !symbol->vfs_fstatat && !symbol->vfs_statx) - tools_loge_exit("no symbol vfs_statx and vfs_fstatat"); - // gcc -fipa-sra eg: avc_denied.isra.5 symbol->avc_denied = try_get_symbol_offset_zero(kallsym, img_buf, "avc_denied"); if (!symbol->avc_denied && is_android) tools_loge_exit("no symbol avc_denied"); diff --git a/user/.gitignore b/user/.gitignore index e755c739..94b9893e 100644 --- a/user/.gitignore +++ b/user/.gitignore @@ -1,39 +1 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - - -build/* - -uapi -version -kpatch - -build_android.sh - +uapi \ No newline at end of file diff --git a/user/supercall.h b/user/supercall.h index 2f200241..cc54225c 100644 --- a/user/supercall.h +++ b/user/supercall.h @@ -16,16 +16,15 @@ #include "uapi/scdefs.h" #include "../version" -// TODO: delete this file and use supercall_ge0a04.h instead when no one has kernelpatch <= 0.10.4, - -// be 0a04 +/// @deprecated +/// KernelPatch version less than 0xa05 static inline long hash_key_cmd(const char *key, long cmd) { long hash = hash_key(key); return hash & 0xFFFF0000 | cmd; } -// ge 0a05 +/// KernelPatch version is greater than or equal to 0x0a05 static inline long ver_and_cmd(const char *key, long cmd) { uint32_t version_code = (MAJOR << 16) + (MINOR << 8) + PATCH; @@ -34,11 +33,19 @@ static inline long ver_and_cmd(const char *key, long cmd) static inline long compact_cmd(const char *key, long cmd) { +#if 1 long ver = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KERNELPATCH_VER)); if (ver >= 0xa05) return ver_and_cmd(key, cmd); +#endif return hash_key_cmd(key, cmd); } +/** + * @brief If KernelPatch installed, @see SUPERCALL_HELLO_ECHO will echoed. + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @return long + */ static inline long sc_hello(const char *key) { if (!key || !key[0]) return -EINVAL; @@ -46,11 +53,25 @@ static inline long sc_hello(const char *key) return ret; } +/** + * @brief Is KernelPatch installed? + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @return true + * @return false + */ static inline bool sc_ready(const char *key) { return sc_hello(key) == SUPERCALL_HELLO_MAGIC; } +/** + * @brief Print messages by printk in the kernel + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param msg + * @return long + */ static inline long sc_klog(const char *key, const char *msg) { if (!key || !key[0]) return -EINVAL; @@ -59,6 +80,12 @@ static inline long sc_klog(const char *key, const char *msg) return ret; } +/** + * @brief KernelPatch version number + * + * @param key + * @return uint32_t + */ static inline uint32_t sc_kp_ver(const char *key) { if (!key || !key[0]) return -EINVAL; @@ -66,6 +93,12 @@ static inline uint32_t sc_kp_ver(const char *key) return (uint32_t)ret; } +/** + * @brief Kernel version number + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @return uint32_t + */ static inline uint32_t sc_k_ver(const char *key) { if (!key || !key[0]) return -EINVAL; @@ -73,170 +106,340 @@ static inline uint32_t sc_k_ver(const char *key) return (uint32_t)ret; } -static inline uint32_t sc_skey_get(const char *key, char *out_key, int outlen) +/** + * @brief Substitute user of current thread + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param profile : if scontext is invalid or illegal, all selinux permission checks will bypass via hook + * @see struct su_profile + * @return long : 0 if succeed + */ +static inline long sc_su(const char *key, struct su_profile *profile) { if (!key || !key[0]) return -EINVAL; - if (outlen < SUPERCALL_KEY_MAX_LEN) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_GET), out_key, outlen); - return (uint32_t)ret; + if (strlen(profile->scontext) >= SUPERCALL_SCONTEXT_LEN) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU), profile); + return ret; } -static inline uint32_t sc_skey_set(const char *key, const char *new_key) +/** + * @brief Substitute user of tid specfied + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param tid : target thread id + * @param profile : if scontext is invalid or illegal, all selinux permission checks will bypass via hook + * @see struct su_profile + * @return long : 0 if succeed + */ +static inline long sc_su_task(const char *key, pid_t tid, struct su_profile *profile) { if (!key || !key[0]) return -EINVAL; - if (!new_key || !new_key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_SET), new_key); - return (uint32_t)ret; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_TASK), tid, profile); + return ret; } -static inline uint32_t sc_skey_root_enable(const char *key, bool enable) +/** + * @brief Grant su permission + * + * @param key + * @param profile : if scontext is invalid or illegal, all selinux permission checks will bypass via hook + * @return long : 0 if succeed + */ +static inline long sc_su_grant_uid(const char *key, struct su_profile *profile) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_ROOT_ENABLE), (long)enable); - return (uint32_t)ret; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GRANT_UID), profile); + return ret; } -static inline long sc_su(const char *key, struct su_profile *profile) +/** + * @brief Revoke su permission + * + * @param key + * @param uid + * @return long 0 if succeed + */ +static inline long sc_su_revoke_uid(const char *key, uid_t uid) { if (!key || !key[0]) return -EINVAL; - if (strlen(profile->scontext) >= SUPERCALL_SCONTEXT_LEN) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU), profile); + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_REVOKE_UID), uid); return ret; } -static inline long sc_su_task(const char *key, pid_t tid, struct su_profile *profile) +/** + * @brief Get numbers of su allowed uids + * + * @param key + * @return long + */ +static inline long sc_su_uid_nums(const char *key) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_TASK), tid, profile); + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_NUMS)); return ret; } -static inline long sc_kpm_load(const char *key, const char *path, const char *args, void *reserved) +/** + * @brief + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param buf + * @param num + * @return long : The numbers of uids if succeed, nagative value if failed + */ +static inline long sc_su_allow_uids(const char *key, uid_t *buf, int num) { if (!key || !key[0]) return -EINVAL; - if (!path || strlen(path) <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_LOAD), path, args, reserved); + if (!buf || num <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_LIST), buf, num); return ret; } -static inline long sc_kpm_control(const char *key, const char *name, const char *ctl_args, char *out_msg, long outlen) +/** + * @brief Get su profile of specified uid + * + * @param key + * @param uid + * @param out_profile + * @return long : 0 if succeed + */ +static inline long sc_su_uid_profile(const char *key, uid_t uid, struct su_profile *out_profile) { if (!key || !key[0]) return -EINVAL; - if (!name || strlen(name) <= 0) return -EINVAL; - if (!ctl_args || strlen(ctl_args) <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_CONTROL), name, ctl_args, out_msg, outlen); + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_PROFILE), uid, out_profile); return ret; } -static inline long sc_kpm_unload(const char *key, const char *name, void *reserved) +/** + * @brief Get full path of current 'su' command + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param out_path + * @param path_len + * @return long : The length of result string if succeed, negative if failed + */ +static inline long sc_su_get_path(const char *key, char *out_path, int path_len) { if (!key || !key[0]) return -EINVAL; - if (!name || strlen(name) <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_UNLOAD), name, reserved); + if (!out_path || out_path <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GET_PATH), out_path, path_len); return ret; } -static inline long sc_kpm_nums(const char *key) +/** + * @brief Reset full path of 'su' command + * + * @param key + * @param path + * @return long : 0 if succeed + */ +static inline long sc_su_reset_path(const char *key, const char *path) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_NUMS)); + if (!path || !path[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_RESET_PATH), path); return ret; } -static inline long sc_kpm_list(const char *key, char *names_buf, int buf_len) +/** + * @brief Get current all-allowed selinux context + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param out_sctx + * @param sctx_len + * @return long 0 if there is a all-allowed selinux context now + */ +static inline long sc_su_get_all_allow_sctx(const char *key, char *out_sctx, int sctx_len) { if (!key || !key[0]) return -EINVAL; - if (!names_buf || buf_len <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_LIST), names_buf, buf_len); + if (!out_sctx) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GET_ALLOW_SCTX), out_sctx); return ret; } -static inline long sc_kpm_info(const char *key, const char *name, char *buf, int buf_len) +/** + * @brief Reset current all-allowed selinux context + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param sctx If sctx is empty string, clear all-allowed selinux, + * otherwise, try to reset a new all-allowed selinux context + * @return long 0 if succeed + */ +static inline long sc_su_reset_all_allow_sctx(const char *key, const char *sctx) { if (!key || !key[0]) return -EINVAL; - if (!buf || buf_len <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_INFO), name, buf, buf_len); + if (!sctx) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_SET_ALLOW_SCTX), sctx); return ret; } -static inline long sc_pid_virt_to_phys(const char *key, pid_t pid, unsigned long vaddr) +/** + * @brief Load module + * + * @param key : superkey + * @param path + * @param args + * @param reserved + * @return long : 0 if succeed + */ +static inline long sc_kpm_load(const char *key, const char *path, const char *args, void *reserved) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_MEM_PHYS), pid, vaddr); + if (!path || strlen(path) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_LOAD), path, args, reserved); return ret; } -static inline long sc_bootlog(const char *key) +/** + * @brief Control module with arguments + * + * @param key : superkey + * @param name : module name + * @param ctl_args : control argument + * @param out_msg : output message buffer + * @param outlen : buffer length of out_msg + * @return long : 0 if succeed + */ +static inline long sc_kpm_control(const char *key, const char *name, const char *ctl_args, char *out_msg, long outlen) { - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_BOOTLOG)); + if (!key || !key[0]) return -EINVAL; + if (!name || strlen(name) <= 0) return -EINVAL; + if (!ctl_args || strlen(ctl_args) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_CONTROL), name, ctl_args, out_msg, outlen); return ret; } -static inline long sc_panic(const char *key) +/** + * @brief Unload module + * + * @param key : superkey + * @param name : module name + * @param reserved + * @return long : 0 if succeed + */ +static inline long sc_kpm_unload(const char *key, const char *name, void *reserved) { - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_PANIC)); + if (!key || !key[0]) return -EINVAL; + if (!name || strlen(name) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_UNLOAD), name, reserved); return ret; } -static inline long __sc_test(const char *key, long a1, long a2, long a3) +/** + * @brief Current loaded module numbers + * + * @param key : superkey + * @return long + */ +static inline long sc_kpm_nums(const char *key) { - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_TEST), a1, a2, a3); + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_NUMS)); return ret; } -#ifdef ANDROID -static inline long sc_su_grant_uid(const char *key, uid_t uid, struct su_profile *profile) +/** + * @brief List names of current loaded modules, splited with '\n' + * + * @param key : superkey + * @param names_buf : output buffer + * @param buf_len : the length of names_buf + * @return long : the length of result string if succeed, negative if failed + */ +static inline long sc_kpm_list(const char *key, char *names_buf, int buf_len) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GRANT_UID), uid, profile); + if (!names_buf || buf_len <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_LIST), names_buf, buf_len); return ret; } -static inline long sc_su_revoke_uid(const char *key, uid_t uid) +/** + * @brief Get module information. + * + * @param key : superkey + * @param name : module name + * @param buf : + * @param buf_len : + * @return long : The length of result string if succeed, negative if failed + */ +static inline long sc_kpm_info(const char *key, const char *name, char *buf, int buf_len) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_REVOKE_UID), uid); + if (!buf || buf_len <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_INFO), name, buf, buf_len); return ret; } -static inline long sc_su_uid_nums(const char *key) +/** + * @brief Get current superkey + * + * @param key : superkey + * @param out_key + * @param outlen + * @return long : 0 if succeed + */ +static inline long sc_skey_get(const char *key, char *out_key, int outlen) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_NUMS)); + if (outlen < SUPERCALL_KEY_MAX_LEN) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_GET), out_key, outlen); return ret; } -static inline long sc_su_allow_uids(const char *key, uid_t *buf, int num) +/** + * @brief Reset current superkey + * + * @param key : superkey + * @param new_key + * @return long : 0 if succeed + */ +static inline long sc_skey_set(const char *key, const char *new_key) { if (!key || !key[0]) return -EINVAL; - if (!buf || num <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_LIST), buf, num); + if (!new_key || !new_key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_SET), new_key); return ret; } -static inline long sc_su_uid_profile(const char *key, uid_t uid, struct su_profile *out_profile) +/** + * @brief Whether to enable hash verification for root superkey. + * + * @param key : superkey + * @param enable + * @return long + */ +static inline long sc_skey_root_enable(const char *key, bool enable) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_PROFILE), uid, out_profile); + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_ROOT_ENABLE), (long)enable); return ret; } -static inline long sc_su_reset_path(const char *key, const char *path) +// todo +static inline long sc_pid_virt_to_phys(const char *key, pid_t pid, unsigned long vaddr) { if (!key || !key[0]) return -EINVAL; - if (!path || !path[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_RESET_PATH), path); + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_MEM_PHYS), pid, vaddr); return ret; } -static inline long sc_su_get_path(const char *key, char *buf, int buf_size) +static inline long sc_bootlog(const char *key) { - if (!key || !key[0]) return -EINVAL; - if (!buf || buf_size <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GET_PATH), buf, buf_size); + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_BOOTLOG)); return ret; } -#endif +static inline long sc_panic(const char *key) +{ + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_PANIC)); + return ret; +} + +static inline long __sc_test(const char *key, long a1, long a2, long a3) +{ + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_TEST), a1, a2, a3); + return ret; +} #endif \ No newline at end of file diff --git a/user_deprecated/.gitignore b/user_deprecated/.gitignore new file mode 100644 index 00000000..e755c739 --- /dev/null +++ b/user_deprecated/.gitignore @@ -0,0 +1,39 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + + +build/* + +uapi +version +kpatch + +build_android.sh + diff --git a/user/CMakeLists.txt b/user_deprecated/CMakeLists.txt similarity index 100% rename from user/CMakeLists.txt rename to user_deprecated/CMakeLists.txt diff --git a/user/Makefile b/user_deprecated/Makefile similarity index 100% rename from user/Makefile rename to user_deprecated/Makefile diff --git a/user/android/android_user.c b/user_deprecated/android/android_user.c similarity index 97% rename from user/android/android_user.c rename to user_deprecated/android/android_user.c index fa9a16ae..c2470654 100644 --- a/user/android/android_user.c +++ b/user_deprecated/android/android_user.c @@ -29,9 +29,9 @@ struct allow_pkg_info const char sctx[SUPERCALL_SCONTEXT_LEN]; }; -static char magiskpolicy_path[] = APATCH_BIN_FLODER "magiskpolicy"; -static char pkg_cfg_path[] = APATCH_FLODER "package_config"; -static char su_path_path[] = APATCH_FLODER "su_path"; +static char magiskpolicy_path[] = AP_BIN_DIR "magiskpolicy"; +static char pkg_cfg_path[] = AP_DIR "package_config"; +static char su_path_path[] = AP_DIR "su_path"; extern const char *key; static bool from_kernel = false; @@ -237,7 +237,7 @@ static void post_fs_data_init() return; } - if (access(APATCH_FLODER, F_OK)) mkdir(APATCH_FLODER, 0700); + if (access(AP_DIR, F_OK)) mkdir(AP_DIR, 0700); if (access(APATCH_LOG_FLODER, F_OK)) mkdir(APATCH_LOG_FLODER, 0700); char *log_args[] = { "/system/bin/cp", "-f", EARLY_INIT_LOG_0, APATCH_LOG_FLODER, NULL }; diff --git a/user/android/android_user.h b/user_deprecated/android/android_user.h similarity index 100% rename from user/android/android_user.h rename to user_deprecated/android/android_user.h diff --git a/user/android/apjni.cpp b/user_deprecated/android/apjni.cpp similarity index 100% rename from user/android/apjni.cpp rename to user_deprecated/android/apjni.cpp diff --git a/user/android/sumgr.c b/user_deprecated/android/sumgr.c similarity index 98% rename from user/android/sumgr.c rename to user_deprecated/android/sumgr.c index 3f168829..de7f01a1 100644 --- a/user/android/sumgr.c +++ b/user_deprecated/android/sumgr.c @@ -12,7 +12,7 @@ #include "../supercall.h" -int su_grant(const char *key, uid_t uid, uid_t to_uid, const char *scontext) +int su_grant(const char *key, uid_t to_uid, const char *scontext) { struct su_profile profile = { 0 }; profile.uid = uid; diff --git a/user/android/sumgr.h b/user_deprecated/android/sumgr.h similarity index 100% rename from user/android/sumgr.h rename to user_deprecated/android/sumgr.h diff --git a/user/kpatch.c b/user_deprecated/kpatch.c similarity index 100% rename from user/kpatch.c rename to user_deprecated/kpatch.c diff --git a/user/kpatch.h b/user_deprecated/kpatch.h similarity index 100% rename from user/kpatch.h rename to user_deprecated/kpatch.h diff --git a/user/kpm.c b/user_deprecated/kpm.c similarity index 100% rename from user/kpm.c rename to user_deprecated/kpm.c diff --git a/user/kpm.h b/user_deprecated/kpm.h similarity index 100% rename from user/kpm.h rename to user_deprecated/kpm.h diff --git a/user/main.c b/user_deprecated/main.c similarity index 100% rename from user/main.c rename to user_deprecated/main.c diff --git a/user/su.c b/user_deprecated/su.c similarity index 99% rename from user/su.c rename to user_deprecated/su.c index e0421899..3b74df60 100644 --- a/user/su.c +++ b/user_deprecated/su.c @@ -36,8 +36,8 @@ enum #define DEFAULT_SHELL "/system/bin/sh" #define DEFAULT_PATH "/product/bin:/apex/com.android.runtime/bin:/system/bin:/odm/bin:/vendor/bin:/usr/bin" #define DEFAULT_ROOT_PATH \ - APATCH_BIN_FLODER \ - ":" ADB_FLODER \ + AP_BIN_DIR \ + ":" ADB_DIR \ ":/sbin:/system/sbin:/product/bin:/apex/com.android.runtime/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin:/usr/bin:/user/sbin" #else diff --git a/user/su.h b/user_deprecated/su.h similarity index 100% rename from user/su.h rename to user_deprecated/su.h diff --git a/user_deprecated/supercall.h b/user_deprecated/supercall.h new file mode 100644 index 00000000..4f594900 --- /dev/null +++ b/user_deprecated/supercall.h @@ -0,0 +1,411 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 bmax121. All Rights Reserved. + */ + +#ifndef _KPU_SUPERCALL_H_ +#define _KPU_SUPERCALL_H_ + +#include +#include +#include +#include +#include +#include + +#include "uapi/scdefs.h" +#include "../version" + +/// @deprecated +/// KernelPatch version less than 0xa05 +static inline long hash_key_cmd(const char *key, long cmd) +{ + long hash = hash_key(key); + return hash & 0xFFFF0000 | cmd; +} + +/// KernelPatch version is greater than or equal to 0x0a05 +static inline long ver_and_cmd(const char *key, long cmd) +{ + uint32_t version_code = (MAJOR << 16) + (MINOR << 8) + PATCH; + return ((long)version_code << 32) | (0x1158 << 16) | (cmd & 0xFFFF); +} + +static inline long compact_cmd(const char *key, long cmd) +{ +#if 1 + long ver = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KERNELPATCH_VER)); + if (ver >= 0xa05) return ver_and_cmd(key, cmd); +#endif + return hash_key_cmd(key, cmd); +} + +/** + * @brief If KernelPatch installed, @see SUPERCALL_HELLO_ECHO will echoed. + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @return long + */ +static inline long sc_hello(const char *key) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_HELLO)); + return ret; +} + +/** + * @brief Is KernelPatch installed? + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @return true + * @return false + */ +static inline bool sc_ready(const char *key) +{ + return sc_hello(key) == SUPERCALL_HELLO_MAGIC; +} + +/** + * @brief Print messages by printk in the kernel + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param msg + * @return long + */ +static inline long sc_klog(const char *key, const char *msg) +{ + if (!key || !key[0]) return -EINVAL; + if (!msg || strlen(msg) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KLOG), msg); + return ret; +} + +/** + * @brief KernelPatch version number + * + * @param key + * @return uint32_t + */ +static inline uint32_t sc_kp_ver(const char *key) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KERNELPATCH_VER)); + return (uint32_t)ret; +} + +/** + * @brief Kernel version number + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @return uint32_t + */ +static inline uint32_t sc_k_ver(const char *key) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KERNEL_VER)); + return (uint32_t)ret; +} + +/** + * @brief Substitute user of current thread + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param profile + * @return long : 0 if succeed + */ +static inline long sc_su(const char *key, struct su_profile *profile) +{ + if (!key || !key[0]) return -EINVAL; + if (strlen(profile->scontext) >= SUPERCALL_SCONTEXT_LEN) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU), profile); + return ret; +} + +/** + * @brief Substitute user of tid specfied + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param tid : target thread id + * @param profile + * @return long : 0 if succeed + */ +static inline long sc_su_task(const char *key, pid_t tid, struct su_profile *profile) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_TASK), tid, profile); + return ret; +} + +/** + * @brief Grant su permission + * + * @param key + * @param profile + * @return long : 0 if succeed + */ +static inline long sc_su_grant_uid(const char *key, struct su_profile *profile) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GRANT_UID), profile); + return ret; +} + +/** + * @brief Revoke su permission + * + * @param key + * @param uid + * @return long 0 if succeed + */ +static inline long sc_su_revoke_uid(const char *key, uid_t uid) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_REVOKE_UID), uid); + return ret; +} + +/** + * @brief Get numbers of su allowed uids + * + * @param key + * @return long + */ +static inline long sc_su_uid_nums(const char *key) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_NUMS)); + return ret; +} + +/** + * @brief + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param buf + * @param num + * @return long : The numbers of uids if succeed, nagative value if failed + */ +static inline long sc_su_allow_uids(const char *key, uid_t *buf, int num) +{ + if (!key || !key[0]) return -EINVAL; + if (!buf || num <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_LIST), buf, num); + return ret; +} + +/** + * @brief Get su profile of specified uid + * + * @param key + * @param uid + * @param out_profile + * @return long : 0 if succeed + */ +static inline long sc_su_uid_profile(const char *key, uid_t uid, struct su_profile *out_profile) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_PROFILE), uid, out_profile); + return ret; +} + +/** + * @brief Reset full path of 'su' command + * + * @param key + * @param path + * @return long : 0 if succeed + */ +static inline long sc_su_reset_path(const char *key, const char *path) +{ + if (!key || !key[0]) return -EINVAL; + if (!path || !path[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_RESET_PATH), path); + return ret; +} + +/** + * @brief Get full path of current 'su' command + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param buf + * @param buf_size + * @return long : The length of result string if succeed, negative if failed + */ +static inline long sc_su_get_path(const char *key, char *buf, int buf_size) +{ + if (!key || !key[0]) return -EINVAL; + if (!buf || buf_size <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GET_PATH), buf, buf_size); + return ret; +} + +/** + * @brief Load module + * + * @param key : superkey + * @param path + * @param args + * @param reserved + * @return long : 0 if succeed + */ +static inline long sc_kpm_load(const char *key, const char *path, const char *args, void *reserved) +{ + if (!key || !key[0]) return -EINVAL; + if (!path || strlen(path) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_LOAD), path, args, reserved); + return ret; +} + +/** + * @brief Control module with arguments + * + * @param key : superkey + * @param name : module name + * @param ctl_args : control argument + * @param out_msg : output message buffer + * @param outlen : buffer length of out_msg + * @return long : 0 if succeed + */ +static inline long sc_kpm_control(const char *key, const char *name, const char *ctl_args, char *out_msg, long outlen) +{ + if (!key || !key[0]) return -EINVAL; + if (!name || strlen(name) <= 0) return -EINVAL; + if (!ctl_args || strlen(ctl_args) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_CONTROL), name, ctl_args, out_msg, outlen); + return ret; +} + +/** + * @brief Unload module + * + * @param key : superkey + * @param name : module name + * @param reserved + * @return long : 0 if succeed + */ +static inline long sc_kpm_unload(const char *key, const char *name, void *reserved) +{ + if (!key || !key[0]) return -EINVAL; + if (!name || strlen(name) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_UNLOAD), name, reserved); + return ret; +} + +/** + * @brief Current loaded module numbers + * + * @param key : superkey + * @return long + */ +static inline long sc_kpm_nums(const char *key) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_NUMS)); + return ret; +} + +/** + * @brief List names of current loaded modules, splited with '\n' + * + * @param key : superkey + * @param names_buf : output buffer + * @param buf_len : the length of names_buf + * @return long : the length of result string if succeed, negative if failed + */ +static inline long sc_kpm_list(const char *key, char *names_buf, int buf_len) +{ + if (!key || !key[0]) return -EINVAL; + if (!names_buf || buf_len <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_LIST), names_buf, buf_len); + return ret; +} + +/** + * @brief Get module information. + * + * @param key : superkey + * @param name : module name + * @param buf : + * @param buf_len : + * @return long : The length of result string if succeed, negative if failed + */ +static inline long sc_kpm_info(const char *key, const char *name, char *buf, int buf_len) +{ + if (!key || !key[0]) return -EINVAL; + if (!buf || buf_len <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_INFO), name, buf, buf_len); + return ret; +} + +/** + * @brief Get current superkey + * + * @param key : superkey + * @param out_key + * @param outlen + * @return long : 0 if succeed + */ +static inline long sc_skey_get(const char *key, char *out_key, int outlen) +{ + if (!key || !key[0]) return -EINVAL; + if (outlen < SUPERCALL_KEY_MAX_LEN) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_GET), out_key, outlen); + return ret; +} + +/** + * @brief Reset current superkey + * + * @param key : superkey + * @param new_key + * @return long : 0 if succeed + */ +static inline long sc_skey_set(const char *key, const char *new_key) +{ + if (!key || !key[0]) return -EINVAL; + if (!new_key || !new_key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_SET), new_key); + return ret; +} + +/** + * @brief Whether to enable hash verification for root superkey. + * + * @param key : superkey + * @param enable + * @return long + */ +static inline long sc_skey_root_enable(const char *key, bool enable) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SKEY_ROOT_ENABLE), (long)enable); + return ret; +} + +// todo +static inline long sc_pid_virt_to_phys(const char *key, pid_t pid, unsigned long vaddr) +{ + if (!key || !key[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_MEM_PHYS), pid, vaddr); + return ret; +} + +static inline long sc_bootlog(const char *key) +{ + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_BOOTLOG)); + return ret; +} + +static inline long sc_panic(const char *key) +{ + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_PANIC)); + return ret; +} + +static inline long __sc_test(const char *key, long a1, long a2, long a3) +{ + long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_TEST), a1, a2, a3); + return ret; +} + +#endif \ No newline at end of file diff --git a/user/supercall_ge0a04.h b/user_deprecated/supercall_ge0a04.h similarity index 95% rename from user/supercall_ge0a04.h rename to user_deprecated/supercall_ge0a04.h index ff427b68..bf272394 100644 --- a/user/supercall_ge0a04.h +++ b/user_deprecated/supercall_ge0a04.h @@ -53,30 +53,30 @@ static inline uint32_t sc_k_ver(const char *key) { if (!key || !key[0]) return -EINVAL; long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KERNEL_VER)); - return (uint32_t)ret; + return (int32_t)ret; } -static inline uint32_t sc_skey_get(const char *key, char *out_key, int outlen) +static inline long sc_skey_get(const char *key, char *out_key, int outlen) { if (!key || !key[0]) return -EINVAL; if (outlen < SUPERCALL_KEY_MAX_LEN) return -EINVAL; long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SKEY_GET), out_key, outlen); - return (uint32_t)ret; + return ret; } -static inline uint32_t sc_skey_set(const char *key, const char *new_key) +static inline long sc_skey_set(const char *key, const char *new_key) { if (!key || !key[0]) return -EINVAL; if (!new_key || !new_key[0]) return -EINVAL; long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SKEY_SET), new_key); - return (uint32_t)ret; + return ret; } -static inline uint32_t sc_skey_root_enable(const char *key, bool enable) +static inline long sc_skey_root_enable(const char *key, bool enable) { if (!key || !key[0]) return -EINVAL; long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SKEY_ROOT_ENABLE), (long)enable); - return (uint32_t)ret; + return ret; } static inline long sc_su(const char *key, struct su_profile *profile) @@ -167,7 +167,6 @@ static inline long __sc_test(const char *key, long a1, long a2, long a3) return ret; } -#ifdef ANDROID static inline long sc_su_grant_uid(const char *key, uid_t uid, struct su_profile *profile) { if (!key || !key[0]) return -EINVAL; @@ -220,6 +219,4 @@ static inline long sc_su_get_path(const char *key, char *buf, int buf_size) return ret; } -#endif - #endif \ No newline at end of file diff --git a/version b/version index 462caf73..bb8bb10b 100644 --- a/version +++ b/version @@ -1,3 +1,3 @@ #define MAJOR 0 -#define MINOR 10 -#define PATCH 7 +#define MINOR 11 +#define PATCH 0