diff --git a/.clang-format b/.clang-format index 4556797b..b3dd3de7 100644 --- a/.clang-format +++ b/.clang-format @@ -51,7 +51,7 @@ BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false -BreakBeforeSemicolons: None +# BreakBeforeSemicolons: None ColumnLimit: 120 CommentPragmas: "^ IWYU pragma:" CompactNamespaces: false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e5dbd28b..7e69287c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,16 +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 + make clean + + unset ANDROID + make + mv kpimg kpimg-linux + mv kpimg.elf kpimg.elf-linux + make clean cd .. cd kpms @@ -125,7 +128,7 @@ jobs: replacesArtifacts: true omitBodyDuringUpdate: true - Build-android-kpatch-kptools: + Build-android-kptools: runs-on: ubuntu-latest permissions: contents: write @@ -149,7 +152,7 @@ jobs: uses: nttld/setup-ndk@v1 id: setup-ndk with: - ndk-version: r25b + ndk-version: r26b add-to-path: true - name: Make hdr @@ -158,21 +161,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 @@ -192,8 +180,6 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.parse_version.outputs.VERSION }} artifacts: | - user/build/android/kpatch-android - user/build/android/libapjni.so tools/build/android/kptools-android allowUpdates: true replacesArtifacts: true @@ -267,6 +253,7 @@ jobs: install: >- msys/make msys/gcc + msys/zlib-devel - name: Copyfile shell: pwsh run: | @@ -283,8 +270,11 @@ jobs: - name: Copyfile2 shell: pwsh run: | - cp .\tools\kptools.exe .\tools\kptools-msys2.exe - 7z a kptools-msys2-win .\tools\kptools-msys2.exe D:\a\_temp\msys64\usr\bin\msys-2.0.dll + mkdir .\win + cp .\tools\kptools.exe .\win\kptools-msys2.exe + cp D:\a\_temp\msys64\usr\bin\msys-2.0.dll .\win + cp D:\a\_temp\msys64\usr\bin\msys-z.dll .\win + 7z a kptools-msys2-win .\win - name: Release uses: ncipollo/release-action@v1.12.0 with: @@ -295,53 +285,6 @@ jobs: allowUpdates: true replacesArtifacts: true - Build-kptools-windows-llvm: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Check out - uses: actions/checkout@v3 - - name: Install mingw32 cross toolchains - run: | - MINGW_LLVM_URL="https://github.com/mstorsjo/llvm-mingw/releases/download/20231128/llvm-mingw-20231128-msvcrt-ubuntu-20.04-x86_64.tar.xz" - mkdir -p $HOME/mingw-llvm - wget $MINGW_LLVM_URL -O $HOME/mingw-llvm/llvm.tar.xz - cd $HOME/mingw-llvm - tar -xvf llvm.tar.xz --strip-components 1 - - name: Generate version - id: parse_version - run: | - MAJOR=$(grep '#define MAJOR' version | awk '{print $3}') - MINOR=$(grep '#define MINOR' version | awk '{print $3}') - PATCH=$(grep '#define PATCH' version | awk '{print $3}') - VERSION="$MAJOR.$MINOR.$PATCH" - echo "Generated Version: $VERSION" - echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - - name: Build kptools - run: | - export PATH="$HOME/mingw-llvm/bin:$PATH" - export ANDROID=1 - ABIS="x86_64 i686 aarch64 armv7" - for i in $ABIS; do - make -C kernel hdr TARGET_COMPILE=placeholder - echo "- Compiling kptools-$i-win.exe" - make -C tools CC=$i-w64-mingw32-clang - mv tools/kptools.exe kptools-$i-win.exe - make -C tools clean - done - 7za a kptools-llvm-win.zip -tZIP *.exe - - name: Release - uses: ncipollo/release-action@v1.12.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - tag: ${{ steps.parse_version.outputs.VERSION }} - artifacts: | - kptools-llvm-win.zip - allowUpdates: true - replacesArtifacts: true - omitBodyDuringUpdate: true - Build-kptools-mac: runs-on: macos-latest permissions: diff --git a/.github/workflows/build_dev.yml b/.github/workflows/build_dev.yml index 2f6ba868..312494b8 100644 --- a/.github/workflows/build_dev.yml +++ b/.github/workflows/build_dev.yml @@ -4,7 +4,7 @@ on: push: branches: ["dev"] paths: - - ".github/workflows/build.yml" + - ".github/workflows/build_dev.yml" - "kernel/**" - "user/**" - "tools/**" @@ -12,7 +12,7 @@ on: pull_request: branches: ["dev"] paths: - - ".github/workflows/build.yml" + - ".github/workflows/build_dev.yml" - "kernel/**" - "user/**" - "tools/**" @@ -48,14 +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 + make clean + + unset ANDROID + make + mv kpimg kpimg-linux + mv kpimg.elf kpimg.elf-linux + make clean cd .. cd kpms @@ -85,7 +89,6 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.parse_version.outputs.VERSION }}-dev - commit: dev artifacts: | kernel/kpimg-linux kernel/kpimg-android @@ -127,14 +130,13 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.parse_version.outputs.VERSION }}-dev - commit: dev artifacts: | kpuser.zip allowUpdates: true replacesArtifacts: true prerelease: true - Build-android-kpatch-kptools: + Build-android-kptools: runs-on: ubuntu-latest permissions: contents: write @@ -158,7 +160,7 @@ jobs: uses: nttld/setup-ndk@v1 id: setup-ndk with: - ndk-version: r25b + ndk-version: r26b add-to-path: true - name: Make hdr @@ -167,21 +169,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 @@ -200,10 +187,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.parse_version.outputs.VERSION }}-dev - commit: dev artifacts: | - user/build/android/kpatch-android - user/build/android/libapjni.so tools/build/android/kptools-android allowUpdates: true replacesArtifacts: true @@ -246,7 +230,6 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.parse_version.outputs.VERSION }}-dev - commit: dev artifacts: | tools/build/kptools-linux allowUpdates: true @@ -289,7 +272,6 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ steps.parse_version.outputs.VERSION }}-dev - commit: dev artifacts: | tools/build/kptools-mac allowUpdates: true diff --git a/.gitignore b/.gitignore index a7005cf7..f09ca221 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,4 @@ build test -.test - +script diff --git a/README.md b/README.md index a2f54da3..95c1211a 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,7 @@ CONFIG_KALLSYMS=y Currently only supports arm64 architecture. -Linux 3.18 - 6.2 (theoretically) -Linux 6.3+ (not yet adapted) +Linux 3.18 - 6.6 (theoretically) ## Get Involved 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/doc/en/super-command.md b/doc/en/super-command.md new file mode 100644 index 00000000..bb18a9d5 --- /dev/null +++ b/doc/en/super-command.md @@ -0,0 +1,3 @@ +# Super Command + +truncate SUPERKEY help 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/Makefile b/kernel/Makefile index 3dc9fdc9..0443cb27 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -68,8 +68,9 @@ ${TARGET}.elf: ${OBJS} .PHONY: hdr hdr: - cp -Rf patch/include/uapi ../user - cp -f include/preset.h ../tools + cp -Rf patch/include/uapi ../user/ + cp -f ../version ../user/ + cp -f include/preset.h ../tools/ .PHONY: clean clean: diff --git a/kernel/base/baselib.c b/kernel/base/baselib.c index 0641b872..7bcf18ff 100644 --- a/kernel/base/baselib.c +++ b/kernel/base/baselib.c @@ -244,7 +244,7 @@ char *lib_strncat(char *dst, const char *src, size_t n) *q++ = ch = *p++; if (!ch) return dst; } - *q = '\0'; + // *q = '\0'; return dst; } @@ -277,7 +277,7 @@ char *lib_strncpy(char *dst, const char *src, size_t n) *q++ = ch = *p++; if (!ch) break; } - *q = '\0'; + // *q = '\0'; return dst; } 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..c568ed29 100644 --- a/kernel/base/hook.c +++ b/kernel/base/hook.c @@ -15,7 +15,7 @@ #define bit(n, st) (((n) >> (st)) & 1) #define sign64_extend(n, len) \ (((uint64_t)((n) << (63u - (len - 1))) >> 63u) ? ((n) | (0xFFFFFFFFFFFFFFFF << (len))) : n) -#define align_ceil(x, align) (((u64)(x) + (u64)(align)-1) & ~((u64)(align)-1)) +#define align_ceil(x, align) (((u64)(x) + (u64)(align) - 1) & ~((u64)(align) - 1)) typedef uint32_t inst_type_t; typedef uint32_t inst_mask_t; @@ -69,7 +69,7 @@ static inst_type_t types[] = { INST_CBZ, INST_CBNZ, INST_TBZ, INST_TBNZ, INST_IGNORE, }; -static int32_t relo_len[] = { 6, 8, 6, 4, 4, 6, 6, 6, 8, 8, 8, 8, 6, 6, 6, 6, 2 }; +static int32_t relo_len[] = { 6, 8, 8, 4, 4, 6, 6, 6, 8, 8, 8, 8, 6, 6, 6, 6, 2 }; // static uint64_t sign_extend(uint64_t x, uint32_t len) // { @@ -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); @@ -167,17 +162,19 @@ hook_err_t relo_b(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t t buf[idx++] = addr & 0xFFFFFFFF; buf[idx++] = addr >> 32u; if (type == INST_BL) { - buf[idx++] = 0xD63F0220; // BLR X17 + buf[idx++] = 0x1000001E; // ADR X30, . + buf[idx++] = 0x910033DE; // ADD X30, X30, #12 + buf[idx++] = 0xD65F0220; // RET X17 } else { - buf[idx++] = 0xD61F0220; // BR X17 + buf[idx++] = 0xD65F0220; // RET X17 } buf[idx++] = ARM64_NOP; 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 +194,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 +243,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); @@ -258,15 +255,15 @@ hook_err_t relo_cb(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t buf[0] = (inst & 0xFF00001F) | 0x40u; // CB(N)Z Rt, #8 buf[1] = 0x14000005; // B #20 buf[2] = 0x58000051; // LDR X17, #8 - buf[3] = 0xd61f0220; // BR X17 + buf[3] = 0xD65F0220; // RET X17 buf[4] = addr & 0xFFFFFFFF; buf[5] = addr >> 32u; 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); @@ -276,15 +273,15 @@ hook_err_t relo_tb(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t buf[0] = (inst & 0xFFF8001F) | 0x40u; // TB(N)Z Rt, #, #8 buf[1] = 0x14000005; // B #20 buf[2] = 0x58000051; // LDR X17, #8 - buf[3] = 0xd61f0220; // BR X17 + buf[3] = 0xd61f0220; // RET X17 buf[4] = addr & 0xFFFFFFFF; buf[5] = addr >> 32u; 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; @@ -321,7 +318,7 @@ KP_EXPORT_SYMBOL(branch_absolute); int32_t ret_absolute(uint32_t *buf, uint64_t addr) { buf[0] = 0x58000051; // LDR X17, #8 - buf[1] = 0xd65f0220; // RET X17 + buf[1] = 0xD65F0220; // RET X17 buf[2] = addr & 0xFFFFFFFF; buf[3] = addr >> 32u; return 4; @@ -333,11 +330,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 +349,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 +383,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 +423,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 +469,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 +553,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 +570,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 +592,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 +606,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 +626,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 +706,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 +717,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/predata.c b/kernel/base/predata.c index 6f1d8daa..35f50494 100644 --- a/kernel/base/predata.c +++ b/kernel/base/predata.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "start.h" #include "pgtable.h" @@ -16,20 +17,24 @@ extern start_preset_t start_preset; static char *superkey = 0; static char *root_superkey = 0; -static struct patch_symbol *patch_symbol = 0; + +struct patch_config *patch_config = 0; +KP_EXPORT_SYMBOL(patch_config); static const char bstr[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; static uint64_t _rand_next = 1000000007; -static int enable_root_key = 1; +static bool enable_root_key = false; int auth_superkey(const char *key) { int rc = 0; - rc = lib_strncmp(superkey, key, SUPER_KEY_LEN); - if (!rc) return rc; + for (int i = 0; superkey[i]; i++) { + rc |= (superkey[i] ^ key[i]); + } + if (!rc) goto out; - if (!enable_root_key) return rc; + if (!enable_root_key) goto out; BYTE hash[SHA256_BLOCK_SIZE]; SHA256_CTX ctx; @@ -39,22 +44,24 @@ int auth_superkey(const char *key) int len = SHA256_BLOCK_SIZE > ROOT_SUPER_KEY_HASH_LEN ? ROOT_SUPER_KEY_HASH_LEN : SHA256_BLOCK_SIZE; rc = lib_memcmp(root_superkey, hash, len); - static int first_time = 1; + static bool first_time = true; if (!rc && first_time) { - first_time = 0; + first_time = false; reset_superkey(key); + enable_root_key = false; } - return rc; +out: + return !!rc; } void reset_superkey(const char *key) { - lib_strncpy(superkey, key, SUPER_KEY_LEN - 1); - superkey[SUPER_KEY_LEN - 1] = '\0'; + lib_strlcpy(superkey, key, SUPER_KEY_LEN); + dsb(ish); } -void enable_auth_root_key(int enable) +void enable_auth_root_key(bool enable) { enable_root_key = enable; } @@ -70,9 +77,9 @@ const char *get_superkey() return superkey; } -struct patch_symbol *get_preset_patch_sym() +const char *get_build_time() { - return patch_symbol; + return setup_header->compile_time; } int on_each_extra_item(int (*callback)(const patch_extra_item_t *extra, const char *arg, const void *con, void *udata), @@ -113,8 +120,11 @@ void predata_init() if (*(uint64_t *)(superkey)) _rand_next *= *(uint64_t *)(superkey); if (*(uint64_t *)(root_superkey)) _rand_next *= *(uint64_t *)(root_superkey); + enable_root_key = false; + // random key if (lib_strnlen(superkey, SUPER_KEY_LEN) <= 0) { + enable_root_key = true; int len = SUPER_KEY_LEN > 16 ? 16 : SUPER_KEY_LEN; len--; for (int i = 0; i < len; ++i) { @@ -124,9 +134,9 @@ void predata_init() } log_boot("gen rand key: %s\n", superkey); - patch_symbol = &start_preset.patch_symbol; + patch_config = &start_preset.patch_config; - for (uintptr_t addr = (uint64_t)patch_symbol; addr < (uintptr_t)patch_symbol + PATCH_SYMBOL_LEN; + for (uintptr_t addr = (uint64_t)patch_config; addr < (uintptr_t)patch_config + PATCH_CONFIG_LEN; addr += sizeof(uintptr_t)) { uintptr_t *p = (uintptr_t *)addr; if (*p) *p += kernel_va; 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/setup1.S b/kernel/base/setup1.S index 10c05e26..9cb6f978 100644 --- a/kernel/base/setup1.S +++ b/kernel/base/setup1.S @@ -109,10 +109,10 @@ start_prepare: mov x2, #ROOT_SUPER_KEY_HASH_LEN bl memcpy8 - // memcpy(&start_preset.patch_symbol, &setup_preset.patch_symbol, sizeof(header.patch_symbol)); - add x0, x11, #start_patch_symbol_offset; - add x1, x10, #setup_patch_symbol_offset - mov x2, #PATCH_SYMBOL_LEN + // memcpy(&start_preset.patch_config, &setup_preset.patch_config, sizeof(header.patch_config)); + add x0, x11, #start_patch_config_offset; + add x1, x10, #setup_patch_config_offset + mov x2, #PATCH_CONFIG_LEN bl memcpy8 // backup map area diff --git a/kernel/base/start.c b/kernel/base/start.c index 4a901b84..5784755e 100644 --- a/kernel/base/start.c +++ b/kernel/base/start.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -20,13 +19,17 @@ #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)) -#define align_ceil(x, align) (((uint64_t)(x) + (uint64_t)(align)-1) & ~((uint64_t)(align)-1)) +#define align_floor(x, align) ((uint64_t)(x) & ~((uint64_t)(align) - 1)) +#define align_ceil(x, align) (((uint64_t)(x) + (uint64_t)(align) - 1) & ~((uint64_t)(align) - 1)) start_preset_t start_preset __attribute__((section(".start.data"))); +setup_header_t *setup_header = 0; +KP_EXPORT_SYMBOL(setup_header); + int (*kallsyms_on_each_symbol)(int (*fn)(void *data, const char *name, struct module *module, unsigned long addr), void *data) = 0; KP_EXPORT_SYMBOL(kallsyms_on_each_symbol); @@ -34,14 +37,10 @@ KP_EXPORT_SYMBOL(kallsyms_on_each_symbol); unsigned long (*kallsyms_lookup_name)(const char *name) = 0; KP_EXPORT_SYMBOL(kallsyms_lookup_name); -int (*lookup_symbol_attrs)(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, - char *name) = 0; -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 +77,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 +118,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 +180,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 +195,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 +239,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 +271,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 +382,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,26 +390,27 @@ 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); endian = *(unsigned char *)&(uint16_t){ 1 } ? little : big; - setup_header_t *header = &start_preset.header; + setup_header = &start_preset.header; kver = VERSION(start_preset.kernel_version.major, start_preset.kernel_version.minor, start_preset.kernel_version.patch); - kpver = VERSION(header->kp_version.major, header->kp_version.minor, header->kp_version.patch); + kpver = VERSION(setup_header->kp_version.major, setup_header->kp_version.minor, setup_header->kp_version.patch); log_boot("Kernel pa: %llx\n", kernel_pa); 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", setup_header->config_flags); + log_boot("KernelPatch Compile Time: %s\n", (uint64_t)setup_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"); uint64_t tcr_el1; asm volatile("mrs %0, tcr_el1" : "=r"(tcr_el1)); @@ -434,14 +436,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 +448,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/start.h b/kernel/base/start.h index 5766bfbc..3cc3b665 100644 --- a/kernel/base/start.h +++ b/kernel/base/start.h @@ -24,7 +24,7 @@ typedef struct uint8_t map_backup[MAP_MAX_SIZE]; uint8_t superkey[SUPER_KEY_LEN]; uint8_t root_superkey[ROOT_SUPER_KEY_HASH_LEN]; - patch_symbol_t patch_symbol; + patch_config_t patch_config; } start_preset_t; #else #define start_header_offset 0 @@ -39,8 +39,8 @@ typedef struct #define start_map_backup_offset (start_map_backup_len_offset + 8) #define start_superkey_offset (start_map_backup_offset + MAP_MAX_SIZE) #define start_root_superkey_offset (start_superkey_offset + SUPER_KEY_LEN) -#define start_patch_symbol_offset (start_root_superkey_offset + ROOT_SUPER_KEY_HASH_LEN) -#define start_patch_extra_offset_offset (start_patch_symbol_offset + PATCH_SYMBOL_LEN) +#define start_patch_config_offset (start_root_superkey_offset + ROOT_SUPER_KEY_HASH_LEN) +#define start_patch_extra_offset_offset (start_patch_config_offset + PATCH_CONFIG_LEN) #define start_patch_extra_size_offset (start_patch_extra_offset_offset + 8) #define start_end (start_patch_extra_size_offset + 8) #endif 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..b9ced847 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 @@ -38,7 +37,7 @@ typedef int8_t chain_item_state; #define CHAIN_ITEM_STATE_BUSY 2 #define local_offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER) -#define local_container_of(ptr, type, member) ({ (type *)((char *)(ptr)-local_offsetof(type, member)); }) +#define local_container_of(ptr, type, member) ({ (type *)((char *)(ptr) - local_offsetof(type, member)); }) #define HOOK_MEM_REGION_NUM 4 #define TRAMPOLINE_NUM 4 @@ -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) @@ -256,18 +319,64 @@ static inline void hook_unwrap(void *func, void *before, void *after) return hook_unwrap_remove(func, before, after, 1); } -static inline void *hook_chain_origin_func(void *hook_args) +/** + * @param hook_args + */ +static inline void *wrap_get_origin_func(void *hook_args) { hook_fargs0_t *args = (hook_fargs0_t *)hook_args; hook_chain_t *chain = (hook_chain_t *)args->chain; 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 *fp_get_origin_func(void *hook_args) +{ + hook_fargs0_t *args = (hook_fargs0_t *)hook_args; + fp_hook_chain_t *chain = (fp_hook_chain_t *)args->chain; + return (void *)chain->hook.origin_fp; +} + static inline void hook_chain_install(hook_chain_t *chain) { hook_install(&chain->hook); 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/kallsyms.h b/kernel/include/kallsyms.h index 7e75e672..049da1a1 100644 --- a/kernel/include/kallsyms.h +++ b/kernel/include/kallsyms.h @@ -7,7 +7,5 @@ struct module; extern int (*kallsyms_on_each_symbol)(int (*fn)(void *, const char *, struct module *, unsigned long), void *data); extern unsigned long (*kallsyms_lookup_name)(const char *name); -extern int (*lookup_symbol_attrs)(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, - char *name); #endif \ No newline at end of file diff --git a/kernel/include/predata.h b/kernel/include/predata.h index 66e60ec1..15683937 100644 --- a/kernel/include/predata.h +++ b/kernel/include/predata.h @@ -9,14 +9,15 @@ #include #include +extern struct patch_config *patch_config; +extern setup_header_t *setup_header; + 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(bool enable); const char *get_superkey(); - +const char *get_build_time(); uint64_t rand_next(); -uint64_t get_build_config(); -struct patch_symbol *get_preset_patch_sym(); int on_each_extra_item(int (*callback)(const patch_extra_item_t *extra, const char *arg, const void *data, void *udata), void *udata); diff --git a/kernel/include/preset.h b/kernel/include/preset.h index 1970d33e..6f9b601b 100644 --- a/kernel/include/preset.h +++ b/kernel/include/preset.h @@ -20,7 +20,7 @@ #define COMPILE_TIME_LEN 0x18 #define MAP_MAX_SIZE 0xa00 #define HOOK_ALLOC_SIZE (1 << 20) -#define MEMORY_ROX_SIZE (2 << 20) +#define MEMORY_ROX_SIZE (4 << 20) #define MEMORY_RW_SIZE (2 << 20) #define MAP_ALIGN 0x10 @@ -30,7 +30,7 @@ #define MAP_SYMBOL_NUM (5) #define MAP_SYMBOL_SIZE (MAP_SYMBOL_NUM * 8) -#define PATCH_SYMBOL_LEN (512) +#define PATCH_CONFIG_LEN (512) #define ADDITIONAL_LEN (512) @@ -98,7 +98,12 @@ _Static_assert(sizeof(map_symbol_t) == MAP_SYMBOL_SIZE, "sizeof map_symbol_t mis #endif #ifndef __ASSEMBLY__ -struct patch_symbol + +#define PATCH_CONFIG_SU_ENABLE 0x1 +#define PATCH_CONFIG_SU_HOOK_NO_WRAP 0x2 +#define PATCH_CONFIG_SU_ENABLE32 0x2 + +struct patch_config { union { @@ -106,7 +111,6 @@ struct patch_symbol { uint64_t kallsyms_lookup_name; uint64_t printk; - uint64_t vm_area_add_early; uint64_t panic; uint64_t rest_init; @@ -120,12 +124,14 @@ struct patch_symbol uint64_t avc_denied; uint64_t slow_avc_audit; uint64_t input_handle_event; + + uint8_t patch_su_config; }; - char _cap[PATCH_SYMBOL_LEN]; + char _cap[PATCH_CONFIG_LEN]; }; }; -typedef struct patch_symbol patch_symbol_t; -_Static_assert(sizeof(patch_symbol_t) == PATCH_SYMBOL_LEN, "sizeof patch_symbol_t mismatch"); +typedef struct patch_config patch_config_t; +_Static_assert(sizeof(patch_config_t) == PATCH_CONFIG_LEN, "sizeof patch_config_t mismatch"); #endif #ifndef __ASSEMBLY__ @@ -211,7 +217,7 @@ typedef struct map_symbol_t map_symbol; uint8_t header_backup[HDR_BACKUP_SIZE]; uint8_t superkey[SUPER_KEY_LEN]; - patch_symbol_t patch_symbol; + patch_config_t patch_config; char additional[ADDITIONAL_LEN]; } setup_preset_be_000a04_t; @@ -236,7 +242,7 @@ typedef struct _setup_preset_t uint8_t superkey[SUPER_KEY_LEN]; uint8_t root_superkey[ROOT_SUPER_KEY_HASH_LEN]; uint8_t __[SETUP_PRESERVE_LEN]; - patch_symbol_t patch_symbol; + patch_config_t patch_config; char additional[ADDITIONAL_LEN]; } setup_preset_t; #else @@ -257,8 +263,8 @@ typedef struct _setup_preset_t #define setup_header_backup_offset (setup_map_symbol_offset + MAP_SYMBOL_SIZE) #define setup_superkey_offset (setup_header_backup_offset + HDR_BACKUP_SIZE) #define setup_root_superkey_offset (setup_superkey_offset + SUPER_KEY_LEN) -#define setup_patch_symbol_offset (setup_root_superkey_offset + ROOT_SUPER_KEY_HASH_LEN + SETUP_PRESERVE_LEN) -#define setup_end (setup_patch_symbol_offset + PATCH_SYMBOL_LEN) +#define setup_patch_config_offset (setup_root_superkey_offset + ROOT_SUPER_KEY_HASH_LEN + SETUP_PRESERVE_LEN) +#define setup_end (setup_patch_config_offset + PATCH_CONFIG_LEN) #endif #ifndef __ASSEMBLY__ diff --git a/kernel/include/stdbool.h b/kernel/include/stdbool.h index 488efdb1..f66cbbb9 100644 --- a/kernel/include/stdbool.h +++ b/kernel/include/stdbool.h @@ -1,8 +1,12 @@ #ifndef _KP_STDBOOL_H_ #define _KP_STDBOOL_H_ -typedef unsigned char bool; -#define true ((bool)1) -#define false ((bool)0) +#ifndef __bool_true_false_are_defined + +#define bool _Bool +#define true 1 +#define false 0 + +#endif #endif \ No newline at end of file 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/arch/arm64/include/asm/ptrace.h b/kernel/linux/arch/arm64/include/asm/ptrace.h index 63caef6c..fc98797e 100644 --- a/kernel/linux/arch/arm64/include/asm/ptrace.h +++ b/kernel/linux/arch/arm64/include/asm/ptrace.h @@ -276,7 +276,7 @@ static inline void forget_syscall(struct pt_regs *regs) static inline unsigned long user_stack_pointer(struct pt_regs *regs) { - // if (compat_user_mode(regs)) return regs->compat_sp; + if (compat_user_mode(regs)) return regs->compat_sp; return regs->sp; } diff --git a/kernel/linux/include/linux/cred.h b/kernel/linux/include/linux/cred.h index b425a0ee..b36d5f77 100644 --- a/kernel/linux/include/linux/cred.h +++ b/kernel/linux/include/linux/cred.h @@ -97,113 +97,82 @@ extern bool kfunc_def(creds_are_invalid)(const struct cred *cred); static inline void __put_cred(struct cred *cred) { - kfunc_call(__put_cred, cred); - kfunc_not_found(); + kfunc_direct_call(__put_cred, cred); } + static inline void exit_creds(struct task_struct *task) { - kfunc_call(exit_creds, task); - kfunc_not_found(); + kfunc_direct_call_void(exit_creds, task); } + static inline int copy_creds(struct task_struct *p, unsigned long clone_flags) { - kfunc_call(copy_creds, p, clone_flags); - kfunc_not_found(); - return 0; + kfunc_direct_call(copy_creds, p, clone_flags); } + static inline const struct cred *get_task_cred(struct task_struct *task) { - kfunc_call(get_task_cred, task); - kfunc_not_found(); - return 0; + kfunc_direct_call(get_task_cred, task); } + static inline struct cred *cred_alloc_blank(void) { - kfunc_call(cred_alloc_blank); - kfunc_not_found(); - return 0; + kfunc_direct_call(cred_alloc_blank); } + static inline struct cred *prepare_creds(void) { - kfunc_call(prepare_creds); - kfunc_not_found(); - return 0; + kfunc_direct_call(prepare_creds); } + static inline struct cred *prepare_exec_creds(void) { - kfunc_call(prepare_exec_creds); - kfunc_not_found(); - return 0; + kfunc_direct_call(prepare_exec_creds); } + static inline int commit_creds(struct cred *new) { - kfunc_call(commit_creds, new); - kfunc_not_found(); - return 0; + kfunc_direct_call(commit_creds, new); } + static inline void abort_creds(struct cred *new) { - kfunc_call(abort_creds, new); - kfunc_not_found(); + kfunc_direct_call_void(abort_creds, new); } + static inline const struct cred *override_creds(const struct cred *new) { - kfunc_call(override_creds, new); - kfunc_not_found(); - return 0; + kfunc_direct_call(override_creds, new); } + static inline void revert_creds(const struct cred *old) { - kfunc_call(revert_creds, old); - kfunc_not_found(); + kfunc_direct_call(revert_creds, old); } + static inline struct cred *prepare_kernel_cred(struct task_struct *daemon) { - kfunc_call(prepare_kernel_cred, 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; + kfunc_direct_call(prepare_kernel_cred, daemon); } + static inline int set_security_override(struct cred *new, u32 secid) { - kfunc_call(set_security_override, new, secid); - kfunc_not_found(); - return 0; + kfunc_direct_call(set_security_override, new, secid); } + 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; + kfunc_direct_call(set_security_override_from_ctx, new, secctx); } + 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); - kfunc_not_found(); + kfunc_direct_call(cred_fscmp, a, b); } static inline bool creds_are_invalid(const struct cred *cred) { - kfunc_call(creds_are_invalid, cred); - kfunc_not_found(); - return 0; + kfunc_direct_call(creds_are_invalid, cred); } #endif diff --git a/kernel/linux/include/linux/err.h b/kernel/linux/include/linux/err.h index df1ea597..9f50c920 100644 --- a/kernel/linux/include/linux/err.h +++ b/kernel/linux/include/linux/err.h @@ -18,11 +18,16 @@ static inline long __must_check PTR_ERR(__force const void *ptr) return (long)ptr; } -static inline int __must_check IS_ERR(__force const void *ptr) +static inline bool __must_check IS_ERR(__force const void *ptr) { return IS_ERR_VALUE((unsigned long)ptr); } +static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr) +{ + return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr); +} + static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr) { if (IS_ERR(ptr)) 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..1404d35f 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 kfunc_def(kstrtoull)(const char *s, unsigned int base, unsigned long long *res); +extern int 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/gen.sh b/kernel/patch/android/gen.sh new file mode 100755 index 00000000..50ec05f7 --- /dev/null +++ b/kernel/patch/android/gen.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +in_file="user_init.sh" +out_file="gen/user_init.c" + +c_string='static const char user_init[] = "' + +temp_string="" + +while IFS= read -r line || [[ -n "$line" ]]; do + escaped_line=$(echo "$line" | sed 's/\\/\\\\/g; s/"/\\"/g') + temp_string+="$escaped_line\\n" +done <"$in_file" + +c_string+="${temp_string}\";" + +echo "$c_string" >$out_file + +touch userd.c diff --git a/kernel/patch/android/gen/user_init.c b/kernel/patch/android/gen/user_init.c new file mode 100644 index 00000000..4dafabdc --- /dev/null +++ b/kernel/patch/android/gen/user_init.c @@ -0,0 +1 @@ +static const char user_init[] = "#!/bin/sh\n\nKPMS_DIR=\"/data/adb/ap/kpms/\"\nMAGISK_POLICY_PATH=\"/data/adb/ap/bin/magiskpolicy\"\nSUPERCMD=\"truncate\"\nMAGISK_SCTX=\"u:r:magisk:s0\"\nAPD_PATH=\"/data/adb/apd\"\nDEV_LOG_DIR=\"/dev/user_init_log/\"\n\nskey=\"$1\"\nevent=\"$2\"\n\nmkdir -p \"$DEV_LOG_DIR\"\n\nLOG_FILE=\"$DEV_LOG_DIR\"\"$event\"\n\nexec >>$LOG_FILE 2>&1\n\nset -x\n\nload_modules() {\n for dir in \"$KPMS_DIR/*\"; do\n if [ ! -d \"$dir\" ]; then continue; fi\n if [ -e \"$dir/disable\" ]; then continue; fi\n main_sh=\"$dir/main.sh\"\n if [ -e \"$main_sh\" ]; then\n touch \"$dir/disable\"\n echo \"loading $dir/main.sh ...\"\n . \"$main_sh\"\n rm -f \"$dir/disable\"\n else\n echo \"Error: $main_sh not found in $dir\"\n fi\n done\n}\n\nhandle() {\n $SUPERCMD $skey event $event \"before\"\n case \"$event\" in\n \"early-init\" | \"init\" | \"late-init\") ;;\n \"post-fs-data\")\n $MAGISK_POLICY_PATH --magisk --live\n load_modules $skey $event\n $SUPERCMD $skey -Z $MAGISK_SCTX exec $APD_PATH -s $skey $event\n ;;\n \"services\")\n $SUPERCMD $skey -Z $MAGISK_SCTX exec $APD_PATH -s $skey $event\n ;;\n \"boot-completed\")\n $SUPERCMD $skey -Z $MAGISK_SCTX exec $APD_PATH -s $skey $event\n $SUPERCMD su -Z $MAGISK_SCTX exec $APD_PATH uid-listener &\n ;;\n *)\n echo \"unknown user_init event: $event\"\n ;;\n esac\n $SUPERCMD $skey event $event \"after\"\n}\n\nhandle\n"; diff --git a/kernel/patch/android/sepolicy_flags.c b/kernel/patch/android/sepolicy_flags.c new file mode 100644 index 00000000..fa17b08b --- /dev/null +++ b/kernel/patch/android/sepolicy_flags.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 1f2003d5. All Rights Reserved. + * Copyright (C) 2024 sekaiacg. All Rights Reserved. + */ + +#include "sepolicy_flags.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * @see: https://android-review.googlesource.com/c/kernel/common/+/3009995 + */ + +static void before_policydb_write(hook_fargs2_t *args, void *udata) +{ + struct _policy_file *fp = (struct _policy_file *)args->arg1; + args->local.data0 = (uint64_t)fp->data; +} + +static void after_policydb_write(hook_fargs2_t *args, void *udata) +{ + struct _policydb *p = (struct _policydb *)args->arg0; + char *data = (char *)args->local.data0; + + if (!args->ret) { + __le32 *config = (__le32 *)(data + POLICYDB_CONFIG_OFFSET); + __le32 before_config = *config; + bool android_netlink_route_exists = before_config & POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE; + bool android_netlink_getneigh_exists = before_config & POLICYDB_CONFIG_ANDROID_NETLINK_GETNEIGH; + if (p->android_netlink_route == 1 && !android_netlink_route_exists) { + *config |= POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE; + } + if (p->android_netlink_getneigh == 1 && !android_netlink_getneigh_exists) { + *config |= POLICYDB_CONFIG_ANDROID_NETLINK_GETNEIGH; + } + } +} + +int android_sepolicy_flags_fix() +{ + unsigned long policydb_write_addr = kallsyms_lookup_name("policydb_write"); + + if (likely(policydb_write_addr)) { + hook_err_t err = hook_wrap2((void *)policydb_write_addr, before_policydb_write, after_policydb_write, 0); + + if (unlikely(err != HOOK_NO_ERR)) { + log_boot("hook policydb_write_addr: %llx, error: %d\n", policydb_write_addr, err); + return -1; + } + } + + return 0; +} diff --git a/kernel/patch/android/sucompat.c b/kernel/patch/android/sucompat.c deleted file mode 100644 index 36eba046..00000000 --- a/kernel/patch/android/sucompat.c +++ /dev/null @@ -1,524 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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; -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; - -static void allow_reclaim_callback(struct rcu_head *rcu) -{ - struct allow_uid *allow = container_of(rcu, struct allow_uid, rcu); - kvfree(allow); -} - -struct su_profile profile_su_allow_uid(uid_t uid) -{ - rcu_read_lock(); - struct allow_uid *pos; - struct su_profile profile = { 0 }; - list_for_each_entry_rcu(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - memcpy(&profile, &pos->profile, sizeof(struct su_profile)); - rcu_read_unlock(); - return profile; - } - } - rcu_read_unlock(); - return profile; -} -KP_EXPORT_SYMBOL(profile_su_allow_uid); - -int is_su_allow_uid(uid_t uid) -{ - rcu_read_lock(); - struct allow_uid *pos; - list_for_each_entry_rcu(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - rcu_read_unlock(); - return 1; - } - } - rcu_read_unlock(); - return 0; -} -KP_EXPORT_SYMBOL(is_su_allow_uid); - -int su_add_allow_uid(uid_t uid, struct su_profile *profile, int async) -{ - rcu_read_lock(); - struct allow_uid *pos, *old = 0; - list_for_each_entry(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - old = pos; - break; - } - } - 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->profile.scontext[sizeof(new->profile.scontext) - 1] = '\0'; - - spin_lock(&list_lock); - if (old) { // update - list_replace_rcu(&old->list, &new->list); - logkfi("update uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext); - } else { // add new one - list_add_rcu(&new->list, &allow_uid_list); - logkfi("new uid: %d, to_uid: %d, sctx: %s\n", uid, new->profile.to_uid, new->profile.scontext); - } - spin_unlock(&list_lock); - - rcu_read_unlock(); - if (old) { - if (async) { - call_rcu(&old->rcu, allow_reclaim_callback); - } else { - synchronize_rcu(); - kvfree(old); - } - } - return 0; -} - -int su_remove_allow_uid(uid_t uid, int async) -{ - struct allow_uid *pos; - spin_lock(&list_lock); - list_for_each_entry(pos, &allow_uid_list, list) - { - if (pos->uid == uid) { - list_del_rcu(&pos->list); - spin_unlock(&list_lock); - logkfi("uid: %d, to_uid: %d, sctx: %s\n", pos->uid, pos->profile.to_uid, pos->profile.scontext); - if (async) { - call_rcu(&pos->rcu, allow_reclaim_callback); - } else { - synchronize_rcu(); - kvfree(pos); - } - return 0; - } - } - spin_unlock(&list_lock); - return 0; -} - -int su_allow_uid_nums() -{ - int num = 0; - rcu_read_lock(); - struct allow_uid *pos; - list_for_each_entry(pos, &allow_uid_list, list) - { - num++; - } - rcu_read_unlock(); - logkfd("%d\n", num); - return num; -} - -int su_allow_uids(uid_t *__user uuids, int unum) -{ - int rc = 0; - int num = 0; - rcu_read_lock(); - struct allow_uid *pos; - list_for_each_entry(pos, &allow_uid_list, list) - { - if (num >= unum) { - 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; - } - num++; - } - rc = num; -out: - rcu_read_unlock(); - return rc; -} - -int su_allow_uid_profile(uid_t uid, struct su_profile *__user uprofile) -{ - int rc = -ENOENT; - rcu_read_lock(); - struct allow_uid *pos; - 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; - } - rc = 0; - goto out; - } -out: - rcu_read_unlock(); - return rc; -} - -// 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); - return 0; -} - -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 TRY_DIRECT_MODIFY_USER - -static void handle_before_execve(hook_local_t *hook_local, char **__user u_filename_p, char **__user uargv, void *udata) -{ - // copy to user len - hook_local->data0 = 0; - - char __user *ufilename = *u_filename_p; - char filename[SU_PATH_MAX_LEN]; - int flen = compat_strncpy_from_user(filename, ufilename, sizeof(filename)); - if (flen <= 0) return; - - if (!strcmp(current_su_path, filename)) { - 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)) { - int cplen = 0; -#ifdef TRY_DIRECT_MODIFY_USER - cplen = compat_copy_to_user(*u_filename_p, sh_path, sizeof(sh_path)); -#endif - if (cplen > 0) { - hook_local->data0 = cplen; - hook_local->data1 = (uint64_t)u_filename_p; - logkfi("call su uid: %d, to_uid: %d, sctx: %s, cplen: %d\n", uid, to_uid, sctx, cplen); - } else { - void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); - if (uptr && !IS_ERR(uptr)) { - *u_filename_p = (char *__user)uptr; - } - logkfi("call su uid: %d, to_uid: %d, sctx: %s, uptr: %llx\n", uid, to_uid, sctx, uptr); - } - } else { - filp_close(filp, 0); - - // command - int cplen = 0; -#ifdef TRY_DIRECT_MODIFY_USER - cplen = compat_copy_to_user(*u_filename_p, apd_path, sizeof(apd_path)); -#endif - uint64_t sp = 0; - if (cplen > 0) { - hook_local->data0 = cplen; - hook_local->data1 = (uint64_t)u_filename_p; - } else { - sp = current_user_stack_pointer(); - sp -= sizeof(apd_path); - sp &= 0xFFFFFFFFFFFFFFF8; - cplen = compat_copy_to_user((void *)sp, apd_path, sizeof(apd_path)); - if (cplen > 0) { - *u_filename_p = (char *)sp; - } - } - - // argv - int argv_cplen = 0; - if (strcmp(legacy_su_path, filename)) { -#ifdef TRY_DIRECT_MODIFY_USER - 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) { - sp = sp ?: current_user_stack_pointer(); - sp -= sizeof(legacy_su_path); - 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(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); - } - } - } - } - logkfi("call apd uid: %d, to_uid: %d, sctx: %s, cplen: %d, %d\n", uid, to_uid, sctx, cplen, argv_cplen); - } - - } else if (!strcmp(SUPERCMD, filename)) { - // key - const char __user *p1 = get_user_arg_ptr(0, *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(0, *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 * 8; - } -} - -#ifdef TRY_DIRECT_MODIFY_USER -static void handle_after_execve(hook_local_t *hook_local) -{ - int cplen = hook_local->data0; - char **__user u_filename_p = (char **__user)hook_local->data1; - if (cplen > 0) { - compat_copy_to_user((void *)*u_filename_p, current_su_path, cplen); - } -} -#endif - -// 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); - void *arg1p = syscall_argn_p(args, 1); - handle_before_execve(&args->local, (char **)arg0p, (char **)arg1p, udata); -} - -#ifdef TRY_DIRECT_MODIFY_USER -static void after_execve(hook_fargs3_t *args, void *udata) -{ - handle_after_execve(&args->local); -} -#else -#define after_execve 0 -#endif - -// 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) -{ - void *arg1p = syscall_argn_p(args, 1); - void *arg2p = syscall_argn_p(args, 2); - handle_before_execve(&args->local, (char **)arg1p, (char **)arg2p, udata); -} - -#ifdef TRY_DIRECT_MODIFY_USER -static void after_execveat(hook_fargs5_t *args, void *udata) -{ - handle_after_execve(&args->local); -} -#else -#define after_execveat 0 -#endif - -// https://elixir.bootlin.com/linux/v6.1/source/fs/stat.c#L431 -// SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, -// struct stat __user *, statbuf, int, flag) - -// https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L492 -// SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) - -// https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L497 -// SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode, int, flags) - -// https://elixir.bootlin.com/linux/v6.1/source/fs/stat.c#L661 -// SYSCALL_DEFINE5(statx, -// int, dfd, const char __user *, filename, unsigned, flags, -// unsigned int, mask, -// struct statx __user *, buffer) -static void su_handler_arg1_ufilename_before(hook_fargs6_t *args, void *udata) -{ - // copy to user len - args->local.data0 = 0; - - uid_t uid = current_uid(); - if (!is_su_allow_uid(uid)) return; - - char __user *ufilename = (char __user *)syscall_argn(args, 1); - char filename[SU_PATH_MAX_LEN]; - int flen = compat_strncpy_from_user(filename, ufilename, 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)); -#endif - if (cplen > 0) { - args->local.data0 = cplen; - args->local.data1 = (uint64_t)ufilename; - // 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); - } - // logkfi("su uid: %d, cp stack: %llx\n", uid, uptr); - } - } -} - -#ifdef TRY_DIRECT_MODIFY_USER -static void su_handler_arg1_ufilename_after(hook_fargs6_t *args, void *udata) -{ - int cplen = args->local.data0; - if (cplen > 0) { - compat_copy_to_user((void *)args->local.data1, current_su_path, cplen); - } -} -#else -#define su_handler_arg1_ufilename_after 0 -#endif - -int su_compat_init() -{ - current_su_path = default_su_path; - - INIT_LIST_HEAD(&allow_uid_list); - 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); - - hook_err_t rc = HOOK_NO_ERR; - - rc = fp_hook_syscalln(__NR_execve, 3, before_execve, after_execve, (void *)__NR_execve); - log_boot("hook __NR_execve rc: %d\n", rc); - - rc = fp_hook_syscalln(__NR_execveat, 5, before_execveat, after_execveat, (void *)__NR_execveat); - 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 *)__NR3264_fstatat); - log_boot("hook __NR3264_fstatat rc: %d\n", rc); - - rc = fp_hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, su_handler_arg1_ufilename_after, - (void *)__NR_faccessat); - 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 *)__NR_faccessat2); - log_boot("hook __NR_faccessat2 rc: %d\n", rc); - - return rc; -} \ 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/user_init.sh b/kernel/patch/android/user_init.sh new file mode 100644 index 00000000..77fe51a5 --- /dev/null +++ b/kernel/patch/android/user_init.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +KPMS_DIR="/data/adb/ap/kpms/" +MAGISK_POLICY_PATH="/data/adb/ap/bin/magiskpolicy" +SUPERCMD="truncate" +MAGISK_SCTX="u:r:magisk:s0" +APD_PATH="/data/adb/apd" +DEV_LOG_DIR="/dev/user_init_log/" + +skey="$1" +event="$2" + +mkdir -p "$DEV_LOG_DIR" + +LOG_FILE="$DEV_LOG_DIR""$event" + +exec >>$LOG_FILE 2>&1 + +set -x + +load_modules() { + for dir in "$KPMS_DIR/*"; do + if [ ! -d "$dir" ]; then continue; fi + if [ -e "$dir/disable" ]; then continue; fi + main_sh="$dir/main.sh" + if [ -e "$main_sh" ]; then + touch "$dir/disable" + echo "loading $dir/main.sh ..." + . "$main_sh" + rm -f "$dir/disable" + else + echo "Error: $main_sh not found in $dir" + fi + done +} + +handle() { + $SUPERCMD $skey event $event "before" + case "$event" in + "early-init" | "init" | "late-init") ;; + "post-fs-data") + $MAGISK_POLICY_PATH --magisk --live + load_modules $skey $event + $SUPERCMD $skey -Z $MAGISK_SCTX exec $APD_PATH -s $skey $event + ;; + "services") + $SUPERCMD $skey -Z $MAGISK_SCTX exec $APD_PATH -s $skey $event + ;; + "boot-completed") + $SUPERCMD $skey -Z $MAGISK_SCTX exec $APD_PATH -s $skey $event + $SUPERCMD su -Z $MAGISK_SCTX exec $APD_PATH uid-listener & + ;; + *) + echo "unknown user_init event: $event" + ;; + esac + $SUPERCMD $skey event $event "after" +} + +handle diff --git a/kernel/patch/android/userd.c b/kernel/patch/android/userd.c index 38d6e5eb..8e73f0c4 100644 --- a/kernel/patch/android/userd.c +++ b/kernel/patch/android/userd.c @@ -33,9 +33,45 @@ #include #include +#define ORIGIN_RC_FILE "/system/etc/init/atrace.rc" +#define REPLACE_RC_FILE "/dev/user_init.rc" + +#define ADB_FLODER "/data/adb/" +#define AP_DIR "/data/adb/ap/" +#define DEV_LOG_DIR "/dev/user_init_log/" +#define AP_BIN_DIR AP_DIR "bin/" +#define AP_LOG_DIR AP_DIR "log/" +#define AP_MAGISKPOLICY_PATH AP_BIN_DIR "magiskpolicy" +#define MAGISK_SCTX "u:r:magisk:s0" +#define USER_INIT_SH_PATH "/dev/user_init.sh" + +#include "gen/user_init.c" + +static const char user_rc_data[] = { // + "\n" + "on early-init\n" + " exec -- " SUPERCMD " su exec " USER_INIT_SH_PATH " %s early-init\n" + "on init\n" + " exec -- " SUPERCMD " su exec " USER_INIT_SH_PATH " %s init\n" + "on late-init\n" + " exec -- " SUPERCMD " su exec " USER_INIT_SH_PATH " %s late-init\n" + "on post-fs-data\n" + " exec -- " SUPERCMD " su exec " USER_INIT_SH_PATH " %s post-fs-data\n" + "on nonencrypted\n" + " exec -- " SUPERCMD " su exec " USER_INIT_SH_PATH " %s services\n" + "on property:vold.decrypt=trigger_restart_framework\n" + " exec -- " SUPERCMD " su exec " USER_INIT_SH_PATH " %s services\n" + "on property:sys.boot_completed=1\n" + " exec -- " SUPERCMD " su exec " USER_INIT_SH_PATH " %s boot-completed\n" + " rm " REPLACE_RC_FILE "\n" + " rm " USER_INIT_SH_PATH "\n" + " exec -- " SUPERCMD " su -c \"mv -f " DEV_LOG_DIR " " AP_LOG_DIR "\"\n" + "" +}; + 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 +87,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 +111,14 @@ 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); + kernel_write_file(USER_INIT_SH_PATH, user_init, sizeof(user_init), 0700); } static void pre_init_second_stage() @@ -128,8 +130,6 @@ static void on_first_app_process() { } -#define TRY_DIRECT_MODIFY_USER - static void handle_before_execve(hook_local_t *hook_local, char **__user u_filename_p, char **__user uargv, char **__user uenvp, void *udata) { @@ -215,8 +215,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); } } @@ -252,39 +252,6 @@ static void after_execveat(hook_fargs5_t *args, void *udata) handle_after_execve(&args->local); } -#define ORIGIN_RC_FILE "/system/etc/init/atrace.rc" -#define REPLACE_RC_FILE "/dev/anduser.rc" - -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" - - "on nonencrypted\n" - " exec -- " SUPERCMD " %s " KPATCH_DATA_PATH " %s android_user services -k\n" - - "on property:vold.decrypt=trigger_restart_framework\n" - " exec -- " SUPERCMD " %s " KPATCH_DATA_PATH " %s android_user services -k\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" - "" -}; - -// todo: struct file *do_filp_open(int dfd, struct filename *pathname, const struct open_flags *op) -// todo: import rc - // https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L1337 // SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, umode_t, mode) static void before_openat(hook_fargs4_t *args, void *udata) @@ -301,7 +268,8 @@ static void before_openat(hook_fargs4_t *args, void *udata) const char __user *filename = (typeof(filename))syscall_argn(args, 1); char buf[32]; - compat_strncpy_from_user(buf, filename, sizeof(buf)); + long rc = compat_strncpy_from_user(buf, filename, sizeof(buf)); + if (rc <= 0) return; if (strcmp(ORIGIN_RC_FILE, buf)) return; replaced = 1; @@ -322,9 +290,9 @@ static void before_openat(hook_fargs4_t *args, void *udata) goto free; } - char added_rc_data[2048]; + char added_rc_data[4096]; 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, sk); kernel_write(newfp, added_rc_data, strlen(added_rc_data), &off); if (off != strlen(added_rc_data) + ori_len) { @@ -360,7 +328,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); } } @@ -382,35 +350,33 @@ static void before_input_handle_event(hook_fargs4_t *args, void *udata) if (volumedown_pressed_count == 3) { log_boot("entering safemode ..."); android_is_safe_mode = 1; - struct file *filp = filp_open(SAFE_MODE_FLAG_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (filp && !IS_ERR(filp)) filp_close(filp, 0); } } } -int kpuserd_init() +int android_user_init() { hook_err_t ret = 0; hook_err_t rc = HOOK_NO_ERR; - rc = fp_hook_syscalln(__NR_execve, 3, before_execve, after_execve, (void *)__NR_execve); + rc = hook_syscalln(__NR_execve, 3, before_execve, after_execve, (void *)__NR_execve); log_boot("hook __NR_execve rc: %d\n", rc); ret |= rc; - rc = fp_hook_syscalln(__NR_execveat, 5, before_execveat, after_execveat, (void *)__NR_execveat); + rc = hook_syscalln(__NR_execveat, 5, before_execveat, after_execveat, (void *)__NR_execveat); log_boot("hook __NR_execveat rc: %d\n", rc); ret |= rc; - rc = fp_hook_syscalln(__NR_openat, 4, before_openat, after_openat, 0); + rc = hook_syscalln(__NR_openat, 4, before_openat, after_openat, 0); log_boot("hook __NR_openat rc: %d\n", rc); ret |= rc; - unsigned long input_handle_event_addr = get_preset_patch_sym()->input_handle_event; - if (!input_handle_event_addr) { + unsigned long input_handle_event_addr = patch_config->input_handle_event; + if (input_handle_event_addr) { rc = hook_wrap4((void *)input_handle_event_addr, before_input_handle_event, 0, 0); ret |= rc; log_boot("hook input_handle_event rc: %d\n", rc); } return ret; -} \ No newline at end of file +} diff --git a/kernel/patch/common/accctl.c b/kernel/patch/common/accctl.c index e8b345d2..6d09f1bf 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,18 @@ #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' }; +uint32_t all_allow_sid = SECSID_NULL; static void su_cred(struct cred *cred, uid_t uid) { @@ -47,26 +48,34 @@ 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 = SECSID_NULL; + 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 && all_allow_sid != SECSID_NULL) { + strncpy(all_allow_sctx, sctx, sizeof(all_allow_sctx) - 1); + all_allow_sctx[sizeof(all_allow_sctx) - 1] = '\0'; + 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 +97,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 (all_allow_sid != SECSID_NULL && !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 +162,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 (all_allow_sid != SECSID_NULL) { + 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 (all_allow_sid != SECSID_NULL) { + 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 = patch_config->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 = patch_config->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/kstorage.c b/kernel/patch/common/kstorage.c new file mode 100644 index 00000000..18912a49 --- /dev/null +++ b/kernel/patch/common/kstorage.c @@ -0,0 +1,257 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KSTRORAGE_MAX_GROUP_NUM 4 + +// static atomic64_t used_max_group = ATOMIC_INIT(0); +static int used_max_group = -1; +static struct list_head kstorage_groups[KSTRORAGE_MAX_GROUP_NUM]; +static spinlock_t kstorage_glocks[KSTRORAGE_MAX_GROUP_NUM]; +static int group_sizes[KSTRORAGE_MAX_GROUP_NUM] = { 0 }; +static spinlock_t used_max_group_lock; + +static void reclaim_callback(struct rcu_head *rcu) +{ + struct kstorage *ks = container_of(rcu, struct kstorage, rcu); + kvfree(ks); +} + +int try_alloc_kstroage_group() +{ + spin_lock(&used_max_group_lock); + used_max_group++; + if (used_max_group < 0 || used_max_group >= KSTRORAGE_MAX_GROUP_NUM) return -1; + spin_unlock(&used_max_group_lock); + return used_max_group; +} + +int kstorage_group_size(int gid) +{ + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return -ENOENT; + return group_sizes[gid]; +} + +int write_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user) +{ + int rc = -ENOENT; + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return rc; + + struct list_head *head = &kstorage_groups[gid]; + spinlock_t *lock = &kstorage_glocks[gid]; + struct kstorage *pos = 0, *old = 0; + + rcu_read_lock(); + + list_for_each_entry(pos, head, list) + { + if (pos->did == did) { + old = pos; + break; + } + } + + struct kstorage *new = (struct kstorage *)vmalloc(sizeof(struct kstorage) + len); + new->gid = gid; + new->did = did; + new->dlen = 0; + if (data_is_user) { + void *drc = memdup_user(data + offset, len); + if (IS_ERR(drc)) { + rcu_read_unlock(); + return PTR_ERR(drc); + } + memcpy(new->data, drc, len); + kvfree(drc); + } else { + memcpy(new->data, data + offset, len); + } + new->dlen = len; + + spin_lock(lock); + if (old) { // update + list_replace_rcu(&old->list, &new->list); + } else { // add new one + list_add_rcu(&new->list, head); + group_sizes[gid]++; + } + spin_unlock(lock); + + rcu_read_unlock(); + + if (old) { + bool async = true; + if (async) { + call_rcu(&old->rcu, reclaim_callback); + } else { + synchronize_rcu(); + kvfree(old); + } + } + return 0; +} +KP_EXPORT_SYMBOL(write_kstorage); + +const struct kstorage *get_kstorage(int gid, long did) +{ + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return ERR_PTR(-ENOENT); + + struct list_head *head = &kstorage_groups[gid]; + struct kstorage *pos = 0; + + list_for_each_entry(pos, head, list) + { + if (pos->did == did) { + return pos; + } + } + + return ERR_PTR(-ENOENT); +} +KP_EXPORT_SYMBOL(get_kstorage); + +int on_each_kstorage_elem(int gid, on_kstorage_cb cb, void *udata) +{ + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return -ENOENT; + + int rc = 0; + + struct list_head *head = &kstorage_groups[gid]; + struct kstorage *pos = 0; + + rcu_read_lock(); + + list_for_each_entry(pos, head, list) + { + int rc = cb(pos, udata); + if (rc) break; + } + + rcu_read_unlock(); + + return rc; +} +KP_EXPORT_SYMBOL(on_each_kstorage_elem); + +int read_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user) +{ + int rc = 0; + rcu_read_lock(); + + const struct kstorage *pos = get_kstorage(gid, did); + + if (IS_ERR(pos)) { + rcu_read_unlock(); + return PTR_ERR(pos); + } + + int min_len = pos->dlen - offset > len ? len : pos->dlen - offset; + + if (data_is_user) { + int cplen = compat_copy_to_user(data, pos->data + offset, min_len); + if (cplen <= 0) { + logkfe("compat_copy_to_user error: %d", cplen); + rc = cplen; + } + } else { + memcpy(data, pos->data + offset, min_len); + } + + rcu_read_unlock(); + return rc; +} +KP_EXPORT_SYMBOL(read_kstorage); + +int list_kstorage_ids(int gid, long *ids, int idslen, bool data_is_user) +{ + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return -ENOENT; + + int cnt = 0; + + struct list_head *head = &kstorage_groups[gid]; + struct kstorage *pos = 0; + + rcu_read_lock(); + + list_for_each_entry(pos, head, list) + { + if (cnt >= idslen) break; + + if (data_is_user) { + int cplen = compat_copy_to_user(ids + cnt, &pos->did, sizeof(pos->did)); + if (cplen <= 0) { + logkfe("compat_copy_to_user error: %d", cplen); + cnt = cplen; + } + } else { + memcpy(ids + cnt, &pos->did, sizeof(pos->did)); + } + cnt++; + } + + rcu_read_unlock(); + + return cnt; +} +KP_EXPORT_SYMBOL(list_kstorage_ids); + +int remove_kstorage(int gid, long did) +{ + int rc = -ENOENT; + if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return rc; + + struct list_head *head = &kstorage_groups[gid]; + spinlock_t *lock = &kstorage_glocks[gid]; + struct kstorage *pos = 0; + + spin_lock(lock); + + list_for_each_entry(pos, head, list) + { + if (pos->did == did) { + list_del_rcu(&pos->list); + spin_unlock(lock); + + group_sizes[did]--; + + bool async = true; + if (async) { + call_rcu(&pos->rcu, reclaim_callback); + } else { + synchronize_rcu(); + kvfree(pos); + } + return 0; + } + } + + spin_unlock(lock); + + return 0; +} +KP_EXPORT_SYMBOL(remove_kstorage); + +int kstorage_init() +{ + for (int i = 0; i < KSTRORAGE_MAX_GROUP_NUM; i++) { + INIT_LIST_HEAD(&kstorage_groups[i]); + spin_lock_init(&kstorage_glocks[i]); + } + spin_lock_init(&used_max_group_lock); + + return 0; +} \ No newline at end of file diff --git a/kernel/patch/common/pmem.c b/kernel/patch/common/pmem.c index 6b0fe703..7db89512 100644 --- a/kernel/patch/common/pmem.c +++ b/kernel/patch/common/pmem.c @@ -13,90 +13,90 @@ // void __put_task_struct(struct task_struct *tsk) //EXPORT_SYMBOL_GPL(__put_task_struct); -uint64_t *local_pgtable_entry(uint64_t pgd, uint64_t va) -{ - uint64_t pxd_bits = page_shift - 3; - uint64_t pxd_ptrs = 1u << pxd_bits; - uint64_t pxd_va = pgd; - uint64_t pxd_pa = virt_to_phys(pxd_va); - uint64_t pxd_entry_va = 0; - uint64_t block_lv = 0; - - for (int64_t lv = 4 - page_level; lv < 4; lv++) { - uint64_t pxd_shift = (page_shift - 3) * (4 - lv) + 3; - uint64_t pxd_index = (va >> pxd_shift) & (pxd_ptrs - 1); - pxd_entry_va = pxd_va + pxd_index * 8; - if (!pxd_entry_va) return 0; - uint64_t pxd_desc = *((uint64_t *)pxd_entry_va); - if ((pxd_desc & 0b11) == 0b11) { // table - pxd_pa = pxd_desc & (((1ul << (48 - page_shift)) - 1) << page_shift); - } else if ((pxd_desc & 0b11) == 0b01) { // block - // 4k page: lv1, lv2. 16k and 64k page: only lv2. - uint64_t block_bits = (3 - lv) * pxd_bits + page_shift; - pxd_pa = pxd_desc & (((1ul << (48 - block_bits)) - 1) << block_bits); - block_lv = lv; - } else { // invalid - return 0; - } - // - pxd_va = phys_to_virt(pxd_pa); - if (block_lv) { - break; - } - } -#if 1 - uint64_t left_bit = page_shift + (block_lv ? (3 - block_lv) * pxd_bits : 0); - uint64_t tpa = pxd_pa + (va & ((1u << left_bit) - 1)); - uint64_t tlva = phys_to_virt(tpa); - uint64_t tkimg = phys_to_kimg(tpa); - // if (tlva != va && tkimg != va) { - // return 0; - // } - logkd("tpa: %llx, tlva: %llx, tkimg: %llx\n", tpa, tlva, tkimg); -#endif - return (uint64_t *)pxd_entry_va; -} - -phys_addr_t pid_virt_to_phys(pid_t pid, uintptr_t vaddr) -{ - if (mm_struct_offset.pgd_offset < 0) { - return -EFAULT; - } - - int rc = 0; - - logkd("pid: %llx, vaddr: %llx\n", pid, vaddr); - logkd("aaaa %llx\n", kfunc(find_get_task_by_vpid)); - - // struct task_struct *task = find_get_task_by_vpid(pid); - struct task_struct *task = find_task_by_vpid(pid); - if (!task) { - logkfe("no such pid: %d\n", pid); - return -ESRCH; - } - - logkd("task: %llx\n", task); - - struct mm_struct *mm = get_task_mm(task); - if (!mm || IS_ERR(mm)) { - // todo - } - - logkd("mm: %llx\n", mm); - - uintptr_t pgd = *(uintptr_t *)((uintptr_t)mm + mm_struct_offset.pgd_offset); - logkd("pgd: %llx\n", pgd); - - for (uintptr_t i = pgd; i < pgd + 512 * 8; i += 8) { - logkd("pgd i: %llx, val: %llx\n", i, *(uintptr_t *)i); - } - - uintptr_t *entry = local_pgtable_entry(pgd, vaddr); - logkd("entry: %llx\n", entry); - logkd("entry value: %llx\n", *(uintptr_t *)entry); - - // remap_pfn_range or direct modify pgtable - - mmput(mm); - return rc; -} \ No newline at end of file +// uint64_t *local_pgtable_entry(uint64_t pgd, uint64_t va) +// { +// uint64_t pxd_bits = page_shift - 3; +// uint64_t pxd_ptrs = 1u << pxd_bits; +// uint64_t pxd_va = pgd; +// uint64_t pxd_pa = virt_to_phys(pxd_va); +// uint64_t pxd_entry_va = 0; +// uint64_t block_lv = 0; + +// for (int64_t lv = 4 - page_level; lv < 4; lv++) { +// uint64_t pxd_shift = (page_shift - 3) * (4 - lv) + 3; +// uint64_t pxd_index = (va >> pxd_shift) & (pxd_ptrs - 1); +// pxd_entry_va = pxd_va + pxd_index * 8; +// if (!pxd_entry_va) return 0; +// uint64_t pxd_desc = *((uint64_t *)pxd_entry_va); +// if ((pxd_desc & 0b11) == 0b11) { // table +// pxd_pa = pxd_desc & (((1ul << (48 - page_shift)) - 1) << page_shift); +// } else if ((pxd_desc & 0b11) == 0b01) { // block +// // 4k page: lv1, lv2. 16k and 64k page: only lv2. +// uint64_t block_bits = (3 - lv) * pxd_bits + page_shift; +// pxd_pa = pxd_desc & (((1ul << (48 - block_bits)) - 1) << block_bits); +// block_lv = lv; +// } else { // invalid +// return 0; +// } +// // +// pxd_va = phys_to_virt(pxd_pa); +// if (block_lv) { +// break; +// } +// } +// #if 1 +// uint64_t left_bit = page_shift + (block_lv ? (3 - block_lv) * pxd_bits : 0); +// uint64_t tpa = pxd_pa + (va & ((1u << left_bit) - 1)); +// uint64_t tlva = phys_to_virt(tpa); +// uint64_t tkimg = phys_to_kimg(tpa); +// // if (tlva != va && tkimg != va) { +// // return 0; +// // } +// logkd("tpa: %llx, tlva: %llx, tkimg: %llx\n", tpa, tlva, tkimg); +// #endif +// return (uint64_t *)pxd_entry_va; +// } + +// phys_addr_t pid_virt_to_phys(pid_t pid, uintptr_t vaddr) +// { +// if (mm_struct_offset.pgd_offset < 0) { +// return -EFAULT; +// } + +// int rc = 0; + +// logkd("pid: %llx, vaddr: %llx\n", pid, vaddr); +// logkd("aaaa %llx\n", kfunc(find_get_task_by_vpid)); + +// // struct task_struct *task = find_get_task_by_vpid(pid); +// struct task_struct *task = find_task_by_vpid(pid); +// if (!task) { +// logkfe("no such pid: %d\n", pid); +// return -ESRCH; +// } + +// logkd("task: %llx\n", task); + +// struct mm_struct *mm = get_task_mm(task); +// if (!mm || IS_ERR(mm)) { +// // todo +// } + +// logkd("mm: %llx\n", mm); + +// uintptr_t pgd = *(uintptr_t *)((uintptr_t)mm + mm_struct_offset.pgd_offset); +// logkd("pgd: %llx\n", pgd); + +// for (uintptr_t i = pgd; i < pgd + 512 * 8; i += 8) { +// logkd("pgd i: %llx, val: %llx\n", i, *(uintptr_t *)i); +// } + +// uintptr_t *entry = local_pgtable_entry(pgd, vaddr); +// logkd("entry: %llx\n", entry); +// logkd("entry value: %llx\n", *(uintptr_t *)entry); + +// // remap_pfn_range or direct modify pgtable + +// mmput(mm); +// return rc; +// } \ No newline at end of file diff --git a/kernel/patch/common/secpass.c b/kernel/patch/common/secpass.c index d1d4a394..2b6bce90 100644 --- a/kernel/patch/common/secpass.c +++ b/kernel/patch/common/secpass.c @@ -52,7 +52,7 @@ int bypass_kcfi() // 6.1.0 // todo: Is there more elegant way? - unsigned long report_cfi_failure_addr = get_preset_patch_sym()->report_cfi_failure; + unsigned long report_cfi_failure_addr = patch_config->report_cfi_failure; if (report_cfi_failure_addr) { hook_err_t err = hook((void *)report_cfi_failure_addr, (void *)replace_report_cfi_failure, (void **)&backup_report_cfi_failure); @@ -64,9 +64,9 @@ int bypass_kcfi() } // todo: direct modify cfi_shadow, __cfi_check? - unsigned long __cfi_slowpath_addr = get_preset_patch_sym()->__cfi_slowpath_diag; + unsigned long __cfi_slowpath_addr = patch_config->__cfi_slowpath_diag; if (!__cfi_slowpath_addr) { - __cfi_slowpath_addr = get_preset_patch_sym()->__cfi_slowpath; + __cfi_slowpath_addr = patch_config->__cfi_slowpath; } if (__cfi_slowpath_addr) { hook_err_t err = diff --git a/kernel/patch/common/selinuxhook.c b/kernel/patch/common/selinuxhook.c deleted file mode 100644 index 2a0ca50e..00000000 --- a/kernel/patch/common/selinuxhook.c +++ /dev/null @@ -1,336 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2023 bmax121. All Rights Reserved. - */ - -#include "accctl.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SHOW_AVC_PASS_LOG - -#if 0 -static void _selinux_debug(u32 ssid, u32 tsid, u16 tclass, u32 requested) -{ - logkfd("ssid: %x, tsid: %x, tclass: %x, requested: %x\n", ssid, tsid, tclass, requested); - char *scontext = 0; - u32 sctx_len = 0; - char *tcontext = 0; - u32 tctx_len = 0; - security_sid_to_context(ssid, &scontext, &sctx_len); - security_sid_to_context(tsid, &tcontext, &tctx_len); - const char *stclass = kvar_val(secclass_map)[tclass - 1].name; - const char *const *perms = kvar_val(secclass_map)[tclass - 1].perms; - char buf[128] = { '\0' }; - for (int i = 0; i < (sizeof(u32) * 8); i++) { - if ((1 << i) & requested) { - int len = min_strlen(buf); - min_snprintf(buf + len, 128 - len, "%s ", perms[i]); - } - } - logkfd("context: %s, tcontext: %s, tclass: %s, perms: %s\n", scontext, tcontext, stclass, buf); -} -#endif - -#define hook_backup(func) (*backup_##func) -#define hook_replace(func) replace_##func -#define hook_call_backup(func, ...) backup_##func(__VA_ARGS__) - -#define hook_kfunc_with(func, replace, backup) \ - if (kfunc(func)) { \ - hook_err_t err_##func = hook(kfunc(func), replace, (void **)&backup); \ - if (err_##func != HOOK_NO_ERR) log_boot("hook %s, %llx, error: %d\n", #func, kfunc(func), err_##func); \ - } else { \ - log_boot("no symbol: %s\n", #func); \ - } - -#define hook_kfunc(func) hook_kfunc_with(func, replace_##func, backup_##func) - -#define find_and_hook_func_with(func, replace, backup) \ - unsigned long addr = kallsyms_lookup_name(#func); \ - if (addr) { \ - hook_err_t err_##func = hook(addr, replace, (void **)&backup); \ - if (err_##func != HOOK_NO_ERR) log_boot("hook %s, %llx, error: %d\n", #func, kfunc(func), err_##func); \ - } else { \ - 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; \ - } - -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) -{ - struct task_ext *ext = get_current_task_ext(); - if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_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; - } - int rc = avc_denied_backup(_state, _ssid, _tsid, _tclass, _requested, _driver, _xperm, _flags, _avd); - return rc; -} - -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) -{ - struct task_ext *ext = get_current_task_ext(); - if (unlikely(task_ext_valid(ext) && (ext->selinux_allow || ext->priv_selinux_allow))) { - return 0; - } - int rc = slow_avc_audit_backup(_state, _ssid, _tsid, _tclass, _requested, _audited, _denied, _result, _a); - return rc; -} - -// static inline void *min_memset(void *dst, int c, size_t n) -// { -// char *q = dst; -// while (n--) { -// *q++ = c; -// } -// return dst; -// } - -// static int hook_backup(avc_has_perm_noaudit)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, -// void *requested, void *flags, struct av_decision *avd) = 0; -// static int hook_replace(avc_has_perm_noaudit)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, -// void *requested, void *flags, struct av_decision *avd) -// { -// // 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))) { -// struct av_decision *avd = (struct av_decision *)avd; -// if (((uint64_t)state & 0xF000000000000000) != 0xF000000000000000) { -// avd = (struct av_decision *)flags; -// } -// if (((uint64_t)avd & 0xF000000000000000) == 0xF000000000000000) { -// avd->allowed = 0xffffffff; -// avd->auditallow = 0; -// avd->auditdeny = 0; -// } -// return 0; -// } - -// int rc = hook_call_backup(avc_has_perm_noaudit, state, ssid, tsid, tclass, requested, flags, avd); - -// return rc; -// } - -// static int hook_backup(avc_has_perm)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, void *requested, -// struct common_audit_data *auditdata) = 0; -// static int hook_replace(avc_has_perm)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, -// void *requested, struct common_audit_data *auditdata) -// { -// HOOK_AVC_RET_ZERO_BEFORE(); -// int rc = hook_call_backup(avc_has_perm, state, ssid, tsid, tclass, requested, auditdata); -// return rc; -// } - -// static int hook_backup(avc_has_perm_flags)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, -// void *requested, struct common_audit_data *auditdata, void *flags) = 0; -// static int hook_replace(avc_has_perm_flags)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, -// void *requested, struct common_audit_data *auditdata, void *flags) -// { -// HOOK_AVC_RET_ZERO_BEFORE(); -// int rc = hook_call_backup(avc_has_perm_flags, state, ssid, tsid, tclass, requested, auditdata, flags); -// return rc; -// } - -// // int avc_has_extended_perms((struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 xperm, struct common_audit_data *ad) -// static int hook_backup(avc_has_extended_perms)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, -// void *requested, void *driver, void *perm, struct common_audit_data *ad); -// static int hook_replace(avc_has_extended_perms)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, -// void *requested, void *driver, void *perm, struct common_audit_data *ad) -// { -// HOOK_AVC_RET_ZERO_BEFORE(); -// int rc = hook_call_backup(avc_has_extended_perms, state, ssid, tsid, tclass, requested, driver, perm, ad); -// return rc; -// } - -// static void make_avc_node_all_perm(struct avc_node *node) -// { -// struct avc_entry *ae = &node->ae; -// struct av_decision *avd = &ae->avd; -// avd->allowed = 0xffffffff; -// avd->auditallow = 0; -// avd->auditdeny = 0; -// if (likely(kfunc(avc_has_extended_perms))) { -// struct avc_xperms_node *xp_node = ae->xp_node; -// if (xp_node) { -// struct extended_perms *xp = &xp_node->xp; -// min_memset(xp->drivers.p, 0xff, sizeof(xp->drivers.p)); -// } -// } -// } - -// struct avc_node *hook_backup(avc_lookup)(void *_state, void *_ssid, void *_tsid, void *_tclass) = 0; - -// // struct selinux_avc *avc, u32 ssid, u32 tsid, u16 tclass -// struct avc_node *hook_replace(avc_lookup)(void *_state, void *_ssid, void *_tsid, void *_tclass) -// { -// struct avc_node *node = hook_call_backup(avc_lookup, _state, _ssid, _tsid, _tclass); -// 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))) { -// make_avc_node_all_perm(node); -// } -// return node; -// } - -// struct avc_node *hook_backup(avc_compute_av)(void *_state, void *_ssid, void *_tsid, void *_tclass, void *_avd, -// void *_xp_node); - -// // struct selinux_state *state,u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct avc_xperms_node *xp_node -// struct avc_node *hook_replace(avc_compute_av)(void *_state, void *_ssid, void *_tsid, void *_tclass, void *_avd, -// void *_xp_node) -// { -// 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))) { -// 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) { -// avd = (struct av_decision *)_tclass; -// xp_node = (struct avc_xperms_node *)_avd; -// } -// avd->allowed = 0xffffffff; -// avd->auditallow = 0; -// avd->auditdeny = 0; -// if (xp_node) { -// struct extended_perms *xp = &xp_node->xp; -// min_memset(xp->drivers.p, 0xff, sizeof(xp->drivers.p)); -// } -// make_avc_node_all_perm(node); -// } -// return node; -// } - -// static void hook_backup(security_compute_av)(void *_state, void *_ssid, void *_tsid, void *_orig_tclass, void *_avd, -// void *_xperms) = 0; - -// // struct selinux_state *state, u32 ssid, u32 tsid, u16 orig_tclass, struct av_decision *avd, struct extended_perms *xperms -// static void hook_replace(security_compute_av)(void *_state, void *_ssid, void *_tsid, void *_orig_tclass, void *_avd, -// void *_xperms) -// { -// 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))) { -// struct av_decision *avd = (struct av_decision *)_avd; -// struct extended_perms *xperms = (struct extended_perms *)_xperms; -// if ((uint64_t)_state <= 0xffffffffL) { -// avd = (struct av_decision *)_orig_tclass; -// xperms = (struct extended_perms *)_avd; -// } -// avd->allowed = 0xffffffff; -// avd->auditallow = 0; -// avd->auditdeny = 0; -// if (xperms) { -// min_memset(xperms->drivers.p, 0xff, sizeof(xperms->drivers.p)); -// } -// } -// } - -// static void hook_backup(security_compute_xperms_decision)(void *_state, void *_ssid, void *_tsid, void *_orig_tclass, -// void *_driver, void *_xpermd) = 0; - -// //struct selinux_state *state, u32 ssid, u32 tsid, u16 orig_tclass, u8 driver, struct extended_perms_decision *xpermd -// static void hook_replace(security_compute_xperms_decision)(void *_state, void *_ssid, void *_tsid, void *_orig_tclass, -// void *_driver, void *_xpermd) -// { -// 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))) { -// struct extended_perms_decision *xpermd = (struct extended_perms_decision *)_xpermd; -// if ((uint64_t)_state <= 0xffffffffL) { -// xpermd = (struct extended_perms_decision *)_driver; -// } -// min_memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); -// min_memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); -// min_memset(xpermd->dontaudit->p, 0xff, sizeof(xpermd->dontaudit->p)); -// } -// } - -// static void hook_backup(security_compute_av_user)(void *_state, void *_ssid, void *_tsid, void *_tclass, -// void *_avd) = 0; - -// // struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd -// static void hook_replace(security_compute_av_user)(void *_state, void *_ssid, void *_tsid, void *_tclass, void *_avd) -// { -// 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))) { -// struct av_decision *avd = (struct av_decision *)_avd; -// if ((uint64_t)_state <= 0xffffffffL) { -// avd = (struct av_decision *)_tclass; -// } -// avd->allowed = 0xffffffff; -// avd->auditallow = 0; -// avd->auditdeny = 0; -// } -// } - -int selinux_hook_install() -{ - 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); - } - } - - // hook_kfunc(avc_denied); - // hook_kfunc(slow_avc_audit); - - // hook_kfunc(avc_has_perm_noaudit); - // hook_kfunc(avc_has_perm); - // hook_kfunc(avc_has_perm_flags); - // hook_kfunc(avc_has_extended_perms); - - // we can't hook avc_compute_av and ..., it will 'avc_update_node' with diffused permission allowed - // hook_kfunc(avc_lookup); - // hook_kfunc(avc_compute_av); - - // hook_kfunc(security_compute_av); - // hook_kfunc(security_compute_xperms_decision); - // hook_kfunc(security_compute_av_user); - - return 0; -} \ No newline at end of file diff --git a/kernel/patch/common/sucompat.c b/kernel/patch/common/sucompat.c new file mode 100644 index 00000000..97c484f0 --- /dev/null +++ b/kernel/patch/common/sucompat.c @@ -0,0 +1,408 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 int su_kstorage_gid = -1; +static int exclude_kstorage_gid = -1; + +int is_su_allow_uid(uid_t uid) +{ + int rc = 0; + rcu_read_lock(); + const struct kstorage *ks = get_kstorage(su_kstorage_gid, uid); + if (IS_ERR_OR_NULL(ks) || ks->dlen <= 0) goto out; + + struct su_profile *profile = (struct su_profile *)ks->data; + rc = profile->uid == uid; + +out: + rcu_read_unlock(); + return rc; +} +KP_EXPORT_SYMBOL(is_su_allow_uid); + +int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext) +{ + if (!scontext) scontext = ""; + struct su_profile profile = { + uid, + to_uid, + }; + memcpy(profile.scontext, scontext, SUPERCALL_SCONTEXT_LEN); + int rc = write_kstorage(su_kstorage_gid, uid, &profile, 0, sizeof(struct su_profile), false); + logkfd("uid: %d, to_uid: %d, sctx: %s, rc: %d\n", uid, to_uid, scontext, rc); + return rc; +} +KP_EXPORT_SYMBOL(su_add_allow_uid); + +int su_remove_allow_uid(uid_t uid) +{ + return remove_kstorage(su_kstorage_gid, uid); +} +KP_EXPORT_SYMBOL(su_remove_allow_uid); + +int su_allow_uid_nums() +{ + return kstorage_group_size(su_kstorage_gid); +} +KP_EXPORT_SYMBOL(su_allow_uid_nums); + +static int allow_uids_cb(struct kstorage *kstorage, void *udata) +{ + struct + { + int is_user; + uid_t *out_uids; + int idx; + int out_num; + } *up = (typeof(up))udata; + + if (up->idx >= up->out_num) { + return -ENOBUFS; + } + + struct su_profile *profile = (struct su_profile *)kstorage->data; + + if (up->is_user) { + int cprc = compat_copy_to_user(up->out_uids + up->idx, &profile->uid, sizeof(uid_t)); + if (cprc <= 0) { + logkfd("compat_copy_to_user error: %d", cprc); + return cprc; + } + } else { + up->out_uids[up->idx] = profile->uid; + } + + up->idx++; + + return 0; +} + +int su_allow_uids(int is_user, uid_t *out_uids, int out_num) +{ + struct + { + int iu; + uid_t *up; + int idx; + int out_num; + } udata = { is_user, out_uids, 0, out_num }; + + on_each_kstorage_elem(su_kstorage_gid, allow_uids_cb, &udata); + + return udata.idx; +} +KP_EXPORT_SYMBOL(su_allow_uids); + +int su_allow_uid_profile(int is_user, uid_t uid, struct su_profile *out_profile) +{ + int rc = 0; + + rcu_read_lock(); + const struct kstorage *ks = get_kstorage(su_kstorage_gid, uid); + if (IS_ERR(ks)) { + rc = -ENOENT; + goto out; + } + struct su_profile *profile = (struct su_profile *)ks->data; + + if (is_user) { + rc = compat_copy_to_user(out_profile, profile, sizeof(struct su_profile)); + if (rc <= 0) { + logkfd("compat_copy_to_user error: %d", rc); + goto out; + } + } else { + memcpy(out_profile, profile, sizeof(struct su_profile)); + } + +out: + 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; + 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); + +const char *su_get_path() +{ + if (!current_su_path) current_su_path = default_su_path; + return current_su_path; +} +KP_EXPORT_SYMBOL(su_get_path); + +static void handle_before_execve(char **__user u_filename_p, char **__user uargv, void *udata) +{ + char __user *ufilename = *u_filename_p; + char filename[SU_PATH_MAX_LEN]; + int flen = compat_strncpy_from_user(filename, ufilename, sizeof(filename)); + if (flen <= 0) return; + + if (!strcmp(current_su_path, filename)) { + uid_t uid = current_uid(); + struct su_profile profile; + if (su_allow_uid_profile(0, uid, &profile)) return; + + uid_t to_uid = profile.to_uid; + 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 + void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); + if (uptr && !IS_ERR(uptr)) { + *u_filename_p = (char *__user)uptr; + } + 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); + + // command + uint64_t sp = 0; + sp = current_user_stack_pointer(); + sp -= sizeof(apd_path); + sp &= 0xFFFFFFFFFFFFFFF8; + int cplen = compat_copy_to_user((void *)sp, apd_path, sizeof(apd_path)); + if (cplen > 0) { + *u_filename_p = (char *)sp; + } + + // argv + int argv_cplen = 0; + if (strcmp(legacy_su_path, filename)) { + if (argv_cplen <= 0) { + sp = sp ?: current_user_stack_pointer(); + sp -= sizeof(legacy_su_path); + 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(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); + } + } + } + } + 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)) { + void handle_supercmd(char **__user u_filename_p, char **__user uargv); + handle_supercmd(u_filename_p, uargv); + return; + } +} + +// https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2107 +// COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, +// const compat_uptr_t __user *, argv, +// const compat_uptr_t __user *, envp) + +// 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); + void *arg1p = syscall_argn_p(args, 1); + handle_before_execve((char **)arg0p, (char **)arg1p, udata); +} + +// https://elixir.bootlin.com/linux/v6.1/source/fs/exec.c#L2114 +// COMPAT_SYSCALL_DEFINE5(execveat, int, fd, +// const char __user *, filename, +// const compat_uptr_t __user *, argv, +// const compat_uptr_t __user *, envp, +// int, flags) + +// 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) +__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); + handle_before_execve((char **)arg1p, (char **)arg2p, udata); +} + +// https://elixir.bootlin.com/linux/v6.1/source/fs/stat.c#L431 +// SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, +// struct stat __user *, statbuf, int, flag) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L492 +// SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/open.c#L497 +// SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode, int, flags) + +// https://elixir.bootlin.com/linux/v6.1/source/fs/stat.c#L661 +// SYSCALL_DEFINE5(statx, +// int, dfd, const char __user *, filename, unsigned, flags, +// unsigned int, mask, +// struct statx __user *, buffer) +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 **u_filename_p = (char __user **)syscall_argn_p(args, 1); + + char filename[SU_PATH_MAX_LEN]; + int flen = compat_strncpy_from_user(filename, *u_filename_p, sizeof(filename)); + if (flen <= 0) return; + + if (!strcmp(current_su_path, filename)) { + void *uptr = copy_to_user_stack(sh_path, sizeof(sh_path)); + if (uptr && !IS_ERR(uptr)) { + *u_filename_p = uptr; + } else { + logkfi("su uid: %d, cp stack error: %d\n", uid, uptr); + } + } +} + +int set_ap_mod_exclude(uid_t uid, int exclude) +{ + int rc = 0; + if (exclude) { + rc = write_kstorage(exclude_kstorage_gid, uid, &exclude, 0, sizeof(exclude), false); + } else { + rc = remove_kstorage(exclude_kstorage_gid, uid); + } + return rc; +} +KP_EXPORT_SYMBOL(set_ap_mod_exclude); + +int get_ap_mod_exclude(uid_t uid) +{ + int exclude = 0; + int rc = read_kstorage(exclude_kstorage_gid, uid, &exclude, 0, sizeof(exclude), false); + if (rc < 0) return 0; + return exclude; +} +KP_EXPORT_SYMBOL(get_ap_mod_exclude); + +int list_ap_mod_exclude(uid_t *uids, int len) +{ + long ids[len]; + int cnt = list_kstorage_ids(exclude_kstorage_gid, ids, len, false); + for (int i = 0; i < len; i++) { + uids[i] = (uid_t)ids[i]; + } + return cnt; +} +KP_EXPORT_SYMBOL(list_ap_mod_exclude); + +int su_compat_init() +{ + current_su_path = default_su_path; + + su_kstorage_gid = try_alloc_kstroage_group(); + if (su_kstorage_gid != KSTORAGE_SU_LIST_GROUP) return -ENOMEM; + + exclude_kstorage_gid = try_alloc_kstroage_group(); + if (exclude_kstorage_gid != KSTORAGE_EXCLUDE_LIST_GROUP) return -ENOMEM; + +#ifdef ANDROID + // default shell + if (!all_allow_sctx[0]) { + strcpy(all_allow_sctx, ALL_ALLOW_SCONTEXT_MAGISK); + } + su_add_allow_uid(2000, 0, all_allow_sctx); + su_add_allow_uid(0, 0, all_allow_sctx); +#endif + + hook_err_t rc = HOOK_NO_ERR; + + uint8_t su_config = patch_config->patch_su_config; + bool enable = !!(su_config & PATCH_CONFIG_SU_ENABLE); + bool wrap = !!(su_config & PATCH_CONFIG_SU_HOOK_NO_WRAP); + log_boot("su config: %x, enable: %d, wrap: %d\n", su_config, enable, wrap); + + // if (!enable) return; + + rc = hook_syscalln(__NR_execve, 3, before_execve, 0, (void *)0); + log_boot("hook __NR_execve rc: %d\n", rc); + + rc = hook_syscalln(__NR3264_fstatat, 4, su_handler_arg1_ufilename_before, 0, (void *)0); + log_boot("hook __NR3264_fstatat rc: %d\n", rc); + + rc = hook_syscalln(__NR_faccessat, 3, su_handler_arg1_ufilename_before, 0, (void *)0); + log_boot("hook __NR_faccessat rc: %d\n", rc); + + // __NR_execve 11 + rc = hook_compat_syscalln(11, 3, before_execve, 0, (void *)1); + log_boot("hook 32 __NR_execve rc: %d\n", rc); + + // __NR_fstatat64 327 + rc = hook_compat_syscalln(327, 4, su_handler_arg1_ufilename_before, 0, (void *)0); + log_boot("hook 32 __NR_fstatat64 rc: %d\n", rc); + + // __NR_faccessat 334 + rc = hook_compat_syscalln(334, 3, su_handler_arg1_ufilename_before, 0, (void *)0); + log_boot("hook 32 __NR_faccessat rc: %d\n", 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..0ac5f37a 100644 --- a/kernel/patch/common/supercall.c +++ b/kernel/patch/common/supercall.c @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #define MAX_KEY_LEN 128 @@ -36,19 +39,6 @@ static long call_test(long arg1, long arg2, long arg3) { - // char *cmd = "/system/bin/touch"; - // // const char *superkey = get_superkey(); - // char *argv[] = { - // cmd, - // "/data/local/tmp/test.txt", - // NULL, - // }; - // char *envp[] = { - // "PATH=/system/bin:/data/adb", - // NULL, - // }; - // int rc = call_usermodehelper(cmd, argv, envp, UMH_WAIT_PROC); - // log_boot("user_init: %d\n", rc); return 0; } @@ -74,6 +64,15 @@ static long call_klog(const char __user *arg1) return 0; } +static long call_buildtime(char __user *out_buildtime, int u_len) +{ + const char *buildtime = get_build_time(); + int len = strlen(buildtime); + if (len >= u_len) return -ENOMEM; + int rc = compat_copy_to_user(out_buildtime, buildtime, len + 1); + return rc; +} + static long call_kpm_load(const char __user *arg1, const char *__user arg2, void *__user reserved) { char path[1024], args[KPM_ARGS_LEN]; @@ -154,7 +153,7 @@ static long call_skey_get(char *__user out_key, int out_len) const char *key = get_superkey(); int klen = strlen(key); if (klen >= out_len) return -ENOMEM; - int rc = compat_copy_to_user(out_key, get_superkey(), klen + 1); + int rc = compat_copy_to_user(out_key, key, klen + 1); return rc; } @@ -173,12 +172,95 @@ static long call_skey_root_enable(int enable) return 0; } -static unsigned long call_pid_virt_to_phys(pid_t pid, uintptr_t vaddr) +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); + kvfree(profile); + return rc; +} + +static long call_revoke_uid(uid_t uid) +{ + return su_remove_allow_uid(uid); +} + +static long call_su_allow_uid_nums() +{ + return su_allow_uid_nums(); +} + +#ifdef ANDROID +extern int android_is_safe_mode; +static long call_su_get_safemode() +{ + int result = android_is_safe_mode; + logkfd("[call_su_get_safemode] %d\n", result); + return result; +} +#endif + +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) { - return pid_virt_to_phys(pid, vaddr); + int len = strlen(all_allow_sctx); + if (ulen <= len) return -ENOBUFS; + return compat_copy_to_user(usctx, all_allow_sctx, len + 1); } -static long supercall(long cmd, long arg1, long arg2, long arg3, long arg4) +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 call_kstorage_read(int gid, long did, void *out_data, int offset, int dlen) +{ + return read_kstorage(gid, did, out_data, offset, dlen, true); +} + +static long call_kstorage_write(int gid, long did, void *data, int offset, int dlen) +{ + return write_kstorage(gid, did, data, offset, dlen, true); +} + +static long call_list_kstorage_ids(int gid, long *ids, int ids_len) +{ + return list_kstorage_ids(gid, ids, ids_len, false); +} + +static long call_kstorage_remove(int gid, long did) +{ + return remove_kstorage(gid, did); +} + +static long supercall(int is_key_auth, long cmd, long arg1, long arg2, long arg3, long arg4) { switch (cmd) { case SUPERCALL_HELLO: @@ -190,8 +272,66 @@ static long supercall(long cmd, long arg1, long arg2, long arg3, long arg4) return kpver; case SUPERCALL_KERNEL_VER: return kver; + case SUPERCALL_BUILD_TIME: + return call_buildtime((char *__user)arg1, (int)arg2); } + 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); + + case SUPERCALL_KSTORAGE_READ: + return call_kstorage_read((int)arg1, (long)arg2, (void *)arg3, (int)((long)arg4 >> 32), (long)arg4 << 32 >> 32); + case SUPERCALL_KSTORAGE_WRITE: + return call_kstorage_write((int)arg1, (long)arg2, (void *)arg3, (int)((long)arg4 >> 32), + (long)arg4 << 32 >> 32); + case SUPERCALL_KSTORAGE_LIST_IDS: + return call_list_kstorage_ids((int)arg1, (long *)arg2, (int)arg3); + case SUPERCALL_KSTORAGE_REMOVE: + return call_kstorage_remove((int)arg1, (long)arg2); + +#ifdef ANDROID + case SUPERCALL_SU_GET_SAFEMODE: + return call_su_get_safemode(); +#endif + 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 +343,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 +355,14 @@ 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); - 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); + switch (cmd) { + 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 +380,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 +398,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..059503bc --- /dev/null +++ b/kernel/patch/common/supercmd.c @@ -0,0 +1,488 @@ +#include +#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.\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" + " buildtime: Print KernelPatch build time.\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" +#ifdef ANDROID + " exclude_list List all exclude UIDs.\n" + " exclude [1|0] Get or Reset exclude policy for UID.\n" +#endif + " event Report EVENT.\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 : Whether to use hash to verify the root superkey.\n" + ""; + +struct cmd_res +{ + const char *msg; + const char *err_msg; + int rc; +}; + +static void handle_cmd_sumgr(char **__user u_filename_p, const char **carr, char *buffer, int buflen, + struct cmd_res *cmd_res) +{ + 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)) { + sprintf(buffer, "illegal uid: %s", carr[2]); + cmd_res->err_msg = buffer; + return; + } + if (carr[3]) kstrtoull(carr[3], 10, &to_uid); + if (carr[4]) scontext = carr[4]; + su_add_allow_uid(uid, to_uid, scontext); + sprintf(buffer, "grant %d, %d, %s", uid, to_uid, scontext); + cmd_res->msg = buffer; + } else if (!strcmp(sub_cmd, "revoke")) { + const char *suid = carr[2]; + unsigned long long uid; + if (!suid || kstrtoull(suid, 10, &uid)) { + sprintf(buffer, "illegal uid: %s\n", suid); + cmd_res->err_msg = buffer; + return; + } + su_remove_allow_uid(uid); + cmd_res->msg = suid; + } else if (!strcmp(sub_cmd, "num")) { + int num = su_allow_uid_nums(); + sprintf(buffer, "%d", num); + cmd_res->msg = buffer; + } else if (!strcmp(sub_cmd, "list")) { + uid_t uids[128]; // default max size 128 + int offset = 0; + buffer[0] = '\0'; + int num = su_allow_uids(0, uids, sizeof(uids) / sizeof(uids[0])); + for (int i = 0; i < num; i++) { + offset += sprintf(buffer + offset, "%d\n", uids[i]); + }; + if (offset > 0) buffer[offset - 1] = '\0'; + cmd_res->msg = buffer; + + } else if (!strcmp(sub_cmd, "profile")) { + unsigned long long uid; + if (!carr[2] || kstrtoull(carr[2], 10, &uid)) { + cmd_res->err_msg = "invalid uid"; + return; + } + struct su_profile profile; + cmd_res->rc = su_allow_uid_profile(0, uid, &profile); + if (cmd_res->rc) return; + + sprintf(buffer, "uid: %d, to_uid: %d, scontext: %s", profile.uid, profile.to_uid, profile.scontext); + cmd_res->msg = buffer; + + } else if (!strcmp(sub_cmd, "path")) { + if (carr[2]) { + cmd_res->rc = su_reset_path(carr[2]); + if (cmd_res->rc) return; + cmd_res->msg = carr[2]; + carr[2] = 0; // no free + } else { + cmd_res->msg = su_get_path(); + } + } else if (!strcmp(sub_cmd, "sctx")) { + if (carr[2]) { + cmd_res->rc = set_all_allow_sctx(carr[2]); + if (!cmd_res->rc) cmd_res->msg = carr[2]; + } else { + cmd_res->msg = all_allow_sctx; + } + } +#ifdef ANDROID + else if (!strcmp(sub_cmd, "exclude")) { + unsigned long long uid; + if (!carr[2] || kstrtoull(carr[2], 10, &uid)) { + cmd_res->err_msg = "invalid uid"; + return; + } else { + if (!carr[3]) { + int exclude = get_ap_mod_exclude(uid); + sprintf(buffer, "%d", exclude); + cmd_res->msg = buffer; + } else { + if (carr[3][0] == '0') { + set_ap_mod_exclude(uid, 0); + cmd_res->msg = "0"; + } else { + set_ap_mod_exclude(uid, 1); + cmd_res->msg = "1"; + } + } + } + } else if (!strcmp(sub_cmd, "exclude_list")) { + uid_t uids[128]; + int offset = 0; + buffer[0] = '\0'; + int cnt = list_ap_mod_exclude(uids, sizeof(uids) / sizeof(uids[0])); + if (cnt < 0) { + cmd_res->rc = cnt; + } else { + for (int i = 0; i < cnt; i++) { + offset += sprintf(buffer + offset, "%d\n", uids[i]); + }; + if (offset > 0) buffer[offset - 1] = '\0'; + cmd_res->msg = buffer; + } + } +#endif + else { + cmd_res->err_msg = "invalid subcommand"; + } +} + +// superkey commands +static void handle_cmd_key_auth(char **__user u_filename_p, const char *cmd, const char **carr, char *buffer, + int buflen, struct cmd_res *cmd_res) +{ + if (!strcmp("key", cmd)) { + const char *sub_cmd = carr[1]; + if (!sub_cmd) sub_cmd = ""; + if (!strcmp("get", sub_cmd)) { + cmd_res->msg = get_superkey(); + } else if (!strcmp("set", sub_cmd)) { + const char *key = carr[2]; + if (!key) { + cmd_res->err_msg = "invalid new key"; + return; + } + cmd_res->msg = key; + reset_superkey(key); + } else if (!strcmp("hash", sub_cmd)) { + const char *able = carr[2]; + if (able && !strcmp("enable", able)) { + cmd_res->msg = able; + enable_auth_root_key(true); + } else if (able && !strcmp("disable", able)) { + cmd_res->msg = able; + enable_auth_root_key(false); + } else { + cmd_res->err_msg = "invalid enable or disable"; + return; + } + } else { + cmd_res->err_msg = "invalid subcommand"; + return; + } + } else if (!strcmp("module", cmd)) { + const char *sub_cmd = carr[1]; + if (!sub_cmd) sub_cmd = ""; + if (!strcmp("num", sub_cmd)) { + int num = get_module_nums(); + sprintf(buffer, "%d\n", num); + cmd_res->msg = buffer; + } else if (!strcmp("list", sub_cmd)) { + list_modules(buffer, buflen); + cmd_res->msg = buffer; + } else if (!strcmp("load", sub_cmd)) { + const char *path = carr[2]; + if (!path) { + cmd_res->err_msg = "invalid module path"; + return; + } + cmd_res->rc = load_module_path(path, carr[3], 0); + if (!cmd_res->rc) cmd_res->msg = path; + } else if (!strcmp("ctl0", sub_cmd)) { + const char *name = carr[2]; + if (!name) { + cmd_res->err_msg = "invalid module name"; + return; + } + const char *mod_args = carr[3]; + if (!mod_args) { + cmd_res->err_msg = "invalid control arguments"; + return; + } + buffer[0] = '\0'; + cmd_res->rc = module_control0(name, mod_args, buffer, buflen); + cmd_res->msg = buffer; + } else if (!strcmp("ctl1", sub_cmd)) { + cmd_res->err_msg = "not implement"; + } else if (!strcmp("unload", sub_cmd)) { + const char *name = carr[2]; + if (!name) { + cmd_res->err_msg = "invalid module name"; + return; + } + cmd_res->rc = unload_module(name, 0); + if (!cmd_res->rc) cmd_res->msg = name; + } else if (!strcmp("info", sub_cmd)) { + const char *name = carr[2]; + if (!name) { + cmd_res->err_msg = "invalid module name"; + return; + } + int sz = get_module_info(name, buffer, buflen); + if (sz <= 0) cmd_res->rc = sz; + cmd_res->msg = buffer; + } else { + cmd_res->err_msg = "invalid subcommand"; + return; + } + } else { + cmd_res->err_msg = "invalid command"; + return; + } +} + +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; + su_allow_uid_profile(0, uid, &profile); + } else { + return; + } + +#define SUPERCMD_ARGS_NO 16 + + // copy 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 (IS_ERR(ua)) break; + const char *a = strndup_user(ua, 512); + if (IS_ERR(a)) break; + parr[i] = a; + // ignore after -c + if (a[0] == '-' && a[1] == 'c') break; + } + + 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\n"); + goto free; + } + break; + default: + break; + } + } + + commit_su(profile.to_uid, profile.scontext); + + struct cmd_res cmd_res = { 0 }; + + char buffer[4096]; + buffer[0] = '\0'; + + // command + const char **carr = parr + pi; + const char *cmd = 0; + + if (pi < SUPERCMD_ARGS_NO - 1) { + cmd = carr[0]; + } else { + cmd_res.err_msg = "too many args\n"; + goto echo; + } + + if (!cmd) { + supercmd_exec(u_filename_p, sh_path, &sp); + *uargv += pi * 8; + goto free; + } + + if (!strcmp("help", cmd)) { + cmd_res.msg = supercmd_help; + } else if (!strcmp("-c", cmd)) { + supercmd_exec(u_filename_p, sh_path, &sp); + *uargv += (carr - parr - 1) * 8; + goto free; + } else if (!strcmp("exec", cmd)) { + if (!carr[1]) { + cmd_res.err_msg = "invalid commmand path"; + goto echo; + } + supercmd_exec(u_filename_p, carr[1], &sp); + *uargv += (carr - parr + 1) * 8; + goto free; + } else if (!strcmp("version", cmd)) { + supercmd_echo(u_filename_p, uargv, &sp, "%x,%x", kver, kpver); + goto free; + } else if (!strcmp("buildtime", cmd)) { + cmd_res.msg = get_build_time(); + goto echo; + } else if (!strcmp("sumgr", cmd)) { + handle_cmd_sumgr(u_filename_p, carr, buffer, sizeof(buffer), &cmd_res); + } else if (!strcmp("event", cmd)) { + if (carr[1]) { + cmd_res.rc = report_user_event(carr[1], carr[2]); + if (!cmd_res.rc) cmd_res.msg = "report success"; + } else { + cmd_res.err_msg = "empty event"; + } + } else if (!strcmp("bootlog", cmd)) { + cmd_res.msg = get_boot_log(); + } else if (!strcmp("test", cmd)) { + void test(); + test(); + cmd_res.msg = "test done..."; + } else { + if (is_key_auth) { + handle_cmd_key_auth(u_filename_p, cmd, carr, buffer, sizeof(buffer), &cmd_res); + } else { + cmd_res.err_msg = "invalid command or a superkey is required"; + } + } + +echo: + if (cmd_res.msg) supercmd_echo(u_filename_p, uargv, &sp, cmd_res.msg); + if (cmd_res.rc) supercmd_echo(u_filename_p, uargv, &sp, "supercmd error code: %d", cmd_res.rc); + if (cmd_res.err_msg) supercmd_echo(u_filename_p, uargv, &sp, "supercmd error message: %s", cmd_res.err_msg); + +free: + // free args + for (int i = 2; i < sizeof(parr) / sizeof(parr[0]); i++) { + const char *a = parr[i]; + if (!a) continue; + kfree(a); + } +} diff --git a/kernel/patch/common/syscall.c b/kernel/patch/common/syscall.c index 7388cb9e..6a7c3909 100644 --- a/kernel/patch/common/syscall.c +++ b/kernel/patch/common/syscall.c @@ -18,10 +18,15 @@ #include #include #include +#include +#include uintptr_t *sys_call_table = 0; KP_EXPORT_SYMBOL(sys_call_table); +uintptr_t *compat_sys_call_table = 0; +KP_EXPORT_SYMBOL(compat_sys_call_table); + int has_syscall_wrapper = 0; KP_EXPORT_SYMBOL(has_syscall_wrapper); @@ -46,7 +51,7 @@ struct user_arg_ptr_compat } ptr; }; -// actually, a0 is true if it is compact +// actually, a0 is true if it is compat const char __user *get_user_arg_ptr(void *a0, void *a1, int nr) { char __user *const __user *native = (char __user *const __user *)a0; @@ -57,7 +62,7 @@ const char __user *get_user_arg_ptr(void *a0, void *a1, int nr) } native = (char __user *const __user *)((unsigned long)native + nr * size); char __user **upptr = memdup_user(native, size); - if (!upptr || IS_ERR(upptr)) return ERR_PTR((long)upptr); + if (IS_ERR(upptr)) return ERR_PTR((long)upptr); char __user *uptr; if (size == 8) { @@ -65,21 +70,24 @@ 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; } int set_user_arg_ptr(void *a0, void *a1, int nr, uintptr_t val) { + uintptr_t valp = (uintptr_t)&val; char __user *const __user *native = (char __user *const __user *)a0; int size = 8; if (has_config_compat) { native = (char __user *const __user *)a1; - if (a0) size = 4; // compat + if (a0) { + size = 4; // compat + valp += 4; + } } native = (char __user *const __user *)((unsigned long)native + nr * size); - uintptr_t valarr[1] = { val }; - int cplen = compat_copy_to_user((void *)native, (void *)valarr, size); + int cplen = compat_copy_to_user((void *)native, (void *)valp, size); return cplen == size ? 0 : cplen; } @@ -92,48 +100,108 @@ typedef long (*raw_syscall4_f)(long arg0, long arg1, long arg2, long arg3); typedef long (*raw_syscall5_f)(long arg0, long arg1, long arg2, long arg3, long arg4); typedef long (*raw_syscall6_f)(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5); +uintptr_t syscalln_name_addr(int nr, int is_compat) +{ + const char *name = 0; + if (!is_compat) { + if (syscall_name_table[nr].addr) { + return syscall_name_table[nr].addr; + } + name = syscall_name_table[nr].name; + } else { + if (compat_syscall_name_table[nr].addr) { + return compat_syscall_name_table[nr].addr; + } + name = compat_syscall_name_table[nr].name; + } + + if (!name) return 0; + + const char *prefix[2]; + prefix[0] = "__arm64_"; + prefix[1] = ""; + const char *suffix[3]; + suffix[0] = ".cfi_jt"; + suffix[1] = ".cfi"; + suffix[2] = ""; + + uintptr_t addr = 0; + + char buffer[256]; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + snprintf(buffer, sizeof(buffer), "%s%s%s", prefix[i], name, suffix[j]); + addr = kallsyms_lookup_name(buffer); + if (addr) break; + } + if (addr) break; + } + if (!is_compat) { + syscall_name_table[nr].addr = addr; + } else { + compat_syscall_name_table[nr].addr = addr; + } + return addr; +} +KP_EXPORT_SYMBOL(syscalln_name_addr); + +uintptr_t syscalln_addr(int nr, int is_compat) +{ + if (!is_compat && sys_call_table) return sys_call_table[nr]; + if (is_compat && compat_sys_call_table) return compat_sys_call_table[nr]; + return syscalln_name_addr(nr, is_compat); +} +KP_EXPORT_SYMBOL(syscalln_addr); + long raw_syscall0(long nr) { - uintptr_t addr = sys_call_table[nr]; + uintptr_t addr = syscalln_addr(nr, 0); 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)(); - return 0; } +KP_EXPORT_SYMBOL(raw_syscall0); long raw_syscall1(long nr, long arg0) { - uintptr_t addr = sys_call_table[nr]; + uintptr_t addr = syscalln_addr(nr, 0); 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); } +KP_EXPORT_SYMBOL(raw_syscall1); long raw_syscall2(long nr, long arg0, long arg1) { - uintptr_t addr = sys_call_table[nr]; + uintptr_t addr = syscalln_addr(nr, 0); 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); } return ((raw_syscall2_f)addr)(arg0, arg1); } +KP_EXPORT_SYMBOL(raw_syscall2); long raw_syscall3(long nr, long arg0, long arg1, long arg2) { - uintptr_t addr = sys_call_table[nr]; + uintptr_t addr = syscalln_addr(nr, 0); 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; @@ -141,13 +209,15 @@ long raw_syscall3(long nr, long arg0, long arg1, long arg2) } return ((raw_syscall3_f)addr)(arg0, arg1, arg2); } +KP_EXPORT_SYMBOL(raw_syscall3); long raw_syscall4(long nr, long arg0, long arg1, long arg2, long arg3) { - uintptr_t addr = sys_call_table[nr]; + uintptr_t addr = syscalln_addr(nr, 0); 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; @@ -156,13 +226,15 @@ long raw_syscall4(long nr, long arg0, long arg1, long arg2, long arg3) } return ((raw_syscall4_f)addr)(arg0, arg1, arg2, arg3); } +KP_EXPORT_SYMBOL(raw_syscall4); long raw_syscall5(long nr, long arg0, long arg1, long arg2, long arg3, long arg4) { - uintptr_t addr = sys_call_table[nr]; + uintptr_t addr = syscalln_addr(nr, 0); 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; @@ -172,13 +244,15 @@ long raw_syscall5(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 } return ((raw_syscall5_f)addr)(arg0, arg1, arg2, arg3, arg4); } +KP_EXPORT_SYMBOL(raw_syscall5); long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) { - uintptr_t addr = sys_call_table[nr]; + uintptr_t addr = syscalln_addr(nr, 0); 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; @@ -189,74 +263,106 @@ 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); } +KP_EXPORT_SYMBOL(raw_syscall6); -static uint64_t search_sys_call_table_addr() +hook_err_t fp_wrap_syscalln(int nr, int narg, int is_compat, void *before, void *after, void *udata) { - uint64_t addr = kernel_va; - uint64_t _etext = kallsyms_lookup_name("_etext"); - addr = addr > _etext ? addr : _etext; + if (!is_compat) { + 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); + } else { + if (!compat_sys_call_table) return HOOK_BAD_ADDRESS; + uintptr_t fp_addr = (uintptr_t)(compat_sys_call_table + nr); + if (has_syscall_wrapper) narg = 1; + return fp_hook_wrap(fp_addr, narg, before, after, udata); + } +} +KP_EXPORT_SYMBOL(fp_wrap_syscalln); - char *prefix[2]; - prefix[0] = "__arm64_"; - prefix[1] = ""; +void fp_unwrap_syscalln(int nr, int is_compat, void *before, void *after) +{ + if (!is_compat) { + if (!sys_call_table) return; + uintptr_t fp_addr = (uintptr_t)(sys_call_table + nr); + fp_hook_unwrap(fp_addr, before, after); + } else { + if (!compat_sys_call_table) return; + uintptr_t fp_addr = (uintptr_t)(compat_sys_call_table + nr); + fp_hook_unwrap(fp_addr, before, after); + } +} +KP_EXPORT_SYMBOL(fp_unwrap_syscalln); - char *io_setup = "sys_io_setup"; - char *io_destory = "sys_io_destroy"; +/* +sys_xxx.cfi_jt - char *suffix[3]; - suffix[0] = ".cfi_jt"; - suffix[1] = ".cfi"; - suffix[2] = ""; +hint #0x22 # bti c +b #0xfffffffffeb452f4 +*/ +hook_err_t inline_wrap_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); +} +KP_EXPORT_SYMBOL(inline_wrap_syscalln); - char buf[128]; - - uint64_t sc0_addr = 0; - uint64_t sc1_addr = 0; - - int i = 0, k = 0; - - for (; k < 3; k++) { - i = 0; - for (; i < 2; i++) { - buf[0] = '\0'; - strcat(buf, prefix[i]); - strcat(buf, io_setup); - strcat(buf, suffix[k]); - sc0_addr = kallsyms_lookup_name(buf); - if (!sc0_addr) continue; - - buf[0] = '\0'; - strcat(buf, prefix[i]); - strcat(buf, io_destory); - strcat(buf, suffix[k]); - sc1_addr = kallsyms_lookup_name(buf); - if (!sc1_addr) return 0; - } - } +void inline_unwrap_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); +} +KP_EXPORT_SYMBOL(inline_unwrap_syscalln); - for (; addr < kernel_va + kernel_size; addr += 8) { - uint64_t val0 = *(uint64_t *)addr; - if (val0 != sc0_addr) continue; - uint64_t val1 = *(uint64_t *)(addr + 8); - if (val1 == sc1_addr) return addr; - } - return 0; +hook_err_t hook_syscalln(int nr, int narg, void *before, void *after, void *udata) +{ + if (sys_call_table) return fp_wrap_syscalln(nr, narg, 0, before, after, udata); + return inline_wrap_syscalln(nr, narg, 0, before, after, udata); } +KP_EXPORT_SYMBOL(hook_syscalln); -int syscall_init() +void unhook_syscalln(int nr, void *before, void *after) { - 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(); + if (sys_call_table) return fp_unwrap_syscalln(nr, 0, before, after); + return inline_unwrap_syscalln(nr, 0, before, after); +} +KP_EXPORT_SYMBOL(unhook_syscalln); + +hook_err_t hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata) +{ + if (compat_sys_call_table) return fp_wrap_syscalln(nr, narg, 1, before, after, udata); + return inline_wrap_syscalln(nr, narg, 1, before, after, udata); +} +KP_EXPORT_SYMBOL(hook_compat_syscalln); + +void unhook_compat_syscalln(int nr, void *before, void *after) +{ + if (compat_sys_call_table) return fp_unwrap_syscalln(nr, 1, before, after); + return inline_unwrap_syscalln(nr, 1, before, after); +} +KP_EXPORT_SYMBOL(unhook_compat_syscalln); + +void syscall_init() +{ + for (int i = 0; i < sizeof(syscall_name_table) / sizeof(syscall_name_table[0]); i++) { + uintptr_t *addr = (uintptr_t *)&syscall_name_table[i].name; + *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].name; + *addr = link2runtime(*addr); } + + sys_call_table = (typeof(sys_call_table))kallsyms_lookup_name("sys_call_table"); 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"); + log_boot("compat_sys_call_table addr: %llx\n", compat_sys_call_table); + has_config_compat = 0; has_syscall_wrapper = 0; @@ -273,9 +379,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..3a838a3f --- /dev/null +++ b/kernel/patch/common/sysname.c @@ -0,0 +1,721 @@ +#include +#include + +struct +{ + const char *name; + uintptr_t addr; +} syscall_name_table[460] = { + [0] = { "sys_io_setup", 0 }, + [1] = { "sys_io_destroy", 0 }, + [2] = { "sys_io_submit", 0 }, + [3] = { "sys_io_cancel", 0 }, + [4] = { "sys_io_getevents", 0 }, + [5] = { "sys_setxattr", 0 }, + [6] = { "sys_lsetxattr", 0 }, + [7] = { "sys_fsetxattr", 0 }, + [8] = { "sys_getxattr", 0 }, + [9] = { "sys_lgetxattr", 0 }, + [10] = { "sys_fgetxattr", 0 }, + [11] = { "sys_listxattr", 0 }, + [12] = { "sys_llistxattr", 0 }, + [13] = { "sys_flistxattr", 0 }, + [14] = { "sys_removexattr", 0 }, + [15] = { "sys_lremovexattr", 0 }, + [16] = { "sys_fremovexattr", 0 }, + [17] = { "sys_getcwd", 0 }, + [19] = { "sys_eventfd2", 0 }, + [20] = { "sys_epoll_create1", 0 }, + [21] = { "sys_epoll_ctl", 0 }, + [22] = { "sys_epoll_pwait", 0 }, + [23] = { "sys_dup", 0 }, + [24] = { "sys_dup3", 0 }, + [25] = { "sys_fcntl", 0 }, + [26] = { "sys_inotify_init1", 0 }, + [27] = { "sys_inotify_add_watch", 0 }, + [28] = { "sys_inotify_rm_watch", 0 }, + [29] = { "sys_ioctl", 0 }, + [30] = { "sys_ioprio_set", 0 }, + [31] = { "sys_ioprio_get", 0 }, + [32] = { "sys_flock", 0 }, + [33] = { "sys_mknodat", 0 }, + [34] = { "sys_mkdirat", 0 }, + [35] = { "sys_unlinkat", 0 }, + [36] = { "sys_symlinkat", 0 }, + [37] = { "sys_linkat", 0 }, + [38] = { "sys_renameat", 0 }, + [39] = { "sys_umount", 0 }, + [40] = { "sys_mount", 0 }, + [41] = { "sys_pivot_root", 0 }, + [43] = { "sys_statfs", 0 }, + [44] = { "sys_fstatfs", 0 }, + [45] = { "sys_truncate", 0 }, + [46] = { "sys_ftruncate", 0 }, + [47] = { "sys_fallocate", 0 }, + [48] = { "sys_faccessat", 0 }, + [49] = { "sys_chdir", 0 }, + [50] = { "sys_fchdir", 0 }, + [51] = { "sys_chroot", 0 }, + [52] = { "sys_fchmod", 0 }, + [53] = { "sys_fchmodat", 0 }, + [54] = { "sys_fchownat", 0 }, + [55] = { "sys_fchown", 0 }, + [56] = { "sys_openat", 0 }, + [57] = { "sys_close", 0 }, + [58] = { "sys_vhangup", 0 }, + [59] = { "sys_pipe2", 0 }, + [60] = { "sys_quotactl", 0 }, + [61] = { "sys_getdents64", 0 }, + [62] = { "sys_lseek", 0 }, + [63] = { "sys_read", 0 }, + [64] = { "sys_write", 0 }, + [65] = { "sys_readv", 0 }, + [66] = { "sys_writev", 0 }, + [67] = { "sys_pread64", 0 }, + [68] = { "sys_pwrite64", 0 }, + [69] = { "sys_preadv", 0 }, + [70] = { "sys_pwritev", 0 }, + [71] = { "sys_sendfile64", 0 }, + [72] = { "sys_pselect6", 0 }, + [73] = { "sys_ppoll", 0 }, + [74] = { "sys_signalfd4", 0 }, + [75] = { "sys_vmsplice", 0 }, + [76] = { "sys_splice", 0 }, + [77] = { "sys_tee", 0 }, + [78] = { "sys_readlinkat", 0 }, + [79] = { "sys_newfstatat", 0 }, + [80] = { "sys_newfstat", 0 }, + [81] = { "sys_sync", 0 }, + [82] = { "sys_fsync", 0 }, + [83] = { "sys_fdatasync", 0 }, + [84] = { "sys_sync_file_range", 0 }, + [85] = { "sys_timerfd_create", 0 }, + [86] = { "sys_timerfd_settime", 0 }, + [87] = { "sys_timerfd_gettime", 0 }, + [88] = { "sys_utimensat", 0 }, + [89] = { "sys_acct", 0 }, + [90] = { "sys_capget", 0 }, + [91] = { "sys_capset", 0 }, + [92] = { "sys_arm64_personality", 0 }, + [93] = { "sys_exit", 0 }, + [94] = { "sys_exit_group", 0 }, + [95] = { "sys_waitid", 0 }, + [96] = { "sys_set_tid_address", 0 }, + [97] = { "sys_unshare", 0 }, + [98] = { "sys_futex", 0 }, + [99] = { "sys_set_robust_list", 0 }, + [100] = { "sys_get_robust_list", 0 }, + [101] = { "sys_nanosleep", 0 }, + [102] = { "sys_getitimer", 0 }, + [103] = { "sys_setitimer", 0 }, + [104] = { "sys_kexec_load", 0 }, + [105] = { "sys_init_module", 0 }, + [106] = { "sys_delete_module", 0 }, + [107] = { "sys_timer_create", 0 }, + [108] = { "sys_timer_gettime", 0 }, + [109] = { "sys_timer_getoverrun", 0 }, + [110] = { "sys_timer_settime", 0 }, + [111] = { "sys_timer_delete", 0 }, + [112] = { "sys_clock_settime", 0 }, + [113] = { "sys_clock_gettime", 0 }, + [114] = { "sys_clock_getres", 0 }, + [115] = { "sys_clock_nanosleep", 0 }, + [116] = { "sys_syslog", 0 }, + [117] = { "sys_ptrace", 0 }, + [118] = { "sys_sched_setparam", 0 }, + [119] = { "sys_sched_setscheduler", 0 }, + [120] = { "sys_sched_getscheduler", 0 }, + [121] = { "sys_sched_getparam", 0 }, + [122] = { "sys_sched_setaffinity", 0 }, + [123] = { "sys_sched_getaffinity", 0 }, + [124] = { "sys_sched_yield", 0 }, + [125] = { "sys_sched_get_priority_max", 0 }, + [126] = { "sys_sched_get_priority_min", 0 }, + [127] = { "sys_sched_rr_get_interval", 0 }, + [128] = { "sys_restart_syscall", 0 }, + [129] = { "sys_kill", 0 }, + [130] = { "sys_tkill", 0 }, + [131] = { "sys_tgkill", 0 }, + [132] = { "sys_sigaltstack", 0 }, + [133] = { "sys_rt_sigsuspend", 0 }, + [134] = { "sys_rt_sigaction", 0 }, + [135] = { "sys_rt_sigprocmask", 0 }, + [136] = { "sys_rt_sigpending", 0 }, + [137] = { "sys_rt_sigtimedwait", 0 }, + [138] = { "sys_rt_sigqueueinfo", 0 }, + [139] = { "sys_rt_sigreturn", 0 }, + [140] = { "sys_setpriority", 0 }, + [141] = { "sys_getpriority", 0 }, + [142] = { "sys_reboot", 0 }, + [143] = { "sys_setregid", 0 }, + [144] = { "sys_setgid", 0 }, + [145] = { "sys_setreuid", 0 }, + [146] = { "sys_setuid", 0 }, + [147] = { "sys_setresuid", 0 }, + [148] = { "sys_getresuid", 0 }, + [149] = { "sys_setresgid", 0 }, + [150] = { "sys_getresgid", 0 }, + [151] = { "sys_setfsuid", 0 }, + [152] = { "sys_setfsgid", 0 }, + [153] = { "sys_times", 0 }, + [154] = { "sys_setpgid", 0 }, + [155] = { "sys_getpgid", 0 }, + [156] = { "sys_getsid", 0 }, + [157] = { "sys_setsid", 0 }, + [158] = { "sys_getgroups", 0 }, + [159] = { "sys_setgroups", 0 }, + [160] = { "sys_newuname", 0 }, + [161] = { "sys_sethostname", 0 }, + [162] = { "sys_setdomainname", 0 }, + [163] = { "sys_getrlimit", 0 }, + [164] = { "sys_setrlimit", 0 }, + [165] = { "sys_getrusage", 0 }, + [166] = { "sys_umask", 0 }, + [167] = { "sys_prctl", 0 }, + [168] = { "sys_getcpu", 0 }, + [169] = { "sys_gettimeofday", 0 }, + [170] = { "sys_settimeofday", 0 }, + [171] = { "sys_adjtimex", 0 }, + [172] = { "sys_getpid", 0 }, + [173] = { "sys_getppid", 0 }, + [174] = { "sys_getuid", 0 }, + [175] = { "sys_geteuid", 0 }, + [176] = { "sys_getgid", 0 }, + [177] = { "sys_getegid", 0 }, + [178] = { "sys_gettid", 0 }, + [179] = { "sys_sysinfo", 0 }, + [180] = { "sys_mq_open", 0 }, + [181] = { "sys_mq_unlink", 0 }, + [182] = { "sys_mq_timedsend", 0 }, + [183] = { "sys_mq_timedreceive", 0 }, + [184] = { "sys_mq_notify", 0 }, + [185] = { "sys_mq_getsetattr", 0 }, + [186] = { "sys_msgget", 0 }, + [187] = { "sys_msgctl", 0 }, + [188] = { "sys_msgrcv", 0 }, + [189] = { "sys_msgsnd", 0 }, + [190] = { "sys_semget", 0 }, + [191] = { "sys_semctl", 0 }, + [192] = { "sys_semtimedop", 0 }, + [193] = { "sys_semop", 0 }, + [194] = { "sys_shmget", 0 }, + [195] = { "sys_shmctl", 0 }, + [196] = { "sys_shmat", 0 }, + [197] = { "sys_shmdt", 0 }, + [198] = { "sys_socket", 0 }, + [199] = { "sys_socketpair", 0 }, + [200] = { "sys_bind", 0 }, + [201] = { "sys_listen", 0 }, + [202] = { "sys_accept", 0 }, + [203] = { "sys_connect", 0 }, + [204] = { "sys_getsockname", 0 }, + [205] = { "sys_getpeername", 0 }, + [206] = { "sys_sendto", 0 }, + [207] = { "sys_recvfrom", 0 }, + [208] = { "sys_setsockopt", 0 }, + [209] = { "sys_getsockopt", 0 }, + [210] = { "sys_shutdown", 0 }, + [211] = { "sys_sendmsg", 0 }, + [212] = { "sys_recvmsg", 0 }, + [213] = { "sys_readahead", 0 }, + [214] = { "sys_brk", 0 }, + [215] = { "sys_munmap", 0 }, + [216] = { "sys_mremap", 0 }, + [217] = { "sys_add_key", 0 }, + [218] = { "sys_request_key", 0 }, + [219] = { "sys_keyctl", 0 }, + [220] = { "sys_clone", 0 }, + [221] = { "sys_execve", 0 }, + [222] = { "sys_mmap", 0 }, + [223] = { "sys_fadvise64_64", 0 }, + [224] = { "sys_swapon", 0 }, + [225] = { "sys_swapoff", 0 }, + [226] = { "sys_mprotect", 0 }, + [227] = { "sys_msync", 0 }, + [228] = { "sys_mlock", 0 }, + [229] = { "sys_munlock", 0 }, + [230] = { "sys_mlockall", 0 }, + [231] = { "sys_munlockall", 0 }, + [232] = { "sys_mincore", 0 }, + [233] = { "sys_madvise", 0 }, + [234] = { "sys_remap_file_pages", 0 }, + [235] = { "sys_mbind", 0 }, + [236] = { "sys_get_mempolicy", 0 }, + [237] = { "sys_set_mempolicy", 0 }, + [238] = { "sys_migrate_pages", 0 }, + [239] = { "sys_move_pages", 0 }, + [240] = { "sys_rt_tgsigqueueinfo", 0 }, + [241] = { "sys_perf_event_open", 0 }, + [242] = { "sys_accept4", 0 }, + [243] = { "sys_recvmmsg", 0 }, + [260] = { "sys_wait4", 0 }, + [261] = { "sys_prlimit64", 0 }, + [262] = { "sys_fanotify_init", 0 }, + [263] = { "sys_fanotify_mark", 0 }, + [264] = { "sys_name_to_handle_at", 0 }, + [265] = { "sys_open_by_handle_at", 0 }, + [266] = { "sys_clock_adjtime", 0 }, + [267] = { "sys_syncfs", 0 }, + [268] = { "sys_setns", 0 }, + [269] = { "sys_sendmmsg", 0 }, + [270] = { "sys_process_vm_readv", 0 }, + [271] = { "sys_process_vm_writev", 0 }, + [272] = { "sys_kcmp", 0 }, + [273] = { "sys_finit_module", 0 }, + [274] = { "sys_sched_setattr", 0 }, + [275] = { "sys_sched_getattr", 0 }, + [276] = { "sys_renameat2", 0 }, + [277] = { "sys_seccomp", 0 }, + [278] = { "sys_getrandom", 0 }, + [279] = { "sys_memfd_create", 0 }, + [280] = { "sys_bpf", 0 }, + [281] = { "sys_execveat", 0 }, + [282] = { "sys_userfaultfd", 0 }, + [283] = { "sys_membarrier", 0 }, + [284] = { "sys_mlock2", 0 }, + [285] = { "sys_copy_file_range", 0 }, + [286] = { "sys_preadv2", 0 }, + [287] = { "sys_pwritev2", 0 }, + [288] = { "sys_pkey_mprotect", 0 }, + [289] = { "sys_pkey_alloc", 0 }, + [290] = { "sys_pkey_free", 0 }, + [291] = { "sys_statx", 0 }, + [292] = { "sys_io_pgetevents", 0 }, + [293] = { "sys_rseq", 0 }, + [294] = { "sys_kexec_file_load", 0 }, + [424] = { "sys_pidfd_send_signal", 0 }, + [425] = { "sys_io_uring_setup", 0 }, + [426] = { "sys_io_uring_enter", 0 }, + [427] = { "sys_io_uring_register", 0 }, + [428] = { "sys_open_tree", 0 }, + [429] = { "sys_move_mount", 0 }, + [430] = { "sys_fsopen", 0 }, + [431] = { "sys_fsconfig", 0 }, + [432] = { "sys_fsmount", 0 }, + [433] = { "sys_fspick", 0 }, + [434] = { "sys_pidfd_open", 0 }, + [435] = { "sys_clone3", 0 }, + [436] = { "sys_close_range", 0 }, + [437] = { "sys_openat2", 0 }, + [438] = { "sys_pidfd_getfd", 0 }, + [439] = { "sys_faccessat2", 0 }, + [440] = { "sys_process_madvise", 0 }, + [441] = { "sys_epoll_pwait2", 0 }, + [442] = { "sys_mount_setattr", 0 }, + [443] = { "sys_quotactl_fd", 0 }, + [444] = { "sys_landlock_create_ruleset", 0 }, + [445] = { "sys_landlock_add_rule", 0 }, + [446] = { "sys_landlock_restrict_self", 0 }, + [447] = { "sys_memfd_secret", 0 }, + [448] = { "sys_process_mrelease", 0 }, + [449] = { "sys_futex_waitv", 0 }, + [450] = { "sys_set_mempolicy_home_node", 0 }, + [451] = { "sys_cachestat", 0 }, +}; +KP_EXPORT_SYMBOL(syscall_name_table); + +struct +{ + const char *name; + uintptr_t addr; +} compat_syscall_name_table[460] = { + [0] = { "sys_restart_syscall", 0 }, + [1] = { "sys_exit", 0 }, + [2] = { "sys_fork", 0 }, + [3] = { "sys_read", 0 }, + [4] = { "sys_write", 0 }, + [5] = { "sys_open", 0 }, + [6] = { "sys_close", 0 }, + [8] = { "sys_creat", 0 }, + [9] = { "sys_link", 0 }, + [10] = { "sys_unlink", 0 }, + [11] = { "sys_execve", 0 }, + [12] = { "sys_chdir", 0 }, + [14] = { "sys_mknod", 0 }, + [15] = { "sys_chmod", 0 }, + [16] = { "sys_lchown16", 0 }, + [19] = { "sys_lseek", 0 }, + [20] = { "sys_getpid", 0 }, + [21] = { "sys_mount", 0 }, + [23] = { "sys_setuid16", 0 }, + [24] = { "sys_getuid16", 0 }, + [26] = { "sys_ptrace", 0 }, + [29] = { "sys_pause", 0 }, + [33] = { "sys_access", 0 }, + [34] = { "sys_nice", 0 }, + [36] = { "sys_sync", 0 }, + [37] = { "sys_kill", 0 }, + [38] = { "sys_rename", 0 }, + [39] = { "sys_mkdir", 0 }, + [40] = { "sys_rmdir", 0 }, + [41] = { "sys_dup", 0 }, + [42] = { "sys_pipe", 0 }, + [43] = { "sys_times", 0 }, + [45] = { "sys_brk", 0 }, + [46] = { "sys_setgid16", 0 }, + [47] = { "sys_getgid16", 0 }, + [49] = { "sys_geteuid16", 0 }, + [50] = { "sys_getegid16", 0 }, + [51] = { "sys_acct", 0 }, + [52] = { "sys_umount", 0 }, + [54] = { "sys_ioctl", 0 }, + [55] = { "sys_fcntl", 0 }, + [57] = { "sys_setpgid", 0 }, + [60] = { "sys_umask", 0 }, + [61] = { "sys_chroot", 0 }, + [62] = { "sys_ustat", 0 }, + [63] = { "sys_dup2", 0 }, + [64] = { "sys_getppid", 0 }, + [65] = { "sys_getpgrp", 0 }, + [66] = { "sys_setsid", 0 }, + [67] = { "sys_sigaction", 0 }, + [70] = { "sys_setreuid16", 0 }, + [71] = { "sys_setregid16", 0 }, + [72] = { "sys_sigsuspend", 0 }, + [73] = { "sys_sigpending", 0 }, + [74] = { "sys_sethostname", 0 }, + [75] = { "sys_setrlimit", 0 }, + [77] = { "sys_getrusage", 0 }, + [78] = { "sys_gettimeofday", 0 }, + [79] = { "sys_settimeofday", 0 }, + [80] = { "sys_getgroups16", 0 }, + [81] = { "sys_setgroups16", 0 }, + [83] = { "sys_symlink", 0 }, + [85] = { "sys_readlink", 0 }, + [86] = { "sys_uselib", 0 }, + [87] = { "sys_swapon", 0 }, + [88] = { "sys_reboot", 0 }, + [91] = { "sys_munmap", 0 }, + [92] = { "sys_truncate", 0 }, + [93] = { "sys_ftruncate", 0 }, + [94] = { "sys_fchmod", 0 }, + [95] = { "sys_fchown16", 0 }, + [96] = { "sys_getpriority", 0 }, + [97] = { "sys_setpriority", 0 }, + [99] = { "sys_statfs", 0 }, + [100] = { "sys_fstatfs", 0 }, + [103] = { "sys_syslog", 0 }, + [104] = { "sys_setitimer", 0 }, + [105] = { "sys_getitimer", 0 }, + [106] = { "sys_newstat", 0 }, + [107] = { "sys_newlstat", 0 }, + [108] = { "sys_newfstat", 0 }, + [111] = { "sys_vhangup", 0 }, + [114] = { "sys_wait4", 0 }, + [115] = { "sys_swapoff", 0 }, + [116] = { "sys_sysinfo", 0 }, + [118] = { "sys_fsync", 0 }, + [119] = { "sys_sigreturn", 0 }, + [120] = { "sys_clone", 0 }, + [121] = { "sys_setdomainname", 0 }, + [122] = { "sys_newuname", 0 }, + [124] = { "sys_adjtimex_time32", 0 }, + [125] = { "sys_mprotect", 0 }, + [126] = { "sys_sigprocmask", 0 }, + [128] = { "sys_init_module", 0 }, + [129] = { "sys_delete_module", 0 }, + [131] = { "sys_quotactl", 0 }, + [132] = { "sys_getpgid", 0 }, + [133] = { "sys_fchdir", 0 }, + [135] = { "sys_sysfs", 0 }, + [136] = { "sys_personality", 0 }, + [138] = { "sys_setfsuid16", 0 }, + [139] = { "sys_setfsgid16", 0 }, + [140] = { "sys_llseek", 0 }, + [141] = { "sys_getdents", 0 }, + [142] = { "sys_select", 0 }, + [143] = { "sys_flock", 0 }, + [144] = { "sys_msync", 0 }, + [145] = { "sys_readv", 0 }, + [146] = { "sys_writev", 0 }, + [147] = { "sys_getsid", 0 }, + [148] = { "sys_fdatasync", 0 }, + [150] = { "sys_mlock", 0 }, + [151] = { "sys_munlock", 0 }, + [152] = { "sys_mlockall", 0 }, + [153] = { "sys_munlockall", 0 }, + [154] = { "sys_sched_setparam", 0 }, + [155] = { "sys_sched_getparam", 0 }, + [156] = { "sys_sched_setscheduler", 0 }, + [157] = { "sys_sched_getscheduler", 0 }, + [158] = { "sys_sched_yield", 0 }, + [159] = { "sys_sched_get_priority_max", 0 }, + [160] = { "sys_sched_get_priority_min", 0 }, + [161] = { "sys_sched_rr_get_interval_time32", 0 }, + [162] = { "sys_nanosleep_time32", 0 }, + [163] = { "sys_mremap", 0 }, + [164] = { "sys_setresuid16", 0 }, + [165] = { "sys_getresuid16", 0 }, + [168] = { "sys_poll", 0 }, + [170] = { "sys_setresgid16", 0 }, + [171] = { "sys_getresgid16", 0 }, + [172] = { "sys_prctl", 0 }, + [173] = { "sys_rt_sigreturn", 0 }, + [174] = { "sys_rt_sigaction", 0 }, + [175] = { "sys_rt_sigprocmask", 0 }, + [176] = { "sys_rt_sigpending", 0 }, + [177] = { "sys_rt_sigtimedwait_time32", 0 }, + [178] = { "sys_rt_sigqueueinfo", 0 }, + [179] = { "sys_rt_sigsuspend", 0 }, + [180] = { "sys_aarch32_pread64", 0 }, + [181] = { "sys_aarch32_pwrite64", 0 }, + [182] = { "sys_chown16", 0 }, + [183] = { "sys_getcwd", 0 }, + [184] = { "sys_capget", 0 }, + [185] = { "sys_capset", 0 }, + [186] = { "sys_sigaltstack", 0 }, + [187] = { "sys_sendfile", 0 }, + [190] = { "sys_vfork", 0 }, + [191] = { "sys_getrlimit", 0 }, + [192] = { "sys_aarch32_mmap2", 0 }, + [193] = { "sys_aarch32_truncate64", 0 }, + [194] = { "sys_aarch32_ftruncate64", 0 }, + [195] = { "sys_stat64", 0 }, + [196] = { "sys_lstat64", 0 }, + [197] = { "sys_fstat64", 0 }, + [198] = { "sys_lchown", 0 }, + [199] = { "sys_getuid", 0 }, + [200] = { "sys_getgid", 0 }, + [201] = { "sys_geteuid", 0 }, + [202] = { "sys_getegid", 0 }, + [203] = { "sys_setreuid", 0 }, + [204] = { "sys_setregid", 0 }, + [205] = { "sys_getgroups", 0 }, + [206] = { "sys_setgroups", 0 }, + [207] = { "sys_fchown", 0 }, + [208] = { "sys_setresuid", 0 }, + [209] = { "sys_getresuid", 0 }, + [210] = { "sys_setresgid", 0 }, + [211] = { "sys_getresgid", 0 }, + [212] = { "sys_chown", 0 }, + [213] = { "sys_setuid", 0 }, + [214] = { "sys_setgid", 0 }, + [215] = { "sys_setfsuid", 0 }, + [216] = { "sys_setfsgid", 0 }, + [217] = { "sys_getdents64", 0 }, + [218] = { "sys_pivot_root", 0 }, + [219] = { "sys_mincore", 0 }, + [220] = { "sys_madvise", 0 }, + [221] = { "sys_fcntl64", 0 }, + [224] = { "sys_gettid", 0 }, + [225] = { "sys_aarch32_readahead", 0 }, + [226] = { "sys_setxattr", 0 }, + [227] = { "sys_lsetxattr", 0 }, + [228] = { "sys_fsetxattr", 0 }, + [229] = { "sys_getxattr", 0 }, + [230] = { "sys_lgetxattr", 0 }, + [231] = { "sys_fgetxattr", 0 }, + [232] = { "sys_listxattr", 0 }, + [233] = { "sys_llistxattr", 0 }, + [234] = { "sys_flistxattr", 0 }, + [235] = { "sys_removexattr", 0 }, + [236] = { "sys_lremovexattr", 0 }, + [237] = { "sys_fremovexattr", 0 }, + [238] = { "sys_tkill", 0 }, + [239] = { "sys_sendfile64", 0 }, + [240] = { "sys_futex_time32", 0 }, + [241] = { "sys_sched_setaffinity", 0 }, + [242] = { "sys_sched_getaffinity", 0 }, + [243] = { "sys_io_setup", 0 }, + [244] = { "sys_io_destroy", 0 }, + [245] = { "sys_io_getevents_time32", 0 }, + [246] = { "sys_io_submit", 0 }, + [247] = { "sys_io_cancel", 0 }, + [248] = { "sys_exit_group", 0 }, + [250] = { "sys_epoll_create", 0 }, + [251] = { "sys_epoll_ctl", 0 }, + [252] = { "sys_epoll_wait", 0 }, + [253] = { "sys_remap_file_pages", 0 }, + [256] = { "sys_set_tid_address", 0 }, + [257] = { "sys_timer_create", 0 }, + [258] = { "sys_timer_settime32", 0 }, + [259] = { "sys_timer_gettime32", 0 }, + [260] = { "sys_timer_getoverrun", 0 }, + [261] = { "sys_timer_delete", 0 }, + [262] = { "sys_clock_settime32", 0 }, + [263] = { "sys_clock_gettime32", 0 }, + [264] = { "sys_clock_getres_time32", 0 }, + [265] = { "sys_clock_nanosleep_time32", 0 }, + [266] = { "sys_aarch32_statfs64", 0 }, + [267] = { "sys_aarch32_fstatfs64", 0 }, + [268] = { "sys_tgkill", 0 }, + [269] = { "sys_utimes_time32", 0 }, + [270] = { "sys_aarch32_fadvise64_64", 0 }, + [272] = { "sys_pciconfig_read", 0 }, + [273] = { "sys_pciconfig_write", 0 }, + [274] = { "sys_mq_open", 0 }, + [275] = { "sys_mq_unlink", 0 }, + [276] = { "sys_mq_timedsend_time32", 0 }, + [277] = { "sys_mq_timedreceive_time32", 0 }, + [278] = { "sys_mq_notify", 0 }, + [279] = { "sys_mq_getsetattr", 0 }, + [280] = { "sys_waitid", 0 }, + [281] = { "sys_socket", 0 }, + [282] = { "sys_bind", 0 }, + [283] = { "sys_connect", 0 }, + [284] = { "sys_listen", 0 }, + [285] = { "sys_accept", 0 }, + [286] = { "sys_getsockname", 0 }, + [287] = { "sys_getpeername", 0 }, + [288] = { "sys_socketpair", 0 }, + [289] = { "sys_send", 0 }, + [290] = { "sys_sendto", 0 }, + [291] = { "sys_recv", 0 }, + [292] = { "sys_recvfrom", 0 }, + [293] = { "sys_shutdown", 0 }, + [294] = { "sys_setsockopt", 0 }, + [295] = { "sys_getsockopt", 0 }, + [296] = { "sys_sendmsg", 0 }, + [297] = { "sys_recvmsg", 0 }, + [298] = { "sys_semop", 0 }, + [299] = { "sys_semget", 0 }, + [300] = { "sys_old_semctl", 0 }, + [301] = { "sys_msgsnd", 0 }, + [302] = { "sys_msgrcv", 0 }, + [303] = { "sys_msgget", 0 }, + [304] = { "sys_old_msgctl", 0 }, + [305] = { "sys_shmat", 0 }, + [306] = { "sys_shmdt", 0 }, + [307] = { "sys_shmget", 0 }, + [308] = { "sys_old_shmctl", 0 }, + [309] = { "sys_add_key", 0 }, + [310] = { "sys_request_key", 0 }, + [311] = { "sys_keyctl", 0 }, + [312] = { "sys_semtimedop_time32", 0 }, + [314] = { "sys_ioprio_set", 0 }, + [315] = { "sys_ioprio_get", 0 }, + [316] = { "sys_inotify_init", 0 }, + [317] = { "sys_inotify_add_watch", 0 }, + [318] = { "sys_inotify_rm_watch", 0 }, + [319] = { "sys_mbind", 0 }, + [320] = { "sys_get_mempolicy", 0 }, + [321] = { "sys_set_mempolicy", 0 }, + [322] = { "sys_openat", 0 }, + [323] = { "sys_mkdirat", 0 }, + [324] = { "sys_mknodat", 0 }, + [325] = { "sys_fchownat", 0 }, + [326] = { "sys_futimesat_time32", 0 }, + [327] = { "sys_fstatat64", 0 }, + [328] = { "sys_unlinkat", 0 }, + [329] = { "sys_renameat", 0 }, + [330] = { "sys_linkat", 0 }, + [331] = { "sys_symlinkat", 0 }, + [332] = { "sys_readlinkat", 0 }, + [333] = { "sys_fchmodat", 0 }, + [334] = { "sys_faccessat", 0 }, + [335] = { "sys_pselect6_time32", 0 }, + [336] = { "sys_ppoll_time32", 0 }, + [337] = { "sys_unshare", 0 }, + [338] = { "sys_set_robust_list", 0 }, + [339] = { "sys_get_robust_list", 0 }, + [340] = { "sys_splice", 0 }, + [341] = { "sys_aarch32_sync_file_range2", 0 }, + [342] = { "sys_tee", 0 }, + [343] = { "sys_vmsplice", 0 }, + [344] = { "sys_move_pages", 0 }, + [345] = { "sys_getcpu", 0 }, + [346] = { "sys_epoll_pwait", 0 }, + [347] = { "sys_kexec_load", 0 }, + [348] = { "sys_utimensat_time32", 0 }, + [349] = { "sys_signalfd", 0 }, + [350] = { "sys_timerfd_create", 0 }, + [351] = { "sys_eventfd", 0 }, + [352] = { "sys_aarch32_fallocate", 0 }, + [353] = { "sys_timerfd_settime32", 0 }, + [354] = { "sys_timerfd_gettime32", 0 }, + [355] = { "sys_signalfd4", 0 }, + [356] = { "sys_eventfd2", 0 }, + [357] = { "sys_epoll_create1", 0 }, + [358] = { "sys_dup3", 0 }, + [359] = { "sys_pipe2", 0 }, + [360] = { "sys_inotify_init1", 0 }, + [361] = { "sys_preadv", 0 }, + [362] = { "sys_pwritev", 0 }, + [363] = { "sys_rt_tgsigqueueinfo", 0 }, + [364] = { "sys_perf_event_open", 0 }, + [365] = { "sys_recvmmsg_time32", 0 }, + [366] = { "sys_accept4", 0 }, + [367] = { "sys_fanotify_init", 0 }, + [368] = { "sys_fanotify_mark", 0 }, + [369] = { "sys_prlimit64", 0 }, + [370] = { "sys_name_to_handle_at", 0 }, + [371] = { "sys_open_by_handle_at", 0 }, + [372] = { "sys_clock_adjtime32", 0 }, + [373] = { "sys_syncfs", 0 }, + [374] = { "sys_sendmmsg", 0 }, + [375] = { "sys_setns", 0 }, + [376] = { "sys_process_vm_readv", 0 }, + [377] = { "sys_process_vm_writev", 0 }, + [378] = { "sys_kcmp", 0 }, + [379] = { "sys_finit_module", 0 }, + [380] = { "sys_sched_setattr", 0 }, + [381] = { "sys_sched_getattr", 0 }, + [382] = { "sys_renameat2", 0 }, + [383] = { "sys_seccomp", 0 }, + [384] = { "sys_getrandom", 0 }, + [385] = { "sys_memfd_create", 0 }, + [386] = { "sys_bpf", 0 }, + [387] = { "sys_execveat", 0 }, + [388] = { "sys_userfaultfd", 0 }, + [389] = { "sys_membarrier", 0 }, + [390] = { "sys_mlock2", 0 }, + [391] = { "sys_copy_file_range", 0 }, + [392] = { "sys_preadv2", 0 }, + [393] = { "sys_pwritev2", 0 }, + [394] = { "sys_pkey_mprotect", 0 }, + [395] = { "sys_pkey_alloc", 0 }, + [396] = { "sys_pkey_free", 0 }, + [397] = { "sys_statx", 0 }, + [398] = { "sys_rseq", 0 }, + [399] = { "sys_io_pgetevents", 0 }, + [400] = { "sys_migrate_pages", 0 }, + [401] = { "sys_kexec_file_load", 0 }, + [403] = { "sys_clock_gettime", 0 }, + [404] = { "sys_clock_settime", 0 }, + [405] = { "sys_clock_adjtime", 0 }, + [406] = { "sys_clock_getres", 0 }, + [407] = { "sys_clock_nanosleep", 0 }, + [408] = { "sys_timer_gettime", 0 }, + [409] = { "sys_timer_settime", 0 }, + [410] = { "sys_timerfd_gettime", 0 }, + [411] = { "sys_timerfd_settime", 0 }, + [412] = { "sys_utimensat", 0 }, + [413] = { "sys_pselect6_time64", 0 }, + [414] = { "sys_ppoll_time64", 0 }, + [416] = { "sys_io_pgetevents", 0 }, + [417] = { "sys_recvmmsg_time64", 0 }, + [418] = { "sys_mq_timedsend", 0 }, + [419] = { "sys_mq_timedreceive", 0 }, + [420] = { "sys_semtimedop", 0 }, + [421] = { "sys_rt_sigtimedwait_time64", 0 }, + [422] = { "sys_futex", 0 }, + [423] = { "sys_sched_rr_get_interval", 0 }, + [424] = { "sys_pidfd_send_signal", 0 }, + [425] = { "sys_io_uring_setup", 0 }, + [426] = { "sys_io_uring_enter", 0 }, + [427] = { "sys_io_uring_register", 0 }, + [428] = { "sys_open_tree", 0 }, + [429] = { "sys_move_mount", 0 }, + [430] = { "sys_fsopen", 0 }, + [431] = { "sys_fsconfig", 0 }, + [432] = { "sys_fsmount", 0 }, + [433] = { "sys_fspick", 0 }, + [434] = { "sys_pidfd_open", 0 }, + [435] = { "sys_clone3", 0 }, + [436] = { "sys_close_range", 0 }, + [437] = { "sys_openat2", 0 }, + [438] = { "sys_pidfd_getfd", 0 }, + [439] = { "sys_faccessat2", 0 }, + [440] = { "sys_process_madvise", 0 }, + [441] = { "sys_epoll_pwait2", 0 }, + [442] = { "sys_mount_setattr", 0 }, + [443] = { "sys_quotactl_fd", 0 }, + [444] = { "sys_landlock_create_ruleset", 0 }, + [445] = { "sys_landlock_add_rule", 0 }, + [446] = { "sys_landlock_restrict_self", 0 }, + [448] = { "sys_process_mrelease", 0 }, + [449] = { "sys_futex_waitv", 0 }, + [450] = { "sys_set_mempolicy_home_node", 0 }, + [451] = { "sys_cachestat", 0 }, +}; +KP_EXPORT_SYMBOL(compat_syscall_name_table); diff --git a/kernel/patch/common/taskob.c b/kernel/patch/common/taskob.c index b41f079d..5b10b9be 100644 --- a/kernel/patch/common/taskob.c +++ b/kernel/patch/common/taskob.c @@ -17,9 +17,9 @@ #include #include #include -#include #include #include +#include static inline void prepare_init_ext(struct task_struct *task) { @@ -27,7 +27,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 +43,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 = offsetof(struct task_ext, _magic); +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 +75,19 @@ int task_observer() prepare_init_ext(init_task); - // __switch_to - unsigned long copy_process_addr = get_preset_patch_sym()->copy_process; + unsigned long copy_process_addr = patch_config->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; + unsigned long cgroup_post_fork_addr = patch_config->cgroup_post_fork; + 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/user_event.c b/kernel/patch/common/user_event.c new file mode 100644 index 00000000..aeac207b --- /dev/null +++ b/kernel/patch/common/user_event.c @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 bmax121. All Rights Reserved. + */ + +#include + +#include + +int report_user_event(const char *event, const char *args) +{ + logki("user report event: %s, args: %s\n", event, args); + return 0; +} \ No newline at end of file diff --git a/kernel/patch/common/utils.c b/kernel/patch/common/utils.c index 6ae68dc3..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); @@ -118,20 +120,20 @@ struct pt_regs *_task_pt_reg(struct task_struct *task) { unsigned long stack = (unsigned long)task_stack_page(task); uintptr_t addr = (uintptr_t)(thread_size + stack); - if (likely(pt_regs_offset > 0)) { + if (pt_regs_offset > 0) { addr -= pt_regs_offset; } 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); // 0x130 } else #endif - if (kver < VERSION(4, 14, 0)) { - addr -= sizeof(struct pt_regs_lt4140); - } else if (kver < VERSION(5, 10, 0)) { - addr -= sizeof(struct pt_regs_lt5100); + if (kver < VERSION(5, 10, 0)) { + 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..829fe53f 100644 --- a/kernel/patch/include/accctl.h +++ b/kernel/patch/include/accctl.h @@ -11,26 +11,30 @@ #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 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_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_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 +/** + * @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/hotpatch.h b/kernel/patch/include/hotpatch.h index 983d72d0..48c405a2 100644 --- a/kernel/patch/include/hotpatch.h +++ b/kernel/patch/include/hotpatch.h @@ -8,6 +8,4 @@ #include -int patch_verify_safety(); - #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/kstorage.h b/kernel/patch/include/kstorage.h new file mode 100644 index 00000000..fca8c68a --- /dev/null +++ b/kernel/patch/include/kstorage.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 bmax121. All Rights Reserved. + */ + +#ifndef _KP_KSTORAGE_H_ +#define _KP_KSTORAGE_H_ + +#include +#include +#include + +struct kstorage +{ + struct list_head list; + struct rcu_head rcu; + + int gid; + long did; + int dlen; + char data[0]; +}; + +int try_alloc_kstroage_group(); + +int kstorage_group_size(int gid); + +int write_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user); + +/// must within rcu read lock +const struct kstorage *get_kstorage(int gid, long did); + +typedef int (*on_kstorage_cb)(struct kstorage *kstorage, void *udata); +int on_each_kstorage_elem(int gid, on_kstorage_cb cb, void *udata); + +int read_kstorage(int gid, long did, void *data, int offset, int len, bool data_is_user); + +int list_kstorage_ids(int gid, long *ids, int idslen, bool data_is_user); + +int remove_kstorage(int gid, long did); + +#endif \ No newline at end of file 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/pidmem.h b/kernel/patch/include/pidmem.h index 5cb10c2e..e9761f16 100644 --- a/kernel/patch/include/pidmem.h +++ b/kernel/patch/include/pidmem.h @@ -8,7 +8,7 @@ #include -phys_addr_t pid_virt_to_phys(pid_t pid, uintptr_t vaddr); +// phys_addr_t pid_virt_to_phys(pid_t pid, uintptr_t vaddr); // void *pid_map_mem(pid_t pid, void *mem, size_t size, ) diff --git a/kernel/patch/include/sepolicy_flags.h b/kernel/patch/include/sepolicy_flags.h new file mode 100644 index 00000000..4a6b9216 --- /dev/null +++ b/kernel/patch/include/sepolicy_flags.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 1f2003d5. All Rights Reserved. + * Copyright (C) 2024 sekaiacg. All Rights Reserved. + */ + +#ifndef _KP_SEPOLICY_FLAGS_H_ +#define _KP_SEPOLICY_FLAGS_H_ + +#include + +#define SELINUX_MAGIC 0xf97cff8c +#define POLICYDB_MAGIC SELINUX_MAGIC +#define POLICYDB_STRING "SE Linux" + +#define POLICYDB_CONFIG_MLS 1 +#define POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE (1 << 31) +#define POLICYDB_CONFIG_ANDROID_NETLINK_GETNEIGH (1 << 30) + +/* + * config offset: + * __le32(POLICYDB_MAGIC) + __le32(POLICYDB_STRING_LEN) + + * char[POLICYDB_STRING_LEN] + __le32(policyvers) + */ +#define POLICYDB_CONFIG_OFFSET (2 * sizeof(__le32) + strlen(POLICYDB_STRING) + sizeof(__le32)) + +struct _policy_file +{ + char *data; + size_t len; +}; + +struct _policydb +{ + int mls_enabled; + int android_netlink_route; + int android_netlink_getneigh; +}; + +#endif \ No newline at end of file diff --git a/kernel/patch/include/sucompat.h b/kernel/patch/include/sucompat.h index f2277871..f09a95e7 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 { @@ -17,7 +23,17 @@ struct allow_uid struct rcu_head rcu; }; -struct su_profile profile_su_allow_uid(uid_t uid); int is_su_allow_uid(uid_t uid); +int su_add_allow_uid(uid_t uid, uid_t to_uid, const char *scontext); +int su_remove_allow_uid(uid_t uid); +int su_allow_uid_nums(); +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); +const char *su_get_path(); + +int get_ap_mod_exclude(uid_t uid); +int set_ap_mod_exclude(uid_t uid, int exclude); +int list_ap_mod_exclude(uid_t *uids, int len); #endif diff --git a/kernel/patch/include/syscall.h b/kernel/patch/include/syscall.h index c49223e9..a20bfc7f 100644 --- a/kernel/patch/include/syscall.h +++ b/kernel/patch/include/syscall.h @@ -12,10 +12,21 @@ #include #include -extern uintptr_t *sys_call_table; extern int has_syscall_wrapper; +extern struct +{ + const char *name; + uintptr_t addr; +} syscall_name_table[460]; + +extern struct +{ + const char *name; + uintptr_t addr; +} 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); long raw_syscall0(long nr); @@ -28,6 +39,10 @@ long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 #define raw_syscall(f) raw_syscall##f +uintptr_t syscalln_name_addr(int nr, int is_compat); + +uintptr_t syscalln_addr(int nr, int is_compat); + static inline uint64_t *syscall_args(void *hook_fargs) { uint64_t *args; @@ -55,37 +70,100 @@ static inline void *syscall_argn_p(void *fdata_args, int n) return syscall_args(fdata_args) + n; } +/** + * @brief + * + * @param nr + * @param narg + * @param is_compat + * @param before + * @param after + * @param udata + * @return hook_err_t + */ +hook_err_t fp_wrap_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 fp_unwrap_syscalln(int nr, int is_compat, void *before, void *after); + static inline hook_err_t fp_hook_syscalln(int nr, int narg, void *before, void *after, void *udata) { - 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); + return fp_wrap_syscalln(nr, narg, 0, before, after, udata); +} + +static inline void fp_unhook_syscalln(int nr, void *before, void *after) +{ + return fp_unwrap_syscalln(nr, 0, before, after); +} + +static inline hook_err_t fp_hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata) +{ + return fp_wrap_syscalln(nr, narg, 1, before, after, udata); } -static inline void fp_unhook_syscall(int nr, void *before, void *after) +static inline void fp_unhook_compat_syscalln(int nr, void *before, void *after) { - uintptr_t fp_addr = (uintptr_t)(sys_call_table + nr); - fp_hook_unwrap(fp_addr, before, after); + return fp_unwrap_syscalln(nr, 1, before, after); } -/* -xxx.cfi_jt example: -hint #0x22 -b #0xfffffffffeb452f4 -*/ +/** + * @brief + * + * @param nr + * @param narg + * @param is_compat + * @param before + * @param after + * @param udata + * @return hook_err_t + */ +hook_err_t inline_wrap_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_unwrap_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_wrap_syscalln(nr, narg, 0, before, after, udata); +} + +static inline void inline_unhook_syscalln(int nr, void *before, void *after) +{ + inline_unwrap_syscalln(nr, 0, before, after); } -static inline void inline_unhook_syscall(int nr, void *before, void *after) +static inline hook_err_t inline_hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata) { - uintptr_t fp = sys_call_table[nr]; - hook_unwrap((void *)fp, before, after); + return inline_wrap_syscalln(nr, narg, 1, before, after, udata); } -int syscall_init(); +static inline void inline_unhook_compat_syscalln(int nr, void *before, void *after) +{ + inline_unwrap_syscalln(nr, 0, before, after); +} + +// + +hook_err_t hook_syscalln(int nr, int narg, void *before, void *after, void *udata); + +void unhook_syscalln(int nr, void *before, void *after); + +hook_err_t hook_compat_syscalln(int nr, int narg, void *before, void *after, void *udata); + +void unhook_compat_syscalln(int nr, void *before, void *after); #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..0cd22f0c 100644 --- a/kernel/patch/include/uapi/scdefs.h +++ b/kernel/patch/include/uapi/scdefs.h @@ -23,6 +23,7 @@ static inline long hash_key(const char *key) #define SUPERCALL_HELLO 0x1000 #define SUPERCALL_KLOG 0x1004 +#define SUPERCALL_BUILD_TIME 0x1007 #define SUPERCALL_KERNELPATCH_VER 0x1008 #define SUPERCALL_KERNEL_VER 0x1009 @@ -41,12 +42,23 @@ static inline long hash_key(const char *key) #define SUPERCALL_KPM_LIST 0x1031 #define SUPERCALL_KPM_INFO 0x1032 -#define SUPERCALL_MEM_PHYS 0x1041 -#define SUPERCALL_MEM_KERNEL_PHYS 0x1042 -#define SUPERCALL_MEM_MAP_KERNEL 0x1048 -#define SUPERCALL_MEM_MAP_USER 0x1049 -#define SUPERCALL_MEM_PROT 0x1049 -#define SUPERCALL_MEM_CACHE_FLUSH 0x1049 +struct kernel_storage +{ + void *data; + int len; +}; + +#define SUPERCALL_KSTORAGE_ALLOC_GROUP 0x1040 +#define SUPERCALL_KSTORAGE_WRITE 0x1041 +#define SUPERCALL_KSTORAGE_READ 0x1042 +#define SUPERCALL_KSTORAGE_LIST_IDS 0x1043 +#define SUPERCALL_KSTORAGE_REMOVE 0x1044 +#define SUPERCALL_KSTORAGE_REMOVE_GROUP 0x1045 + +#define KSTORAGE_SU_LIST_GROUP 0 +#define KSTORAGE_EXCLUDE_LIST_GROUP 1 +#define KSTORAGE_UNUSED_GROUP_2 2 +#define KSTORAGE_UNUSED_GROUP_3 3 #define SUPERCALL_BOOTLOG 0x10fd #define SUPERCALL_PANIC 0x10fe @@ -63,39 +75,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_SU_GET_SAFEMODE 0x1112 #define SUPERCALL_MAX 0x1200 diff --git a/kernel/patch/include/user_event.h b/kernel/patch/include/user_event.h new file mode 100644 index 00000000..c64f61bd --- /dev/null +++ b/kernel/patch/include/user_event.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 bmax121. All Rights Reserved. + */ + +#ifndef _KP_USER_EVENT_H_ +#define _KP_USER_EVENT_H_ + +int report_user_event(const char *event, const char *args); + +#endif \ No newline at end of file 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/ksyms/task_cred.c b/kernel/patch/ksyms/task_cred.c index 216ec48c..6d4036b3 100644 --- a/kernel/patch/ksyms/task_cred.c +++ b/kernel/patch/ksyms/task_cred.c @@ -476,13 +476,14 @@ int resolve_current() init_task = (struct task_struct *)kallsyms_lookup_name("init_task"); uint64_t init_thread_union_addr = kallsyms_lookup_name("init_thread_union"); + #if 0 init_task = 0; init_thread_union_addr = 0; #endif - log_boot(" init_task lookup: %llx\n", init_task); - log_boot(" init_thread_union lookup: %llx\n", init_thread_union_addr); + log_boot(" init_task addr lookup: %llx\n", init_task); + log_boot(" init_thread_union addr lookup: %llx\n", init_thread_union_addr); if (is_kimg_range(sp_el0)) { if (sp_el0 == init_thread_union_addr) { @@ -585,11 +586,19 @@ int resolve_current() return 0; } +// todo int resolve_mm_struct_offset() { + if (!init_mm) return 0; + log_boot("struct mm_struct: \n"); + // struct mm_struct *mm = get_task_mm(init_task); + // uintptr_t init_mm_addr = (uintptr_t)mm; + uintptr_t init_mm_addr = (uintptr_t)init_mm; + if (!init_mm_addr) return 0; + for (uintptr_t i = init_mm_addr; i < init_mm_addr + MM_STRUCT_MAX_SIZE; i += sizeof(uintptr_t)) { uint64_t pgd = *(uintptr_t *)i; if (pgd == phys_to_kimg(pgd_pa)) { @@ -605,8 +614,11 @@ int resolve_struct() full_cap = CAP_FULL_SET; int err = 0; + if ((err = resolve_current())) goto out; + if ((err = resolve_task_offset())) goto out; + if ((err = resolve_cred_offset())) goto out; resolve_mm_struct_offset(); diff --git a/kernel/patch/module/module.c b/kernel/patch/module/module.c index ea1c2c1c..087cd4bf 100644 --- a/kernel/patch/module/module.c +++ b/kernel/patch/module/module.c @@ -58,12 +58,7 @@ static char *next_string(char *string, unsigned long *secsize) /* Update size with this section: return offset. */ static long get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr, unsigned int section) { - long ret; - /* Additional bytes needed by arch in front of individual sections */ - int arm64_mod_section_prepend = 0; - *size += arm64_mod_section_prepend; - ret = ALIGN(*size, sechdr->sh_addralign ?: 1); - ret = *size; + long ret = ALIGN(*size, sechdr->sh_addralign ?: 1); *size = ret + sechdr->sh_size; return ret; } @@ -460,6 +455,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 +486,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 +524,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 +627,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 +650,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..1f3d4dd8 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,72 @@ void before_panic(hook_fargs12_t *args, void *udata) printk("==== End KernelPatch for Kernel panic ====\n"); } +void linux_misc_symbol_init(); +void linux_libs_symbol_init(); + +int resolve_struct(); +int task_observer(); +int bypass_kcfi(); +int bypass_selinux(); +int resolve_pt_regs(); +int supercall_install(); +void module_init(); +void syscall_init(); +int kstorage_init(); +int su_compat_init(); + +#ifdef ANDROID +int android_user_init(); +int android_sepolicy_flags_fix(); +#endif + 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 = kstorage_init(); + log_boot("kstorage_init 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 = android_sepolicy_flags_fix(); + log_boot("android_sepolicy_flags_fix 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 +112,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) @@ -120,31 +122,36 @@ static void after_kernel_init(hook_fargs4_t *args, void *udata) 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; + unsigned long panic_addr = patch_config->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; + unsigned long init_addr = patch_config->rest_init; + if (!init_addr) init_addr = patch_config->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; + unsigned long kernel_init_addr = patch_config->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/CMakeLists.txt b/tools/CMakeLists.txt index d6ddfc7b..f998fd87 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -19,4 +19,10 @@ set(SOURCES add_executable( kptools ${SOURCES} -) \ No newline at end of file +) + +find_package(ZLIB REQUIRED) + +target_link_libraries(kptools PRIVATE ${ZLIB_LIBRARIES}) + +target_include_directories(kptools PRIVATE ${ZLIB_INCLUDE_DIRS}) \ No newline at end of file diff --git a/tools/Makefile b/tools/Makefile index 4218ac6c..a065542b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,6 +1,6 @@ CFLAGS = -std=c11 -Wall -Wextra -Wno-unused -Wno-unused-parameter - +LDFLAGS = -lz ifdef DEBUG CFLAGS += -DDEBUG -g endif @@ -13,7 +13,7 @@ all: kptools .PHONY: kptools kptools: ${objs} - ${CC} -o $@ $^ + ${CC} -o $@ $^ $(LDFLAGS) %.o : %.c $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ diff --git a/tools/kallsym.c b/tools/kallsym.c index ebfc0219..e49777fb 100644 --- a/tools/kallsym.c +++ b/tools/kallsym.c @@ -17,6 +17,28 @@ #include "insn.h" #include "common.h" +#define IKCFG_ST "IKCFG_ST" +#define IKCFG_ED "IKCFG_ED" +#include "zlib.h" + +#ifdef _WIN32 +#include +static void *memmem(const void *haystack, size_t haystack_len, const void *const needle, const size_t needle_len) +{ + if (haystack == NULL) return NULL; // or assert(haystack != NULL); + if (haystack_len == 0) return NULL; + if (needle == NULL) return NULL; // or assert(needle != NULL); + if (needle_len == 0) return NULL; + + for (const char *h = haystack; haystack_len >= needle_len; ++h, --haystack_len) { + if (!memcmp(h, needle, needle_len)) { + return (void *)h; + } + } + return NULL; +} +#endif + static int find_linux_banner(kallsym_t *info, char *img, int32_t imglen) { /* @@ -36,7 +58,7 @@ static int find_linux_banner(kallsym_t *info, char *img, int32_t imglen) char *imgend = img + imglen; char *banner = (char *)img; info->banner_num = 0; - while ((banner = (char *)memmem(banner + 1, imgend - banner, linux_banner_prefix, prefix_len)) != NULL) { + while ((banner = (char *)memmem(banner + 1, imgend - banner - 1, linux_banner_prefix, prefix_len)) != NULL) { if (isdigit(*(banner + prefix_len)) && *(banner + prefix_len + 1) == '.') { info->linux_banner_offset[info->banner_num++] = (int32_t)(banner - img); tools_logi("linux_banner %d: %s", info->banner_num, banner); @@ -81,6 +103,7 @@ static int find_token_table(kallsym_t *info, char *img, int32_t imglen) char nums_syms[20] = { '\0' }; for (int32_t i = 0; i < 10; i++) nums_syms[i * 2] = '0' + i; + // We just check first 10 letters, not all letters are guaranteed to appear, // In fact, the previous numbers may not always appear too. char letters_syms[20] = { '\0' }; @@ -114,7 +137,11 @@ static int find_token_table(kallsym_t *info, char *img, int32_t imglen) } int32_t offset = pos + 2 - img; + // align + offset = align_ceil(offset, 4); + info->kallsyms_token_table_offset = offset; + tools_logi("kallsyms_token_table offset: 0x%08x\n", offset); // rebuild token_table @@ -169,15 +196,12 @@ static int find_token_index(kallsym_t *info, char *img, int32_t imglen) static int get_markers_elem_size(kallsym_t *info) { - /* - Before 4.20, type of kallsyms_markers is PTR which - depends on macro BITS_PER_LONG. When BITS_PER_LONG is 64, PTR is .quad (8 - bytes), otherwise .long (4bytes). Since 4.20, type of kallsyms_markers is - .long (4 bytes) - */ + if (info->kallsyms_markers_elem_size) return info->kallsyms_markers_elem_size; + int32_t elem_size = info->asm_long_size; if (info->version.major < 4 || (info->version.major == 4 && info->version.minor < 20)) elem_size = info->asm_PTR_size; + return elem_size; } @@ -203,6 +227,7 @@ static inline int get_offsets_elem_size(kallsym_t *info) static int try_find_arm64_relo_table(kallsym_t *info, char *img, int32_t imglen) { if (!info->try_relo) return 0; + uint64_t min_va = ELF64_KERNEL_MIN_VA; uint64_t max_va = ELF64_KERNEL_MAX_VA; uint64_t kernel_va = max_va; @@ -227,13 +252,12 @@ static int try_find_arm64_relo_table(kallsym_t *info, char *img, int32_t imglen) } } - if (info->elf64_kernel_base) { - tools_logi("find arm64 relocation kernel_va: 0x%" PRIx64 ", but try use: %" PRIx64 "\n", kernel_va, - info->elf64_kernel_base); - kernel_va = info->elf64_kernel_base; + if (info->kernel_base) { + tools_logi("arm64 relocation kernel_va: 0x%" PRIx64 ", try: %" PRIx64 "\n", kernel_va, info->kernel_base); + kernel_va = info->kernel_base; } else { - info->elf64_kernel_base = kernel_va; - tools_logi("find arm64 relocation kernel_va: 0x%" PRIx64 "\n", kernel_va); + info->kernel_base = kernel_va; + tools_logi("arm64 relocation kernel_va: 0x%" PRIx64 "\n", kernel_va); } int32_t cand_start = cand - 24 * rela_num; @@ -251,7 +275,7 @@ static int try_find_arm64_relo_table(kallsym_t *info, char *img, int32_t imglen) return 0; } - tools_logi("find arm64 relocation table range: [0x%08x, 0x%08x), count: 0x%08x\n", cand_start, cand_end, rela_num); + tools_logi("arm64 relocation table range: [0x%08x, 0x%08x), count: 0x%08x\n", cand_start, cand_end, rela_num); // apply relocations int32_t max_offset = imglen - 8; @@ -422,75 +446,49 @@ static int32_t find_approx_addresses_or_offset(kallsym_t *info, char *img, int32 static int find_num_syms(kallsym_t *info, char *img, int32_t imglen) { - int32_t approx_end = info->_approx_addresses_or_offsets_end; +#define NSYMS_MAX_GAP 10 + + int32_t approx_end = info->kallsyms_names_offset; // int32_t num_syms_elem_size = get_num_syms_elem_size(info); int32_t num_syms_elem_size = 4; int32_t approx_num_syms = info->_approx_addresses_or_offsets_num; - int32_t nsyms = 0; - int32_t nsyms_max_offset = approx_end + 4096; - int32_t NSYMS_MAX_GAP = 20; - int32_t LAST_SYM_EQUAL_NUM = 10; - int32_t cand = approx_end / num_syms_elem_size * num_syms_elem_size - LAST_SYM_EQUAL_NUM * num_syms_elem_size; - - for (; cand < nsyms_max_offset; cand += num_syms_elem_size) { - nsyms = (int)int_unpack(img + cand, num_syms_elem_size, info->is_be); - if (approx_num_syms >= nsyms && approx_num_syms - nsyms < NSYMS_MAX_GAP) break; - } - if (cand >= nsyms_max_offset) { - tools_loge("kallsyms_num_syms error\n"); - return -1; - } else { + for (int32_t cand = approx_end; cand > approx_end - 4096; cand -= num_syms_elem_size) { + int nsyms = (int)int_unpack(img + cand, num_syms_elem_size, info->is_be); + if (!nsyms) continue; + if (approx_num_syms > nsyms && approx_num_syms - nsyms > NSYMS_MAX_GAP) continue; + if (nsyms > approx_num_syms && nsyms - approx_num_syms > NSYMS_MAX_GAP) continue; + // find info->kallsyms_num_syms = nsyms; info->kallsyms_num_syms_offset = cand; - tools_logi("kallsyms_num_syms offset: 0x%08x, value: 0x%08x\n", cand, nsyms); + break; } - return 0; -} -static int find_markers_1(kallsym_t *info, char *img, int32_t imglen) -{ - int32_t elem_size = get_markers_elem_size(info); - int32_t cand = info->kallsyms_token_table_offset - elem_size; - int64_t marker; - for (;; cand -= elem_size) { - marker = int_unpack(img + cand, elem_size, info->is_be); - if (marker) break; - } - int32_t marker_end = cand + elem_size; - int64_t last_marker = 0x7fffffff; - for (;; cand -= elem_size) { - marker = int_unpack(img + cand, elem_size, info->is_be); - if (!marker || last_marker <= marker) break; - last_marker = marker; - } - int32_t marker_num = (marker_end - cand) / elem_size; - if (marker || marker_num < KSYM_MIN_MARKER) { - tools_loge("find kallsyms_markers error\n"); - return -1; + if (info->kallsyms_num_syms_offset) { + info->kallsyms_num_syms = approx_num_syms - NSYMS_MAX_GAP; + tools_logw("can't find kallsyms_num_syms, try: 0x%08x\n", info->kallsyms_num_syms); + } else { + tools_logi("kallsyms_num_syms offset: 0x%08x, value: 0x%08x\n", info->kallsyms_num_syms_offset, + info->kallsyms_num_syms); } - info->kallsyms_markers_offset = cand; - info->_marker_num = marker_num; - tools_logi("kallsyms_markers range: [0x%08x, 0x%08x), count: 0x%08x\n", cand, marker_end, marker_num); return 0; } -static int find_markers_2(kallsym_t *info, char *img, int32_t imglen) +static int find_markers_internal(kallsym_t *info, char *img, int32_t imglen, int32_t elem_size) { - int32_t elem_size = get_markers_elem_size(info); - int32_t cand = info->kallsyms_token_table_offset - KSYM_MIN_MARKER * elem_size; + int32_t cand = info->kallsyms_token_table_offset; - int64_t marker, last_marker = 0x7fffffff; + int64_t marker, last_marker = imglen; int count = 0; - while (cand > 0x1000) { + while (cand > 0x10000) { marker = int_unpack(img + cand, elem_size, info->is_be); if (last_marker > marker) { count++; if (!marker && count > KSYM_MIN_MARKER) break; } else { count = 0; - last_marker = 0x7fffffff; + last_marker = imglen; } last_marker = marker; @@ -505,17 +503,20 @@ static int find_markers_2(kallsym_t *info, char *img, int32_t imglen) int32_t marker_end = cand + count * elem_size + elem_size; info->kallsyms_markers_offset = cand; info->_marker_num = count; + info->kallsyms_markers_elem_size = elem_size; tools_logi("kallsyms_markers range: [0x%08x, 0x%08x), count: 0x%08x\n", cand, marker_end, count); return 0; } -static inline int find_markers(kallsym_t *info, char *img, int32_t imglen) +static int find_markers(kallsym_t *info, char *img, int32_t imglen) { - // todo: remove one - int rc = find_markers_1(info, img, imglen); - if (!rc) return rc; - return find_markers_2(info, img, imglen); + int32_t elem_size = get_markers_elem_size(info); + int rc = find_markers_internal(info, img, imglen, elem_size); + if (rc && elem_size == 8) { + return find_markers_internal(info, img, imglen, 4); + } + return rc; } static int decompress_symbol_name(kallsym_t *info, char *img, int32_t *pos_to_next, char *out_type, char *out_symbol) @@ -558,7 +559,8 @@ static int is_symbol_name_pos(kallsym_t *info, char *img, int32_t pos, char *sym static int find_names(kallsym_t *info, char *img, int32_t imglen) { int32_t marker_elem_size = get_markers_elem_size(info); - int32_t cand = info->_approx_addresses_or_offsets_offset; + // int32_t cand = info->_approx_addresses_or_offsets_offset; + int32_t cand = 0x4000; int32_t test_marker_num = -1; for (; cand < info->kallsyms_markers_offset; cand++) { int32_t pos = cand; @@ -604,7 +606,7 @@ static int find_names(kallsym_t *info, char *img, int32_t imglen) return 0; } -int arm64_verify_pid_vnr(kallsym_t *info, char *img, int32_t offset) +static int arm64_verify_pid_vnr(kallsym_t *info, char *img, int32_t offset) { for (int i = 0; i < 6; i++) { int32_t insn_offset = offset + i * 4; @@ -612,15 +614,15 @@ int arm64_verify_pid_vnr(kallsym_t *info, char *img, int32_t offset) enum aarch64_insn_encoding_class enc = aarch64_get_insn_class(insn); if (enc == AARCH64_INSN_CLS_BR_SYS) { if (aarch64_insn_extract_system_reg(insn) == AARCH64_INSN_SPCLREG_SP_EL0) { - info->elf64_current_heuris = AARCH64_INSN_SPCLREG_SP_EL0; - tools_logi("pid_vnr verfied succeed, sp_el0, insn: 0x%x\n", insn); + tools_logi("pid_vnr verfied sp_el0, insn: 0x%x\n", insn); + info->current_type = SP_EL0; return 0; } } else if (enc == AARCH64_INSN_CLS_DP_IMM) { u32 rn = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RN, insn); if (rn == AARCH64_INSN_REG_SP) { - info->elf64_current_heuris = AARCH64_INSN_REG_SP; - tools_logi("pid_vnr verfied succeed, sp, insn: 0x%x\n", insn); + tools_logi("pid_vnr verfied sp, insn: 0x%x\n", insn); + info->current_type = SP; return 0; } } @@ -658,28 +660,48 @@ static int correct_addresses_or_offsets_by_vectors(kallsym_t *info, char *img, i } int32_t elem_size = info->has_relative_base ? get_offsets_elem_size(info) : get_addresses_elem_size(info); - uint64_t first_elem_val = uint_unpack(img + info->_approx_addresses_or_offsets_offset, elem_size, info->is_be); - // we need some buffer, for some kernel _head(stripped) is ffffff8008080000 and stext (first symbol) is ffffff8008080800, + uint64_t base_cand[3] = { 0 }; + int base_cand_num = 1; + + if (!info->has_relative_base) { + uint64_t base = uint_unpack(img + info->_approx_addresses_or_offsets_offset, elem_size, info->is_be); + base_cand[0] = base; + if (info->kernel_base) { + base_cand[++base_cand_num] = info->kernel_base; + } + if (info->kernel_base != ELF64_KERNEL_MIN_VA) { + base_cand[++base_cand_num] = ELF64_KERNEL_MIN_VA; + } + } + int32_t search_start = info->_approx_addresses_or_offsets_offset; int32_t search_end = info->_approx_addresses_or_offsets_end - pid_vnr_index * elem_size; - // search - for (pos = search_start; pos < search_end; pos += elem_size) { - int32_t vector_offset = - uint_unpack(img + pos + vector_index * elem_size, elem_size, info->is_be) - first_elem_val; - int32_t vector_next_offset = - uint_unpack(img + pos + vector_index * elem_size + elem_size, elem_size, info->is_be) - first_elem_val; - if (vector_next_offset - vector_offset >= 0x600 && (vector_offset & ((1 << 11) - 1)) == 0) { - int32_t pid_vnr_offset = - uint_unpack(img + pos + pid_vnr_index * elem_size, elem_size, info->is_be) - first_elem_val; - if (!arm64_verify_pid_vnr(info, img, pid_vnr_offset)) { - tools_logi("vectors offset: 0x%08x\n", vector_offset); - tools_logi("pid_vnr offset: 0x%08x\n", pid_vnr_offset); - break; + int break_flag = 0; + for (int i = 0; i < base_cand_num; i++) { + uint64_t base = base_cand[i]; + + for (pos = search_start; pos < search_end; pos += elem_size) { + int32_t vector_offset = uint_unpack(img + pos + vector_index * elem_size, elem_size, info->is_be) - base; + int32_t vector_next_offset = + uint_unpack(img + pos + vector_index * elem_size + elem_size, elem_size, info->is_be) - base; + if (vector_next_offset - vector_offset >= 0x600 && (vector_offset & ((1 << 11) - 1)) == 0) { + int32_t pid_vnr_offset = + uint_unpack(img + pos + pid_vnr_index * elem_size, elem_size, info->is_be) - base; + if (!arm64_verify_pid_vnr(info, img, pid_vnr_offset)) { + tools_logi("vectors index: %d, offset: 0x%08x\n", vector_index, vector_offset); + tools_logi("pid_vnr offset: 0x%08x\n", pid_vnr_offset); + info->kernel_base = base; + break_flag = 1; + break; + } } } + + if (break_flag) break; } + if (pos >= search_end) { tools_loge("can't locate vectors\n"); return -1; @@ -691,6 +713,7 @@ static int correct_addresses_or_offsets_by_vectors(kallsym_t *info, char *img, i } else { info->kallsyms_addresses_offset = pos; tools_logi("kallsyms_addresses offset: 0x%08x\n", pos); + tools_logi("kernel base address: 0x%08llx\n", info->kernel_base); } return 0; @@ -701,8 +724,7 @@ static int correct_addresses_or_offsets_by_banner(kallsym_t *info, char *img, in int32_t pos = info->kallsyms_names_offset; int32_t index = 0; char symbol[KSYM_SYMBOL_LEN] = { '\0' }; - // Pick a symbol (linux_banner) whose offset we know, use its index to fix the - // beginning of the addresses or offsets table + while (pos < info->kallsyms_markers_offset) { memset(symbol, 0, sizeof(symbol)); int32_t ret = decompress_symbol_name(info, img, &pos, NULL, symbol); @@ -712,6 +734,8 @@ static int correct_addresses_or_offsets_by_banner(kallsym_t *info, char *img, in tools_logi("names table linux_banner index: 0x%08x\n", index); break; } + if (!strcmp(symbol, "pid_vnr")) { + } index++; } @@ -730,8 +754,8 @@ static int correct_addresses_or_offsets_by_banner(kallsym_t *info, char *img, in int32_t end = pos + 4096 + elem_size; for (; pos < end; pos += elem_size) { - uint64_t first_elem_val = uint_unpack(img + pos, elem_size, info->is_be); - int32_t offset = uint_unpack(img + pos + index * elem_size, elem_size, info->is_be) - first_elem_val; + uint64_t base = uint_unpack(img + pos, elem_size, info->is_be); + int32_t offset = uint_unpack(img + pos + index * elem_size, elem_size, info->is_be) - base; if (offset == target_offset) break; } if (pos < end) { @@ -741,17 +765,27 @@ static int correct_addresses_or_offsets_by_banner(kallsym_t *info, char *img, in } } if (info->symbol_banner_idx < 0) { - tools_loge("correct addressed or offsets error\n"); + tools_loge("correct address or offsets error\n"); return -1; } + int32_t elem_size = info->has_relative_base ? get_offsets_elem_size(info) : get_addresses_elem_size(info); + if (info->has_relative_base) { info->kallsyms_offsets_offset = pos; tools_logi("kallsyms_offsets offset: 0x%08x\n", pos); } else { info->kallsyms_addresses_offset = pos; tools_logi("kallsyms_addresses offset: 0x%08x\n", pos); + info->kernel_base = uint_unpack(img + info->kallsyms_addresses_offset, elem_size, info->is_be); + tools_logi("kernel base address: 0x%llx\n", info->kernel_base); + } + + int32_t pid_vnr_offset = get_symbol_offset(info, img, "pid_vnr"); + if (arm64_verify_pid_vnr(info, img, pid_vnr_offset)) { + tools_logw("pid_vnr verification failed\n"); } + return 0; } @@ -760,9 +794,11 @@ static int correct_addresses_or_offsets(kallsym_t *info, char *img, int32_t imgl int rc = 0; #if 1 rc = correct_addresses_or_offsets_by_banner(info, img, imglen); + info->is_kallsysms_all_yes = 1; #endif if (rc) { - tools_logw("no linux_banner? maybe CONFIG_KALLSYMS_ALL=n?\n"); + info->is_kallsysms_all_yes = 0; + tools_logw("no linux_banner, CONFIG_KALLSYMS_ALL=n\n"); } if (rc) rc = correct_addresses_or_offsets_by_vectors(info, img, imglen); return rc; @@ -787,7 +823,7 @@ void init_not_tested_arch_kallsym_t(kallsym_t *info, int32_t is_64) if (is_64) info->asm_PTR_size = 8; } -int retry_relo_retry(kallsym_t *info, char *img, int32_t imglen) +static int retry_relo(kallsym_t *info, char *img, int32_t imglen) { int rc = -1; static int32_t (*funcs[])(kallsym_t *, char *, int32_t) = { @@ -834,21 +870,21 @@ int analyze_kallsym_info(kallsym_t *info, char *img, int32_t imglen, enum arch_t memcpy(copied_img, img, imglen); // 1st - rc = retry_relo_retry(info, copied_img, imglen); + rc = retry_relo(info, copied_img, imglen); if (!rc) goto out; // 2nd if (!info->try_relo) { memcpy(copied_img, img, imglen); - rc = retry_relo_retry(info, copied_img, imglen); + rc = retry_relo(info, copied_img, imglen); if (!rc) goto out; } // 3rd - if (info->elf64_kernel_base != ELF64_KERNEL_MIN_VA) { - info->elf64_kernel_base = ELF64_KERNEL_MIN_VA; + if (info->kernel_base != ELF64_KERNEL_MIN_VA) { + info->kernel_base = ELF64_KERNEL_MIN_VA; memcpy(copied_img, img, imglen); - rc = retry_relo_retry(info, copied_img, imglen); + rc = retry_relo(info, copied_img, imglen); } out: @@ -868,9 +904,9 @@ int32_t get_symbol_index_offset(kallsym_t *info, char *img, int32_t index) elem_size = get_addresses_elem_size(info); pos = info->kallsyms_addresses_offset; } - uint64_t first = uint_unpack(img + pos, elem_size, info->is_be); uint64_t target = uint_unpack(img + pos + index * elem_size, elem_size, info->is_be); - return (int32_t)(target - first); + if (info->has_relative_base) return target; + return (int32_t)(target - info->kernel_base); } int get_symbol_offset_and_size(kallsym_t *info, char *img, char *symbol, int32_t *size) @@ -934,6 +970,67 @@ int dump_all_symbols(kallsym_t *info, char *img) } return 0; } +int decompress_data(const unsigned char *compressed_data, size_t compressed_size) +{ + FILE *temp = fopen("temp.gz", "wb"); + if (!temp) { + fprintf(stderr, "Failed to create temp file\n"); + return -1; + } + + fwrite(compressed_data, 1, compressed_size, temp); + fclose(temp); + + gzFile gz = gzopen("temp.gz", "rb"); + if (!gz) { + fprintf(stderr, "Failed to open temp file for decompression\n"); + return -1; + } + + char buffer[1024]; + int bytes_read; + while ((bytes_read = gzread(gz, buffer, sizeof(buffer))) > 0) { + fwrite(buffer, 1, bytes_read, stdout); + } + + gzclose(gz); + return 0; +} + +int dump_all_ikconfig(char *img, int32_t imglen) +{ + char *pos_start = memmem(img, imglen, IKCFG_ST, strlen(IKCFG_ST)); + if (pos_start == NULL) { + fprintf(stderr, "Cannot find kernel config start (IKCFG_ST).\n"); + return 1; + } + size_t kcfg_start = pos_start - img + 8; + + // 查找 "IKCFG_ED" + char *pos_end = memmem(img, imglen, IKCFG_ED, strlen(IKCFG_ED)); + if (pos_end == NULL) { + fprintf(stderr, "Cannot find kernel config end (IKCFG_ED).\n"); + return 1; + } + size_t kcfg_end = pos_end - img - 1; + size_t kcfg_bytes = kcfg_end - kcfg_start + 1; + + printf("Kernel config start: %zu, end: %zu, bytes: %zu\n", kcfg_start, kcfg_end, kcfg_bytes); + + unsigned char *extracted_data = (unsigned char *)malloc(kcfg_bytes); + if (!extracted_data) { + fprintf(stderr, "Memory allocation for extracted data failed.\n"); + return 1; + } + + memcpy(extracted_data, img + kcfg_start, kcfg_bytes); + + int ret = decompress_data(extracted_data, kcfg_bytes); + + free(extracted_data); + + return 0; +} int on_each_symbol(kallsym_t *info, char *img, void *userdata, int32_t (*fn)(int32_t index, char type, const char *symbol, int32_t offset, void *userdata)) diff --git a/tools/kallsym.h b/tools/kallsym.h index 4643b162..28e9fe05 100644 --- a/tools/kallsym.h +++ b/tools/kallsym.h @@ -14,6 +14,8 @@ #define KSYM_TOKEN_NUMS 256 #define KSYM_SYMBOL_LEN 512 +#define KSYM_MAX_SYMS 1000000 + #define KSYM_MIN_NEQ_SYMS 25600 #define KSYM_MIN_MARKER (KSYM_MIN_NEQ_SYMS / 256) #define KSYM_FIND_NAMES_USED_MARKER 5 @@ -54,6 +56,12 @@ enum arch_type X86 }; +enum current_type +{ + SP_EL0, + SP +}; + #define ELF64_KERNEL_MIN_VA 0xffffff8008080000 #define ELF64_KERNEL_MAX_VA 0xffffffffffffffff @@ -78,6 +86,7 @@ typedef struct char *kallsyms_token_table[KSYM_TOKEN_NUMS]; int32_t asm_long_size; int32_t asm_PTR_size; + int32_t kallsyms_markers_elem_size; int32_t kallsyms_num_syms; int32_t has_relative_base; @@ -98,33 +107,19 @@ typedef struct int32_t try_relo; int32_t relo_applied; + uint64_t kernel_base; + int32_t elf64_rela_num; int32_t elf64_rela_offset; - uint64_t elf64_kernel_base; - int32_t elf64_current_heuris; -} kallsym_t; + int32_t is_kallsysms_all_yes; + enum current_type current_type; -#ifdef _WIN32 -#include -static void *memmem(const void *haystack, size_t haystack_len, const void *const needle, const size_t needle_len) -{ - if (haystack == NULL) return NULL; // or assert(haystack != NULL); - if (haystack_len == 0) return NULL; - if (needle == NULL) return NULL; // or assert(needle != NULL); - if (needle_len == 0) return NULL; - - for (const char *h = haystack; haystack_len >= needle_len; ++h, --haystack_len) { - if (!memcmp(h, needle, needle_len)) { - return (void *)h; - } - } - return NULL; -} -#endif +} kallsym_t; int analyze_kallsym_info(kallsym_t *info, char *img, int32_t imglen, enum arch_type arch, int32_t is_64); int dump_all_symbols(kallsym_t *info, char *img); +int dump_all_ikconfig(char *img, int32_t imglen); int get_symbol_index_offset(kallsym_t *info, char *img, int32_t index); int get_symbol_offset_and_size(kallsym_t *info, char *img, char *symbol, int32_t *size); int get_symbol_offset(kallsym_t *info, char *img, char *symbol); diff --git a/tools/kptools.c b/tools/kptools.c index af14d8d2..a322141e 100644 --- a/tools/kptools.c +++ b/tools/kptools.c @@ -43,6 +43,7 @@ void print_usage(char **argv) " -u, --unpatch Unpatch patched kernel image(-i).\n" " -r, --reset-skey Reset superkey of patched image(-i).\n" " -d, --dump Dump kallsyms infomations of kernel image(-i).\n" + " -f, --flag Dump ikconfig infomations of kernel image(-i).\n" " -l, --list Print all patch informations of kernel image if (-i) specified.\n" " Print extra item informations if (-M) specified.\n" " Print KernelPatch image informations if (-k) specified.\n" @@ -51,7 +52,7 @@ void print_usage(char **argv) " -i, --image PATH Kernel image path.\n" " -k, --kpimg PATH KernelPatch image path.\n" " -s, --skey KEY Set the superkey and save it directly in the boot.img.\n" - " -S, --root-skey KEY Set the root-superkey that uses hash verification, and the superkey can be changed dynamically.\n" + " -S, --root-skey KEY Set the root-superkey useing hash verification, and the superkey can be changed dynamically.\n" " -o, --out PATH Patched image path.\n" " -a --addition KEY=VALUE Add additional information.\n" @@ -81,16 +82,15 @@ int main(int argc, char *argv[]) { "unpatch", no_argument, NULL, 'u' }, { "resetkey", no_argument, NULL, 'r' }, { "dump", no_argument, NULL, 'd' }, - + { "flag", no_argument, NULL, 'f' }, { "list", no_argument, NULL, 'l' }, { "image", required_argument, NULL, 'i' }, { "kpimg", required_argument, NULL, 'k' }, { "skey", required_argument, NULL, 's' }, - { "skey-hash", required_argument, NULL, 'S' }, + { "root-skey", 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 +99,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 = "hvpurdfli: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; @@ -128,6 +127,7 @@ int main(int argc, char *argv[]) case 'u': case 'r': case 'd': + case 'f': case 'l': cmd = opt; break; @@ -148,9 +148,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,10 +187,12 @@ 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 == 'f') { + ret = dump_ikconfig(kimg_path); } else if (cmd == 'u') { ret = unpatch_img(kimg_path, out_path); } else if (cmd == 'r') { diff --git a/tools/patch.c b/tools/patch.c index cc887a89..9302929a 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; @@ -475,7 +462,7 @@ int patch_update_img(const char *kimg_path, const char *kpimg_path, const char * start_offset = align_ceil(out_all_len, SZ_4K); tools_logi("patch overlap, move start from 0x%x to 0x%x\n", align_kernel_size, start_offset); } - tools_logi("layout kimg: 0x0-0x%x, kpimg: 0x%x,0x%x, extra: 0x%x,0x%x, end: 0x%x, start: 0x%x\n", ori_kimg_len, + tools_logi("layout kimg: 0x0,0x%x, kpimg: 0x%x,0x%x, extra: 0x%x,0x%x, end: 0x%x, start: 0x%x\n", ori_kimg_len, align_kimg_len, kpimg_len, out_img_len, extra_size, out_all_len, start_offset); kernel_file_t out_kernel_file; @@ -544,7 +531,7 @@ int patch_update_img(const char *kimg_path, const char *kpimg_path, const char * memcpy(setup->header_backup, kallsym_kimg, sizeof(setup->header_backup)); // start symbol - fillin_patch_symbol(&kallsym, kallsym_kimg, ori_kimg_len, &setup->patch_symbol, kinfo->is_be, 0); + fillin_patch_config(&kallsym, kallsym_kimg, ori_kimg_len, &setup->patch_config, kinfo->is_be, 0); // superkey if (!root_key) { @@ -696,4 +683,18 @@ int dump_kallsym(const char *kimg_path) set_log_enable(false); free_kernel_file(&kernel_file); return 0; +} +int dump_ikconfig(const char *kimg_path) +{ + if (!kimg_path) tools_loge_exit("empty kernel image\n"); + set_log_enable(true); + // read image files + kernel_file_t kernel_file; + read_kernel_file(kimg_path, &kernel_file); + + + dump_all_ikconfig(kernel_file.kimg,kernel_file.kimg_len); + set_log_enable(false); + free_kernel_file(&kernel_file); + return 0; } \ No newline at end of file diff --git a/tools/patch.h b/tools/patch.h index d2443e67..d253087d 100644 --- a/tools/patch.h +++ b/tools/patch.h @@ -69,11 +69,11 @@ 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); +int dump_ikconfig(const char *kimg_path); int print_kp_image_info_path(const char *kpimg_path); int print_image_patch_info(patched_kimg_t *pimg); diff --git a/tools/symbol.c b/tools/symbol.c index d3787b90..e8d3c405 100644 --- a/tools/symbol.c +++ b/tools/symbol.c @@ -101,7 +101,7 @@ static int get_cand_arr_symbol_offset_zero(kallsym_t *kallsym, char *img_buf, ch return offset; } -int fillin_patch_symbol(kallsym_t *kallsym, char *img_buf, int imglen, patch_symbol_t *symbol, int32_t target_is_be, +int fillin_patch_config(kallsym_t *kallsym, char *img_buf, int imglen, patch_config_t *symbol, int32_t target_is_be, bool is_android) { symbol->panic = get_symbol_offset_zero(kallsym, img_buf, "panic"); diff --git a/tools/symbol.h b/tools/symbol.h index 03a00a9a..86f22bc3 100644 --- a/tools/symbol.h +++ b/tools/symbol.h @@ -19,7 +19,7 @@ int32_t get_symbol_offset_exit(kallsym_t *info, char *img, char *symbol); int32_t find_suffixed_symbol(kallsym_t *kallsym, char *img_buf, const char *symbol); void select_map_area(kallsym_t *kallsym, char *image_buf, int32_t *map_start, int32_t *max_size); int fillin_map_symbol(kallsym_t *kallsym, char *img_buf, map_symbol_t *symbol, int32_t target_is_be); -int fillin_patch_symbol(kallsym_t *kallsym, char *img_buf, int imglen, patch_symbol_t *symbol, int32_t target_is_be, +int fillin_patch_config(kallsym_t *kallsym, char *img_buf, int imglen, patch_config_t *symbol, int32_t target_is_be, bool is_android); #endif \ No newline at end of file diff --git a/user/.gitignore b/user/.gitignore index e755c739..f9663c85 100644 --- a/user/.gitignore +++ b/user/.gitignore @@ -1,39 +1,2 @@ -# 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 - +version \ No newline at end of file diff --git a/user/supercall.h b/user/supercall.h index 2f200241..f27d539d 100644 --- a/user/supercall.h +++ b/user/supercall.h @@ -14,229 +14,534 @@ #include #include "uapi/scdefs.h" -#include "../version" +#include "version" -// TODO: delete this file and use supercall_ge0a04.h instead when no one has kernelpatch <= 0.10.4, - -// be 0a04 -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; return ((long)version_code << 32) | (0x1158 << 16) | (cmd & 0xFFFF); } -static inline long compact_cmd(const char *key, long cmd) -{ - long ver = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KERNELPATCH_VER)); - if (ver >= 0xa05) return ver_and_cmd(key, cmd); - 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)); + long ret = syscall(__NR_supercall, key, ver_and_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); + long ret = syscall(__NR_supercall, key, ver_and_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)); + long ret = syscall(__NR_supercall, key, ver_and_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)); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KERNEL_VER)); return (uint32_t)ret; } -static inline uint32_t sc_skey_get(const char *key, char *out_key, int outlen) +/** + * @brief KernelPatch build time + * + * @param key : superkey or 'su' string if caller uid is su allowed + * @param out_buildtime + * @param outlen + * @return long + */ +static inline long sc_kp_buildtime(const char *key, char *out_buildtime, 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); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_BUILD_TIME, out_buildtime, outlen)); return (uint32_t)ret; } -static inline uint32_t sc_skey_set(const char *key, const char *new_key) +/** + * @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 (!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; + if (strlen(profile->scontext) >= SUPERCALL_SCONTEXT_LEN) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU), profile); + return ret; } -static inline uint32_t sc_skey_root_enable(const char *key, bool enable) +/** + * @brief Substitute user of tid specfied thread + * + * @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; - 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, ver_and_cmd(key, SUPERCALL_SU_TASK), tid, profile); + return ret; } -static inline long sc_su(const char *key, struct su_profile *profile) +/** + * @brief + * + * @param key + * @param gid group id + * @param did data id + * @param data + * @param dlen + * @return long + */ +static inline long sc_kstorage_write(const char *key, int gid, long did, void *data, int offset, int dlen) { 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, ver_and_cmd(key, SUPERCALL_KSTORAGE_WRITE), gid, did, data, + (((long)offset << 32) | dlen)); return ret; } -static inline long sc_su_task(const char *key, pid_t tid, struct su_profile *profile) +/** + * @brief + * + * @param key + * @param gid + * @param did + * @param out_data + * @param dlen + * @return long + */ +static inline long sc_kstorage_read(const char *key, int gid, long did, void *out_data, int offset, int dlen) { 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, ver_and_cmd(key, SUPERCALL_KSTORAGE_READ), gid, did, out_data, + (((long)offset << 32) | dlen)); return ret; } -static inline long sc_kpm_load(const char *key, const char *path, const char *args, void *reserved) +/** + * @brief + * + * @param key + * @param gid + * @param ids + * @param ids_len + * @return long numbers of listed ids + */ +static inline long sc_kstorage_list_ids(const char *key, int gid, long *ids, int ids_len) { 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); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_LIST_IDS), gid, ids, ids_len); return ret; } -static inline long sc_kpm_control(const char *key, const char *name, const char *ctl_args, char *out_msg, long outlen) +/** + * @brief + * + * @param key + * @param gid + * @param did + * @return long + */ +static inline long sc_kstorage_remove(const char *key, int gid, long did) { 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, ver_and_cmd(key, SUPERCALL_KSTORAGE_REMOVE), gid); return ret; } -static inline long sc_kpm_unload(const char *key, const char *name, void *reserved) +/** + * @brief + * + * @param key + * @param uid + * @param exclude + * @return long + */ +static inline long sc_set_ap_mod_exclude(const char *key, uid_t uid, int exclude) +{ + if (exclude) { + return sc_kstorage_write(key, KSTORAGE_EXCLUDE_LIST_GROUP, uid, &exclude, 0, sizeof(exclude)); + } else { + return sc_kstorage_remove(key, SUPERCALL_KSTORAGE_REMOVE, uid, gid); + } +} + +/** + * @brief + * + * @param key + * @param uid + * @param exclude + * @return long + */ +static inline int sc_get_ap_mod_exclude(const char *key, uid_t uid) +{ + int exclude = 0; + int rc = sc_kstorage_read(key, KSTORAGE_EXCLUDE_LIST_GROUP, uid, &exclude, 0, sizeof(exclude)); + if (rc < 0) return 0; + return exclude; +} + +/** + * @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; - if (!name || strlen(name) <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_UNLOAD), name, reserved); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GRANT_UID), profile); return ret; } -static inline long sc_kpm_nums(const char *key) +/** + * @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_KPM_NUMS)); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_REVOKE_UID), uid); return ret; } -static inline long sc_kpm_list(const char *key, char *names_buf, int buf_len) +/** + * @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; - if (!names_buf || buf_len <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_LIST), names_buf, buf_len); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_NUMS)); return ret; } -static inline long sc_kpm_info(const char *key, const char *name, char *buf, int buf_len) +/** + * @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 || buf_len <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_KPM_INFO), name, buf, buf_len); + if (!buf || num <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_LIST), buf, num); return ret; } -static inline long sc_pid_virt_to_phys(const char *key, pid_t pid, unsigned long vaddr) +/** + * @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_MEM_PHYS), pid, vaddr); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_PROFILE), uid, out_profile); return ret; } -static inline long sc_bootlog(const char *key) +/** + * @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) { - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_BOOTLOG)); + if (!key || !key[0]) return -EINVAL; + if (!out_path || path_len <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GET_PATH), out_path, path_len); return ret; } -static inline long sc_panic(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) { - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_PANIC)); + if (!key || !key[0]) return -EINVAL; + if (!path || !path[0]) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_RESET_PATH), path); return ret; } -static inline long __sc_test(const char *key, long a1, long a2, long a3) +/** + * @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) { - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_TEST), a1, a2, a3); + if (!key || !key[0]) return -EINVAL; + if (!out_sctx) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GET_ALLOW_SCTX), out_sctx); return ret; } -#ifdef ANDROID -static inline long sc_su_grant_uid(const char *key, uid_t uid, struct su_profile *profile) +/** + * @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; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_GRANT_UID), uid, profile); + if (!sctx) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_SET_ALLOW_SCTX), sctx); return ret; } -static inline long sc_su_revoke_uid(const char *key, uid_t uid) +/** + * @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_SU_REVOKE_UID), uid); + if (!path || strlen(path) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_LOAD), path, args, reserved); return ret; } -static inline long sc_su_uid_nums(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) { if (!key || !key[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_NUMS)); + if (!name || strlen(name) <= 0) return -EINVAL; + if (!ctl_args || strlen(ctl_args) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_CONTROL), name, ctl_args, out_msg, outlen); return ret; } -static inline long sc_su_allow_uids(const char *key, uid_t *buf, int num) +/** + * @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 (!buf || num <= 0) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_LIST), buf, num); + if (!name || strlen(name) <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_UNLOAD), name, reserved); return ret; } -static inline long sc_su_uid_profile(const char *key, uid_t uid, struct su_profile *out_profile) +/** + * @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_SU_PROFILE), uid, out_profile); + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_NUMS)); return ret; } -static inline long sc_su_reset_path(const char *key, const char *path) +/** + * @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 (!path || !path[0]) return -EINVAL; - long ret = syscall(__NR_supercall, key, compact_cmd(key, SUPERCALL_SU_RESET_PATH), path); + if (!names_buf || buf_len <= 0) return -EINVAL; + long ret = syscall(__NR_supercall, key, ver_and_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, ver_and_cmd(key, SUPERCALL_KPM_INFO), name, buf, buf_len); return ret; } -static inline long sc_su_get_path(const char *key, char *buf, int buf_size) +/** + * @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, ver_and_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, ver_and_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, ver_and_cmd(key, SUPERCALL_SKEY_ROOT_ENABLE), (long)enable); + return ret; +} + +/** + * @brief Get whether in safe mode + * + * @param key + * @return long + */ +static inline long sc_su_get_safemode(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); + return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GET_SAFEMODE)); +} + +static inline long sc_bootlog(const char *key) +{ + long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_BOOTLOG)); return ret; } -#endif +static inline long sc_panic(const char *key) +{ + long ret = syscall(__NR_supercall, key, ver_and_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, ver_and_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 97% rename from user/kpatch.c rename to user_deprecated/kpatch.c index 63cec4c0..93090c70 100644 --- a/user/kpatch.c +++ b/user_deprecated/kpatch.c @@ -58,7 +58,7 @@ void panic(const char *key) int __test(const char *key) { // return __sc_test(key, 0, 0, 0); - return sc_pid_virt_to_phys(key, getpid(), (unsigned long)__test); + return 0; } extern const char program_name[]; 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..f921de3a --- /dev/null +++ b/user_deprecated/supercall.h @@ -0,0 +1,403 @@ +/* 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; +} + +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 91% rename from user/supercall_ge0a04.h rename to user_deprecated/supercall_ge0a04.h index ff427b68..beecbf03 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) @@ -142,13 +142,6 @@ static inline long sc_kpm_info(const char *key, const char *name, char *buf, int return ret; } -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, ver_and_cmd(key, SUPERCALL_MEM_PHYS), pid, vaddr); - return ret; -} - static inline long sc_bootlog(const char *key) { long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_BOOTLOG)); @@ -167,7 +160,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 +212,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 44ea3065..126798bf 100644 --- a/version +++ b/version @@ -1,3 +1,3 @@ #define MAJOR 0 -#define MINOR 10 -#define PATCH 5 +#define MINOR 11 +#define PATCH 1