From eaa2a41408c13850dfcd2461f25c4720823677fd Mon Sep 17 00:00:00 2001 From: bmax Date: Wed, 22 Nov 2023 20:50:44 +0800 Subject: [PATCH] v0.5.0: kpm support, and su support, and some fix ... --- .clang-format | 13 +- .github/workflows/build.yml | 48 +- .gitignore | 1 + README.md | 14 +- README_zh-CN.md | 14 +- doc/en/module.md | 4 + doc/zh-cn/module.md | 4 + kernel/.gitignore | 2 +- kernel/Makefile | 17 +- kernel/base/cache.S | 290 ++++ kernel/base/fphook.c | 303 ++++ kernel/base/hmem.c | 84 +- kernel/base/hook.c | 210 +-- kernel/base/log.c | 7 + kernel/base/map.c | 41 +- kernel/base/map1.S | 2 + kernel/base/predata.c | 24 +- kernel/base/setup1.S | 4 +- kernel/base/start.c | 240 ++-- kernel/base/start.h | 21 +- kernel/base/symbol.c | 15 +- kernel/base/tlsf.c | 1219 +++++++++++++++++ kernel/include/barrier.h | 77 ++ kernel/include/cache.h | 24 + kernel/include/common.h | 36 + kernel/include/compiler.h | 31 + kernel/include/error.h | 20 - kernel/include/hook.h | 264 +++- kernel/include/io.h | 174 +++ kernel/include/kpmalloc.h | 49 + kernel/include/kpmodule.h | 25 + kernel/include/ktypes.h | 10 +- kernel/include/log.h | 12 +- kernel/include/pgtable.h | 8 + kernel/include/predata.h | 6 +- kernel/{base => include}/preset.h | 23 +- kernel/include/stdbool.h | 2 +- kernel/include/stddef.h | 2 + kernel/include/symbol.h | 7 +- kernel/include/tlsf.h | 87 ++ kernel/kpimg.lds | 20 +- kernel/linux/arch/arm64/include/asm/atomic.h | 257 ++++ kernel/linux/arch/arm64/include/asm/cmpxchg.h | 182 +++ kernel/linux/arch/arm64/include/asm/current.h | 4 +- kernel/linux/arch/arm64/include/asm/elf.h | 243 ++++ kernel/linux/arch/arm64/include/asm/hwcap.h | 68 + kernel/linux/arch/arm64/include/asm/io.h | 6 + kernel/linux/arch/arm64/include/asm/ptrace.h | 24 +- kernel/linux/arch/arm64/include/asm/uaccess.h | 41 + .../linux/arch/arm64/include/uapi/asm/hwcap.h | 108 ++ .../arch/arm64/include/uapi/asm/ptrace.h | 6 +- .../include/asm-generic/bitops/fls_ffs.h | 149 ++ kernel/linux/include/asm-generic/compat.h | 174 +++ kernel/linux/include/asm-generic/module.h | 53 + kernel/linux/include/linux/bitops.h | 159 ++- kernel/linux/include/linux/compiler.h | 58 + kernel/linux/include/linux/cpumask.h | 33 + kernel/linux/include/linux/elf-em.h | 70 + kernel/linux/include/linux/elf.h | 475 +++++++ kernel/linux/include/linux/errno.h | 2 + kernel/linux/include/linux/fs.h | 61 +- kernel/linux/include/linux/gfp.h | 1 + .../include/linux/include/linux/export.h | 171 +++ .../linux/include/linux/include/linux/smp.h | 9 + kernel/linux/include/linux/kernel.h | 54 +- kernel/linux/include/linux/list.h | 34 +- kernel/linux/include/linux/panic.h | 12 + kernel/linux/include/linux/rculist.h | 0 kernel/linux/include/linux/rcupdate.h | 25 +- kernel/linux/include/linux/sched.h | 45 + kernel/linux/include/linux/seq_buf.h | 10 +- kernel/linux/include/linux/slab.h | 44 +- kernel/linux/include/linux/socket.h | 3 +- kernel/linux/include/linux/stacktrace.h | 51 + kernel/linux/include/linux/stop_machine.h | 34 + kernel/linux/include/linux/string.h | 219 +-- kernel/linux/include/linux/syscall.h | 768 ----------- kernel/linux/include/linux/trace_seq.h | 46 +- kernel/linux/include/linux/uaccess.h | 43 +- kernel/linux/include/linux/vmalloc.h | 52 +- kernel/linux/include/uapi/asm-generic/errno.h | 2 +- kernel/linux/include/uapi/asm-generic/fcntl.h | 225 +++ kernel/linux/include/uapi/linux/capability.h | 2 +- kernel/linux/include/uapi/linux/elf.h | 475 +++++++ kernel/linux/include/uapi/linux/fs.h | 282 ++++ .../linux/security/selinux/include/security.h | 4 +- .../tools/arch/arm64/include/asm/barrier.h | 71 +- kernel/minc/print.c | 9 +- kernel/minc/stdlib.c | 15 +- kernel/minc/string.c | 86 +- kernel/module/hello/Makefile | 23 - kernel/module/hello/hello.c | 11 - kernel/module/module.c | 1 - kernel/module/module.h | 19 - kernel/patch/accctl/selinuxhook.c | 187 --- kernel/patch/accctl/supercall.c | 136 -- kernel/patch/android/kpuserd.c | 194 +++ kernel/patch/android/sucompat.c | 235 ++-- kernel/patch/android/supercall.c | 46 +- kernel/patch/{accctl => common}/accctl.c | 100 +- kernel/patch/common/hotpatch.c | 82 ++ kernel/patch/common/secpass.c | 82 ++ kernel/patch/common/selinuxhook.c | 222 +++ kernel/patch/common/supercall.c | 183 +++ kernel/patch/{extend => common}/syscall.c | 96 +- kernel/patch/common/taskob.c | 143 ++ kernel/patch/common/utils.c | 46 + kernel/patch/extend/lsmext.c | 69 - kernel/patch/extend/taskob.c | 89 -- kernel/patch/include/accctl.h | 14 +- kernel/patch/include/hotpatch.h | 8 + kernel/patch/include/kconfig.h | 8 + kernel/patch/include/kputils.h | 9 + kernel/patch/include/ksyms.h | 40 +- kernel/patch/include/lsmext.h | 42 - kernel/patch/include/module.h | 56 + kernel/patch/include/syscall.h | 149 +- kernel/patch/include/taskext.h | 2 +- kernel/patch/include/taskob.h | 5 + kernel/patch/include/uapi/lsmdef.h | 303 ---- kernel/patch/include/uapi/scdefs.h | 34 +- kernel/patch/ksyms/libs.c | 301 ++++ kernel/patch/ksyms/misc.c | 508 +++---- kernel/patch/ksyms/misc_len.c | 32 +- kernel/patch/{struct => ksyms}/task_cred.c | 230 ++-- kernel/patch/module/insn.c | 926 +++++++++++++ kernel/patch/module/insn.h | 330 +++++ kernel/patch/module/module.c | 585 ++++++++ kernel/patch/module/relo.c | 329 +++++ kernel/patch/module/relo.h | 11 + kernel/patch/old/hooksysc.h | 111 ++ kernel/patch/{accctl => old}/lsmhook.c | 1 - kernel/patch/{ksyms => old}/security.c | 629 ++++----- kernel/patch/{ksyms => old}/selinux.c | 16 +- kernel/patch/patch.c | 161 +-- kernel/version | 2 +- {kernel/module => kpm-demo/hello}/.gitignore | 6 - kpm-demo/hello/Makefile | 30 + kpm-demo/hello/hello.c | 23 + kpm-demo/hello/hello.lds | 5 + kpm-demo/inlinehook/.gitignore | 19 + kpm-demo/inlinehook/Makefile | 30 + kpm-demo/inlinehook/inlinehook.c | 64 + kpm-demo/syscallhook/.gitignore | 19 + kpm-demo/syscallhook/Makefile | 30 + kpm-demo/syscallhook/syscallhook.c | 120 ++ tools/Makefile | 6 + tools/image.c | 3 +- tools/kallsym.c | 140 +- tools/kptools.c | 25 +- tools/version | 4 +- user/kpatch.c | 31 +- user/main.c | 242 ++-- user/supercall.h | 58 +- 154 files changed, 12107 insertions(+), 3973 deletions(-) create mode 100644 kernel/base/cache.S create mode 100644 kernel/base/fphook.c create mode 100644 kernel/base/log.c create mode 100644 kernel/base/map1.S create mode 100644 kernel/base/tlsf.c create mode 100644 kernel/include/barrier.h delete mode 100644 kernel/include/error.h create mode 100644 kernel/include/io.h create mode 100644 kernel/include/kpmalloc.h create mode 100644 kernel/include/kpmodule.h rename kernel/{base => include}/preset.h (86%) create mode 100644 kernel/include/tlsf.h create mode 100644 kernel/linux/arch/arm64/include/asm/atomic.h create mode 100644 kernel/linux/arch/arm64/include/asm/cmpxchg.h create mode 100644 kernel/linux/arch/arm64/include/asm/elf.h create mode 100644 kernel/linux/arch/arm64/include/asm/hwcap.h create mode 100644 kernel/linux/arch/arm64/include/asm/io.h create mode 100644 kernel/linux/arch/arm64/include/asm/uaccess.h create mode 100644 kernel/linux/arch/arm64/include/uapi/asm/hwcap.h create mode 100644 kernel/linux/include/asm-generic/bitops/fls_ffs.h create mode 100644 kernel/linux/include/asm-generic/compat.h create mode 100644 kernel/linux/include/asm-generic/module.h create mode 100644 kernel/linux/include/linux/compiler.h create mode 100644 kernel/linux/include/linux/cpumask.h create mode 100644 kernel/linux/include/linux/elf-em.h create mode 100644 kernel/linux/include/linux/elf.h create mode 100644 kernel/linux/include/linux/include/linux/export.h create mode 100644 kernel/linux/include/linux/include/linux/smp.h create mode 100644 kernel/linux/include/linux/panic.h create mode 100644 kernel/linux/include/linux/rculist.h create mode 100644 kernel/linux/include/linux/stacktrace.h create mode 100644 kernel/linux/include/uapi/asm-generic/fcntl.h create mode 100644 kernel/linux/include/uapi/linux/elf.h create mode 100644 kernel/linux/include/uapi/linux/fs.h delete mode 100644 kernel/module/hello/Makefile delete mode 100644 kernel/module/hello/hello.c delete mode 100644 kernel/module/module.c delete mode 100644 kernel/module/module.h delete mode 100644 kernel/patch/accctl/selinuxhook.c delete mode 100644 kernel/patch/accctl/supercall.c create mode 100644 kernel/patch/android/kpuserd.c rename kernel/patch/{accctl => common}/accctl.c (60%) create mode 100644 kernel/patch/common/hotpatch.c create mode 100644 kernel/patch/common/secpass.c create mode 100644 kernel/patch/common/selinuxhook.c create mode 100644 kernel/patch/common/supercall.c rename kernel/patch/{extend => common}/syscall.c (56%) create mode 100644 kernel/patch/common/taskob.c create mode 100644 kernel/patch/common/utils.c delete mode 100644 kernel/patch/extend/lsmext.c delete mode 100644 kernel/patch/extend/taskob.c create mode 100644 kernel/patch/include/hotpatch.h create mode 100644 kernel/patch/include/kconfig.h create mode 100644 kernel/patch/include/kputils.h delete mode 100644 kernel/patch/include/lsmext.h create mode 100644 kernel/patch/include/module.h delete mode 100644 kernel/patch/include/uapi/lsmdef.h create mode 100644 kernel/patch/ksyms/libs.c rename kernel/patch/{struct => ksyms}/task_cred.c (70%) create mode 100644 kernel/patch/module/insn.c create mode 100644 kernel/patch/module/insn.h create mode 100644 kernel/patch/module/module.c create mode 100644 kernel/patch/module/relo.c create mode 100644 kernel/patch/module/relo.h create mode 100644 kernel/patch/old/hooksysc.h rename kernel/patch/{accctl => old}/lsmhook.c (99%) rename kernel/patch/{ksyms => old}/security.c (56%) rename kernel/patch/{ksyms => old}/selinux.c (94%) rename {kernel/module => kpm-demo/hello}/.gitignore (70%) create mode 100644 kpm-demo/hello/Makefile create mode 100644 kpm-demo/hello/hello.c create mode 100644 kpm-demo/hello/hello.lds create mode 100644 kpm-demo/inlinehook/.gitignore create mode 100644 kpm-demo/inlinehook/Makefile create mode 100644 kpm-demo/inlinehook/inlinehook.c create mode 100644 kpm-demo/syscallhook/.gitignore create mode 100644 kpm-demo/syscallhook/Makefile create mode 100644 kpm-demo/syscallhook/syscallhook.c diff --git a/.clang-format b/.clang-format index bbc33d9f..5cc9e034 100644 --- a/.clang-format +++ b/.clang-format @@ -19,7 +19,7 @@ AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: false -AllowShortIfStatementsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None @@ -53,7 +53,7 @@ BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false BreakBeforeSemicolons: None ColumnLimit: 120 -CommentPragmas: '^ IWYU pragma:' +CommentPragmas: "^ IWYU pragma:" CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 @@ -66,9 +66,9 @@ FixNamespaceComments: false IncludeBlocks: Preserve IncludeCategories: - - Regex: '.*' + - Regex: ".*" Priority: 1 -IncludeIsMainRegex: '(Test)?$' +IncludeIsMainRegex: "(Test)?$" IndentCaseLabels: false IndentPPDirectives: None IndentWidth: 4 @@ -76,8 +76,8 @@ IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false -MacroBlockBegin: '' -MacroBlockEnd: '' +MacroBlockBegin: "" +MacroBlockEnd: "" MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBinPackProtocolList: Auto @@ -116,4 +116,3 @@ Standard: Cpp11 TabWidth: 4 UseTab: Never UseCRLF: false -... diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 277243af..2b5de2c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,13 +2,13 @@ name: Build CI on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] jobs: Build-kpimg: - runs-on: ubuntu-latest + runs-on: ubuntu-latest permissions: contents: write steps: @@ -28,20 +28,30 @@ jobs: echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - name: Install Compiler run: | - curl -o arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz - tar -Jxf arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz + curl -o arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz + tar -Jxf arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz - 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-${{ steps.parse_version.outputs.VERSION }} + mv kpimg.elf kpimg.elf-${{ steps.parse_version.outputs.VERSION }} make clean export ANDROID=1 make - unset ANDROID mv kpimg kpimg-android-${{ steps.parse_version.outputs.VERSION }} - + mv kpimg.elf kpimg.elf-android-${{ steps.parse_version.outputs.VERSION }} + unset ANDROID + + - name: Upload elf + uses: actions/upload-artifact@v3 + with: + path: | + kernel/kpimg.elf-${{ steps.parse_version.outputs.VERSION }} + kernel/kpimg.elf-android-${{ steps.parse_version.outputs.VERSION }} + name: kpimg.elf + - name: Release uses: ncipollo/release-action@v1.12.0 with: @@ -55,7 +65,7 @@ jobs: replacesArtifacts: true Release-lib: - runs-on: ubuntu-latest + runs-on: ubuntu-latest permissions: contents: write steps: @@ -79,7 +89,7 @@ jobs: cd .. zip -r kpuser.zip user mv kpuser.zip kpuser-src-${{ steps.parse_version.outputs.VERSION }}.zip - + - name: Release uses: ncipollo/release-action@v1.12.0 with: @@ -91,7 +101,7 @@ jobs: replacesArtifacts: true Build-android: - runs-on: ubuntu-latest + runs-on: ubuntu-latest permissions: contents: write steps: @@ -109,7 +119,7 @@ jobs: VERSION="$MAJOR.$MINOR.$PATCH" echo "Generated Version: $VERSION" echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - + TOOLS_MAJOR=$(grep '#define MAJOR' tools/version | awk '{print $3}') TOOLS_MINOR=$(grep '#define MINOR' tools/version | awk '{print $3}') TOOLS_PATCH=$(grep '#define PATCH' tools/version | awk '{print $3}') @@ -128,7 +138,7 @@ jobs: export TARGET_COMPILE=placeholder cd kernel make hdr - + - name: Build kpatch-android run: | cd user @@ -156,7 +166,7 @@ jobs: -DANDROID_ABI=arm64-v8a ../.. cmake --build . mv kptools kptools-android-${{ steps.parse_version.outputs.TOOLS_VERSION }} - + - name: Release uses: ncipollo/release-action@v1.12.0 with: @@ -184,7 +194,7 @@ jobs: VERSION="$MAJOR.$MINOR.$PATCH" echo "Generated Version: $VERSION" echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - + TOOLS_MAJOR=$(grep '#define MAJOR' tools/version | awk '{print $3}') TOOLS_MINOR=$(grep '#define MINOR' tools/version | awk '{print $3}') TOOLS_PATCH=$(grep '#define PATCH' tools/version | awk '{print $3}') @@ -206,7 +216,7 @@ jobs: make mv kptools kptools-linux-${{ steps.parse_version.outputs.TOOLS_VERSION }} - - name: Release + - name: Release uses: ncipollo/release-action@v1.12.0 with: token: ${{ secrets.GITHUB_TOKEN }} @@ -232,14 +242,14 @@ jobs: VERSION="$MAJOR.$MINOR.$PATCH" echo "Generated Version: $VERSION" echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - + TOOLS_MAJOR=$(grep '#define MAJOR' tools/version | awk '{print $3}') TOOLS_MINOR=$(grep '#define MINOR' tools/version | awk '{print $3}') TOOLS_PATCH=$(grep '#define PATCH' tools/version | awk '{print $3}') TOOLS_VERSION="$TOOLS_MAJOR.$TOOLS_MINOR.$TOOLS_PATCH" echo "Generated Tools Version: $TOOLS_VERSION" echo "TOOLS_VERSION=$TOOLS_VERSION" >> $GITHUB_OUTPUT - + - name: Make hdr run: | export TARGET_COMPILE=placeholder @@ -253,7 +263,7 @@ jobs: cmake .. make mv kptools kptools-mac-${{ steps.parse_version.outputs.TOOLS_VERSION }} - - name: Release + - name: Release uses: ncipollo/release-action@v1.12.0 with: token: ${{ secrets.GITHUB_TOKEN }} @@ -261,4 +271,4 @@ jobs: artifacts: | tools/build/kptools-mac-${{ steps.parse_version.outputs.TOOLS_VERSION }} allowUpdates: true - replacesArtifacts: true \ No newline at end of file + replacesArtifacts: true diff --git a/.gitignore b/.gitignore index bb02c610..7db4f923 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ **/.DS_Store build + test .test diff --git a/README.md b/README.md index cf64fd67..3158dce9 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,15 @@ **Patching and hooking the Linux kernel with only stripped Linux kernel image.** +``` shell + _ __ _ ____ _ _ +| |/ /___ _ __ _ __ ___| | _ \ __ _| |_ ___| |__ +| ' // _ \ '__| '_ \ / _ \ | |_) / _` | __/ __| '_ \ +| . \ __/ | | | | | __/ | __/ (_| | || (__| | | | +|_|\_\___|_| |_| |_|\___|_|_| \__,_|\__\___|_| |_| + +``` + If you are using Android, [AndroidKernelPatch](https://github.com/bmax121/AndroidKernelPatch) would be a better choice. **English** | [简体中文](README_zh-CN.md) @@ -10,13 +19,11 @@ KernelPatch provides the fundamental capability to parse Linux kernel images wit Building upon this foundation, KernelPatch offers essential features such as system-call-hook and inline-hook in the kernel. You have complete control over the kernel, allowing you to implement desired functionalities such as privilege escalation, hiding, monitoring, and more. -**KernelPatch is intended solely for learning and communication purposes. It is strictly prohibited from being used for any illegal activities.** - ## Supported Versions Currently only supports arm64 architecture. -Linux 3.8 - 6.2 (theoretically) +Linux 3.18 - 6.2 (theoretically) Linux 6.3+ (not yet adapted) ## Get Help @@ -33,7 +40,6 @@ Linux 6.3+ (not yet adapted) - [vmlinux-to-elf](https://github.com/marin-m/vmlinux-to-elf): Some ideas for parsing kernel symbols. - [android-inline-hook](https://github.com/bytedance/android-inline-hook): Some code for fixing arm64 inline hook instructions. -- [https://elixir.bootlin.com](https://elixir.bootlin.com/linux/v6.2.16/C/ident/): Linux source code online. ## License diff --git a/README_zh-CN.md b/README_zh-CN.md index f52dad72..cf3df4ba 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -2,19 +2,26 @@ **Patching and hooking the Linux kernel with only stripped Linux kernel image.** +``` shell + _ __ _ ____ _ _ +| |/ /___ _ __ _ __ ___| | _ \ __ _| |_ ___| |__ +| ' // _ \ '__| '_ \ / _ \ | |_) / _` | __/ __| '_ \ +| . \ __/ | | | | | __/ | __/ (_| | || (__| | | | +|_|\_\___|_| |_| |_|\___|_|_| \__,_|\__\___|_| |_| + +``` + 如果你在使用 Android,[AndroidKernelPatch](https://github.com/bmax121/AndroidKernelPatch) 会是更好的选择。 KernelPatch 提供可以在无源码无符号情况下解析Linux内核镜像,获取任意符号偏移,并向内核中注入任意代码的基础能力。 在此基础上,KernelPatch 还提供了系统调用 hook,内核 inline-hook 等基础功能。 你可以完全的掌控内核,实现你想要的功能,比如提权,隐藏,监控等等。 -**KernelPatch 仅供学习交流。严禁用于任何非法用途。** - ## 支持情况 当前只支持 arm64 -Linux 3.8 - 6.2 (理论上) +Linux 3.18 - 6.2 (理论上) Linux 6.3+ (暂未适配) ## 获取帮助 @@ -31,7 +38,6 @@ Linux 6.3+ (暂未适配) - [vmlinux-to-elf](https://github.com/marin-m/vmlinux-to-elf): 参考学习了解析内核符号的思路 - [android-inline-hook](https://github.com/bytedance/android-inline-hook): 用了 arm64 inline hook 指令修复的代码 -- [linux source code online](https://elixir.bootlin.com/linux/v6.2.16/C/ident/): 内核源码在线 ## 许可证 diff --git a/doc/en/module.md b/doc/en/module.md index bd186728..2c533a30 100644 --- a/doc/en/module.md +++ b/doc/en/module.md @@ -1 +1,5 @@ # KernelPatch Module + +todo + +[demo here](/kpm-demo/) \ No newline at end of file diff --git a/doc/zh-cn/module.md b/doc/zh-cn/module.md index bd186728..2c533a30 100644 --- a/doc/zh-cn/module.md +++ b/doc/zh-cn/module.md @@ -1 +1,5 @@ # KernelPatch Module + +todo + +[demo here](/kpm-demo/) \ No newline at end of file diff --git a/kernel/.gitignore b/kernel/.gitignore index a257a09b..33132a55 100644 --- a/kernel/.gitignore +++ b/kernel/.gitignore @@ -16,7 +16,7 @@ *.bin *.elf -# +# kernel patch module *.kpm kpimg \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index b89f9d88..9a0af4c4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,5 +1,5 @@ ifndef TARGET_COMPILE - $(error TARGET_COMPILE is not set) + $(error TARGET_COMPILE not set) endif TARGET=kpimg @@ -24,23 +24,23 @@ INCLUDE := -I. -Iinclude -Ipatch/include -Ilinux -Ilinux/include -Ilinux/arch/ar BASE_SRCS += base/setup.c BASE_SRCS += base/setup1.S +BASE_SRCS += base/cache.S +BASE_SRCS += base/tlsf.c BASE_SRCS += base/start.c BASE_SRCS += base/map.c +BASE_SRCS += base/map1.S BASE_SRCS += base/hook.c +BASE_SRCS += base/fphook.c BASE_SRCS += base/hmem.c BASE_SRCS += base/predata.c BASE_SRCS += base/symbol.c BASE_SRCS += $(wildcard minc/*.c) -BASE_SRCS += $(wildcard module/*.c) - BASE_SRCS += $(wildcard patch/*.c) -BASE_SRCS += $(wildcard patch/accctl/*.c) -BASE_SRCS += $(wildcard patch/extend/*.c) +BASE_SRCS += $(wildcard patch/common/*.c) +BASE_SRCS += $(wildcard patch/module/*.c) BASE_SRCS += $(wildcard patch/ksyms/*.c) -BASE_SRCS += $(wildcard patch/struct/*.c) -BASE_SRCS += $(wildcard patch/debug/*.c) ifdef ANDROID BASE_SRCS += $(wildcard patch/android/*.c) @@ -66,10 +66,11 @@ ${TARGET}.elf: ${OBJS} %.o: %.S ${CC} $(CFLAGS) $(INCLUDE) -c -o $@ $< +.PHONY: hdr hdr: cp -r patch/include/uapi ../user cp version ../user - cp base/preset.h ../tools + cp include/preset.h ../tools .PHONY: clean clean: diff --git a/kernel/base/cache.S b/kernel/base/cache.S new file mode 100644 index 00000000..cd7f0eb2 --- /dev/null +++ b/kernel/base/cache.S @@ -0,0 +1,290 @@ +#define ASM_NL ; + +#define ALIGN .align 4,0x90 +#define ALIGN_STR ".align 4,0x90" + +#define DMA_BIDIRECTIONAL 0 +#define DMA_TO_DEVICE 1 +#define DMA_FROM_DEVICE 2 +#define DMA_NONE = 3 + +#define USER(l, x...) \ +9999: x; \ + # todo: + # .section __ex_table,"a"; \ + .align 3; \ + .quad 9999b,l; \ + .previous + +#define ENTRY(name) \ + .globl name ASM_NL \ + ALIGN ASM_NL \ + name: + +#define END(name) \ + .size name, .-name + +#define ENDPROC(name) \ + .type name, @function ASM_NL \ + END(name) + +/* + * dcache_line_size - get the minimum D-cache line size from the CTR register. + */ + .macro dcache_line_size, reg, tmp + mrs \tmp, ctr_el0 // read CTR + ubfm \tmp, \tmp, #16, #19 // cache line size encoding + mov \reg, #4 // bytes per word + lsl \reg, \reg, \tmp // actual cache line size + .endm + +/* + * icache_line_size - get the minimum I-cache line size from the CTR register. + */ + .macro icache_line_size, reg, tmp + mrs \tmp, ctr_el0 // read CTR + and \tmp, \tmp, #0xf // cache line size encoding + mov \reg, #4 // bytes per word + lsl \reg, \reg, \tmp // actual cache line size + .endm + +/* + * __flush_dcache_all() + * + * Flush the whole D-cache. + * + * Corrupted registers: x0-x7, x9-x11 + */ +ENTRY(__flush_dcache_all) + dmb sy // ensure ordering with previous memory accesses + mrs x0, clidr_el1 // read clidr + and x3, x0, #0x7000000 // extract loc from clidr + lsr x3, x3, #23 // left align loc bit field + cbz x3, finished // if loc is 0, then no need to clean + mov x10, #0 // start clean at cache level 0 +loop1: + add x2, x10, x10, lsr #1 // work out 3x current cache level + lsr x1, x0, x2 // extract cache type bits from clidr + and x1, x1, #7 // mask of the bits for current cache only + cmp x1, #2 // see what cache we have at this level + b.lt skip // skip if no cache, or just i-cache + # todo: + # save_and_disable_irqs x9 // make CSSELR and CCSIDR access atomic + msr csselr_el1, x10 // select current cache level in csselr + isb // isb to sych the new cssr&csidr + mrs x1, ccsidr_el1 // read the new ccsidr + # todo + # restore_irqs x9 + and x2, x1, #7 // extract the length of the cache lines + add x2, x2, #4 // add 4 (line length offset) + mov x4, #0x3ff + and x4, x4, x1, lsr #3 // find maximum number on the way size + clz w5, w4 // find bit position of way size increment + mov x7, #0x7fff + and x7, x7, x1, lsr #13 // extract max number of the index size +loop2: + mov x9, x4 // create working copy of max way size +loop3: + lsl x6, x9, x5 + orr x11, x10, x6 // factor way and cache number into x11 + lsl x6, x7, x2 + orr x11, x11, x6 // factor index number into x11 + dc cisw, x11 // clean & invalidate by set/way + subs x9, x9, #1 // decrement the way + b.ge loop3 + subs x7, x7, #1 // decrement the index + b.ge loop2 +skip: + add x10, x10, #2 // increment cache number + cmp x3, x10 + b.gt loop1 +finished: + mov x10, #0 // swith back to cache level 0 + msr csselr_el1, x10 // select current cache level in csselr + dsb sy + isb + ret +ENDPROC(__flush_dcache_all) + +/* + * flush_cache_all() + * + * Flush the entire cache system. The data cache flush is now achieved + * using atomic clean / invalidates working outwards from L1 cache. This + * is done using Set/Way based cache maintainance instructions. The + * instruction cache can still be invalidated back to the point of + * unification in a single instruction. + */ +ENTRY(flush_cache_all) + mov x12, lr + bl __flush_dcache_all + mov x0, #0 + ic ialluis // I+BTB cache invalidate + ret x12 +ENDPROC(flush_cache_all) + +/* + * flush_icache_range(start,end) + * + * Ensure that the I and D caches are coherent within specified region. + * This is typically used when code has been written to a memory region, + * and will be executed. + * + * - start - virtual start address of region + * - end - virtual end address of region + */ +ENTRY(flush_icache_range) + /* FALLTHROUGH */ + +/* + * __flush_cache_user_range(start,end) + * + * Ensure that the I and D caches are coherent within specified region. + * This is typically used when code has been written to a memory region, + * and will be executed. + * + * - start - virtual start address of region + * - end - virtual end address of region + */ +ENTRY(__flush_cache_user_range) + dcache_line_size x2, x3 + sub x3, x2, #1 + bic x4, x0, x3 +1: +USER(9f, dc cvau, x4 ) // clean D line to PoU + add x4, x4, x2 + cmp x4, x1 + b.lo 1b + dsb ish + + icache_line_size x2, x3 + sub x3, x2, #1 + bic x4, x0, x3 +1: +USER(9f, ic ivau, x4 ) // invalidate I line PoU + add x4, x4, x2 + cmp x4, x1 + b.lo 1b +9: // ignore any faulting cache operation + dsb ish + isb + ret +ENDPROC(flush_icache_range) +ENDPROC(__flush_cache_user_range) + +/* + * __flush_dcache_area(kaddr, size) + * + * Ensure that the data held in the page kaddr is written back to the + * page in question. + * + * - kaddr - kernel address + * - size - size in question + */ +ENTRY(__flush_dcache_area) + dcache_line_size x2, x3 + add x1, x0, x1 + sub x3, x2, #1 + bic x0, x0, x3 +1: dc civac, x0 // clean & invalidate D line / unified line + add x0, x0, x2 + cmp x0, x1 + b.lo 1b + dsb sy + ret +ENDPROC(__flush_dcache_area) + +/* + * __inval_cache_range(start, end) + * - start - start address of region + * - end - end address of region + */ +ENTRY(__inval_cache_range) + /* FALLTHROUGH */ + +/* + * __dma_inv_range(start, end) + * - start - virtual start address of region + * - end - virtual end address of region + */ +__dma_inv_range: + dcache_line_size x2, x3 + sub x3, x2, #1 + tst x1, x3 // end cache line aligned? + bic x1, x1, x3 + b.eq 1f + dc civac, x1 // clean & invalidate D / U line +1: tst x0, x3 // start cache line aligned? + bic x0, x0, x3 + b.eq 2f + dc civac, x0 // clean & invalidate D / U line + b 3f +2: dc ivac, x0 // invalidate D / U line +3: add x0, x0, x2 + cmp x0, x1 + b.lo 2b + dsb sy + ret +ENDPROC(__inval_cache_range) +ENDPROC(__dma_inv_range) + +/* + * __dma_clean_range(start, end) + * - start - virtual start address of region + * - end - virtual end address of region + */ +__dma_clean_range: + dcache_line_size x2, x3 + sub x3, x2, #1 + bic x0, x0, x3 + # dc cvac, x0 + dc civac, x0 + add x0, x0, x2 + cmp x0, x1 + b.lo 1b + dsb sy + ret +ENDPROC(__dma_clean_range) + +/* + * __dma_flush_range(start, end) + * - start - virtual start address of region + * - end - virtual end address of region + */ +ENTRY(__dma_flush_range) + dcache_line_size x2, x3 + sub x3, x2, #1 + bic x0, x0, x3 +1: dc civac, x0 // clean & invalidate D / U line + add x0, x0, x2 + cmp x0, x1 + b.lo 1b + dsb sy + ret +ENDPROC(__dma_flush_range) + +/* + * __dma_map_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(__dma_map_area) + add x1, x1, x0 + cmp w2, #DMA_FROM_DEVICE + b.eq __dma_inv_range + b __dma_clean_range +ENDPROC(__dma_map_area) + +/* + * __dma_unmap_area(start, size, dir) + * - start - kernel virtual start address + * - size - size of region + * - dir - DMA direction + */ +ENTRY(__dma_unmap_area) + add x1, x1, x0 + cmp w2, #DMA_TO_DEVICE + b.ne __dma_inv_range + ret +ENDPROC(__dma_unmap_area) \ No newline at end of file diff --git a/kernel/base/fphook.c b/kernel/base/fphook.c new file mode 100644 index 00000000..9e8a19bd --- /dev/null +++ b/kernel/base/fphook.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include + +// transit0 +typedef uint64_t (*transit0_func_t)(); + +uint64_t __attribute__((section(".fp.transit0.text"))) __attribute__((__noinline__)) _fp_transit0() +{ + uint64_t this_va; + asm volatile("adr %0, ." : "=r"(this_va)); + uint32_t *vptr = (uint32_t *)this_va; + while (*--vptr != ARM64_NOP) { + }; + fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); + hook_fargs0_t fargs; + fargs.early_ret = 0; + fargs.chain = hook_chain; + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain0_callback func = hook_chain->befores[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + if (!fargs.early_ret) { + transit0_func_t origin_func = (transit0_func_t)hook_chain->hook.origin_fp; + fargs.ret = origin_func(); + } + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain0_callback func = hook_chain->afters[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + return fargs.ret; +} +extern void _fp_transit0_end(); + +// transit4 +typedef uint64_t (*transit4_func_t)(uint64_t, uint64_t, uint64_t, uint64_t); + +uint64_t __attribute__((section(".fp.transit4.text"))) __attribute__((__noinline__)) +_fp_transit4(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) +{ + uint64_t this_va; + asm volatile("adr %0, ." : "=r"(this_va)); + uint32_t *vptr = (uint32_t *)this_va; + while (*--vptr != ARM64_NOP) { + }; + fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); + hook_fargs4_t fargs; + fargs.early_ret = 0; + fargs.arg0 = arg0; + fargs.arg1 = arg1; + fargs.arg2 = arg2; + fargs.arg3 = arg3; + fargs.chain = hook_chain; + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain4_callback func = hook_chain->befores[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + if (!fargs.early_ret) { + transit4_func_t origin_func = (transit4_func_t)hook_chain->hook.origin_fp; + fargs.ret = origin_func(fargs.arg0, fargs.arg1, fargs.arg2, fargs.arg3); + } + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain4_callback func = hook_chain->afters[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + return fargs.ret; +} + +extern void _fp_transit4_end(); + +// transit8: +typedef uint64_t (*transit8_func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); + +uint64_t __attribute__((section(".fp.transit8.text"))) __attribute__((__noinline__)) +_fp_transit8(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, + uint64_t arg7) +{ + uint64_t this_va; + asm volatile("adr %0, ." : "=r"(this_va)); + uint32_t *vptr = (uint32_t *)this_va; + while (*--vptr != ARM64_NOP) { + }; + fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); + hook_fargs8_t fargs; + fargs.early_ret = 0; + fargs.arg0 = arg0; + fargs.arg1 = arg1; + fargs.arg2 = arg2; + fargs.arg3 = arg3; + fargs.arg4 = arg4; + fargs.arg5 = arg5; + fargs.arg6 = arg6; + fargs.arg7 = arg7; + fargs.chain = hook_chain; + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain8_callback func = hook_chain->befores[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + if (!fargs.early_ret) { + transit8_func_t origin_func = (transit8_func_t)hook_chain->hook.origin_fp; + fargs.ret = + origin_func(fargs.arg0, fargs.arg1, fargs.arg2, fargs.arg3, fargs.arg4, fargs.arg5, fargs.arg6, fargs.arg7); + } + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain8_callback func = hook_chain->afters[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + return fargs.ret; +} + +extern void _fp_transit8_end(); + +// transit12: +typedef uint64_t (*transit12_func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t, uint64_t, uint64_t); + +uint64_t __attribute__((section(".fp.transit12.text"))) __attribute__((__noinline__)) +_fp_transit12(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, + uint64_t arg7, uint64_t arg8, uint64_t arg9, uint64_t arg10, uint64_t arg11) +{ + uint64_t this_va; + asm volatile("adr %0, ." : "=r"(this_va)); + uint32_t *vptr = (uint32_t *)this_va; + while (*--vptr != ARM64_NOP) { + }; + fp_hook_chain_t *hook_chain = local_container_of((uint64_t)vptr, fp_hook_chain_t, transit); + hook_fargs12_t fargs; + fargs.early_ret = 0; + fargs.arg0 = arg0; + fargs.arg1 = arg1; + fargs.arg2 = arg2; + fargs.arg3 = arg3; + fargs.arg4 = arg4; + fargs.arg5 = arg5; + fargs.arg6 = arg6; + fargs.arg7 = arg7; + fargs.arg8 = arg8; + fargs.arg9 = arg9; + fargs.arg10 = arg10; + fargs.arg11 = arg11; + fargs.chain = hook_chain; + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain12_callback func = hook_chain->befores[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + if (!fargs.early_ret) { + transit12_func_t origin_func = (transit12_func_t)hook_chain->hook.origin_fp; + fargs.ret = origin_func(fargs.arg0, fargs.arg1, fargs.arg2, fargs.arg3, fargs.arg4, fargs.arg5, fargs.arg6, + fargs.arg7, fargs.arg8, fargs.arg9, fargs.arg10, fargs.arg11); + } + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; + hook_chain12_callback func = hook_chain->afters[i]; + if (func) func(&fargs, hook_chain->udata[i]); + } + return fargs.ret; +} + +extern void _fp_transit12_end(); + +static hook_err_t hook_chain_prepare(uint32_t *transit, int32_t argno) +{ + uint64_t transit_start, transit_end; + switch (argno) { + case 0: + transit_start = (uint64_t)_fp_transit0; + transit_end = (uint64_t)_fp_transit0_end; + break; + case 1: + case 2: + case 3: + case 4: + transit_start = (uint64_t)_fp_transit4; + transit_end = (uint64_t)_fp_transit4_end; + break; + case 5: + case 6: + case 7: + case 8: + transit_start = (uint64_t)_fp_transit8; + transit_end = (uint64_t)_fp_transit8_end; + break; + default: + transit_start = (uint64_t)_fp_transit12; + transit_end = (uint64_t)_fp_transit12_end; + break; + } + + int32_t transit_num = (transit_end - transit_start) / 4; + + // todo: assert + if (transit_num >= TRANSIT_INST_NUM) return -HOOK_TRANSIT_NO_MEM; + + transit[0] = ARM64_NOP; + for (int i = 0; i < transit_num; i++) { + transit[i + 1] = ((uint32_t *)transit_start)[i]; + } + return HOOK_NO_ERR; +} + +void fp_hook(uintptr_t fp_addr, void *replace, void **backup) +{ + uint64_t *entry = pgtable_entry_kernel(fp_addr); + uint64_t ori_prot = *entry; + *entry = (ori_prot | PTE_DBM) & ~PTE_RDONLY; + flush_tlb_kernel_page(fp_addr); + *(uintptr_t *)backup = *(uintptr_t *)fp_addr; + *(uintptr_t *)fp_addr = (uintptr_t)replace; + dsb(ish); + *entry = ori_prot; + flush_tlb_kernel_page(fp_addr); +} +KP_EXPORT_SYMBOL(fp_hook); + +void fp_unhook(uintptr_t fp_addr, void *backup) +{ + uint64_t *entry = pgtable_entry_kernel(fp_addr); + uint64_t ori_prot = *entry; + *entry = (ori_prot | PTE_DBM) & ~PTE_RDONLY; + flush_tlb_kernel_page(fp_addr); + *(uintptr_t *)fp_addr = (uintptr_t)backup; + dsb(ish); + isb(); + flush_icache_all(); + *entry = ori_prot; + flush_tlb_kernel_page(fp_addr); +} +KP_EXPORT_SYMBOL(fp_unhook); + +hook_err_t fp_hook_wrap(uintptr_t fp_addr, int32_t argno, void *before, void *after, void *udata) +{ + hook_err_t err = HOOK_NO_ERR; + if (!fp_addr) return -HOOK_INPUT_NULL; + fp_hook_chain_t *chain = hook_get_mem_from_origin(fp_addr); + if (!chain) { + chain = (fp_hook_chain_t *)hook_mem_zalloc(fp_addr, FUNCTION_POINTER_CHAIN); + if (!chain) return -HOOK_NO_MEM; + chain->hook.fp_addr = fp_addr; + chain->hook.replace_addr = (uint64_t)chain->transit; + err = hook_chain_prepare(chain->transit, argno); + if (err) return err; + flush_icache_all(); + fp_hook(chain->hook.fp_addr, (void *)chain->hook.replace_addr, (void **)&chain->hook.origin_fp); + } + + for (int i = 0; i < FP_HOOK_CHAIN_NUM; i++) { + // todo: atomic or lock + if (chain->states[i] == CHAIN_ITEM_STATE_EMPTY) { + chain->states[i] = CHAIN_ITEM_STATE_BUSY; + dsb(ish); + chain->udata[i] = udata; + chain->befores[i] = before; + chain->afters[i] = after; + if (i + 1 > chain->chain_items_max) { + chain->chain_items_max = i + 1; + } + dsb(ish); + chain->states[i] = CHAIN_ITEM_STATE_READY; + logkv("Wrap func pointer add: %llx, %llx, %llx successed\n", chain->hook.fp_addr, before, after); + return HOOK_NO_ERR; + } + } + logkv("Wrap func pointer add: %llx, %llx, %llx failed\n", chain->hook.fp_addr, before, after); + return -HOOK_CHAIN_FULL; +} +KP_EXPORT_SYMBOL(fp_hook_wrap); + +void fp_hook_unwrap(uintptr_t fp_addr, void *before, void *after) +{ + uint64_t origin = branch_func_addr(fp_addr); + fp_hook_chain_t *chain = (fp_hook_chain_t *)hook_get_mem_from_origin(origin); + if (!chain) return; + for (int i = 0; i < FP_HOOK_CHAIN_NUM; i++) { + if (chain->states[i] == CHAIN_ITEM_STATE_READY) + if ((before && chain->befores[i] == before) || (after && chain->afters[i] == after)) { + chain->states[i] = CHAIN_ITEM_STATE_BUSY; + dsb(ish); + chain->udata[i] = 0; + chain->befores[i] = 0; + chain->afters[i] = 0; + dsb(ish); + chain->states[i] = CHAIN_ITEM_STATE_EMPTY; + break; + } + } + logkv("Wrap func pointer remove: %llx, %llx, %llx\n", chain->hook.fp_addr, before, after); + + for (int i = 0; i < FP_HOOK_CHAIN_NUM; i++) { + if (chain->states[i] != CHAIN_ITEM_STATE_EMPTY) return; + } + fp_unhook(chain->hook.fp_addr, (void *)chain->hook.origin_fp); + hook_mem_free(chain); + logkv("Unwrap func pointer: %llx, %llx, %llx\n", fp_addr, before, after); +} +KP_EXPORT_SYMBOL(fp_hook_unwrap); \ No newline at end of file diff --git a/kernel/base/hmem.c b/kernel/base/hmem.c index f527106b..cfd13b4a 100644 --- a/kernel/base/hmem.c +++ b/kernel/base/hmem.c @@ -1,76 +1,72 @@ #include "hook.h" #include -#include -// todo: refactor -// todo: SCTLR_ELx.WXN Preventing execution from Writable memory - -static uint64_t mem_region_start[HOOK_MEM_REGION_NUM] = { 0 }; -static uint64_t mem_region_end[HOOK_MEM_REGION_NUM] = { 0 }; +static uint64_t mem_region_start = 0; +static uint64_t mem_region_end = 0; typedef struct { int using; - hook_chain_t chain; -} hook_mem_warp_t; + enum hook_type type; + uintptr_t addr; + // must align 8 + union + { + hook_t inl; + hook_chain_t inl_chain; + fp_hook_chain_t fp_chain; + } chain __attribute__((aligned(8))); +} hook_mem_warp_t __attribute__((aligned(16))); int hook_mem_add(uint64_t start, int32_t size) { for (uint64_t i = start; i < start + size; i += 8) { *(uint64_t *)i = 0; } - - for (int i = 0; i < HOOK_MEM_REGION_NUM; i++) { - if (!mem_region_start[i]) { - mem_region_start[i] = start; - mem_region_end[i] = start + size; - return 0; - } - } - return ERR_CAP_FULL; + mem_region_start = start; + mem_region_end = start + size; + return 0; } -hook_chain_t *hook_mem_alloc() +void *hook_mem_zalloc(uintptr_t origin_addr, enum hook_type type) { - for (int i = 0; i < HOOK_MEM_REGION_NUM; i++) { - uint64_t start = mem_region_start[i]; - if (!start) - continue; - for (uint64_t addr = start; addr < mem_region_end[i]; addr += sizeof(hook_mem_warp_t)) { - hook_mem_warp_t *wrap = (hook_mem_warp_t *)addr; - // todo: lock - if (wrap->using) - continue; + uint64_t start = mem_region_start; + for (uint64_t addr = start; addr < mem_region_end; addr += sizeof(hook_mem_warp_t)) { + hook_mem_warp_t *wrap = (hook_mem_warp_t *)addr; + if (wrap->using) continue; - wrap->using = 1; + wrap->using = 1; + wrap->addr = origin_addr; + wrap->type = type; - for (int j = local_offsetof(hook_mem_warp_t, chain); j < sizeof(hook_mem_warp_t); j += 8) { - *(uint64_t *)(addr + j) = 0; - } - return &wrap->chain; + for (uintptr_t i = (uintptr_t)&wrap->chain; i < (uintptr_t)&wrap->chain + sizeof(wrap->chain); i += 8) { + *(uint64_t *)i = 0; + } + + // todo: assert + if (((uintptr_t)&wrap->chain) & 0b111) { + return 0; } + return &wrap->chain; } return 0; } -inline void hook_mem_free(hook_chain_t *free) +void hook_mem_free(void *hook_mem) { - hook_mem_warp_t *warp = local_container_of(free, hook_mem_warp_t, chain); + hook_mem_warp_t *warp = local_container_of(hook_mem, hook_mem_warp_t, chain); warp->using = 0; } -hook_chain_t *hook_get_chain_from_origin(uint64_t origin_addr) +void *hook_get_mem_from_origin(uint64_t origin_addr) { - for (int i = 0; i < HOOK_MEM_REGION_NUM; i++) { - uint64_t start = mem_region_start[i]; - if (!start) - continue; - for (uint64_t addr = start; addr < mem_region_end[i]; addr += sizeof(hook_mem_warp_t)) { - hook_mem_warp_t *wrap = (hook_mem_warp_t *)addr; - if (wrap->using && wrap->chain.hook.origin_addr == origin_addr) { - return &wrap->chain; - } + uint64_t start = mem_region_start; + + for (uint64_t addr = start; addr < mem_region_end; addr += sizeof(hook_mem_warp_t)) { + hook_mem_warp_t *wrap = (hook_mem_warp_t *)addr; + if (wrap->using && wrap->addr == origin_addr) { + return &wrap->chain; } } return 0; diff --git a/kernel/base/hook.c b/kernel/base/hook.c index 17166486..6d1cdaa5 100644 --- a/kernel/base/hook.c +++ b/kernel/base/hook.c @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include #define bits32(n, high, low) ((uint32_t)((n) << (31u - (high))) >> (31u - (high) + (low))) #define bit(n, st) (((n) >> (st)) & 1) @@ -82,8 +85,7 @@ 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; - if (!(addr >= tramp_start && addr < tramp_end)) - return addr; + if (!(addr >= tramp_start && addr < tramp_end)) return addr; uint32_t addr_inst_index = (addr - tramp_start) / 4; uint64_t fix_addr = hook->relo_addr; for (int i = 0; i < addr_inst_index; i++) { @@ -99,7 +101,7 @@ static uint64_t relo_in_tramp(hook_t *hook, uint64_t addr) } #ifdef HOOK_INTO_BRANCH_FUNC -uint64_t relo_func(uint64_t addr) +uint64_t branch_func_addr(uint64_t addr) { uint32_t inst = *(uint32_t *)addr; if ((inst & MASK_B) == INST_B) { @@ -156,8 +158,7 @@ hook_err_t relo_adr(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t addr = inst_addr + sign64_extend((immhi << 2u) | immlo, 21u); } else { addr = (inst_addr + sign64_extend((immhi << 14u) | (immlo << 12u), 33u)) & 0xFFFFFFFFFFFFF000; - if (is_in_tramp(hook, addr)) - return HOOK_BAD_RELO; + if (is_in_tramp(hook, addr)) return -HOOK_BAD_RELO; } buf[0] = 0x58000040u | xd; // LDR Xd, #8 buf[1] = 0x14000003; // B #12 @@ -175,8 +176,7 @@ hook_err_t relo_ldr(hook_t *hook, uint64_t inst_addr, uint32_t inst, inst_type_t uint64_t offset = sign64_extend((imm19 << 2u), 21u); uint64_t addr = inst_addr + offset; - if (is_in_tramp(hook, addr) && type != INST_PRFM_LIT) - return HOOK_BAD_RELO; + if (is_in_tramp(hook, addr) && type != INST_PRFM_LIT) return -HOOK_BAD_RELO; addr = relo_in_tramp(hook, addr); @@ -276,6 +276,7 @@ int32_t branch_relative(uint32_t *buf, uint64_t src_addr, uint64_t dst_addr) } return 0; } +KP_EXPORT_SYMBOL(branch_relative); int32_t branch_absolute(uint32_t *buf, uint64_t addr) { @@ -285,16 +286,17 @@ int32_t branch_absolute(uint32_t *buf, uint64_t addr) buf[3] = addr >> 32u; return 4; } +KP_EXPORT_SYMBOL(branch_absolute); int32_t branch_from_to(uint32_t *tramp_buf, uint64_t src_addr, uint64_t dst_addr) { #if 1 uint32_t len = branch_relative(tramp_buf, src_addr, dst_addr); - if (len) - return len; + if (len) return len; #endif return branch_absolute(tramp_buf, dst_addr); } +KP_EXPORT_SYMBOL(branch_from_to); // transit0 typedef uint64_t (*transit0_func_t)(); @@ -310,19 +312,19 @@ uint64_t __attribute__((section(".transit0.text"))) __attribute__((__noinline__) hook_fargs0_t fargs; fargs.early_ret = 0; fargs.chain = hook_chain; - for (int32_t i = 0; i < HOOK_CHAIN_NUM; i++) { + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain0_callback func = hook_chain->befores[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } if (!fargs.early_ret) { transit0_func_t origin_func = (transit0_func_t)hook_chain->hook.relo_addr; fargs.ret = origin_func(); } - for (int32_t i = HOOK_CHAIN_NUM - 1; i >= 0; i--) { + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain0_callback func = hook_chain->afters[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } return fargs.ret; } @@ -347,19 +349,19 @@ _transit4(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) fargs.arg2 = arg2; fargs.arg3 = arg3; fargs.chain = hook_chain; - for (int32_t i = 0; i < HOOK_CHAIN_NUM; i++) { + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain4_callback func = hook_chain->befores[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } if (!fargs.early_ret) { transit4_func_t origin_func = (transit4_func_t)hook_chain->hook.relo_addr; fargs.ret = origin_func(fargs.arg0, fargs.arg1, fargs.arg2, fargs.arg3); } - for (int32_t i = HOOK_CHAIN_NUM - 1; i >= 0; i--) { + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain4_callback func = hook_chain->afters[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } return fargs.ret; } @@ -390,20 +392,20 @@ _transit8(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t a fargs.arg6 = arg6; fargs.arg7 = arg7; fargs.chain = hook_chain; - for (int32_t i = 0; i < HOOK_CHAIN_NUM; i++) { + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain8_callback func = hook_chain->befores[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } if (!fargs.early_ret) { transit8_func_t origin_func = (transit8_func_t)hook_chain->hook.relo_addr; fargs.ret = origin_func(fargs.arg0, fargs.arg1, fargs.arg2, fargs.arg3, fargs.arg4, fargs.arg5, fargs.arg6, fargs.arg7); } - for (int32_t i = HOOK_CHAIN_NUM - 1; i >= 0; i--) { + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain8_callback func = hook_chain->afters[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } return fargs.ret; } @@ -439,20 +441,20 @@ _transit12(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t fargs.arg10 = arg10; fargs.arg11 = arg11; fargs.chain = hook_chain; - for (int32_t i = 0; i < HOOK_CHAIN_NUM; i++) { + for (int32_t i = 0; i < hook_chain->chain_items_max; i++) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain12_callback func = hook_chain->befores[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } if (!fargs.early_ret) { transit12_func_t origin_func = (transit12_func_t)hook_chain->hook.relo_addr; fargs.ret = origin_func(fargs.arg0, fargs.arg1, fargs.arg2, fargs.arg3, fargs.arg4, fargs.arg5, fargs.arg6, fargs.arg7, fargs.arg8, fargs.arg9, fargs.arg10, fargs.arg11); } - for (int32_t i = HOOK_CHAIN_NUM - 1; i >= 0; i--) { + for (int32_t i = hook_chain->chain_items_max - 1; i >= 0; i--) { + if (hook_chain->states[i] != CHAIN_ITEM_STATE_READY) continue; hook_chain12_callback func = hook_chain->afters[i]; - if (func) - func(&fargs, hook_chain->udata[i]); + if (func) func(&fargs, hook_chain->udata[i]); } return fargs.ret; } @@ -511,12 +513,10 @@ static __noinline hook_err_t relocate_inst(hook_t *hook, uint64_t inst_addr, uin return rc; } -// todo: stop_machine -// todo: no task has the function in its call stack hook_err_t hook_prepare(hook_t *hook) { if (!hook->func_addr || !hook->origin_addr || !hook->replace_addr || !hook->relo_addr) { - return HOOK_INPUT_NULL; + return -HOOK_INPUT_NULL; } // backup origin instruction for (int i = 0; i < TRAMPOLINE_NUM; i++) { @@ -535,7 +535,7 @@ hook_err_t hook_prepare(hook_t *hook) uint32_t inst = hook->origin_insts[i]; hook_err_t relo_res = relocate_inst(hook, inst_addr, inst); if (relo_res) { - return HOOK_BAD_RELO; + return -HOOK_BAD_RELO; } } @@ -546,7 +546,9 @@ hook_err_t hook_prepare(hook_t *hook) hook->relo_insts_len += branch_from_to(buf, back_src_addr, back_dst_addr); return HOOK_NO_ERR; } +KP_EXPORT_SYMBOL(hook_prepare); +// todo: void hook_install(hook_t *hook) { uint64_t va = hook->origin_addr; @@ -554,6 +556,7 @@ void hook_install(hook_t *hook) uint64_t ori_prot = *entry; *entry = (ori_prot | PTE_DBM) & ~PTE_RDONLY; flush_tlb_kernel_page(va); + // todo: for (int32_t i = 0; i < hook->tramp_insts_len; i++) { *((uint32_t *)hook->origin_addr + i) = hook->tramp_insts[i]; } @@ -561,6 +564,7 @@ void hook_install(hook_t *hook) *entry = ori_prot; flush_tlb_kernel_page(va); } +KP_EXPORT_SYMBOL(hook_install); void hook_uninstall(hook_t *hook) { @@ -576,87 +580,82 @@ void hook_uninstall(hook_t *hook) *entry = ori_prot; flush_tlb_kernel_page(va); } +KP_EXPORT_SYMBOL(hook_uninstall); hook_err_t hook(void *func, void *replace, void **backup) { hook_err_t err = HOOK_NO_ERR; if (!func || !replace || !backup) { - return HOOK_INPUT_NULL; + return -HOOK_INPUT_NULL; } - hook_chain_t *chain = (hook_chain_t *)hook_mem_alloc(); - if (!chain) - return HOOK_NO_MEM; - hook_t *hook = &chain->hook; + uint64_t origin_addr = branch_func_addr((uintptr_t)func); + hook_t *hook = (hook_t *)hook_mem_zalloc(origin_addr, INLINE); + if (!hook) return -HOOK_NO_MEM; hook->func_addr = (uint64_t)func; - hook->origin_addr = relo_func(hook->func_addr); + hook->origin_addr = origin_addr; hook->replace_addr = (uint64_t)replace; hook->relo_addr = (uint64_t)hook->relo_insts; *backup = (void *)hook->relo_addr; logkv("Hook func: %llx, origin: %llx, replace: %llx, relocate: %llx, chain: %llx\n", hook->func_addr, - hook->origin_addr, hook->replace_addr, hook->relo_addr, chain); + hook->origin_addr, hook->replace_addr, hook->relo_addr, hook); err = hook_prepare(hook); - if (err) - goto out; + if (err) goto out; hook_install(hook); logkv("Hook func: %llx succsseed\n", hook->func_addr); return HOOK_NO_ERR; out: - hook_mem_free(chain); + hook_mem_free(hook); logkv("Hook func: %llx failed, err: %d\n", hook->func_addr, err); return err; } +KP_EXPORT_SYMBOL(hook); void unhook(void *func) { - uint64_t origin = relo_func((uint64_t)func); - hook_chain_t *chain = hook_get_chain_from_origin(origin); - if (!chain) - return; - hook_uninstall(&chain->hook); - hook_mem_free(chain); + uint64_t origin = branch_func_addr((uint64_t)func); + hook_t *hook = hook_get_mem_from_origin(origin); + if (!hook) return; + hook_uninstall(hook); + hook_mem_free(hook); logkv("Unhook func: %llx\n", func); } +KP_EXPORT_SYMBOL(unhook); -hook_err_t hook_chain_prepare(hook_chain_t *chain, int32_t argno) +static hook_err_t hook_chain_prepare(uint32_t *transit, int32_t argno) { - hook_t *hook = &chain->hook; - hook_err_t err = hook_prepare(hook); - if (err) - return err; - - uint64_t transit, transit_end; + uint64_t transit_start, transit_end; switch (argno) { case 0: - transit = (uint64_t)_transit0; + transit_start = (uint64_t)_transit0; transit_end = (uint64_t)_transit0_end; break; case 1: case 2: case 3: case 4: - transit = (uint64_t)_transit4; + transit_start = (uint64_t)_transit4; transit_end = (uint64_t)_transit4_end; break; case 5: case 6: case 7: case 8: - transit = (uint64_t)_transit8; + transit_start = (uint64_t)_transit8; transit_end = (uint64_t)_transit8_end; break; default: - transit = (uint64_t)_transit12; + transit_start = (uint64_t)_transit12; transit_end = (uint64_t)_transit12_end; break; } - int32_t transit_num = (transit_end - transit) / 4; - if (transit_num >= TRANSIT_INST_NUM) - return HOOK_TRANSIT_NO_MEM; + int32_t transit_num = (transit_end - transit_start) / 4; + // todo:assert + if (transit_num >= TRANSIT_INST_NUM) return -HOOK_TRANSIT_NO_MEM; - chain->transit[0] = ARM64_NOP; + transit[0] = ARM64_NOP; for (int i = 0; i < transit_num; i++) { - chain->transit[i + 1] = ((uint32_t *)transit)[i]; + transit[i + 1] = ((uint32_t *)transit_start)[i]; } return HOOK_NO_ERR; } @@ -664,44 +663,57 @@ hook_err_t hook_chain_prepare(hook_chain_t *chain, 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 (!chain->befores[i] && !chain->afters[i]) { + // todo: atomic or lock + if (chain->states[i] == CHAIN_ITEM_STATE_EMPTY) { + chain->states[i] = CHAIN_ITEM_STATE_BUSY; + dsb(ish); chain->udata[i] = udata; chain->befores[i] = before; chain->afters[i] = after; + if (i + 1 > chain->chain_items_max) { + chain->chain_items_max = i + 1; + } + dsb(ish); + chain->states[i] = CHAIN_ITEM_STATE_READY; logkv("Wrap chain add: %llx, %llx, %llx successed\n", chain->hook.func_addr, before, after); return HOOK_NO_ERR; } } - logkv("Wrap chain add: %llx, %llx, %llx filed\n", chain->hook.func_addr, before, after); - return HOOK_CHAIN_FULL; + logkv("Wrap chain add: %llx, %llx, %llx failed\n", chain->hook.func_addr, before, after); + return -HOOK_CHAIN_FULL; } +KP_EXPORT_SYMBOL(hook_chain_add); void hook_chain_remove(hook_chain_t *chain, void *before, void *after) { for (int i = 0; i < HOOK_CHAIN_NUM; i++) { - if ((before && chain->befores[i] == before) || (after && chain->afters[i] == after)) { - chain->udata[i] = 0; - chain->befores[i] = 0; - chain->afters[i] = 0; - break; - } + if (chain->states[i] == CHAIN_ITEM_STATE_READY) + if ((before && chain->befores[i] == before) || (after && chain->afters[i] == after)) { + chain->states[i] = CHAIN_ITEM_STATE_BUSY; + dsb(ish); + chain->udata[i] = 0; + chain->befores[i] = 0; + chain->afters[i] = 0; + dsb(ish); + chain->states[i] = CHAIN_ITEM_STATE_EMPTY; + break; + } } logkv("Wrap chain remove: %llx, %llx, %llx\n", chain->hook.func_addr, before, after); } +KP_EXPORT_SYMBOL(hook_chain_remove); // todo: lock hook_err_t hook_wrap(void *func, int32_t argno, void *before, void *after, void *udata) { - if (!func) - return HOOK_INPUT_NULL; + if (!func) return -HOOK_INPUT_NULL; uint64_t faddr = (uint64_t)func; - uint64_t origin = relo_func(faddr); - hook_chain_t *chain = hook_get_chain_from_origin(origin); - if (chain) - return hook_chain_add(chain, before, after, udata); - chain = hook_mem_alloc(); - if (!chain) - return HOOK_NO_MEM; + uint64_t origin = branch_func_addr(faddr); + hook_chain_t *chain = (hook_chain_t *)hook_get_mem_from_origin(origin); + if (chain) return hook_chain_add(chain, before, after, udata); + chain = (hook_chain_t *)hook_mem_zalloc(origin, INLINE_CHAIN); + if (!chain) return -HOOK_NO_MEM; + chain->chain_items_max = 0; hook_t *hook = &chain->hook; hook->func_addr = faddr; hook->origin_addr = origin; @@ -709,12 +721,12 @@ hook_err_t hook_wrap(void *func, int32_t argno, void *before, void *after, void hook->relo_addr = (uint64_t)hook->relo_insts; logkv("Wrap func: %llx, origin: %llx, replace: %llx, relocate: %llx, chain: %llx\n", hook->func_addr, hook->origin_addr, hook->replace_addr, hook->relo_addr, chain); - hook_err_t err = hook_chain_prepare(chain, argno); - if (err) - goto err; + hook_err_t err = hook_prepare(hook); + if (err) goto err; + err = hook_chain_prepare(chain->transit, argno); + if (err) goto err; err = hook_chain_add(chain, before, after, udata); - if (err) - goto err; + if (err) goto err; hook_chain_install(chain); logkv("Wrap func: %llx succsseed\n", hook->func_addr); return HOOK_NO_ERR; @@ -723,20 +735,22 @@ hook_err_t hook_wrap(void *func, int32_t argno, void *before, void *after, void logkv("Wrap func: %llx failed, err: %d\n", hook->func_addr, err); return err; } +KP_EXPORT_SYMBOL(hook_wrap); void hook_unwrap(void *func, void *before, void *after) { uint64_t faddr = (uint64_t)func; - uint64_t origin = relo_func(faddr); - hook_chain_t *chain = hook_get_chain_from_origin(origin); - if (!chain) - return; + uint64_t origin = branch_func_addr(faddr); + hook_chain_t *chain = (hook_chain_t *)hook_get_mem_from_origin(origin); + if (!chain) return; hook_chain_remove(chain, before, after); + + // todo: for (int i = 0; i < HOOK_CHAIN_NUM; i++) { - if (chain->befores[i] || chain->afters[i]) - return; + if (chain->states[i] != CHAIN_ITEM_STATE_EMPTY) return; } hook_chain_uninstall(chain); hook_mem_free(chain); logkv("Unwrap func: %llx\n", func); } +KP_EXPORT_SYMBOL(hook_unwrap); diff --git a/kernel/base/log.c b/kernel/base/log.c new file mode 100644 index 00000000..cfb603fa --- /dev/null +++ b/kernel/base/log.c @@ -0,0 +1,7 @@ +#include + +#define BOOT_LOG_SIZE 1024 + +static char boot_log[BOOT_LOG_SIZE] = { 0 }; +static int boot_log_len = 0; +static int boot_log_fin = 0; diff --git a/kernel/base/map.c b/kernel/base/map.c index 2e60a23d..986eca33 100644 --- a/kernel/base/map.c +++ b/kernel/base/map.c @@ -106,12 +106,12 @@ static map_preset_t *__noinline mem_proc() page_shift = 16; } preset->page_shift = page_shift; - preset->page_offset = preset->vabits_flag ? -(1ul << va1_bits) : (0xffffffffffffffff << (va1_bits - 1)); + preset->page_offset = preset->vabits_flag ? -(1ul << va1_bits) : (0xFFFFFFFFFFFFFFFF << (va1_bits - 1)); return preset; } // todo: 52-bits pa -static uint64_t __noinline get_or_create_pte(map_preset_t *preset, uint64_t va, uint64_t pa) +static uint64_t __noinline get_or_create_pte(map_preset_t *preset, uint64_t va, uint64_t pa, uint64_t attr_indx) { #ifdef MAP_DEBUG printk_f printk = (printk_f)(preset->printk_relo); @@ -129,18 +129,23 @@ static uint64_t __noinline get_or_create_pte(map_preset_t *preset, uint64_t va, uint64_t pxd_ptrs = 1u << pxd_bits; uint64_t ttbr1_el1; asm volatile("mrs %0, ttbr1_el1" : "=r"(ttbr1_el1)); + uint64_t baddr = ttbr1_el1 & 0xFFFFFFFFFFFE; uint64_t page_size = 1 << page_shift; uint64_t page_size_mask = ~(page_size - 1); - uint64_t pxd_pa = ttbr1_el1 & page_size_mask; + uint64_t attr_prot = 0xC0000000000703 | attr_indx; + + uint64_t pxd_pa = baddr & page_size_mask; uint64_t pxd_va = phys_to_lm(preset, pxd_pa); uint64_t pxd_entry_va = 0; - uint64_t block_flag = 0; - uint64_t alloc_flag = 0; - for (int64_t lv = 4 - page_level; lv < 4; lv++) { + for (uint64_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); + uint64_t alloc_flag = 0; + uint64_t block_flag = 0; + pxd_entry_va = pxd_va + pxd_index * 8; + uint64_t pxd_desc = *((uint64_t *)pxd_entry_va); if ((pxd_desc & 0b11) == 0b11) { // table @@ -156,10 +161,8 @@ static uint64_t __noinline get_or_create_pte(map_preset_t *preset, uint64_t va, alloc_flag = 1; } else { pxd_pa = pa; - alloc_flag = 0; } - uint64_t attr_prot = lv == 3 ? 0xC8000000000700 : 0x1000000000000000; - pxd_desc = (pxd_pa) | 0b11 | attr_prot; + pxd_desc = (pxd_pa) | attr_prot; *((uint64_t *)pxd_entry_va) = pxd_desc; } pxd_va = phys_to_lm(preset, pxd_pa); @@ -182,12 +185,13 @@ void __noinline _paging_init() #ifdef MAP_DEBUG printk_f printk = (printk_f)(preset->printk_relo); #define map_debug(idx, val) printk(preset->str_fmt_px, idx, val) -#else -#define map_debug(idx, val) -#endif for (int i = 0; i < sizeof(map_preset_t); i += 8) { map_debug(i, *(uint64_t *)((uint64_t)preset + i)); } +#else +#define map_debug(idx, val) +#endif + // todo: memblock_free uint64_t old_start_pa = preset->start_offset + preset->kernel_pa; ((memblock_reserve_f)preset->memblock_reserve_relo)(old_start_pa, preset->start_size); @@ -208,26 +212,33 @@ void __noinline _paging_init() flush_icache_all(); ((paging_init_f)(paging_init_va))(); + // AttrIndx[2:0] encoding + uint64_t ktext_pte = get_or_create_pte(preset, preset->memblock_reserve_relo, 0, 0); + uint64_t attrs = *(uint64_t *)ktext_pte; + map_debug(0x100, attrs); + uint64_t attr_indx = attrs & 0b11100; + // clear wxn // todo: restore wxn later uint64_t sctlr_el1 = 0; asm volatile("mrs %[reg], sctlr_el1" : [reg] "+r"(sctlr_el1)); sctlr_el1 &= 0xFFFFFFFFFFF7FFFF; asm volatile("msr sctlr_el1, %[reg]" : : [reg] "r"(sctlr_el1)); - asm volatile("isb"); // start uint64_t old_start_va = phys_to_lm(preset, old_start_pa); - // todo: random address // uint64_t vm_gurad_enough = page_size << 3; uint64_t offset = 0; uint64_t start_va = preset->kimage_voffset_relo ? phys_to_kimg(preset, start_pa) + offset : phys_to_lm(preset, start_pa); for (uint64_t off = 0; off < alloc_size; off += page_size) { - uint64_t entry = get_or_create_pte(preset, start_va + off, start_pa + off); + uint64_t entry = get_or_create_pte(preset, start_va + off, start_pa + off, attr_indx); *(uint64_t *)entry = (*(uint64_t *)entry | 0x8000000000000) & 0xFFDFFFFFFFFFFF7F; } flush_tlb_all(); + for (uint64_t i = start_va; i < start_va + alloc_size; i += 8) { + *(uint64_t *)i = 0; + } for (uint64_t i = 0; i < preset->start_size; i += 8) { *(uint64_t *)(start_va + i) = *(uint64_t *)(old_start_va + i); } diff --git a/kernel/base/map1.S b/kernel/base/map1.S new file mode 100644 index 00000000..780e3a8f --- /dev/null +++ b/kernel/base/map1.S @@ -0,0 +1,2 @@ + +// todo: \ No newline at end of file diff --git a/kernel/base/predata.c b/kernel/base/predata.c index b8d71458..f551e44f 100644 --- a/kernel/base/predata.c +++ b/kernel/base/predata.c @@ -5,28 +5,32 @@ #include "start.h" static char superkey[SUPER_KEY_LEN] = { '\0' }; -static int32_t superkey_len = 0; +static int superkey_len = 0; +static struct patch_config *patch_config = 0; -int superkey_auth(const char *key, int32_t len) +int superkey_auth(const char *key, int len) { - if (!key || len <= 0 || superkey_len != len) - return -1; + if (!key || len <= 0 || superkey_len != len) return -1; for (int i = 0; i < len; i++) { - if (superkey[i] != key[i]) - return -1; + if (superkey[i] != key[i]) return -1; } return 0; } -int predata_init() +struct patch_config *get_preset_patch_cfg() { - for (int32_t i = 0; i < SUPER_KEY_LEN; i++) { - char c = start_preset.superkey[i]; + return patch_config; +} + +void predata_init(const char *skey, struct patch_config *config) +{ + for (int i = 0; i < SUPER_KEY_LEN; i++) { + char c = skey[i]; if (!c) { superkey_len = i; break; } superkey[i] = c; } - return 0; + patch_config = config; } \ No newline at end of file diff --git a/kernel/base/setup1.S b/kernel/base/setup1.S index fb3ecebb..16b943a5 100644 --- a/kernel/base/setup1.S +++ b/kernel/base/setup1.S @@ -179,8 +179,10 @@ map_prepare: add x12, x12, :lo12:_kp_start sub x11, x11, x12 str x11, [x9, #map_start_size_offset] - // map_preset.alloc_size = HOOK_ALLOC_SIZE; + // map_preset.alloc_size = HOOK_ALLOC_SIZE + MEMORY_ROX_SIZE + MEMORY_RW_SIZE; mov x11, #HOOK_ALLOC_SIZE + add x11, x11, #MEMORY_ROX_SIZE + add x11, x11, #MEMORY_RW_SIZE str x11, [x9, #map_alloc_size_offset] // backup and hook paging_init diff --git a/kernel/base/start.c b/kernel/base/start.c index ee97df05..e6fbff33 100644 --- a/kernel/base/start.c +++ b/kernel/base/start.c @@ -4,22 +4,45 @@ #include #include #include -#include #include #include #include +#include +#include #include "start.h" #include "hook.h" +#include "tlsf.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)) start_preset_t start_preset __attribute__((section(".start.data"))); 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); + 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; + +const char kernel_patch_logo[] = "\n" + " _ __ _ ____ _ _ \n" + "| |/ /___ _ __ _ __ ___| | _ \\ __ _| |_ ___| |__ \n" + "| ' // _ \\ '__| '_ \\ / _ \\ | |_) / _` | __/ __| '_ \\ \n" + "| . \\ __/ | | | | | __/ | __/ (_| | || (__| | | |\n" + "|_|\\_\\___|_| |_| |_|\\___|_|_| \\__,_|\\__\\___|_| |_|\n"; +KP_EXPORT_SYMBOL(kernel_patch_logo); static struct vm_struct { @@ -45,11 +68,19 @@ KP_EXPORT_SYMBOL(kpver); endian_t endian = little; KP_EXPORT_SYMBOL(endian); +uint64_t _kp_hook_start = 0; +uint64_t _kp_hook_end = 0; +uint64_t _kp_rox_start = 0; +uint64_t _kp_rox_end = 0; +uint64_t _kp_rw_start = 0; +uint64_t _kp_rw_end = 0; +uint64_t _kp_region_start = 0; +uint64_t _kp_region_end = 0; + uint64_t kernel_va = 0; uint64_t kernel_stext_va = 0; uint64_t kernel_pa = 0; int64_t kernel_size = 0; -int64_t vabits_flag = 0; int64_t memstart_addr = 0; uint64_t kimage_voffset = 0; uint64_t page_offset = 0; @@ -59,6 +90,35 @@ int64_t va_bits = 0; uint64_t kp_kimg_offset = 0; // int64_t pa_bits = 0; +tlsf_t kp_rw_mem = 0; +tlsf_t kp_rox_mem = 0; + +#define BOOT_LOG_SIZE 4096 +static char boot_log[BOOT_LOG_SIZE] = { 0 }; +static int boot_log_offset = 0; + +static inline bool hw_dirty() +{ + uint64_t tcr_el1; + asm volatile("mrs %0, tcr_el1" : "=r"(tcr_el1)); + return tcr_el1 & 0x10000000000; +} + +const char *get_boot_log() +{ + return boot_log; +} + +void log_boot(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + int ret = vsprintf(boot_log + boot_log_offset, fmt, va); + va_end(va); + printk("KP %s", boot_log + boot_log_offset); + boot_log_offset += ret; +} + uint64_t *pgtable_entry_kernel(uint64_t va) { uint64_t page_level = (va_bits - 4) / (page_shift - 3); @@ -66,10 +126,10 @@ uint64_t *pgtable_entry_kernel(uint64_t va) uint64_t pxd_ptrs = 1u << pxd_bits; uint64_t ttbr1_el1; asm volatile("mrs %0, ttbr1_el1" : "=r"(ttbr1_el1)); + uint64_t baddr = ttbr1_el1 & 0xFFFFFFFFFFFE; uint64_t page_size = 1 << page_shift; uint64_t page_size_mask = ~(page_size - 1); - uint64_t pxd_pa = ttbr1_el1 & page_size_mask; - + uint64_t pxd_pa = baddr & page_size_mask; uint64_t pxd_va = phys_to_virt(pxd_pa); uint64_t pxd_entry_va = 0; uint64_t block_lv = 0; @@ -78,12 +138,8 @@ uint64_t *pgtable_entry_kernel(uint64_t va) 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; - } + 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 @@ -110,25 +166,29 @@ uint64_t *pgtable_entry_kernel(uint64_t va) return 0; } #endif - // todo: some cache ??????????? - // printk("pgtable va: %llx, entry: %llx, desc: %llx\n", va, pxd_entry_va, *(uint64_t *)pxd_entry_va); - printk(""); + // todo: + __flush_dcache_all(); return (uint64_t *)pxd_entry_va; } +KP_EXPORT_SYMBOL(pgtable_entry_kernel); -static __noinline int prot_myself() +static __noinline void prot_myself() { + uint64_t *kpte = pgtable_entry_kernel(kernel_stext_va); + 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; + log_boot("Region: %llx, %llx\n", _kp_region_start, _kp_region_end); + // text, rodata uint64_t text_start = (uint64_t)_kp_text_start; uint64_t text_end = (uint64_t)_kp_text_end; uint64_t align_text_end = align_ceil(text_end, page_size); - printk("KP Text start: %llx\n", text_start); - printk("KP Text end: %llx\n", text_end); + log_boot("Text: %llx, %llx\n", text_start, text_end); for (uint64_t i = text_start; i < align_text_end; i += page_size) { uint64_t *pte = pgtable_entry_kernel(i); - if (!pte) - return ERR_PGTABLE; *pte |= PTE_SHARED; *pte = *pte & ~PTE_PXN; if (kimage_voffset) { @@ -142,13 +202,10 @@ static __noinline int prot_myself() uint64_t data_start = (uint64_t)_kp_data_start; uint64_t data_end = (uint64_t)_kp_data_end; uint64_t align_data_end = align_ceil(data_end, page_size); - printk("KP Data start: %llx\n", data_start); - printk("KP Data end: %llx\n", data_end); + log_boot("Data: %llx, %llx\n", data_start, data_end); for (uint64_t i = data_start; i < align_data_end; i += page_size) { uint64_t *pte = pgtable_entry_kernel(i); - if (!pte) - return ERR_PGTABLE; *pte = (*pte | PTE_DBM | PTE_SHARED) & ~PTE_RDONLY; if (kimage_voffset) { *pte |= PTE_PXN; @@ -157,45 +214,77 @@ static __noinline int prot_myself() flush_tlb_kernel_range(data_start, align_data_end); // rwx for hook - // todo: w when needed - uint64_t hook_start = (uint64_t)_kp_end; - uint64_t hook_end = hook_start + HOOK_ALLOC_SIZE; - printk("KP Hook start: %llx\n", hook_start); - printk("KP Hook end: %llx\n", hook_end); + // todo: remove + _kp_hook_start = (uint64_t)_kp_end; + _kp_hook_end = _kp_hook_start + HOOK_ALLOC_SIZE; + log_boot("Hook: %llx, %llx\n", _kp_hook_start, _kp_hook_end); - for (uint64_t i = hook_start; i < hook_end; i += page_size) { + 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; } - flush_tlb_kernel_range(hook_start, hook_end); - hook_mem_add(hook_start, HOOK_ALLOC_SIZE); + flush_tlb_kernel_range(_kp_hook_start, _kp_hook_end); + hook_mem_add(_kp_hook_start, HOOK_ALLOC_SIZE); + + // rw memory + _kp_rw_start = _kp_hook_end; + _kp_rw_end = _kp_rw_start + MEMORY_RW_SIZE; + log_boot("RW: %llx, %llx\n", _kp_rw_start, _kp_rw_end); + + for (uint64_t i = _kp_rw_start; i < _kp_rw_end; i += page_size) { + uint64_t *pte = pgtable_entry_kernel(i); + *pte = (*pte | PTE_DBM | PTE_SHARED) & ~PTE_RDONLY; + if (kimage_voffset) { + *pte |= PTE_PXN; + } + } + flush_tlb_kernel_range(_kp_rw_start, _kp_rw_end); + kp_rw_mem = tlsf_create_with_pool((void *)_kp_rw_start, MEMORY_RW_SIZE); + + // rox memory + kp_rox_mem = tlsf_malloc(kp_rw_mem, tlsf_size()); + tlsf_create(kp_rox_mem); + + _kp_rox_start = _kp_rw_end; + _kp_rox_end = _kp_rox_start + MEMORY_ROX_SIZE; + log_boot("ROX: %llx, %llx\n", _kp_rox_start, _kp_rox_end); + + tlsf_add_pool(kp_rox_mem, (void *)_kp_rox_start, MEMORY_ROX_SIZE); + + 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; + // todo: tlsf malloc block_split will write to alloced memory + // if (kimage_voffset) { + // *pte |= PTE_RDONLY; + // *pte &= ~PTE_DBM; + // } + } + flush_tlb_kernel_range(_kp_rox_start, _kp_rox_end); // add to vmalloc area if (kimage_voffset) { - printk("KP Add to vmalloc area\n"); + // log_boot("Add to vmalloc area", 0, 0); void (*vm_area_add_early)(struct vm_struct *vm) = (typeof(vm_area_add_early))kallsyms_lookup_name("vm_area_add_early"); - kp_vm.addr = (void *)text_start; - kp_vm.phys_addr = kp_kimg_to_phys(text_start); - kp_vm.size = hook_end - text_start; + kp_vm.addr = (void *)_kp_region_start; + kp_vm.phys_addr = kp_kimg_to_phys(_kp_region_start); + kp_vm.size = _kp_region_end - _kp_region_start; kp_vm.flags = 0x00000044; - kp_vm.caller = (void *)text_start; + kp_vm.caller = (void *)_kp_region_start; vm_area_add_early(&kp_vm); } - return 0; } -static __noinline int restore_map() +static __noinline void restore_map() { uint64_t start = kernel_va + start_preset.map_offset; uint64_t end = start + start_preset.map_backup_len; - printk("KP Restore start: %llx\n", start); - printk("KP Restore end: %llx\n", end); + log_boot("Restore: %llx, %llx\n", start, end); for (uint64_t i = start; i < align_ceil(end, page_size); i += page_size) { uint64_t *pte = pgtable_entry_kernel(i); - if (!pte) - return ERR_PGTABLE; uint64_t orig = *pte; *pte = (orig | PTE_DBM) & ~PTE_RDONLY; flush_tlb_kernel_page(i); @@ -206,26 +295,19 @@ static __noinline int restore_map() flush_tlb_kernel_page(i); } flush_icache_all(); - return 0; } -static __noinline int pgtable_init() +static __noinline void pgtable_init() { uint64_t addr = kallsyms_lookup_name("memstart_addr"); if (addr) { memstart_addr = *(int64_t *)addr; } + addr = kallsyms_lookup_name("kimage_voffset"); if (addr) { kimage_voffset = *(uint64_t *)addr; } - addr = kallsyms_lookup_name("vabits_actual"); - if (addr) { - vabits_flag = 1; - } - if (kver >= VERSION(6, 0, 0)) { - vabits_flag = 1; - } uint64_t tcr_el1; asm volatile("mrs %0, tcr_el1" : "=r"(tcr_el1)); @@ -239,18 +321,17 @@ static __noinline int pgtable_init() } else if (tg1 == 3) { page_shift = 16; } - page_size = 1 << page_shift; - page_offset = vabits_flag ? -(1ul << va_bits) : (0xffffffffffffffff << (va_bits - 1)); - - return 0; + uint64_t vabits_actual_addr = kallsyms_lookup_name("vabits_actual"); + page_offset = (vabits_actual_addr || kver >= VERSION(6, 0, 0)) ? -(1ul << va_bits) : + (0xffffffffffffffff << (va_bits - 1)); } #define log_reg(regname) \ do { \ uint64_t regname##_val = 0; \ asm volatile("mrs %[val], " #regname : [val] "+r"(regname##_val)); \ - printk("KP " #regname ": %llx\n", regname##_val); \ + log_boot("" #regname ": %llx\n", regname##_val); \ } while (0) static __noinline void log_regs() @@ -305,7 +386,7 @@ static __noinline void log_regs() // log_reg(PMSIDR_EL1); // | R [4] | Sampling Profiling ID Register } -static __noinline int start_init(uint64_t kva, uint64_t offset) +static __noinline void start_init(uint64_t kva, uint64_t offset) { kernel_va = kva; kp_kimg_offset = offset; @@ -318,32 +399,27 @@ static __noinline int start_init(uint64_t kva, uint64_t offset) if (!printk) { printk = (typeof(printk))kallsyms_lookup_name("_printk"); } - if (!printk) { - return ERR_NO_SUCH_SYMBOL; - } + vsprintf = (typeof(vsprintf))kallsyms_lookup_name("vsprintf"); - printk("KP ==== KernelPatch Starting ====\n"); + log_boot(kernel_patch_logo); endian = *(unsigned char *)&(uint16_t){ 1 } ? little : big; kver = VERSION(start_preset.kernel_version.major, start_preset.kernel_version.minor, start_preset.kernel_version.patch); kpver = VERSION(start_preset.kp_version.major, start_preset.kp_version.minor, start_preset.kp_version.patch); - // todo: ?? In some case, (ranchu, api28, 4.4.302, api29, 4.14.175), sometimes, format string (%xx) cause "BUG: recent printk recursion!" - printk("KP Kernel pa: %llx\n", kernel_pa); - printk("KP Kernel va: %llx\n", kernel_va); - printk("KP Kernel Patch Version: %x\n", kpver); - printk("KP Kernel Patch Compile Time: %s\n", start_preset.compile_time); + + log_boot("Kernel pa: %llx\n", kernel_pa); + log_boot("Kernel va: %llx\n", kernel_va); + log_boot("Kernel Patch Version: %x\n", kpver); + log_boot("Kernel Patch Compile Time: %s\n", (uint64_t)start_preset.compile_time); 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"); - - return 0; } -static __noinline int nice_zone() +static int nice_zone() { int err = 0; - printk("KP ==== KernelPatch Entering Nicezone ====\n"); err = patch(); @@ -352,24 +428,14 @@ static __noinline int nice_zone() int __attribute__((section(".start.text"))) __noinline start(uint64_t kva, uint64_t offset) { - int err = 0; - if ((err = start_init(kva, offset))) - goto out; + int rc = 0; + start_init(kva, offset); + pgtable_init(); + prot_myself(); + restore_map(); log_regs(); - if ((err = pgtable_init())) - goto out; - if ((err = prot_myself())) - goto out; - if ((err = restore_map())) - goto out; - - if ((err = predata_init())) - goto out; - if ((err = symbol_init())) - goto out; - - if ((err = nice_zone())) - goto out; -out: - return err; + predata_init((const char *)start_preset.superkey, &start_preset.patch_config); + symbol_init(); + rc = nice_zone(); + return rc; } diff --git a/kernel/base/start.h b/kernel/base/start.h index 3905f987..d1bc206f 100644 --- a/kernel/base/start.h +++ b/kernel/base/start.h @@ -1,11 +1,7 @@ #ifndef _KP_START_H_ #define _KP_START_H_ -#include "preset.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)) +#include #ifndef __ASSEMBLY__ typedef struct @@ -38,19 +34,4 @@ typedef struct #define start_patch_config_offset (start_map_backup_offset + MAP_MAX_SIZE) #endif -#ifndef __ASSEMBLY__ - -extern start_preset_t start_preset; - -int predata_init(); - -void _kp_start(); -void _kp_text_start(); -void _kp_text_end(); -void _kp_data_start(); -void _kp_data_end(); -void _kp_end(); - -#endif - #endif // _KP_START_H_ \ No newline at end of file diff --git a/kernel/base/symbol.c b/kernel/base/symbol.c index bb458693..f71dcfc5 100644 --- a/kernel/base/symbol.c +++ b/kernel/base/symbol.c @@ -10,7 +10,7 @@ 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 exec_base_addr = 0; +static unsigned long runtime_base_addr = 0; // DJB2 static unsigned long sym_hash(const char *str) @@ -31,8 +31,7 @@ int local_strcmp(const char *s1, const char *s2) int d = 0; while (1) { d = (int)(ch = *c1++) - (int)*c2++; - if (d || !ch) - break; + if (d || !ch) break; } return d; } @@ -51,16 +50,14 @@ unsigned long symbol_lookup_name(const char *name) int symbol_init() { - exec_base_addr = (unsigned long)_link_base; + runtime_base_addr = (unsigned long)_link_base; symbol_start = (uint64_t)_kp_symbol_start; symbol_end = (uint64_t)_kp_symbol_end; - printk("KP Symbol link base: %llx\n", link_base_addr); - printk("KP Symbol exec base: %llx\n", exec_base_addr); - printk("KP Symbol start: %llx\n", symbol_start); - printk("KP Symbol end: %llx\n", 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 + exec_base_addr; + symbol->addr = symbol->addr - link_base_addr + runtime_base_addr; symbol->hash = sym_hash(symbol->name); } return 0; diff --git a/kernel/base/tlsf.c b/kernel/base/tlsf.c new file mode 100644 index 00000000..a87d5c2f --- /dev/null +++ b/kernel/base/tlsf.c @@ -0,0 +1,1219 @@ +#include +#include +#include + +#include "tlsf.h" + +// todo: +#define printf logkd +#define CHAR_BIT 8 +#define tlsf_assert(x) + +#if defined(__cplusplus) +#define tlsf_decl inline +#else +#define tlsf_decl static +#endif + +/* +** Architecture-specific bit manipulation routines. +** +** TLSF achieves O(1) cost for malloc and free operations by limiting +** the search for a free block to a free list of guaranteed size +** adequate to fulfill the request, combined with efficient free list +** queries using bitmasks and architecture-specific bit-manipulation +** routines. +** +** Most modern processors provide instructions to count leading zeroes +** in a word, find the lowest and highest set bit, etc. These +** specific implementations will be used when available, falling back +** to a reasonably efficient generic implementation. +** +** NOTE: TLSF spec relies on ffs/fls returning value 0..31. +** ffs/fls return 1-32 by default, returning 0 for error. +*/ + +/* +** Detect whether or not we are building for a 32- or 64-bit (LP/LLP) +** architecture. There is no reliable portable method at compile-time. +*/ +#if defined(__alpha__) || defined(__ia64__) || defined(__x86_64__) || defined(_WIN64) || defined(__LP64__) || \ + defined(__LLP64__) +#define TLSF_64BIT +#endif + +/* +** gcc 3.4 and above have builtin support, specialized for architecture. +** Some compilers masquerade as gcc; patchlevel test filters them out. +*/ +#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__GNUC_PATCHLEVEL__) + +#if defined(__SNC__) +/* SNC for Playstation 3. */ + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __builtin_clz(reverse); + return bit - 1; +} + +#else + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + return __builtin_ffs(word) - 1; +} + +#endif + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __builtin_clz(word) : 0; + return bit - 1; +} + +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64)) +/* Microsoft Visual C++ support on x86/X64 architectures. */ + +#include + +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) + +tlsf_decl int tlsf_fls(unsigned int word) +{ + unsigned long index; + return _BitScanReverse(&index, word) ? index : -1; +} + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + unsigned long index; + return _BitScanForward(&index, word) ? index : -1; +} + +#elif defined(_MSC_VER) && defined(_M_PPC) +/* Microsoft Visual C++ support on PowerPC architectures. */ + +#include + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = 32 - _CountLeadingZeros(word); + return bit - 1; +} + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - _CountLeadingZeros(reverse); + return bit - 1; +} + +#elif defined(__ARMCC_VERSION) +/* RealView Compilation Tools for ARM */ + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __clz(reverse); + return bit - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __clz(word) : 0; + return bit - 1; +} + +#elif defined(__ghs__) +/* Green Hills support for PowerPC */ + +#include + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __CLZ32(reverse); + return bit - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __CLZ32(word) : 0; + return bit - 1; +} + +#else +/* Fall back to generic implementation. */ + +tlsf_decl int tlsf_fls_generic(unsigned int word) +{ + int bit = 32; + + if (!word) bit -= 1; + if (!(word & 0xffff0000)) { + word <<= 16; + bit -= 16; + } + if (!(word & 0xff000000)) { + word <<= 8; + bit -= 8; + } + if (!(word & 0xf0000000)) { + word <<= 4; + bit -= 4; + } + if (!(word & 0xc0000000)) { + word <<= 2; + bit -= 2; + } + if (!(word & 0x80000000)) { + word <<= 1; + bit -= 1; + } + + return bit; +} + +/* Implement ffs in terms of fls. */ +tlsf_decl int tlsf_ffs(unsigned int word) +{ + return tlsf_fls_generic(word & (~word + 1)) - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + return tlsf_fls_generic(word) - 1; +} + +#endif + +/* Possibly 64-bit version of tlsf_fls. */ +#if defined(TLSF_64BIT) +tlsf_decl int tlsf_fls_sizet(size_t size) +{ + int high = (int)(size >> 32); + int bits = 0; + if (high) { + bits = 32 + tlsf_fls(high); + } else { + bits = tlsf_fls((int)size & 0xffffffff); + } + return bits; +} +#else +#define tlsf_fls_sizet tlsf_fls +#endif + +#undef tlsf_decl + +/* +** Constants. +*/ + +/* Public constants: may be modified. */ +enum tlsf_public +{ + /* log2 of number of linear subdivisions of block sizes. Larger + ** values require more memory in the control structure. Values of + ** 4 or 5 are typical. + */ + SL_INDEX_COUNT_LOG2 = 5, +}; + +/* Private constants: do not modify. */ +enum tlsf_private +{ +#if defined(TLSF_64BIT) + /* All allocation sizes and addresses are aligned to 8 bytes. */ + ALIGN_SIZE_LOG2 = 3, +#else + /* All allocation sizes and addresses are aligned to 4 bytes. */ + ALIGN_SIZE_LOG2 = 2, +#endif + ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2), + +/* + ** We support allocations of sizes up to (1 << FL_INDEX_MAX) bits. + ** However, because we linearly subdivide the second-level lists, and + ** our minimum size granularity is 4 bytes, it doesn't make sense to + ** create first-level lists for sizes smaller than SL_INDEX_COUNT * 4, + ** or (1 << (SL_INDEX_COUNT_LOG2 + 2)) bytes, as there we will be + ** trying to split size ranges into more slots than we have available. + ** Instead, we calculate the minimum threshold size, and place all + ** blocks below that size into the 0th first-level list. + */ + +#if defined(TLSF_64BIT) + /* + ** TODO: We can increase this to support larger sizes, at the expense + ** of more overhead in the TLSF structure. + */ + FL_INDEX_MAX = 32, +#else + FL_INDEX_MAX = 30, +#endif + SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2), + FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2), + FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1), + + SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT), +}; + +/* +** Cast and min/max macros. +*/ + +#define tlsf_cast(t, exp) ((t)(exp)) +#define tlsf_min(a, b) ((a) < (b) ? (a) : (b)) +#define tlsf_max(a, b) ((a) > (b) ? (a) : (b)) + +/* +** Set assert macro, if it has not been provided by the user. +*/ +#if !defined(tlsf_assert) +#define tlsf_assert assert +#endif + +/* +** Static assertion mechanism. +*/ + +#define _tlsf_glue2(x, y) x##y +#define _tlsf_glue(x, y) _tlsf_glue2(x, y) +#define tlsf_static_assert(exp) typedef char _tlsf_glue(static_assert, __LINE__)[(exp) ? 1 : -1] + +/* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */ +tlsf_static_assert(sizeof(int) * CHAR_BIT == 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64); + +/* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */ +tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT); + +/* Ensure we've properly tuned our sizes. */ +tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + +/* +** Data structures and associated constants. +*/ + +/* +** Block header structure. +** +** There are several implementation subtleties involved: +** - The prev_phys_block field is only valid if the previous block is free. +** - The prev_phys_block field is actually stored at the end of the +** previous block. It appears at the beginning of this structure only to +** simplify the implementation. +** - The next_free / prev_free fields are only valid if the block is free. +*/ +typedef struct block_header_t +{ + /* Points to the previous physical block. */ + struct block_header_t *prev_phys_block; + + /* The size of this block, excluding the block header. */ + size_t size; + + /* Next and previous free blocks. */ + struct block_header_t *next_free; + struct block_header_t *prev_free; +} block_header_t; + +/* +** Since block sizes are always at least a multiple of 4, the two least +** significant bits of the size field are used to store the block status: +** - bit 0: whether block is busy or free +** - bit 1: whether previous block is busy or free +*/ +static const size_t block_header_free_bit = 1 << 0; +static const size_t block_header_prev_free_bit = 1 << 1; + +/* +** The size of the block header exposed to used blocks is the size field. +** The prev_phys_block field is stored *inside* the previous free block. +*/ +static const size_t block_header_overhead = sizeof(size_t); + +/* User data starts directly after the size field in a used block. */ +static const size_t block_start_offset = offsetof(block_header_t, size) + sizeof(size_t); + +/* +** A free block must be large enough to store its header minus the size of +** the prev_phys_block field, and no larger than the number of addressable +** bits for FL_INDEX. +*/ +static const size_t block_size_min = sizeof(block_header_t) - sizeof(block_header_t *); +static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX; + +/* The TLSF control structure. */ +typedef struct control_t +{ + /* Empty lists point at this block to indicate they are free. */ + block_header_t block_null; + + /* Bitmaps for free lists. */ + unsigned int fl_bitmap; + unsigned int sl_bitmap[FL_INDEX_COUNT]; + + /* Head of free lists. */ + block_header_t *blocks[FL_INDEX_COUNT][SL_INDEX_COUNT]; +} control_t; + +/* A type used for casting when doing pointer arithmetic. */ +typedef ptrdiff_t tlsfptr_t; + +/* +** block_header_t member functions. +*/ + +static size_t block_size(const block_header_t *block) +{ + return block->size & ~(block_header_free_bit | block_header_prev_free_bit); +} + +static void block_set_size(block_header_t *block, size_t size) +{ + const size_t oldsize = block->size; + block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit)); +} + +static int block_is_last(const block_header_t *block) +{ + return block_size(block) == 0; +} + +static int block_is_free(const block_header_t *block) +{ + return tlsf_cast(int, block->size &block_header_free_bit); +} + +static void block_set_free(block_header_t *block) +{ + block->size |= block_header_free_bit; +} + +static void block_set_used(block_header_t *block) +{ + block->size &= ~block_header_free_bit; +} + +static int block_is_prev_free(const block_header_t *block) +{ + return tlsf_cast(int, block->size &block_header_prev_free_bit); +} + +static void block_set_prev_free(block_header_t *block) +{ + block->size |= block_header_prev_free_bit; +} + +static void block_set_prev_used(block_header_t *block) +{ + block->size &= ~block_header_prev_free_bit; +} + +static block_header_t *block_from_ptr(const void *ptr) +{ + return tlsf_cast(block_header_t *, tlsf_cast(unsigned char *, ptr) - block_start_offset); +} + +static void *block_to_ptr(const block_header_t *block) +{ + return tlsf_cast(void *, tlsf_cast(unsigned char *, block) + block_start_offset); +} + +/* Return location of next block after block of given size. */ +static block_header_t *offset_to_block(const void *ptr, size_t size) +{ + return tlsf_cast(block_header_t *, tlsf_cast(tlsfptr_t, ptr) + size); +} + +/* Return location of previous block. */ +static block_header_t *block_prev(const block_header_t *block) +{ + tlsf_assert(block_is_prev_free(block) && "previous block must be free"); + return block->prev_phys_block; +} + +/* Return location of next existing block. */ +static block_header_t *block_next(const block_header_t *block) +{ + block_header_t *next = offset_to_block(block_to_ptr(block), block_size(block) - block_header_overhead); + tlsf_assert(!block_is_last(block)); + return next; +} + +/* Link a new block with its physical neighbor, return the neighbor. */ +static block_header_t *block_link_next(block_header_t *block) +{ + block_header_t *next = block_next(block); + next->prev_phys_block = block; + return next; +} + +static void block_mark_as_free(block_header_t *block) +{ + /* Link the block to the next block, first. */ + block_header_t *next = block_link_next(block); + block_set_prev_free(next); + block_set_free(block); +} + +static void block_mark_as_used(block_header_t *block) +{ + block_header_t *next = block_next(block); + block_set_prev_used(next); + block_set_used(block); +} + +static size_t align_up(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return (x + (align - 1)) & ~(align - 1); +} + +static size_t align_down(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return x - (x & (align - 1)); +} + +static void *align_ptr(const void *ptr, size_t align) +{ + const tlsfptr_t aligned = (tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1); + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return tlsf_cast(void *, aligned); +} + +/* +** Adjust an allocation size to be aligned to word size, and no smaller +** than internal minimum. +*/ +static size_t adjust_request_size(size_t size, size_t align) +{ + size_t adjust = 0; + if (size) { + const size_t aligned = align_up(size, align); + + /* aligned sized must not exceed block_size_max or we'll go out of bounds on sl_bitmap */ + if (aligned < block_size_max) { + adjust = tlsf_max(aligned, block_size_min); + } + } + return adjust; +} + +/* +** TLSF utility functions. In most cases, these are direct translations of +** the documentation found in the white paper. +*/ + +static void mapping_insert(size_t size, int *fli, int *sli) +{ + int fl, sl; + if (size < SMALL_BLOCK_SIZE) { + /* Store small blocks in first list. */ + fl = 0; + sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + } else { + fl = tlsf_fls_sizet(size); + sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ (1 << SL_INDEX_COUNT_LOG2); + fl -= (FL_INDEX_SHIFT - 1); + } + *fli = fl; + *sli = sl; +} + +/* This version rounds up to the next block size (for allocations) */ +static void mapping_search(size_t size, int *fli, int *sli) +{ + if (size >= SMALL_BLOCK_SIZE) { + const size_t round = (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1; + size += round; + } + mapping_insert(size, fli, sli); +} + +static block_header_t *search_suitable_block(control_t *control, int *fli, int *sli) +{ + int fl = *fli; + int sl = *sli; + + /* + ** First, search for a block in the list associated with the given + ** fl/sl index. + */ + unsigned int sl_map = control->sl_bitmap[fl] & (~0U << sl); + if (!sl_map) { + /* No block exists. Search in the next largest first-level list. */ + const unsigned int fl_map = control->fl_bitmap & (~0U << (fl + 1)); + if (!fl_map) { + /* No free blocks available, memory has been exhausted. */ + return 0; + } + + fl = tlsf_ffs(fl_map); + *fli = fl; + sl_map = control->sl_bitmap[fl]; + } + tlsf_assert(sl_map && "internal error - second level bitmap is null"); + sl = tlsf_ffs(sl_map); + *sli = sl; + + /* Return the first block in the free list. */ + return control->blocks[fl][sl]; +} + +/* Remove a free block from the free list.*/ +static void remove_free_block(control_t *control, block_header_t *block, int fl, int sl) +{ + block_header_t *prev = block->prev_free; + block_header_t *next = block->next_free; + tlsf_assert(prev && "prev_free field can not be null"); + tlsf_assert(next && "next_free field can not be null"); + next->prev_free = prev; + prev->next_free = next; + + /* If this block is the head of the free list, set new head. */ + if (control->blocks[fl][sl] == block) { + control->blocks[fl][sl] = next; + + /* If the new head is null, clear the bitmap. */ + if (next == &control->block_null) { + control->sl_bitmap[fl] &= ~(1U << sl); + + /* If the second bitmap is now empty, clear the fl bitmap. */ + if (!control->sl_bitmap[fl]) { + control->fl_bitmap &= ~(1U << fl); + } + } + } +} + +/* Insert a free block into the free block list. */ +static void insert_free_block(control_t *control, block_header_t *block, int fl, int sl) +{ + block_header_t *current = control->blocks[fl][sl]; + tlsf_assert(current && "free list cannot have a null entry"); + tlsf_assert(block && "cannot insert a null entry into the free list"); + block->next_free = current; + block->prev_free = &control->block_null; + current->prev_free = block; + + tlsf_assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE) && "block not aligned properly"); + /* + ** Insert the new block at the head of the list, and mark the first- + ** and second-level bitmaps appropriately. + */ + control->blocks[fl][sl] = block; + control->fl_bitmap |= (1U << fl); + control->sl_bitmap[fl] |= (1U << sl); +} + +/* Remove a given block from the free list. */ +static void block_remove(control_t *control, block_header_t *block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* Insert a given block into the free list. */ +static void block_insert(control_t *control, block_header_t *block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + insert_free_block(control, block, fl, sl); +} + +static int block_can_split(block_header_t *block, size_t size) +{ + return block_size(block) >= sizeof(block_header_t) + size; +} + +/* Split a block into two, the second of which is free. */ +static block_header_t *block_split(block_header_t *block, size_t size) +{ + /* Calculate the amount of space left in the remaining block. */ + block_header_t *remaining = offset_to_block(block_to_ptr(block), size - block_header_overhead); + + const size_t remain_size = block_size(block) - (size + block_header_overhead); + + tlsf_assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE) && + "remaining block not aligned properly"); + + tlsf_assert(block_size(block) == remain_size + size + block_header_overhead); + block_set_size(remaining, remain_size); + tlsf_assert(block_size(remaining) >= block_size_min && "block split with invalid size"); + + block_set_size(block, size); + block_mark_as_free(remaining); + + return remaining; +} + +/* Absorb a free block's storage into an adjacent previous free block. */ +static block_header_t *block_absorb(block_header_t *prev, block_header_t *block) +{ + tlsf_assert(!block_is_last(prev) && "previous block can't be last"); + /* Note: Leaves flags untouched. */ + prev->size += block_size(block) + block_header_overhead; + block_link_next(prev); + return prev; +} + +/* Merge a just-freed block with an adjacent previous free block. */ +static block_header_t *block_merge_prev(control_t *control, block_header_t *block) +{ + if (block_is_prev_free(block)) { + block_header_t *prev = block_prev(block); + tlsf_assert(prev && "prev physical block can't be null"); + tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such"); + block_remove(control, prev); + block = block_absorb(prev, block); + } + + return block; +} + +/* Merge a just-freed block with an adjacent free block. */ +static block_header_t *block_merge_next(control_t *control, block_header_t *block) +{ + block_header_t *next = block_next(block); + tlsf_assert(next && "next physical block can't be null"); + + if (block_is_free(next)) { + tlsf_assert(!block_is_last(block) && "previous block can't be last"); + block_remove(control, next); + block = block_absorb(block, next); + } + + return block; +} + +/* Trim any trailing block space off the end of a block, return to pool. */ +static void block_trim_free(control_t *control, block_header_t *block, size_t size) +{ + tlsf_assert(block_is_free(block) && "block must be free"); + if (block_can_split(block, size)) { + block_header_t *remaining_block = block_split(block, size); + block_link_next(block); + block_set_prev_free(remaining_block); + block_insert(control, remaining_block); + } +} + +/* Trim any trailing block space off the end of a used block, return to pool. */ +static void block_trim_used(control_t *control, block_header_t *block, size_t size) +{ + tlsf_assert(!block_is_free(block) && "block must be used"); + if (block_can_split(block, size)) { + /* If the next block is free, we must coalesce. */ + block_header_t *remaining_block = block_split(block, size); + block_set_prev_used(remaining_block); + + remaining_block = block_merge_next(control, remaining_block); + block_insert(control, remaining_block); + } +} + +static block_header_t *block_trim_free_leading(control_t *control, block_header_t *block, size_t size) +{ + block_header_t *remaining_block = block; + if (block_can_split(block, size)) { + /* We want the 2nd block. */ + remaining_block = block_split(block, size - block_header_overhead); + block_set_prev_free(remaining_block); + + block_link_next(block); + block_insert(control, block); + } + + return remaining_block; +} + +static block_header_t *block_locate_free(control_t *control, size_t size) +{ + int fl = 0, sl = 0; + block_header_t *block = 0; + + if (size) { + mapping_search(size, &fl, &sl); + + /* + ** mapping_search can futz with the size, so for excessively large sizes it can sometimes wind up + ** with indices that are off the end of the block array. + ** So, we protect against that here, since this is the only callsite of mapping_search. + ** Note that we don't need to check sl, since it comes from a modulo operation that guarantees it's always in range. + */ + if (fl < FL_INDEX_COUNT) { + block = search_suitable_block(control, &fl, &sl); + } + } + + if (block) { + tlsf_assert(block_size(block) >= size); + remove_free_block(control, block, fl, sl); + } + + return block; +} + +static void *block_prepare_used(control_t *control, block_header_t *block, size_t size) +{ + void *p = 0; + if (block) { + tlsf_assert(size && "size must be non-zero"); + block_trim_free(control, block, size); + block_mark_as_used(block); + p = block_to_ptr(block); + } + return p; +} + +/* Clear structure and point all empty lists at the null block. */ +static void control_construct(control_t *control) +{ + int i, j; + + control->block_null.next_free = &control->block_null; + control->block_null.prev_free = &control->block_null; + + control->fl_bitmap = 0; + for (i = 0; i < FL_INDEX_COUNT; ++i) { + control->sl_bitmap[i] = 0; + for (j = 0; j < SL_INDEX_COUNT; ++j) { + control->blocks[i][j] = &control->block_null; + } + } +} + +typedef struct integrity_t +{ + int prev_status; + int status; +} integrity_t; + +#define tlsf_insist(x) \ + { \ + tlsf_assert(x); \ + if (!(x)) { \ + status--; \ + } \ + } + +static void integrity_walker(void *ptr, size_t size, int used, void *user) +{ + block_header_t *block = block_from_ptr(ptr); + integrity_t *integ = tlsf_cast(integrity_t *, user); + const int this_prev_status = block_is_prev_free(block) ? 1 : 0; + const int this_status = block_is_free(block) ? 1 : 0; + const size_t this_block_size = block_size(block); + + int status = 0; + (void)used; + tlsf_insist(integ->prev_status == this_prev_status && "prev status incorrect"); + tlsf_insist(size == this_block_size && "block size incorrect"); + + integ->prev_status = this_status; + integ->status += status; +} + +int tlsf_check(tlsf_t tlsf) +{ + int i, j; + + control_t *control = tlsf_cast(control_t *, tlsf); + int status = 0; + + /* Check that the free lists and bitmaps are accurate. */ + for (i = 0; i < FL_INDEX_COUNT; ++i) { + for (j = 0; j < SL_INDEX_COUNT; ++j) { + const int fl_map = control->fl_bitmap & (1U << i); + const int sl_list = control->sl_bitmap[i]; + const int sl_map = sl_list & (1U << j); + const block_header_t *block = control->blocks[i][j]; + + /* Check that first- and second-level lists agree. */ + if (!fl_map) { + tlsf_insist(!sl_map && "second-level map must be null"); + } + + if (!sl_map) { + tlsf_insist(block == &control->block_null && "block list must be null"); + continue; + } + + /* Check that there is at least one free block. */ + tlsf_insist(sl_list && "no free blocks in second-level map"); + tlsf_insist(block != &control->block_null && "block should not be null"); + + while (block != &control->block_null) { + int fli, sli; + tlsf_insist(block_is_free(block) && "block should be free"); + tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced"); + tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced"); + tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free"); + tlsf_insist(block_size(block) >= block_size_min && "block not minimum size"); + + mapping_insert(block_size(block), &fli, &sli); + tlsf_insist(fli == i && sli == j && "block size indexed in wrong list"); + block = block->next_free; + } + } + } + + return status; +} + +#undef tlsf_insist + +static void default_walker(void *ptr, size_t size, int used, void *user) +{ + (void)user; + printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr)); +} + +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void *user) +{ + tlsf_walker pool_walker = walker ? walker : default_walker; + block_header_t *block = offset_to_block(pool, -(int)block_header_overhead); + + while (block && !block_is_last(block)) { + pool_walker(block_to_ptr(block), block_size(block), !block_is_free(block), user); + block = block_next(block); + } +} + +size_t tlsf_block_size(void *ptr) +{ + size_t size = 0; + if (ptr) { + const block_header_t *block = block_from_ptr(ptr); + size = block_size(block); + } + return size; +} + +int tlsf_check_pool(pool_t pool) +{ + /* Check that the blocks are physically correct. */ + integrity_t integ = { 0, 0 }; + tlsf_walk_pool(pool, integrity_walker, &integ); + + return integ.status; +} + +/* +** Size of the TLSF structures in a given memory block passed to +** tlsf_create, equal to the size of a control_t +*/ +size_t tlsf_size(void) +{ + return sizeof(control_t); +} + +size_t tlsf_align_size(void) +{ + return ALIGN_SIZE; +} + +size_t tlsf_block_size_min(void) +{ + return block_size_min; +} + +size_t tlsf_block_size_max(void) +{ + return block_size_max; +} + +/* +** Overhead of the TLSF structures in a given memory block passed to +** tlsf_add_pool, equal to the overhead of a free block and the +** sentinel block. +*/ +size_t tlsf_pool_overhead(void) +{ + return 2 * block_header_overhead; +} + +size_t tlsf_alloc_overhead(void) +{ + return block_header_overhead; +} + +pool_t tlsf_add_pool(tlsf_t tlsf, void *mem, size_t bytes) +{ + block_header_t *block; + block_header_t *next; + + const size_t pool_overhead = tlsf_pool_overhead(); + const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE); + + if (((ptrdiff_t)mem % ALIGN_SIZE) != 0) { + printf("tlsf_add_pool: Memory must be aligned by %u bytes.\n", (unsigned int)ALIGN_SIZE); + return 0; + } + + if (pool_bytes < block_size_min || pool_bytes > block_size_max) { +#if defined(TLSF_64BIT) + printf("tlsf_add_pool: Memory size must be between 0x%x and 0x%x00 bytes.\n", + (unsigned int)(pool_overhead + block_size_min), (unsigned int)((pool_overhead + block_size_max) / 256)); +#else + printf("tlsf_add_pool: Memory size must be between %u and %u bytes.\n", + (unsigned int)(pool_overhead + block_size_min), (unsigned int)(pool_overhead + block_size_max)); +#endif + return 0; + } + + /* + ** Create the main free block. Offset the start of the block slightly + ** so that the prev_phys_block field falls outside of the pool - + ** it will never be used. + */ + block = offset_to_block(mem, -(tlsfptr_t)block_header_overhead); + block_set_size(block, pool_bytes); + block_set_free(block); + block_set_prev_used(block); + block_insert(tlsf_cast(control_t *, tlsf), block); + + /* Split the block to create a zero-size sentinel block. */ + next = block_link_next(block); + block_set_size(next, 0); + block_set_used(next); + block_set_prev_free(next); + + return mem; +} + +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + block_header_t *block = offset_to_block(pool, -(int)block_header_overhead); + + int fl = 0, sl = 0; + + tlsf_assert(block_is_free(block) && "block should be free"); + tlsf_assert(!block_is_free(block_next(block)) && "next block should not be free"); + tlsf_assert(block_size(block_next(block)) == 0 && "next block size should be zero"); + + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* +** TLSF main interface. +*/ + +#if TLSF_DEBUG +int test_ffs_fls() +{ + /* Verify ffs/fls work properly. */ + int rv = 0; + rv += (tlsf_ffs(0) == -1) ? 0 : 0x1; + rv += (tlsf_fls(0) == -1) ? 0 : 0x2; + rv += (tlsf_ffs(1) == 0) ? 0 : 0x4; + rv += (tlsf_fls(1) == 0) ? 0 : 0x8; + rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10; + rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20; + rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40; + rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80; + +#if defined(TLSF_64BIT) + rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100; + rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200; + rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400; +#endif + + if (rv) { + printf("test_ffs_fls: %x ffs/fls tests failed.\n", rv); + } + return rv; +} +#endif + +tlsf_t tlsf_create(void *mem) +{ +#if TLSF_DEBUG + if (test_ffs_fls()) { + return 0; + } +#endif + + if (((tlsfptr_t)mem % ALIGN_SIZE) != 0) { + printf("tlsf_create: Memory must be aligned to %u bytes.\n", (unsigned int)ALIGN_SIZE); + return 0; + } + + control_construct(tlsf_cast(control_t *, mem)); + + return tlsf_cast(tlsf_t, mem); +} + +tlsf_t tlsf_create_with_pool(void *mem, size_t bytes) +{ + tlsf_t tlsf = tlsf_create(mem); + tlsf_add_pool(tlsf, (char *)mem + tlsf_size(), bytes - tlsf_size()); + return tlsf; +} + +void tlsf_destroy(tlsf_t tlsf) +{ + /* Nothing to do. */ + (void)tlsf; +} + +pool_t tlsf_get_pool(tlsf_t tlsf) +{ + return tlsf_cast(pool_t, (char *)tlsf + tlsf_size()); +} + +void *tlsf_malloc(tlsf_t tlsf, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + block_header_t *block = block_locate_free(control, adjust); + return block_prepare_used(control, block, adjust); +} + +void *tlsf_memalign(tlsf_t tlsf, size_t align, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + /* + ** We must allocate an additional minimum block size bytes so that if + ** our free block will leave an alignment gap which is smaller, we can + ** trim a leading free block and release it back to the pool. We must + ** do this because the previous physical block is in use, therefore + ** the prev_phys_block field is not valid, and we can't simply adjust + ** the size of that block. + */ + const size_t gap_minimum = sizeof(block_header_t); + const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align); + + /* + ** If alignment is less than or equals base alignment, we're done. + ** If we requested 0 bytes, return null, as tlsf_malloc(0) does. + */ + const size_t aligned_size = (adjust && align > ALIGN_SIZE) ? size_with_gap : adjust; + + block_header_t *block = block_locate_free(control, aligned_size); + + /* This can't be a static assert. */ + tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead); + + if (block) { + void *ptr = block_to_ptr(block); + void *aligned = align_ptr(ptr, align); + size_t gap = tlsf_cast(size_t, tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + + /* If gap size is too small, offset to next aligned boundary. */ + if (gap && gap < gap_minimum) { + const size_t gap_remain = gap_minimum - gap; + const size_t offset = tlsf_max(gap_remain, align); + const void *next_aligned = tlsf_cast(void *, tlsf_cast(tlsfptr_t, aligned) + offset); + + aligned = align_ptr(next_aligned, align); + gap = tlsf_cast(size_t, tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + } + + if (gap) { + tlsf_assert(gap >= gap_minimum && "gap size too small"); + block = block_trim_free_leading(control, block, gap); + } + } + + return block_prepare_used(control, block, adjust); +} + +void tlsf_free(tlsf_t tlsf, void *ptr) +{ + /* Don't attempt to free a NULL pointer. */ + if (ptr) { + control_t *control = tlsf_cast(control_t *, tlsf); + block_header_t *block = block_from_ptr(ptr); + tlsf_assert(!block_is_free(block) && "block already marked as free"); + block_mark_as_free(block); + block = block_merge_prev(control, block); + block = block_merge_next(control, block); + block_insert(control, block); + } +} + +static void *memcpy(void *dst, const void *src, size_t n) +{ + const char *p = src; + char *q = dst; + while (n--) { + *q++ = *p++; + } + return dst; +} + +/* +** The TLSF block information provides us with enough information to +** provide a reasonably intelligent implementation of realloc, growing or +** shrinking the currently allocated block as required. +** +** This routine handles the somewhat esoteric edge cases of realloc: +** - a non-zero size with a null pointer will behave like malloc +** - a zero size with a non-null pointer will behave like free +** - a request that cannot be satisfied will leave the original buffer +** untouched +** - an extended buffer size will leave the newly-allocated area with +** contents undefined +*/ +void *tlsf_realloc(tlsf_t tlsf, void *ptr, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + void *p = 0; + + /* Zero-size requests are treated as free. */ + if (ptr && size == 0) { + tlsf_free(tlsf, ptr); + } + /* Requests with NULL pointers are treated as malloc. */ + else if (!ptr) { + p = tlsf_malloc(tlsf, size); + } else { + block_header_t *block = block_from_ptr(ptr); + block_header_t *next = block_next(block); + + const size_t cursize = block_size(block); + const size_t combined = cursize + block_size(next) + block_header_overhead; + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + tlsf_assert(!block_is_free(block) && "block already marked as free"); + + /* + ** If the next block is used, or when combined with the current + ** block, does not offer enough space, we must reallocate and copy. + */ + if (adjust > cursize && (!block_is_free(next) || adjust > combined)) { + p = tlsf_malloc(tlsf, size); + if (p) { + const size_t minsize = tlsf_min(cursize, size); + memcpy(p, ptr, minsize); + tlsf_free(tlsf, ptr); + } + } else { + /* Do we need to expand to the next block? */ + if (adjust > cursize) { + block_merge_next(control, block); + block_mark_as_used(block); + } + + /* Trim the resulting block and return the original pointer. */ + block_trim_used(control, block, adjust); + p = ptr; + } + } + + return p; +} \ No newline at end of file diff --git a/kernel/include/barrier.h b/kernel/include/barrier.h new file mode 100644 index 00000000..4f5ad784 --- /dev/null +++ b/kernel/include/barrier.h @@ -0,0 +1,77 @@ +#ifndef _KP_BARRIER_H_ +#define _KP_BARRIER_H_ + +#define mb() asm volatile("dmb ish" ::: "memory") +#define wmb() asm volatile("dmb ishst" ::: "memory") +#define rmb() asm volatile("dmb ishld" ::: "memory") + +/* + * Kernel uses dmb variants on arm64 for smp_*() barriers. Pretty much the same + * implementation as above mb()/wmb()/rmb(), though for the latter kernel uses + * dsb. In any case, should above mb()/wmb()/rmb() change, make sure the below + * smp_*() don't. + */ +#define smp_mb() asm volatile("dmb ish" ::: "memory") +#define smp_wmb() asm volatile("dmb ishst" ::: "memory") +#define smp_rmb() asm volatile("dmb ishld" ::: "memory") + +#define smp_store_release(p, v) \ + do { \ + union \ + { \ + typeof(*p) __val; \ + char __c[1]; \ + } __u = { .__val = (v) }; \ + compiletime_assert_atomic_type(*p); \ + \ + switch (sizeof(*p)) { \ + case 1: \ + asm volatile("stlrb %w1, %0" : "=Q"(*p) : "r"(*(u8 *)__u.__c) : "memory"); \ + break; \ + case 2: \ + asm volatile("stlrh %w1, %0" : "=Q"(*p) : "r"(*(u16 *)__u.__c) : "memory"); \ + break; \ + case 4: \ + asm volatile("stlr %w1, %0" : "=Q"(*p) : "r"(*(u32 *)__u.__c) : "memory"); \ + break; \ + case 8: \ + asm volatile("stlr %1, %0" : "=Q"(*p) : "r"(*(u64 *)__u.__c) : "memory"); \ + break; \ + default: \ + /* Only to shut up gcc ... */ \ + mb(); \ + break; \ + } \ + } while (0) + +#define smp_load_acquire(p) \ + ({ \ + union \ + { \ + typeof(*p) __val; \ + char __c[1]; \ + } __u = { .__c = { 0 } }; \ + compiletime_assert_atomic_type(*p); \ + \ + switch (sizeof(*p)) { \ + case 1: \ + asm volatile("ldarb %w0, %1" : "=r"(*(u8 *)__u.__c) : "Q"(*p) : "memory"); \ + break; \ + case 2: \ + asm volatile("ldarh %w0, %1" : "=r"(*(u16 *)__u.__c) : "Q"(*p) : "memory"); \ + break; \ + case 4: \ + asm volatile("ldar %w0, %1" : "=r"(*(u32 *)__u.__c) : "Q"(*p) : "memory"); \ + break; \ + case 8: \ + asm volatile("ldar %0, %1" : "=r"(*(u64 *)__u.__c) : "Q"(*p) : "memory"); \ + break; \ + default: \ + /* Only to shut up gcc ... */ \ + mb(); \ + break; \ + } \ + __u.__val; \ + }) + +#endif \ No newline at end of file diff --git a/kernel/include/cache.h b/kernel/include/cache.h index 30e484bc..ab797865 100644 --- a/kernel/include/cache.h +++ b/kernel/include/cache.h @@ -18,4 +18,28 @@ static inline void flush_icache_all(void) asm volatile("isb" : : : "memory"); } +/* + * These definitions mirror those in pci.h, so they can be used + * interchangeably with their PCI_ counterparts. + */ +enum dma_data_direction +{ + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +void flush_cache_all(void); +void flush_icache_range(unsigned long start, unsigned long end); +void __flush_dcache_all(); +void __flush_dcache_area(void *addr, size_t len); +void __flush_cache_user_range(unsigned long start, unsigned long end); +void __inval_cache_range(unsigned long start, unsigned long end); +void __dma_inv_range(unsigned long start, unsigned long end); +void __dma_clean_range(unsigned long start, unsigned long end); +void __dma_flush_range(unsigned long start, unsigned long end); +void __dma_map_area(unsigned long start, unsigned long size, enum dma_data_direction dir); +void __dma_unmap_area(unsigned long start, unsigned long size, enum dma_data_direction dir); + #endif \ No newline at end of file diff --git a/kernel/include/common.h b/kernel/include/common.h index e314e741..08dd2fc7 100644 --- a/kernel/include/common.h +++ b/kernel/include/common.h @@ -2,6 +2,7 @@ #define _KP_COMMON_H_ #include +#include #define VERSION(major, minor, patch) (((major) << 16) + ((minor) << 8) + (patch)) @@ -15,4 +16,39 @@ extern uint32_t kver; extern uint32_t kpver; extern endian_t endian; +extern const char kernel_patch_logo[]; + +extern void _kp_start(); +extern void _kp_text_start(); +extern void _kp_text_end(); +extern void _kp_data_start(); +extern void _kp_data_end(); +extern void _kp_end(); + +extern uint64_t _kp_hook_start; +extern uint64_t _kp_hook_end; + +extern uint64_t _kp_rox_start; +extern uint64_t _kp_rox_end; +extern uint64_t _kp_rw_start; +extern uint64_t _kp_rw_end; + +extern uint64_t _kp_region_start; +extern uint64_t _kp_region_end; + +static inline bool is_kp_text_area(unsigned long addr) +{ + return addr >= (unsigned long)_kp_text_start && addr < (unsigned long)_kp_text_end; +} + +static inline bool is_kp_hook_area(unsigned long addr) +{ + return addr >= (unsigned long)_kp_hook_start && addr < (unsigned long)_kp_hook_end; +} + +static inline bool is_kpm_rox_area(unsigned long addr) +{ + return addr >= (unsigned long)_kp_rox_start && addr < (unsigned long)_kp_rox_end; +} + #endif \ No newline at end of file diff --git a/kernel/include/compiler.h b/kernel/include/compiler.h index f7826f9f..b8bcb760 100644 --- a/kernel/include/compiler.h +++ b/kernel/include/compiler.h @@ -51,4 +51,35 @@ #define __used __attribute__((__unused__)) #define __maybe_unused __attribute__((unused)) +// #define static_assert _Static_assert + +#define __compiler_offsetof(a, b) __builtin_offsetof(a, b) + +#define __compiletime_object_size(obj) -1 +#define __compiletime_warning(message) +#define __compiletime_error(message) + +#define __compiletime_error_fallback(condition) \ + do { \ + ((void)sizeof(char[1 - 2 * condition])); \ + } while (0) + +#define __native_word(t) \ + (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) + +#define __compiletime_assert(condition, msg, prefix, suffix) \ + do { \ + bool __cond = !(condition); \ + extern void prefix##suffix(void) __compiletime_error(msg); \ + if (__cond) prefix##suffix(); \ + __compiletime_error_fallback(__cond); \ + } while (0) + +#define _compiletime_assert(condition, msg, prefix, suffix) __compiletime_assert(condition, msg, prefix, suffix) + +#define compiletime_assert(condition, msg) _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + +#define compiletime_assert_atomic_type(t) \ + compiletime_assert(__native_word(t), "Need native word sized stores/loads for atomicity.") + #endif \ No newline at end of file diff --git a/kernel/include/error.h b/kernel/include/error.h deleted file mode 100644 index bda973b7..00000000 --- a/kernel/include/error.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _KP_ERROR_H_ -#define _KP_ERROR_H - -#define ERR_NO_ERR 0 - -#define ERR_COMMON -1 -#define ERR_DIRTY_EXT -2 -#define ERR_NOT_IMPL -3 -#define ERR_NO_SUCH_ID -4 -#define ERR_CAP_FULL -5 -#define ERR_NO_KFUNC -6 -#define ERR_NO_KVAR -7 -#define ERR_EXIST -8 -#define ERR_ADDR -9 -#define ERR_PGTABLE -10 -#define ERR_NO_SUCH_SYMBOL -11 -#define ERR_STRUCT_LAYOUT -12 -#define ERR_COPY_TO_USER -13 - -#endif \ No newline at end of file diff --git a/kernel/include/hook.h b/kernel/include/hook.h index 88e3cf91..8aea73fd 100644 --- a/kernel/include/hook.h +++ b/kernel/include/hook.h @@ -9,26 +9,41 @@ typedef enum { HOOK_NO_ERR = 0, - HOOK_INPUT_NULL, - HOOK_NO_MEM, - HOOK_BAD_RELO, - HOOK_TRANSIT_NO_MEM, - HOOK_CHAIN_FULL, - HOOK_NOT_HOOK, + HOOK_INPUT_NULL = 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_err_t; +enum hook_type +{ + NONE = 0, + INLINE, + INLINE_CHAIN, + FUNCTION_POINTER_CHAIN, +}; + +typedef int8_t chain_item_state; + +#define CHAIN_ITEM_STATE_EMPTY 0 +#define CHAIN_ITEM_STATE_READY 1 +#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 HOOK_MEM_REGION_NUM 4 #define TRAMPOLINE_NUM 4 #define RELOCATE_INST_NUM (TRAMPOLINE_NUM * 8 + 8) -#define HOOK_CHAIN_NUM 4 -#define HOOK_LOCAL_DATA_NUM 8 +#define HOOK_CHAIN_NUM 0x10 +#define TRANSIT_INST_NUM 0x60 + +#define FP_HOOK_CHAIN_NUM 0x20 -#define TRANSIT_INST_NUM 64 -#define TRANSIT_ALIGN 32 #define ARM64_NOP 0xd503201f typedef struct @@ -39,7 +54,6 @@ typedef struct uint64_t replace_addr; uint64_t relo_addr; // out - // must align int32_t tramp_insts_len; int32_t relo_insts_len; uint32_t origin_insts[TRAMPOLINE_NUM] __attribute__((aligned(8))); @@ -49,29 +63,59 @@ typedef struct struct _hook_chain; +#define HOOK_LOCAL_DATA_NUM 8 + typedef struct { - uint64_t data[HOOK_LOCAL_DATA_NUM]; + union + { + struct + { + uint64_t data0; + uint64_t data1; + uint64_t data2; + uint64_t data3; + uint64_t data4; + uint64_t data5; + uint64_t data6; + uint64_t data7; + }; + uint64_t data[HOOK_LOCAL_DATA_NUM]; + }; } hook_local_t; typedef struct { - struct _hook_chain *chain; + void *chain; int early_ret; hook_local_t local; uint64_t ret; + union + { + struct + { + }; + uint64_t args[0]; + }; } hook_fargs0_t __attribute__((aligned(8))); typedef struct { - struct _hook_chain *chain; + void *chain; int early_ret; hook_local_t local; uint64_t ret; - uint64_t arg0; - uint64_t arg1; - uint64_t arg2; - uint64_t arg3; + union + { + struct + { + uint64_t arg0; + uint64_t arg1; + uint64_t arg2; + uint64_t arg3; + }; + uint64_t args[4]; + }; } hook_fargs4_t __attribute__((aligned(8))); typedef hook_fargs4_t hook_fargs1_t; @@ -80,18 +124,25 @@ typedef hook_fargs4_t hook_fargs3_t; typedef struct { - struct _hook_chain *chain; + void *chain; int early_ret; hook_local_t local; uint64_t ret; - uint64_t arg0; - uint64_t arg1; - uint64_t arg2; - uint64_t arg3; - uint64_t arg4; - uint64_t arg5; - uint64_t arg6; - uint64_t arg7; + union + { + struct + { + uint64_t arg0; + uint64_t arg1; + uint64_t arg2; + uint64_t arg3; + uint64_t arg4; + uint64_t arg5; + uint64_t arg6; + uint64_t arg7; + }; + uint64_t args[8]; + }; } hook_fargs8_t __attribute__((aligned(8))); typedef hook_fargs8_t hook_fargs5_t; @@ -100,22 +151,29 @@ typedef hook_fargs8_t hook_fargs7_t; typedef struct { - struct _hook_chain *chain; + void *chain; int early_ret; hook_local_t local; uint64_t ret; - uint64_t arg0; - uint64_t arg1; - uint64_t arg2; - uint64_t arg3; - uint64_t arg4; - uint64_t arg5; - uint64_t arg6; - uint64_t arg7; - uint64_t arg8; - uint64_t arg9; - uint64_t arg10; - uint64_t arg11; + union + { + struct + { + uint64_t arg0; + uint64_t arg1; + uint64_t arg2; + uint64_t arg3; + uint64_t arg4; + uint64_t arg5; + uint64_t arg6; + uint64_t arg7; + uint64_t arg8; + uint64_t arg9; + uint64_t arg10; + uint64_t arg11; + }; + uint64_t args[12]; + }; } hook_fargs12_t __attribute__((aligned(8))); typedef hook_fargs12_t hook_fargs9_t; @@ -138,26 +196,47 @@ typedef void (*hook_chain12_callback)(hook_fargs12_t *fargs, void *udata); typedef struct _hook_chain { + // must be the first element hook_t hook; + int32_t chain_items_max; + chain_item_state states[HOOK_CHAIN_NUM]; void *udata[HOOK_CHAIN_NUM]; void *befores[HOOK_CHAIN_NUM]; void *afters[HOOK_CHAIN_NUM]; - uint32_t transit[TRANSIT_ALIGN / 4 + TRANSIT_INST_NUM]; + uint32_t transit[TRANSIT_INST_NUM]; } hook_chain_t __attribute__((aligned(8))); +typedef struct +{ + uintptr_t fp_addr; + uint64_t replace_addr; + uint64_t origin_fp; +} fp_hook_t __attribute__((aligned(8))); + +typedef struct _fphook_chain +{ + fp_hook_t hook; + int32_t chain_items_max; + chain_item_state states[FP_HOOK_CHAIN_NUM]; + void *udata[FP_HOOK_CHAIN_NUM]; + void *befores[FP_HOOK_CHAIN_NUM]; + void *afters[FP_HOOK_CHAIN_NUM]; + uint32_t transit[TRANSIT_INST_NUM]; +} fp_hook_chain_t __attribute__((aligned(8))); + int hook_mem_add(uint64_t start, int32_t size); -hook_chain_t *hook_mem_alloc(); -void hook_mem_free(hook_chain_t *free); -hook_chain_t *hook_get_chain_from_origin(uint64_t origin_addr); +void *hook_mem_zalloc(uintptr_t origin_addr, enum hook_type type); +void hook_mem_free(void *hook_mem); +void *hook_get_mem_from_origin(uint64_t origin_addr); int32_t branch_from_to(uint32_t *tramp_buf, uint64_t src_addr, uint64_t dst_addr); int32_t branch_relative(uint32_t *buf, uint64_t src_addr, uint64_t dst_addr); int32_t branch_absolute(uint32_t *buf, uint64_t addr); #ifdef HOOK_INTO_BRANCH_FUNC -uint64_t relo_func(uint64_t addr); +uint64_t branch_func_addr(uint64_t addr); #else -static inline uint64_t relo_func(uint64_t addr) +static inline uint64_t branch_func_addr(uint64_t addr) { return addr; } @@ -170,7 +249,16 @@ hook_err_t hook(void *func, void *replace, void **backup); void unhook(void *func); // todo: hook priority -hook_err_t hook_chain_prepare(hook_chain_t *chain, int32_t argno); +hook_err_t hook_chain_add(hook_chain_t *chain, void *before, void *after, void *udata); +void hook_chain_remove(hook_chain_t *chain, void *before, void *after); +hook_err_t hook_wrap(void *func, int32_t argno, void *before, void *after, void *udata); +void hook_unwrap(void *func, void *before, void *after); + +void fp_hook(uintptr_t fp_addr, void *replace, void **backup); +void fp_unhook(uintptr_t fp_addr, void *backup); +hook_err_t fp_hook_wrap(uintptr_t fp_addr, int32_t argno, void *before, void *after, void *udata); +void fp_hook_unwrap(uintptr_t fp_addr, void *before, void *after); + static inline void hook_chain_install(hook_chain_t *chain) { hook_install(&chain->hook); @@ -179,11 +267,8 @@ static inline void hook_chain_uninstall(hook_chain_t *chain) { hook_uninstall(&chain->hook); } -hook_err_t hook_chain_add(hook_chain_t *chain, void *before, void *after, void *udata); -void hook_chain_remove(hook_chain_t *chain, void *before, void *after); -hook_err_t hook_wrap(void *func, int32_t argno, void *before, void *after, void *udata); -void hook_unwrap(void *func, void *before, void *after); +// static inline hook_err_t hook_wrap0(void *func, hook_chain0_callback before, hook_chain0_callback after, void *udata) { return hook_wrap(func, 0, before, after, udata); @@ -249,9 +334,82 @@ static inline hook_err_t hook_wrap12(void *func, hook_chain12_callback before, h return hook_wrap(func, 12, before, after, udata); } -static inline void hook_unwrapn(void *func, void *before, void *after) +static inline hook_err_t fp_hook_wrap0(uintptr_t fp_addr, hook_chain0_callback before, hook_chain0_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 0, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap1(uintptr_t fp_addr, hook_chain1_callback before, hook_chain1_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 1, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap2(uintptr_t fp_addr, hook_chain2_callback before, hook_chain2_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 2, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap3(uintptr_t fp_addr, hook_chain3_callback before, hook_chain3_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 3, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap4(uintptr_t fp_addr, hook_chain4_callback before, hook_chain4_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 4, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap5(uintptr_t fp_addr, hook_chain5_callback before, hook_chain5_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 5, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap6(uintptr_t fp_addr, hook_chain6_callback before, hook_chain6_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 6, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap7(uintptr_t fp_addr, hook_chain7_callback before, hook_chain7_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 7, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap8(uintptr_t fp_addr, hook_chain8_callback before, hook_chain8_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 8, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap9(uintptr_t fp_addr, hook_chain9_callback before, hook_chain9_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 9, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap10(uintptr_t fp_addr, hook_chain10_callback before, hook_chain10_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 10, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap11(uintptr_t fp_addr, hook_chain11_callback before, hook_chain11_callback after, + void *udata) +{ + return fp_hook_wrap(fp_addr, 11, before, after, udata); +} + +static inline hook_err_t fp_hook_wrap12(uintptr_t fp_addr, hook_chain12_callback before, hook_chain12_callback after, + void *udata) { - return hook_unwrap(func, before, after); + return fp_hook_wrap(fp_addr, 12, before, after, udata); } #endif diff --git a/kernel/include/io.h b/kernel/include/io.h new file mode 100644 index 00000000..29e64074 --- /dev/null +++ b/kernel/include/io.h @@ -0,0 +1,174 @@ +#ifndef __KP_IO_H +#define __KP_IO_H + +#include +#include + +// todo: +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) + +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) + +/* + * Generic IO read/write. These perform native-endian accesses. + */ +static inline void __raw_writeb(u8 val, volatile void __iomem *addr) +{ + asm volatile("strb %w0, [%1]" : : "r"(val), "r"(addr)); +} + +static inline void __raw_writew(u16 val, volatile void __iomem *addr) +{ + asm volatile("strh %w0, [%1]" : : "r"(val), "r"(addr)); +} + +static inline void __raw_writel(u32 val, volatile void __iomem *addr) +{ + asm volatile("str %w0, [%1]" : : "r"(val), "r"(addr)); +} + +static inline void __raw_writeq(u64 val, volatile void __iomem *addr) +{ + asm volatile("str %0, [%1]" : : "r"(val), "r"(addr)); +} + +static inline u8 __raw_readb(const volatile void __iomem *addr) +{ + u8 val; + asm volatile( + // "ldrb %w0, [%1]" + "ldarb %w0, [%1]" + : "=r"(val) + : "r"(addr)); + return val; +} + +static inline u16 __raw_readw(const volatile void __iomem *addr) +{ + u16 val; + + asm volatile( + // "ldrh %w0, [%1]" + "ldarh %w0, [%1]" + : "=r"(val) + : "r"(addr)); + return val; +} + +static inline u32 __raw_readl(const volatile void __iomem *addr) +{ + u32 val; + asm volatile( + // "ldr %w0, [%1]" + "ldar %w0, [%1]" + : "=r"(val) + : "r"(addr)); + return val; +} + +static inline u64 __raw_readq(const volatile void __iomem *addr) +{ + u64 val; + asm volatile( + // "ldr %0, [%1]" + "ldar %0, [%1]" + : "=r"(val) + : "r"(addr)); + return val; +} + +/* IO barriers */ +#define __iormb() rmb() +#define __iowmb() wmb() + +#define mmiowb() \ + do { \ + } while (0) + +/* + * Relaxed I/O memory access primitives. These follow the Device memory + * ordering rules but do not guarantee any ordering relative to Normal memory + * accesses. + */ +#define readb_relaxed(c) \ + ({ \ + u8 __v = __raw_readb(c); \ + __v; \ + }) +#define readw_relaxed(c) \ + ({ \ + u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); \ + __v; \ + }) +#define readl_relaxed(c) \ + ({ \ + u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); \ + __v; \ + }) +#define readq_relaxed(c) \ + ({ \ + u64 __v = le64_to_cpu((__force __le64)__raw_readq(c)); \ + __v; \ + }) + +#define writeb_relaxed(v, c) ((void)__raw_writeb((v), (c))) +#define writew_relaxed(v, c) ((void)__raw_writew((__force u16)cpu_to_le16(v), (c))) +#define writel_relaxed(v, c) ((void)__raw_writel((__force u32)cpu_to_le32(v), (c))) +#define writeq_relaxed(v, c) ((void)__raw_writeq((__force u64)cpu_to_le64(v), (c))) + +/* + * I/O memory access primitives. Reads are ordered relative to any + * following Normal memory access. Writes are ordered relative to any prior + * Normal memory access. + */ +#define readb(c) \ + ({ \ + u8 __v = readb_relaxed(c); \ + __iormb(); \ + __v; \ + }) +#define readw(c) \ + ({ \ + u16 __v = readw_relaxed(c); \ + __iormb(); \ + __v; \ + }) +#define readl(c) \ + ({ \ + u32 __v = readl_relaxed(c); \ + __iormb(); \ + __v; \ + }) +#define readq(c) \ + ({ \ + u64 __v = readq_relaxed(c); \ + __iormb(); \ + __v; \ + }) + +#define writeb(v, c) \ + ({ \ + __iowmb(); \ + writeb_relaxed((v), (c)); \ + }) +#define writew(v, c) \ + ({ \ + __iowmb(); \ + writew_relaxed((v), (c)); \ + }) +#define writel(v, c) \ + ({ \ + __iowmb(); \ + writel_relaxed((v), (c)); \ + }) +#define writeq(v, c) \ + ({ \ + __iowmb(); \ + writeq_relaxed((v), (c)); \ + }) + +#endif \ No newline at end of file diff --git a/kernel/include/kpmalloc.h b/kernel/include/kpmalloc.h new file mode 100644 index 00000000..29d0febf --- /dev/null +++ b/kernel/include/kpmalloc.h @@ -0,0 +1,49 @@ +#ifndef _KP_KPMALLOC_H_ +#define _KP_KPMALLOC_H_ + +#include + +extern tlsf_t kp_rw_mem; +extern tlsf_t kp_rox_mem; + +static inline void *kp_malloc_exec(size_t bytes) +{ + return tlsf_malloc(kp_rox_mem, bytes); +} + +static inline void *kp_memalign_exec(size_t align, size_t bytes) +{ + return tlsf_memalign(kp_rox_mem, align, bytes); +} + +static inline void *kp_realloc_exec(void *ptr, size_t size) +{ + return tlsf_realloc(kp_rox_mem, ptr, size); +} + +static inline void kp_free_exec(void *ptr) +{ + tlsf_free(kp_rox_mem, ptr); +} + +static inline void *kp_malloc(size_t bytes) +{ + return tlsf_malloc(kp_rw_mem, bytes); +} + +static inline void *kp_memalign(size_t align, size_t bytes) +{ + return tlsf_memalign(kp_rw_mem, align, bytes); +} + +static inline void *kp_realloc(void *ptr, size_t size) +{ + return tlsf_realloc(kp_rw_mem, ptr, size); +} + +static inline void kp_free(void *ptr) +{ + tlsf_free(kp_rw_mem, ptr); +} + +#endif \ No newline at end of file diff --git a/kernel/include/kpmodule.h b/kernel/include/kpmodule.h new file mode 100644 index 00000000..498fe683 --- /dev/null +++ b/kernel/include/kpmodule.h @@ -0,0 +1,25 @@ +#ifndef _KP_KPMODULE_H_ +#define _KP_KPMODULE_H_ + +#define MAX_KPM_NUM 32 + +#define KPM_INFO(name, info) \ + static const char __kpm_info_##name[] __attribute__((__used__)) \ + __attribute__((section(".kpm.info"), unused, aligned(1))) = #name "=" info + +#define KPM_NAME(x) KPM_INFO(name, x) +#define KPM_VERSION(x) KPM_INFO(version, x) +#define KPM_LICENSE(x) KPM_INFO(license, x) +#define KPM_AUTHOR(x) KPM_INFO(author, x) +#define KPM_DESCRIPTION(x) KPM_INFO(description, x) + +typedef int (*initcall_t)(const char *args); +typedef void (*exitcall_t)(); + +#define KPM_INIT(fn) \ + static initcall_t __kpm_initcall_##fn __attribute__((__used__)) __attribute__((__section__(".kpm.init"))) = fn + +#define KPM_EXIT(fn) \ + static exitcall_t __kpm_exitcall_##fn __attribute__((__used__)) __attribute__((__section__(".kpm.exit"))) = fn + +#endif \ No newline at end of file diff --git a/kernel/include/ktypes.h b/kernel/include/ktypes.h index 11df6d0b..fc407452 100644 --- a/kernel/include/ktypes.h +++ b/kernel/include/ktypes.h @@ -5,6 +5,9 @@ #include #include +#define BITS_PER_LONG 64 +#define BITS_PER_LONG_LONG 64 + #define __bitwise #define __user #define __must_check @@ -22,6 +25,11 @@ typedef int8_t s8; typedef uint64_t __u64; typedef uint32_t __u32; typedef uint16_t __u16; +typedef uint8_t __u8; +typedef int8_t __s8; +typedef int16_t __s16; +typedef int32_t __s32; +typedef int64_t __s64; typedef __u16 __bitwise __le16; typedef __u16 __bitwise __be16; @@ -210,8 +218,6 @@ typedef void (*swap_func_t)(void *a, void *b, int size); typedef int (*cmp_r_func_t)(const void *a, const void *b, const void *priv); typedef int (*cmp_func_t)(const void *a, const void *b); - - #define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER) #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) diff --git a/kernel/include/log.h b/kernel/include/log.h index fdb1592e..afb17920 100644 --- a/kernel/include/log.h +++ b/kernel/include/log.h @@ -1,10 +1,15 @@ #ifndef _KP_LOG_H_ #define _KP_LOG_H_ +#include + +#define PREFIX_MAX 48 +#define LOG_LINE_MAX (1024 - PREFIX_MAX) + extern void (*printk)(const char *fmt, ...); -// #define logkv(fmt, ...) printk("[+] KP V " fmt, ##__VA_ARGS__) -#define logkv(fmt, ...) +#define logkv(fmt, ...) printk("[+] KP V " fmt, ##__VA_ARGS__) +// #define logkv(fmt, ...) // #define logkfv(fmt, ...) printk("[+] KP V %s: " fmt, __func__, ##__VA_ARGS__) #define logkfv(fmt, ...) @@ -21,4 +26,7 @@ extern void (*printk)(const char *fmt, ...); #define logke(fmt, ...) printk("[-] KP E " fmt, ##__VA_ARGS__) #define logkfe(fmt, ...) printk("[-] KP E %s: " fmt, __func__, ##__VA_ARGS__) +void log_boot(const char *fmt, ...); +const char *get_boot_log(); + #endif \ No newline at end of file diff --git a/kernel/include/pgtable.h b/kernel/include/pgtable.h index f9124f0a..e9a4a014 100644 --- a/kernel/include/pgtable.h +++ b/kernel/include/pgtable.h @@ -3,6 +3,13 @@ #include +#define MT_DEVICE_nGnRnE +#define MT_DEVICE_nGnRE +#define MT_DEVICE_GRE +#define MT_NORMAL_NC +#define MT_NORMAL +#define MT_NORMAL_WT + #define PTE_VALID (1ul << 0) #define PTE_TYPE_MASK (3ul << 0) #define PTE_TYPE_PAGE (3ul << 0) @@ -73,6 +80,7 @@ static inline void flush_tlb_all(void) isb(); } +// __TLBI_VADDR static inline uint64_t tlbi_vaddr(uint64_t addr, uint64_t asid) { uint64_t x = addr >> 12; diff --git a/kernel/include/predata.h b/kernel/include/predata.h index a7bf7ef7..478b79e6 100644 --- a/kernel/include/predata.h +++ b/kernel/include/predata.h @@ -3,9 +3,11 @@ #include #include +#include -int superkey_auth(const char *key, int32_t len); +int superkey_auth(const char *key, int len); +struct patch_config *get_preset_patch_cfg(); -int predata_init(); +void predata_init(const char *skey, struct patch_config *config); #endif \ No newline at end of file diff --git a/kernel/base/preset.h b/kernel/include/preset.h similarity index 86% rename from kernel/base/preset.h rename to kernel/include/preset.h index 6e05e952..7a64e0f6 100644 --- a/kernel/base/preset.h +++ b/kernel/include/preset.h @@ -11,10 +11,12 @@ #define HDR_BACKUP_SIZE 0x8 #define COMPILE_TIME_LEN 0x18 #define MAP_MAX_SIZE 0xa00 -#define HOOK_ALLOC_SIZE (256 * 1024) +#define HOOK_ALLOC_SIZE (1 << 20) +#define MEMORY_ROX_SIZE (2 << 20) +#define MEMORY_RW_SIZE (2 << 20) #define MAP_ALIGN 16 -#define PATCH_CONFIG_DIR_LEN 128 +#define PATCH_CONFIG_LEN (512) #define VERSION(major, minor, patch) (((major) << 16) + ((minor) << 8) + (patch)) @@ -45,12 +47,21 @@ typedef struct _setup_header_t // 64-bytes #endif #ifndef __ASSEMBLY__ -typedef struct +#ifndef ANDROID +struct patch_config { - char default_dir[PATCH_CONFIG_DIR_LEN]; -} patch_config_t; + char val[PATCH_CONFIG_LEN]; +}; #else -#define patch_config_size (PATCH_CONFIG_DIR_LEN) +struct patch_config +{ + char su_config_file[128]; + char test_kpm_file[128]; +}; +#endif +typedef struct patch_config patch_config_t; +#else +#define patch_config_size (PATCH_CONFIG_LEN) #endif #ifndef __ASSEMBLY__ diff --git a/kernel/include/stdbool.h b/kernel/include/stdbool.h index c5c08b73..488efdb1 100644 --- a/kernel/include/stdbool.h +++ b/kernel/include/stdbool.h @@ -1,7 +1,7 @@ #ifndef _KP_STDBOOL_H_ #define _KP_STDBOOL_H_ -typedef int bool; +typedef unsigned char bool; #define true ((bool)1) #define false ((bool)0) diff --git a/kernel/include/stddef.h b/kernel/include/stddef.h index 407c85f0..93b12217 100644 --- a/kernel/include/stddef.h +++ b/kernel/include/stddef.h @@ -5,4 +5,6 @@ #define RET_VOID ((void)0) +#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER) + #endif \ No newline at end of file diff --git a/kernel/include/symbol.h b/kernel/include/symbol.h index d1de933c..dd699446 100644 --- a/kernel/include/symbol.h +++ b/kernel/include/symbol.h @@ -3,6 +3,7 @@ #define KP_SYMBOL_LEN 31 +// todo: name len typedef struct { const char name[KP_SYMBOL_LEN + 1]; @@ -10,9 +11,11 @@ typedef struct unsigned long hash; } kp_symbol_t; -#define KP_EXPORT_SYMBOL(sym) \ +#define _KP_EXPORT_SYMBOL(sym) \ static kp_symbol_t __kp_symbol_##sym __attribute__((used)) \ - __attribute__((section(".kp.symbol"))) = { .name = #sym, .addr = (unsigned long)&sym, .hash = 0 }; + __attribute__((section(".kp.symbol"))) = { .name = #sym, .addr = (unsigned long)&sym, .hash = 0 } + +#define KP_EXPORT_SYMBOL(sym) _KP_EXPORT_SYMBOL(sym) unsigned long symbol_lookup_name(const char *name); diff --git a/kernel/include/tlsf.h b/kernel/include/tlsf.h new file mode 100644 index 00000000..e13876a5 --- /dev/null +++ b/kernel/include/tlsf.h @@ -0,0 +1,87 @@ +#ifndef INCLUDED_tlsf +#define INCLUDED_tlsf + +/* +** Two Level Segregated Fit memory allocator, version 3.1. +** Written by Matthew Conte +** http://tlsf.baisoku.org +** +** Based on the original documentation by Miguel Masmano: +** http://www.gii.upv.es/tlsf/main/docs +** +** This implementation was written to the specification +** of the document, therefore no GPL restrictions apply. +** +** Copyright (c) 2006-2016, Matthew Conte +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of the copyright holder nor the +** names of its contributors may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL MATTHEW CONTE BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +from: +https://github.com/mattconte/tlsf +*/ + +#include +#include + +/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */ +/* pool_t: a block of memory that TLSF can manage. */ +typedef void *tlsf_t; +typedef void *pool_t; + +/* Create/destroy a memory pool. */ +tlsf_t tlsf_create(void *mem); +tlsf_t tlsf_create_with_pool(void *mem, size_t bytes); +void tlsf_destroy(tlsf_t tlsf); +pool_t tlsf_get_pool(tlsf_t tlsf); + +/* Add/remove memory pools. */ +pool_t tlsf_add_pool(tlsf_t tlsf, void *mem, size_t bytes); +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool); + +/* malloc/memalign/realloc/free replacements. */ +void *tlsf_malloc(tlsf_t tlsf, size_t bytes); +void *tlsf_memalign(tlsf_t tlsf, size_t align, size_t bytes); +void *tlsf_realloc(tlsf_t tlsf, void *ptr, size_t size); +void tlsf_free(tlsf_t tlsf, void *ptr); + +/* Returns internal block size, not original request size */ +size_t tlsf_block_size(void *ptr); + +/* Overheads/limits of internal structures. */ +size_t tlsf_size(void); +size_t tlsf_align_size(void); +size_t tlsf_block_size_min(void); +size_t tlsf_block_size_max(void); +size_t tlsf_pool_overhead(void); +size_t tlsf_alloc_overhead(void); + +typedef void (*tlsf_walker)(void *ptr, size_t size, int used, void *user); +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void *user); +/* Returns nonzero if any internal consistency check fails. */ +int tlsf_check(tlsf_t tlsf); +int tlsf_check_pool(pool_t pool); + +#endif \ No newline at end of file diff --git a/kernel/kpimg.lds b/kernel/kpimg.lds index 80d55e33..0c332851 100644 --- a/kernel/kpimg.lds +++ b/kernel/kpimg.lds @@ -31,9 +31,10 @@ SECTIONS . = ALIGN(16); .setup.map : { _map_start = .; - base/map*.o(.map.data) - base/map*.o(.map.text) - base/map*.o(.text) + base/map.o(.map.data) + base/map.o(.map.text) + base/map.o(.text) + base/map1.o(.text) . = ALIGN(16); _map_end = .; } @@ -44,8 +45,8 @@ SECTIONS .kp.text : { _kp_text_start = .; - base/start*.o(.start.text) - base/start*.o(.text) + base/start.o(.start.text) + base/start.o(.text) base/hook.o(.transit0.text); _transit0_end = .; @@ -56,6 +57,15 @@ SECTIONS base/hook.o(.transit12.text); _transit12_end = .; + base/fphook.o(.fp.transit0.text); + _fp_transit0_end = .; + base/fphook.o(.fp.transit4.text); + _fp_transit4_end = .; + base/fphook.o(.fp.transit8.text); + _fp_transit8_end = .; + base/fphook.o(.fp.transit12.text); + _fp_transit12_end = .; + base/*(.text) base/*(.rodata*) diff --git a/kernel/linux/arch/arm64/include/asm/atomic.h b/kernel/linux/arch/arm64/include/asm/atomic.h new file mode 100644 index 00000000..3074e1ac --- /dev/null +++ b/kernel/linux/arch/arm64/include/asm/atomic.h @@ -0,0 +1,257 @@ +/* + * Based on arch/arm/include/asm/atomic.h + * + * Copyright (C) 1996 Russell King. + * Copyright (C) 2002 Deep Blue Solutions Ltd. + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_ATOMIC_H +#define __ASM_ATOMIC_H + +#include +#include +#include + +#define ATOMIC_INIT(i) \ + { \ + (i) \ + } + +/* + * On ARM, ordinary assignment (str instruction) doesn't clear the local + * strex/ldrex monitor on some implementations. The reason we can use it for + * atomic_set() is the clrex or dummy strex done on every exception return. + */ +#define atomic_read(v) ACCESS_ONCE((v)->counter) +#define atomic_set(v, i) (((v)->counter) = (i)) + +/* + * AArch64 UP and SMP safe atomic ops. We use load exclusive and + * store exclusive to ensure that these are atomic. We may loop + * to ensure that the update happens. + */ + +#define ATOMIC_OP(op, asm_op) \ + static inline void atomic_##op(int i, atomic_t *v) \ + { \ + unsigned long tmp; \ + int result; \ + \ + asm volatile("// atomic_" #op "\n" \ + "1: ldxr %w0, %2\n" \ + " " #asm_op " %w0, %w0, %w3\n" \ + " stxr %w1, %w0, %2\n" \ + " cbnz %w1, 1b" \ + : "=&r"(result), "=&r"(tmp), "+Q"(v->counter) \ + : "Ir"(i)); \ + } + +#define ATOMIC_OP_RETURN(op, asm_op) \ + static inline int atomic_##op##_return(int i, atomic_t *v) \ + { \ + unsigned long tmp; \ + int result; \ + \ + asm volatile("// atomic_" #op "_return\n" \ + "1: ldxr %w0, %2\n" \ + " " #asm_op " %w0, %w0, %w3\n" \ + " stlxr %w1, %w0, %2\n" \ + " cbnz %w1, 1b" \ + : "=&r"(result), "=&r"(tmp), "+Q"(v->counter) \ + : "Ir"(i) \ + : "memory"); \ + \ + smp_mb(); \ + return result; \ + } + +#define ATOMIC_OPS(op, asm_op) \ + ATOMIC_OP(op, asm_op) \ + ATOMIC_OP_RETURN(op, asm_op) + +ATOMIC_OPS(add, add) +ATOMIC_OPS(sub, sub) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) +{ + unsigned long tmp; + int oldval; + + smp_mb(); + + asm volatile("// atomic_cmpxchg\n" + "1: ldxr %w1, %2\n" + " cmp %w1, %w3\n" + " b.ne 2f\n" + " stxr %w0, %w4, %2\n" + " cbnz %w0, 1b\n" + "2:" + : "=&r"(tmp), "=&r"(oldval), "+Q"(ptr->counter) + : "Ir"(old), "r"(new) + : "cc"); + + smp_mb(); + return oldval; +} + +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +static inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ + int c, old; + + c = atomic_read(v); + while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c) + c = old; + return c; +} + +#define atomic_inc(v) atomic_add(1, v) +#define atomic_dec(v) atomic_sub(1, v) + +#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) +#define atomic_inc_return(v) (atomic_add_return(1, v)) +#define atomic_dec_return(v) (atomic_sub_return(1, v)) +#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) + +#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0) + +/* + * 64-bit atomic operations. + */ +#define ATOMIC64_INIT(i) \ + { \ + (i) \ + } + +#define atomic64_read(v) ACCESS_ONCE((v)->counter) +#define atomic64_set(v, i) (((v)->counter) = (i)) + +#define ATOMIC64_OP(op, asm_op) \ + static inline void atomic64_##op(long i, atomic64_t *v) \ + { \ + long result; \ + unsigned long tmp; \ + \ + asm volatile("// atomic64_" #op "\n" \ + "1: ldxr %0, %2\n" \ + " " #asm_op " %0, %0, %3\n" \ + " stxr %w1, %0, %2\n" \ + " cbnz %w1, 1b" \ + : "=&r"(result), "=&r"(tmp), "+Q"(v->counter) \ + : "Ir"(i)); \ + } + +#define ATOMIC64_OP_RETURN(op, asm_op) \ + static inline long atomic64_##op##_return(long i, atomic64_t *v) \ + { \ + long result; \ + unsigned long tmp; \ + \ + asm volatile("// atomic64_" #op "_return\n" \ + "1: ldxr %0, %2\n" \ + " " #asm_op " %0, %0, %3\n" \ + " stlxr %w1, %0, %2\n" \ + " cbnz %w1, 1b" \ + : "=&r"(result), "=&r"(tmp), "+Q"(v->counter) \ + : "Ir"(i) \ + : "memory"); \ + \ + smp_mb(); \ + return result; \ + } + +#define ATOMIC64_OPS(op, asm_op) \ + ATOMIC64_OP(op, asm_op) \ + ATOMIC64_OP_RETURN(op, asm_op) + +ATOMIC64_OPS(add, add) +ATOMIC64_OPS(sub, sub) + +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP + +static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) +{ + long oldval; + unsigned long res; + + smp_mb(); + + asm volatile("// atomic64_cmpxchg\n" + "1: ldxr %1, %2\n" + " cmp %1, %3\n" + " b.ne 2f\n" + " stxr %w0, %4, %2\n" + " cbnz %w0, 1b\n" + "2:" + : "=&r"(res), "=&r"(oldval), "+Q"(ptr->counter) + : "Ir"(old), "r"(new) + : "cc"); + + smp_mb(); + return oldval; +} + +#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) + +static inline long atomic64_dec_if_positive(atomic64_t *v) +{ + long result; + unsigned long tmp; + + asm volatile("// atomic64_dec_if_positive\n" + "1: ldxr %0, %2\n" + " subs %0, %0, #1\n" + " b.mi 2f\n" + " stlxr %w1, %0, %2\n" + " cbnz %w1, 1b\n" + " dmb ish\n" + "2:" + : "=&r"(result), "=&r"(tmp), "+Q"(v->counter) + : + : "cc", "memory"); + + return result; +} + +static inline int atomic64_add_unless(atomic64_t *v, long a, long u) +{ + long c, old; + + c = atomic64_read(v); + while (c != u && (old = atomic64_cmpxchg((v), c, c + a)) != c) + c = old; + + return c != u; +} + +#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) +#define atomic64_inc(v) atomic64_add(1LL, (v)) +#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) +#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) +#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) +#define atomic64_dec(v) atomic64_sub(1LL, (v)) +#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) +#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) + +#endif \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/asm/cmpxchg.h b/kernel/linux/arch/arm64/include/asm/cmpxchg.h new file mode 100644 index 00000000..a33b3f28 --- /dev/null +++ b/kernel/linux/arch/arm64/include/asm/cmpxchg.h @@ -0,0 +1,182 @@ +/* + * Based on arch/arm/include/asm/cmpxchg.h + * + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_CMPXCHG_H +#define __ASM_CMPXCHG_H + +#include +#include + +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) +{ + unsigned long ret, tmp; + + switch (size) { + case 1: + asm volatile("// __xchg1\n" + "1: ldxrb %w0, %2\n" + " stlxrb %w1, %w3, %2\n" + " cbnz %w1, 1b\n" + : "=&r"(ret), "=&r"(tmp), "+Q"(*(u8 *)ptr) + : "r"(x) + : "memory"); + break; + case 2: + asm volatile("// __xchg2\n" + "1: ldxrh %w0, %2\n" + " stlxrh %w1, %w3, %2\n" + " cbnz %w1, 1b\n" + : "=&r"(ret), "=&r"(tmp), "+Q"(*(u16 *)ptr) + : "r"(x) + : "memory"); + break; + case 4: + asm volatile("// __xchg4\n" + "1: ldxr %w0, %2\n" + " stlxr %w1, %w3, %2\n" + " cbnz %w1, 1b\n" + : "=&r"(ret), "=&r"(tmp), "+Q"(*(u32 *)ptr) + : "r"(x) + : "memory"); + break; + case 8: + asm volatile("// __xchg8\n" + "1: ldxr %0, %2\n" + " stlxr %w1, %3, %2\n" + " cbnz %w1, 1b\n" + : "=&r"(ret), "=&r"(tmp), "+Q"(*(u64 *)ptr) + : "r"(x) + : "memory"); + break; + default: + // BUILD_BUG(); + } + + smp_mb(); + return ret; +} + +#define xchg(ptr, x) \ + ({ \ + __typeof__(*(ptr)) __ret; \ + __ret = (__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))); \ + __ret; \ + }) + +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) +{ + unsigned long oldval = 0, res; + + switch (size) { + case 1: + do { + asm volatile("// __cmpxchg1\n" + " ldxrb %w1, %2\n" + " mov %w0, #0\n" + " cmp %w1, %w3\n" + " b.ne 1f\n" + " stxrb %w0, %w4, %2\n" + "1:\n" + : "=&r"(res), "=&r"(oldval), "+Q"(*(u8 *)ptr) + : "Ir"(old), "r"(new) + : "cc"); + } while (res); + break; + + case 2: + do { + asm volatile("// __cmpxchg2\n" + " ldxrh %w1, %2\n" + " mov %w0, #0\n" + " cmp %w1, %w3\n" + " b.ne 1f\n" + " stxrh %w0, %w4, %2\n" + "1:\n" + : "=&r"(res), "=&r"(oldval), "+Q"(*(u16 *)ptr) + : "Ir"(old), "r"(new) + : "cc"); + } while (res); + break; + + case 4: + do { + asm volatile("// __cmpxchg4\n" + " ldxr %w1, %2\n" + " mov %w0, #0\n" + " cmp %w1, %w3\n" + " b.ne 1f\n" + " stxr %w0, %w4, %2\n" + "1:\n" + : "=&r"(res), "=&r"(oldval), "+Q"(*(u32 *)ptr) + : "Ir"(old), "r"(new) + : "cc"); + } while (res); + break; + + case 8: + do { + asm volatile("// __cmpxchg8\n" + " ldxr %1, %2\n" + " mov %w0, #0\n" + " cmp %1, %3\n" + " b.ne 1f\n" + " stxr %w0, %4, %2\n" + "1:\n" + : "=&r"(res), "=&r"(oldval), "+Q"(*(u64 *)ptr) + : "Ir"(old), "r"(new) + : "cc"); + } while (res); + break; + + default: + // BUILD_BUG(); + } + + return oldval; +} + +static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, unsigned long new, int size) +{ + unsigned long ret; + + smp_mb(); + ret = __cmpxchg(ptr, old, new, size); + smp_mb(); + + return ret; +} + +#define cmpxchg(ptr, o, n) \ + ({ \ + __typeof__(*(ptr)) __ret; \ + __ret = (__typeof__(*(ptr)))__cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))); \ + __ret; \ + }) + +#define cmpxchg_local(ptr, o, n) \ + ({ \ + __typeof__(*(ptr)) __ret; \ + __ret = (__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))); \ + __ret; \ + }) + +#define cmpxchg64(ptr, o, n) cmpxchg((ptr), (o), (n)) +#define cmpxchg64_local(ptr, o, n) cmpxchg_local((ptr), (o), (n)) + +#define cmpxchg64_relaxed(ptr, o, n) cmpxchg_local((ptr), (o), (n)) + +#endif /* __ASM_CMPXCHG_H */ \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/asm/current.h b/kernel/linux/arch/arm64/include/asm/current.h index e00aa0f1..935fd326 100644 --- a/kernel/linux/arch/arm64/include/asm/current.h +++ b/kernel/linux/arch/arm64/include/asm/current.h @@ -43,8 +43,7 @@ static inline struct thread_info *current_thread_info() } } struct thread_info *ti = legacy_current_thread_info_sp_el0(); - if (thread_info_is_sp) - ti = legacy_current_thread_info_sp(); + if (thread_info_is_sp) ti = legacy_current_thread_info_sp(); return ti; } @@ -76,7 +75,6 @@ static inline struct task_ext *get_task_ext(struct task_struct *task) { uint64_t addr = (uint64_t)get_stack(task); addr += stack_end_offset; - addr = (addr + 15) & ~0xf; return (struct task_ext *)(addr); } diff --git a/kernel/linux/arch/arm64/include/asm/elf.h b/kernel/linux/arch/arm64/include/asm/elf.h new file mode 100644 index 00000000..8bebf960 --- /dev/null +++ b/kernel/linux/arch/arm64/include/asm/elf.h @@ -0,0 +1,243 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2012 ARM Ltd. + */ +#ifndef __ASM_ELF_H +#define __ASM_ELF_H + +#include +#include +#include + +/* + * AArch64 static relocation types. + */ + +/* Miscellaneous. */ +#define R_ARM_NONE 0 +#define R_AARCH64_NONE 256 + +/* Data. */ +#define R_AARCH64_ABS64 257 +#define R_AARCH64_ABS32 258 +#define R_AARCH64_ABS16 259 +#define R_AARCH64_PREL64 260 +#define R_AARCH64_PREL32 261 +#define R_AARCH64_PREL16 262 + +/* Instructions. */ +#define R_AARCH64_MOVW_UABS_G0 263 +#define R_AARCH64_MOVW_UABS_G0_NC 264 +#define R_AARCH64_MOVW_UABS_G1 265 +#define R_AARCH64_MOVW_UABS_G1_NC 266 +#define R_AARCH64_MOVW_UABS_G2 267 +#define R_AARCH64_MOVW_UABS_G2_NC 268 +#define R_AARCH64_MOVW_UABS_G3 269 + +#define R_AARCH64_MOVW_SABS_G0 270 +#define R_AARCH64_MOVW_SABS_G1 271 +#define R_AARCH64_MOVW_SABS_G2 272 + +#define R_AARCH64_LD_PREL_LO19 273 +#define R_AARCH64_ADR_PREL_LO21 274 +#define R_AARCH64_ADR_PREL_PG_HI21 275 +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 +#define R_AARCH64_ADD_ABS_LO12_NC 277 +#define R_AARCH64_LDST8_ABS_LO12_NC 278 + +#define R_AARCH64_TSTBR14 279 +#define R_AARCH64_CONDBR19 280 +#define R_AARCH64_JUMP26 282 +#define R_AARCH64_CALL26 283 +#define R_AARCH64_LDST16_ABS_LO12_NC 284 +#define R_AARCH64_LDST32_ABS_LO12_NC 285 +#define R_AARCH64_LDST64_ABS_LO12_NC 286 +#define R_AARCH64_LDST128_ABS_LO12_NC 299 + +#define R_AARCH64_MOVW_PREL_G0 287 +#define R_AARCH64_MOVW_PREL_G0_NC 288 +#define R_AARCH64_MOVW_PREL_G1 289 +#define R_AARCH64_MOVW_PREL_G1_NC 290 +#define R_AARCH64_MOVW_PREL_G2 291 +#define R_AARCH64_MOVW_PREL_G2_NC 292 +#define R_AARCH64_MOVW_PREL_G3 293 + +#define R_AARCH64_RELATIVE 1027 + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS64 +#ifdef __AARCH64EB__ +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_AARCH64 + +/* + * This yields a string that ld.so will use to load implementation + * specific libraries for optimization. This is more specific in + * intent than poking at uname or /proc/cpuinfo. + */ +#define ELF_PLATFORM_SIZE 16 +#ifdef __AARCH64EB__ +#define ELF_PLATFORM ("aarch64_be") +#else +#define ELF_PLATFORM ("aarch64") +#endif + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_AARCH64) + +/* + * An executable for which elf_read_implies_exec() returns TRUE will + * have the READ_IMPLIES_EXEC personality flag set automatically. + * + * The decision process for determining the results are: + * + * CPU*: | arm32 | arm64 | + * ELF: | | | + * ---------------------|------------|------------| + * missing PT_GNU_STACK | exec-all | exec-none | + * PT_GNU_STACK == RWX | exec-stack | exec-stack | + * PT_GNU_STACK == RW | exec-none | exec-none | + * + * exec-all : all PROT_READ user mappings are executable, except when + * backed by files on a noexec-filesystem. + * exec-none : only PROT_EXEC user mappings are executable. + * exec-stack: only the stack and PROT_EXEC user mappings are executable. + * + * *all arm64 CPUs support NX, so there is no "lacks NX" column. + * + */ +#define compat_elf_read_implies_exec(ex, stk) (stk == EXSTACK_DEFAULT) + +#define CORE_DUMP_USE_REGSET +#define ELF_EXEC_PAGESIZE PAGE_SIZE + +/* + * This is the base location for PIE (ET_DYN with INTERP) loads. On + * 64-bit, this is above 4GB to leave the entire 32-bit address + * space open for things that want to use the area for 32-bit pointers. + */ +#ifdef CONFIG_ARM64_FORCE_52BIT +#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) +#else +#define ELF_ET_DYN_BASE (2 * DEFAULT_MAP_WINDOW_64 / 3) +#endif /* CONFIG_ARM64_FORCE_52BIT */ + +#ifndef __ASSEMBLY__ + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) +#define ELF_CORE_COPY_REGS(dest, regs) *(struct user_pt_regs *)&(dest) = (regs)->user_regs; + +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; +typedef struct user_fpsimd_state elf_fpregset_t; + +/* + * When the program starts, a1 contains a pointer to a function to be + * registered with atexit, as per the SVR4 ABI. A value of 0 means we have no + * such handler. + */ +#define ELF_PLAT_INIT(_r, load_addr) (_r)->regs[0] = 0 + +#define SET_PERSONALITY(ex) \ + ({ \ + clear_thread_flag(TIF_32BIT); \ + current->personality &= ~READ_IMPLIES_EXEC; \ + }) + +/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ +#define ARCH_DLINFO \ + do { \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, (elf_addr_t)current->mm->context.vdso); \ + \ + /* \ + * Should always be nonzero unless there's a kernel bug. \ + * If we haven't determined a sensible value to give to \ + * userspace, omit the entry: \ + */ \ + if (likely(signal_minsigstksz)) \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz); \ + else \ + NEW_AUX_ENT(AT_IGNORE, 0); \ + } while (0) + +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES +struct linux_binprm; +extern int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp); + +/* 1GB of VA */ +#ifdef CONFIG_COMPAT +#define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? 0x7ff >> (PAGE_SHIFT - 12) : 0x3ffff >> (PAGE_SHIFT - 12)) +#else +#define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12)) +#endif + +#ifdef __AARCH64EB__ +#define COMPAT_ELF_PLATFORM ("v8b") +#else +#define COMPAT_ELF_PLATFORM ("v8l") +#endif + +#ifdef CONFIG_COMPAT + +/* PIE load location for compat arm. Must match ARM ELF_ET_DYN_BASE. */ +#define COMPAT_ELF_ET_DYN_BASE 0x000400000UL + +/* AArch32 registers. */ +#define COMPAT_ELF_NGREG 18 +typedef unsigned int compat_elf_greg_t; +typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; + +/* AArch32 EABI. */ +#define EF_ARM_EABI_MASK 0xff000000 +#define compat_elf_check_arch(x) \ + (system_supports_32bit_el0() && ((x)->e_machine == EM_ARM) && ((x)->e_flags & EF_ARM_EABI_MASK)) + +#define compat_start_thread compat_start_thread +/* + * Unlike the native SET_PERSONALITY macro, the compat version maintains + * READ_IMPLIES_EXEC across an execve() since this is the behaviour on + * arch/arm/. + */ +#define COMPAT_SET_PERSONALITY(ex) ({ set_thread_flag(TIF_32BIT); }) +#ifdef CONFIG_COMPAT_VDSO +#define COMPAT_ARCH_DLINFO \ + do { \ + /* \ + * Note that we use Elf64_Off instead of elf_addr_t because \ + * elf_addr_t in compat is defined as Elf32_Addr and casting \ + * current->mm->context.vdso to it triggers a cast warning of \ + * cast from pointer to integer of different size. \ + */ \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, (Elf64_Off)current->mm->context.vdso); \ + } while (0) +#else +#define COMPAT_ARCH_DLINFO +#endif +extern int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp); +#define compat_arch_setup_additional_pages aarch32_setup_additional_pages + +#endif /* CONFIG_COMPAT */ + +struct arch_elf_state +{ + int flags; +}; + +#define ARM64_ELF_BTI (1 << 0) + +#define INIT_ARCH_ELF_STATE \ + { \ + .flags = 0, \ + } + +#endif /* !__ASSEMBLY__ */ + +#endif \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/asm/hwcap.h b/kernel/linux/arch/arm64/include/asm/hwcap.h new file mode 100644 index 00000000..18194b4a --- /dev/null +++ b/kernel/linux/arch/arm64/include/asm/hwcap.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_HWCAP_H +#define __ASM_HWCAP_H + +#include + +#define COMPAT_HWCAP_HALF (1 << 1) +#define COMPAT_HWCAP_THUMB (1 << 2) +#define COMPAT_HWCAP_FAST_MULT (1 << 4) +#define COMPAT_HWCAP_VFP (1 << 6) +#define COMPAT_HWCAP_EDSP (1 << 7) +#define COMPAT_HWCAP_NEON (1 << 12) +#define COMPAT_HWCAP_VFPv3 (1 << 13) +#define COMPAT_HWCAP_TLS (1 << 15) +#define COMPAT_HWCAP_VFPv4 (1 << 16) +#define COMPAT_HWCAP_IDIVA (1 << 17) +#define COMPAT_HWCAP_IDIVT (1 << 18) +#define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA | COMPAT_HWCAP_IDIVT) +#define COMPAT_HWCAP_LPAE (1 << 20) +#define COMPAT_HWCAP_EVTSTRM (1 << 21) + +#define COMPAT_HWCAP2_AES (1 << 0) +#define COMPAT_HWCAP2_PMULL (1 << 1) +#define COMPAT_HWCAP2_SHA1 (1 << 2) +#define COMPAT_HWCAP2_SHA2 (1 << 3) +#define COMPAT_HWCAP2_CRC32 (1 << 4) +#define COMPAT_HWCAP2_SB (1 << 5) +#define COMPAT_HWCAP2_SSBS (1 << 6) + +#ifndef __ASSEMBLY__ +/* + * This yields a mask that user programs can use to figure out what + * instruction set this cpu supports. + */ +#define ELF_HWCAP cpu_get_elf_hwcap() +#define ELF_HWCAP2 cpu_get_elf_hwcap2() + +#ifdef CONFIG_COMPAT +#define COMPAT_ELF_HWCAP (compat_elf_hwcap) +#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2) +extern unsigned int compat_elf_hwcap, compat_elf_hwcap2; +#endif + +enum +{ + CAP_HWCAP = 1, +#ifdef CONFIG_COMPAT + CAP_COMPAT_HWCAP, + CAP_COMPAT_HWCAP2, +#endif +}; + +#endif +#endif \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/asm/io.h b/kernel/linux/arch/arm64/include/asm/io.h new file mode 100644 index 00000000..f4483f8f --- /dev/null +++ b/kernel/linux/arch/arm64/include/asm/io.h @@ -0,0 +1,6 @@ +#ifndef __ASM_IO_H +#define __ASM_IO_H + +#include + +#endif \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/asm/ptrace.h b/kernel/linux/arch/arm64/include/asm/ptrace.h index 5b9b14a6..f03b0515 100644 --- a/kernel/linux/arch/arm64/include/asm/ptrace.h +++ b/kernel/linux/arch/arm64/include/asm/ptrace.h @@ -4,7 +4,6 @@ #include #include #include -#include #include /* Current Exception Level values, as contained in CurrentEL */ @@ -33,15 +32,14 @@ #define __GIC_PRIO_IRQOFF_NS 0xa0 #define GIC_PRIO_PSR_I_SET (1 << 4) -#define GIC_PRIO_IRQOFF \ - ({ \ - extern struct static_key_false gic_nonsecure_priorities; \ - u8 __prio = __GIC_PRIO_IRQOFF; \ - \ - if (static_branch_unlikely(&gic_nonsecure_priorities)) \ - __prio = __GIC_PRIO_IRQOFF_NS; \ - \ - __prio; \ +#define GIC_PRIO_IRQOFF \ + ({ \ + extern struct static_key_false gic_nonsecure_priorities; \ + u8 __prio = __GIC_PRIO_IRQOFF; \ + \ + if (static_branch_unlikely(&gic_nonsecure_priorities)) __prio = __GIC_PRIO_IRQOFF_NS; \ + \ + __prio; \ }) /* Additional SPSR bits not exposed in the UABI */ @@ -141,8 +139,7 @@ static inline unsigned long compat_psr_to_pstate(const unsigned long psr) pstate = psr & ~COMPAT_PSR_DIT_BIT; - if (psr & COMPAT_PSR_DIT_BIT) - pstate |= PSR_AA32_DIT_BIT; + if (psr & COMPAT_PSR_DIT_BIT) pstate |= PSR_AA32_DIT_BIT; return pstate; } @@ -153,8 +150,7 @@ static inline unsigned long pstate_to_compat_psr(const unsigned long pstate) psr = pstate & ~PSR_AA32_DIT_BIT; - if (pstate & PSR_AA32_DIT_BIT) - psr |= COMPAT_PSR_DIT_BIT; + if (pstate & PSR_AA32_DIT_BIT) psr |= COMPAT_PSR_DIT_BIT; return psr; } diff --git a/kernel/linux/arch/arm64/include/asm/uaccess.h b/kernel/linux/arch/arm64/include/asm/uaccess.h new file mode 100644 index 00000000..9dca11ac --- /dev/null +++ b/kernel/linux/arch/arm64/include/asm/uaccess.h @@ -0,0 +1,41 @@ +/* + * Based on arch/arm/include/asm/uaccess.h + * + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_UACCESS_H +#define __ASM_UACCESS_H + +#include + +// todo: + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#define KERNEL_DS (-1UL) +// #define get_ds() (KERNEL_DS) + +// #define USER_DS TASK_SIZE_64 +// #define get_fs() (current_thread_info()->addr_limit) + +// static inline void set_fs(mm_segment_t fs) +// { +// current_thread_info()->addr_limit = fs; +// } + +// #define segment_eq(a, b) ((a) == (b)) + +#endif \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/uapi/asm/hwcap.h b/kernel/linux/arch/arm64/include/uapi/asm/hwcap.h new file mode 100644 index 00000000..1fef0707 --- /dev/null +++ b/kernel/linux/arch/arm64/include/uapi/asm/hwcap.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef _UAPI__ASM_HWCAP_H +#define _UAPI__ASM_HWCAP_H + +/* + * HWCAP flags - for AT_HWCAP + * + * Bits 62 and 63 are reserved for use by libc. + * Bits 32-61 are unallocated for potential use by libc. + */ +#define HWCAP_FP (1 << 0) +#define HWCAP_ASIMD (1 << 1) +#define HWCAP_EVTSTRM (1 << 2) +#define HWCAP_AES (1 << 3) +#define HWCAP_PMULL (1 << 4) +#define HWCAP_SHA1 (1 << 5) +#define HWCAP_SHA2 (1 << 6) +#define HWCAP_CRC32 (1 << 7) +#define HWCAP_ATOMICS (1 << 8) +#define HWCAP_FPHP (1 << 9) +#define HWCAP_ASIMDHP (1 << 10) +#define HWCAP_CPUID (1 << 11) +#define HWCAP_ASIMDRDM (1 << 12) +#define HWCAP_JSCVT (1 << 13) +#define HWCAP_FCMA (1 << 14) +#define HWCAP_LRCPC (1 << 15) +#define HWCAP_DCPOP (1 << 16) +#define HWCAP_SHA3 (1 << 17) +#define HWCAP_SM3 (1 << 18) +#define HWCAP_SM4 (1 << 19) +#define HWCAP_ASIMDDP (1 << 20) +#define HWCAP_SHA512 (1 << 21) +#define HWCAP_SVE (1 << 22) +#define HWCAP_ASIMDFHM (1 << 23) +#define HWCAP_DIT (1 << 24) +#define HWCAP_USCAT (1 << 25) +#define HWCAP_ILRCPC (1 << 26) +#define HWCAP_FLAGM (1 << 27) +#define HWCAP_SSBS (1 << 28) +#define HWCAP_SB (1 << 29) +#define HWCAP_PACA (1 << 30) +#define HWCAP_PACG (1UL << 31) + +/* + * HWCAP2 flags - for AT_HWCAP2 + */ +#define HWCAP2_DCPODP (1 << 0) +#define HWCAP2_SVE2 (1 << 1) +#define HWCAP2_SVEAES (1 << 2) +#define HWCAP2_SVEPMULL (1 << 3) +#define HWCAP2_SVEBITPERM (1 << 4) +#define HWCAP2_SVESHA3 (1 << 5) +#define HWCAP2_SVESM4 (1 << 6) +#define HWCAP2_FLAGM2 (1 << 7) +#define HWCAP2_FRINT (1 << 8) +#define HWCAP2_SVEI8MM (1 << 9) +#define HWCAP2_SVEF32MM (1 << 10) +#define HWCAP2_SVEF64MM (1 << 11) +#define HWCAP2_SVEBF16 (1 << 12) +#define HWCAP2_I8MM (1 << 13) +#define HWCAP2_BF16 (1 << 14) +#define HWCAP2_DGH (1 << 15) +#define HWCAP2_RNG (1 << 16) +#define HWCAP2_BTI (1 << 17) +#define HWCAP2_MTE (1 << 18) +#define HWCAP2_ECV (1 << 19) +#define HWCAP2_AFP (1 << 20) +#define HWCAP2_RPRES (1 << 21) +#define HWCAP2_MTE3 (1 << 22) +#define HWCAP2_SME (1 << 23) +#define HWCAP2_SME_I16I64 (1 << 24) +#define HWCAP2_SME_F64F64 (1 << 25) +#define HWCAP2_SME_I8I32 (1 << 26) +#define HWCAP2_SME_F16F32 (1 << 27) +#define HWCAP2_SME_B16F32 (1 << 28) +#define HWCAP2_SME_F32F32 (1 << 29) +#define HWCAP2_SME_FA64 (1 << 30) +#define HWCAP2_WFXT (1UL << 31) +#define HWCAP2_EBF16 (1UL << 32) +#define HWCAP2_SVE_EBF16 (1UL << 33) +#define HWCAP2_CSSC (1UL << 34) +#define HWCAP2_RPRFM (1UL << 35) +#define HWCAP2_SVE2P1 (1UL << 36) +#define HWCAP2_SME2 (1UL << 37) +#define HWCAP2_SME2P1 (1UL << 38) +#define HWCAP2_SME_I16I32 (1UL << 39) +#define HWCAP2_SME_BI32I32 (1UL << 40) +#define HWCAP2_SME_B16B16 (1UL << 41) +#define HWCAP2_SME_F16F16 (1UL << 42) +#define HWCAP2_MOPS (1UL << 43) +#define HWCAP2_HBC (1UL << 44) + +#endif /* _UAPI__ASM_HWCAP_H */ \ No newline at end of file diff --git a/kernel/linux/arch/arm64/include/uapi/asm/ptrace.h b/kernel/linux/arch/arm64/include/uapi/asm/ptrace.h index 9bef00e5..87b89927 100644 --- a/kernel/linux/arch/arm64/include/uapi/asm/ptrace.h +++ b/kernel/linux/arch/arm64/include/uapi/asm/ptrace.h @@ -208,9 +208,9 @@ struct user_sve_header ((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE - SVE_PT_SVE_OFFSET + (__SVE_VQ_BYTES - 1)) / __SVE_VQ_BYTES * \ __SVE_VQ_BYTES) -#define SVE_PT_SIZE(vq, flags) \ - (((flags)&SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ? SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) : \ - SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags)) +#define SVE_PT_SIZE(vq, flags) \ + (((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ? SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) : \ + SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags)) /* pointer authentication masks (NT_ARM_PAC_MASK) */ diff --git a/kernel/linux/include/asm-generic/bitops/fls_ffs.h b/kernel/linux/include/asm-generic/bitops/fls_ffs.h new file mode 100644 index 00000000..d0b07e3b --- /dev/null +++ b/kernel/linux/include/asm-generic/bitops/fls_ffs.h @@ -0,0 +1,149 @@ +#ifndef _ASM_GENERIC_BITOPS_FLS_FSS_H_ +#define _ASM_GENERIC_BITOPS_FLS_FFS_H_ + +#include + +/** + * fls - find last (most-significant) bit set + * @x: the word to search + * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ +static __always_inline int fls(unsigned int x) +{ + int r = 32; + + if (!x) return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +static __always_inline unsigned long __fls(unsigned long word) +{ + int num = BITS_PER_LONG - 1; + +#if BITS_PER_LONG == 64 + if (!(word & (~0ul << 32))) { + num -= 32; + word <<= 32; + } +#endif + if (!(word & (~0ul << (BITS_PER_LONG - 16)))) { + num -= 16; + word <<= 16; + } + if (!(word & (~0ul << (BITS_PER_LONG - 8)))) { + num -= 8; + word <<= 8; + } + if (!(word & (~0ul << (BITS_PER_LONG - 4)))) { + num -= 4; + word <<= 4; + } + if (!(word & (~0ul << (BITS_PER_LONG - 2)))) { + num -= 2; + word <<= 2; + } + if (!(word & (~0ul << (BITS_PER_LONG - 1)))) num -= 1; + return num; +} + +static __always_inline int fls64(__u64 x) +{ + if (x == 0) return 0; + return __fls(x) + 1; +} + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static __always_inline unsigned long __ffs(unsigned long word) +{ + int num = 0; + +#if BITS_PER_LONG == 64 + if ((word & 0xffffffff) == 0) { + num += 32; + word >>= 32; + } +#endif + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) num += 1; + return num; +} + +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ +static inline int ffs(int x) +{ + int r = 1; + + if (!x) return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} + +#endif \ No newline at end of file diff --git a/kernel/linux/include/asm-generic/compat.h b/kernel/linux/include/asm-generic/compat.h new file mode 100644 index 00000000..77db514c --- /dev/null +++ b/kernel/linux/include/asm-generic/compat.h @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_GENERIC_COMPAT_H +#define __ASM_GENERIC_COMPAT_H + +#include + +#ifndef COMPAT_USER_HZ +#define COMPAT_USER_HZ 100 +#endif + +#ifndef COMPAT_RLIM_INFINITY +#define COMPAT_RLIM_INFINITY 0xffffffff +#endif + +#ifndef COMPAT_OFF_T_MAX +#define COMPAT_OFF_T_MAX 0x7fffffff +#endif + +#ifndef compat_arg_u64 +#ifndef CONFIG_CPU_BIG_ENDIAN +#define compat_arg_u64(name) u32 name##_lo, u32 name##_hi +#define compat_arg_u64_dual(name) u32, name##_lo, u32, name##_hi +#else +#define compat_arg_u64(name) u32 name##_hi, u32 name##_lo +#define compat_arg_u64_dual(name) u32, name##_hi, u32, name##_lo +#endif +#define compat_arg_u64_glue(name) (((u64)name##_lo & 0xffffffffUL) | ((u64)name##_hi << 32)) +#endif /* compat_arg_u64 */ + +/* These types are common across all compat ABIs */ +typedef u32 compat_size_t; +typedef s32 compat_ssize_t; +typedef s32 compat_clock_t; +typedef s32 compat_pid_t; +typedef u32 compat_ino_t; +typedef s32 compat_off_t; +typedef s64 compat_loff_t; +typedef s32 compat_daddr_t; +typedef s32 compat_timer_t; +typedef s32 compat_key_t; +typedef s16 compat_short_t; +typedef s32 compat_int_t; +typedef s32 compat_long_t; +typedef u16 compat_ushort_t; +typedef u32 compat_uint_t; +typedef u32 compat_ulong_t; +typedef u32 compat_uptr_t; +typedef u32 compat_caddr_t; +typedef u32 compat_aio_context_t; +typedef u32 compat_old_sigset_t; + +#ifndef __compat_uid_t +typedef u32 __compat_uid_t; +typedef u32 __compat_gid_t; +#endif + +#ifndef __compat_uid32_t +typedef u32 __compat_uid32_t; +typedef u32 __compat_gid32_t; +#endif + +#ifndef compat_mode_t +typedef u32 compat_mode_t; +#endif + +#ifdef CONFIG_COMPAT_FOR_U64_ALIGNMENT +typedef s64 __attribute__((aligned(4))) compat_s64; +typedef u64 __attribute__((aligned(4))) compat_u64; +#else +typedef s64 compat_s64; +typedef u64 compat_u64; +#endif + +#ifndef _COMPAT_NSIG +typedef u32 compat_sigset_word; +#define _COMPAT_NSIG _NSIG +#define _COMPAT_NSIG_BPW 32 +#endif + +#ifndef compat_dev_t +typedef u32 compat_dev_t; +#endif + +#ifndef compat_ipc_pid_t +typedef s32 compat_ipc_pid_t; +#endif + +#ifndef compat_fsid_t +typedef __kernel_fsid_t compat_fsid_t; +#endif + +#ifndef compat_statfs +struct compat_statfs +{ + compat_int_t f_type; + compat_int_t f_bsize; + compat_int_t f_blocks; + compat_int_t f_bfree; + compat_int_t f_bavail; + compat_int_t f_files; + compat_int_t f_ffree; + compat_fsid_t f_fsid; + compat_int_t f_namelen; + compat_int_t f_frsize; + compat_int_t f_flags; + compat_int_t f_spare[4]; +}; +#endif + +#ifndef compat_ipc64_perm +struct compat_ipc64_perm +{ + compat_key_t key; + __compat_uid32_t uid; + __compat_gid32_t gid; + __compat_uid32_t cuid; + __compat_gid32_t cgid; + compat_mode_t mode; + unsigned char __pad1[4 - sizeof(compat_mode_t)]; + compat_ushort_t seq; + compat_ushort_t __pad2; + compat_ulong_t unused1; + compat_ulong_t unused2; +}; + +struct compat_semid64_ds +{ + struct compat_ipc64_perm sem_perm; + compat_ulong_t sem_otime; + compat_ulong_t sem_otime_high; + compat_ulong_t sem_ctime; + compat_ulong_t sem_ctime_high; + compat_ulong_t sem_nsems; + compat_ulong_t __unused3; + compat_ulong_t __unused4; +}; + +struct compat_msqid64_ds +{ + struct compat_ipc64_perm msg_perm; + compat_ulong_t msg_stime; + compat_ulong_t msg_stime_high; + compat_ulong_t msg_rtime; + compat_ulong_t msg_rtime_high; + compat_ulong_t msg_ctime; + compat_ulong_t msg_ctime_high; + compat_ulong_t msg_cbytes; + compat_ulong_t msg_qnum; + compat_ulong_t msg_qbytes; + compat_pid_t msg_lspid; + compat_pid_t msg_lrpid; + compat_ulong_t __unused4; + compat_ulong_t __unused5; +}; + +struct compat_shmid64_ds +{ + struct compat_ipc64_perm shm_perm; + compat_size_t shm_segsz; + compat_ulong_t shm_atime; + compat_ulong_t shm_atime_high; + compat_ulong_t shm_dtime; + compat_ulong_t shm_dtime_high; + compat_ulong_t shm_ctime; + compat_ulong_t shm_ctime_high; + compat_pid_t shm_cpid; + compat_pid_t shm_lpid; + compat_ulong_t shm_nattch; + compat_ulong_t __unused4; + compat_ulong_t __unused5; +}; +#endif + +#endif \ No newline at end of file diff --git a/kernel/linux/include/asm-generic/module.h b/kernel/linux/include/asm-generic/module.h new file mode 100644 index 00000000..5ec05005 --- /dev/null +++ b/kernel/linux/include/asm-generic/module.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_GENERIC_MODULE_H +#define __ASM_GENERIC_MODULE_H + +#include + +/* + * Many architectures just need a simple module + * loader without arch specific data. + */ +#ifndef CONFIG_HAVE_MOD_ARCH_SPECIFIC +struct mod_arch_specific +{ +}; +#endif + +#define CONFIG_64BIT + +#ifdef CONFIG_64BIT +#define Elf_Shdr Elf64_Shdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Sym Elf64_Sym +#define Elf_Dyn Elf64_Dyn +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Addr Elf64_Addr +#ifdef CONFIG_MODULES_USE_ELF_REL +#define Elf_Rel Elf64_Rel +#endif +#ifdef CONFIG_MODULES_USE_ELF_RELA +#define Elf_Rela Elf64_Rela +#endif +#define ELF_R_TYPE(X) ELF64_R_TYPE(X) +#define ELF_R_SYM(X) ELF64_R_SYM(X) + +#else /* CONFIG_64BIT */ + +#define Elf_Shdr Elf32_Shdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Sym Elf32_Sym +#define Elf_Dyn Elf32_Dyn +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Addr Elf32_Addr +#ifdef CONFIG_MODULES_USE_ELF_REL +#define Elf_Rel Elf32_Rel +#endif +#ifdef CONFIG_MODULES_USE_ELF_RELA +#define Elf_Rela Elf32_Rela +#endif +#define ELF_R_TYPE(X) ELF32_R_TYPE(X) +#define ELF_R_SYM(X) ELF32_R_SYM(X) +#endif + +#endif /* __ASM_GENERIC_MODULE_H */ \ No newline at end of file diff --git a/kernel/linux/include/linux/bitops.h b/kernel/linux/include/linux/bitops.h index 3d40abe2..d06dec0c 100644 --- a/kernel/linux/include/linux/bitops.h +++ b/kernel/linux/include/linux/bitops.h @@ -2,13 +2,127 @@ #define _LINUX_BITOPS_H #include +#include + +#define FIELD_SIZEOF(t, f) (sizeof(((t *)0)->f)) +#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d)) +#define DIV_ROUND_UP_ULL(ll, d) \ + ({ \ + unsigned long long _tmp = (ll) + (d)-1; \ + do_div(_tmp, d); \ + _tmp; \ + }) + +#define BIT(nr) (1UL << (nr)) +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BITS_PER_BYTE 8 +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long flags; + *p |= mask; +} + +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long flags; + *p &= ~mask; +} + +static inline unsigned int __sw_hweight8(unsigned int w) +{ + unsigned int res = w - ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res + (res >> 4)) & 0x0F; +} + +static inline unsigned int __sw_hweight16(unsigned int w) +{ + unsigned int res = w - ((w >> 1) & 0x5555); + res = (res & 0x3333) + ((res >> 2) & 0x3333); + res = (res + (res >> 4)) & 0x0F0F; + return (res + (res >> 8)) & 0x00FF; +} + +static inline unsigned int __sw_hweight32(unsigned int w) +{ + unsigned int res = w - ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res + (res >> 4)) & 0x0F0F0F0F; + res = res + (res >> 8); + return (res + (res >> 16)) & 0x000000FF; +} + +static inline unsigned long __sw_hweight64(__u64 w) +{ + __u64 res = w - ((w >> 1) & 0x5555555555555555ul); + res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); + res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful; + res = res + (res >> 8); + res = res + (res >> 16); + return (res + (res >> 32)) & 0x00000000000000FFul; +} + +static inline unsigned int __arch_hweight32(unsigned int w) +{ + return __sw_hweight32(w); +} + +static inline unsigned int __arch_hweight16(unsigned int w) +{ + return __sw_hweight16(w); +} + +static inline unsigned int __arch_hweight8(unsigned int w) +{ + return __sw_hweight8(w); +} + +static inline unsigned long __arch_hweight64(__u64 w) +{ + return __sw_hweight64(w); +} + +/* + * Compile time versions of __arch_hweightN() + */ +#define __const_hweight8(w) \ + ((unsigned int)((!!((w) & (1ULL << 0))) + (!!((w) & (1ULL << 1))) + (!!((w) & (1ULL << 2))) + \ + (!!((w) & (1ULL << 3))) + (!!((w) & (1ULL << 4))) + (!!((w) & (1ULL << 5))) + \ + (!!((w) & (1ULL << 6))) + (!!((w) & (1ULL << 7))))) + +#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8)) +#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16)) +#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32)) + +/* + * Generic interface. + */ +#define hweight8(w) (__builtin_constant_p(w) ? __const_hweight8(w) : __arch_hweight8(w)) +#define hweight16(w) (__builtin_constant_p(w) ? __const_hweight16(w) : __arch_hweight16(w)) +#define hweight32(w) (__builtin_constant_p(w) ? __const_hweight32(w) : __arch_hweight32(w)) +#define hweight64(w) (__builtin_constant_p(w) ? __const_hweight64(w) : __arch_hweight64(w)) + +/* + * Interface for known constant arguments + */ +#define HWEIGHT8(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight8(w)) +#define HWEIGHT16(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight16(w)) +#define HWEIGHT32(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight32(w)) +#define HWEIGHT64(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight64(w)) + +/* + * Type invariant interface to the compile time constant hweight functions. + */ +#define HWEIGHT(w) HWEIGHT64((u64)w) -/* Set bits in the first 'n' bytes when loaded from memory */ -#ifdef __LITTLE_ENDIAN #define aligned_byte_mask(n) ((1UL << 8 * (n)) - 1) -#else -#define aligned_byte_mask(n) (~0xffUL << (BITS_PER_LONG - 8 - 8 * (n))) -#endif #define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) @@ -16,11 +130,6 @@ #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u32)) #define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) -extern unsigned int __sw_hweight8(unsigned int w); -extern unsigned int __sw_hweight16(unsigned int w); -extern unsigned int __sw_hweight32(unsigned int w); -extern unsigned long __sw_hweight64(__u64 w); - #define for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); (bit) < (size); (bit) = find_next_bit((addr), (size), (bit) + 1)) @@ -167,15 +276,13 @@ static __always_inline __s64 sign_extend64(__u64 value, int index) static inline unsigned fls_long(unsigned long l) { - if (sizeof(l) == 4) - return fls(l); + if (sizeof(l) == 4) return fls(l); return fls64(l); } static inline int get_count_order(unsigned int count) { - if (count == 0) - return -1; + if (count == 0) return -1; return fls(--count); } @@ -188,8 +295,7 @@ static inline int get_count_order(unsigned int count) */ static inline int get_count_order_long(unsigned long l) { - if (l == 0UL) - return -1; + if (l == 0UL) return -1; return (int)fls_long(--l); } @@ -203,12 +309,6 @@ static inline int get_count_order_long(unsigned long l) */ static inline unsigned long __ffs64(u64 word) { -#if BITS_PER_LONG == 32 - if (((u32)word) == 0UL) - return __ffs((u32)(word >> 32)) + 32; -#elif BITS_PER_LONG != 64 -#error BITS_PER_LONG not 32 or 64 -#endif return __ffs((unsigned long)word); } @@ -234,7 +334,6 @@ static __always_inline void __assign_bit(long nr, volatile unsigned long *addr, __clear_bit(nr, addr); } -#ifndef set_mask_bits #define set_mask_bits(ptr, mask, bits) \ ({ \ const typeof(*(ptr)) mask__ = (mask), bits__ = (bits); \ @@ -247,9 +346,7 @@ static __always_inline void __assign_bit(long nr, volatile unsigned long *addr, \ old__; \ }) -#endif -#ifndef bit_clear_unless #define bit_clear_unless(ptr, clear, test) \ ({ \ const typeof(*(ptr)) clear__ = (clear), test__ = (test); \ @@ -262,17 +359,5 @@ static __always_inline void __assign_bit(long nr, volatile unsigned long *addr, \ !(old__ & test__); \ }) -#endif - -#ifndef find_last_bit -/** - * find_last_bit - find the last set bit in a memory region - * @addr: The address to start the search at - * @size: The number of bits to search - * - * Returns the bit number of the last set bit, or size. - */ -extern unsigned long find_last_bit(const unsigned long *addr, unsigned long size); -#endif #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/compiler.h b/kernel/linux/include/linux/compiler.h new file mode 100644 index 00000000..525321b1 --- /dev/null +++ b/kernel/linux/include/linux/compiler.h @@ -0,0 +1,58 @@ +#ifndef __LINUX_COMPILER_H +#define __LINUX_COMPILER_H + +/* + * Prevent the compiler from merging or refetching reads or writes. The + * compiler is also forbidden from reordering successive instances of + * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the + * compiler is aware of some particular ordering. One way to make the + * compiler aware of ordering is to put the two invocations of READ_ONCE, + * WRITE_ONCE or ACCESS_ONCE() in different C statements. + * + * In contrast to ACCESS_ONCE these two macros will also work on aggregate + * data types like structs or unions. If the size of the accessed data + * type exceeds the word size of the machine (e.g., 32 bits or 64 bits) + * READ_ONCE() and WRITE_ONCE() will fall back to memcpy and print a + * compile-time warning. + * + * Their two major use cases are: (1) Mediating communication between + * process-level code and irq/NMI handlers, all running on the same CPU, + * and (2) Ensuring that the compiler does not fold, spindle, or otherwise + * mutilate accesses that either do not require ordering or that interact + * with an explicit memory barrier or atomic instruction that provides the + * required ordering. + */ + +#define READ_ONCE(x) \ + ({ \ + union \ + { \ + typeof(x) __val; \ + char __c[1]; \ + } __u; \ + __read_once_size(&(x), __u.__c, sizeof(x)); \ + __u.__val; \ + }) + +#define WRITE_ONCE(x, val) \ + ({ \ + typeof(x) __val = (val); \ + __write_once_size(&(x), &__val, sizeof(__val)); \ + __val; \ + }) + +/* + * Prevent the compiler from merging or refetching accesses. The compiler + * is also forbidden from reordering successive instances of ACCESS_ONCE(), + * but only when the compiler is aware of some particular ordering. One way + * to make the compiler aware of ordering is to put the two invocations of + * ACCESS_ONCE() in different C statements. + * + * This macro does absolutely -nothing- to prevent the CPU from reordering, + * merging, or refetching absolutely anything at any time. Its main intended + * use is to mediate communication between process-level code and irq/NMI + * handlers, all running on the same CPU. + */ +#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) + +#endif \ No newline at end of file diff --git a/kernel/linux/include/linux/cpumask.h b/kernel/linux/include/linux/cpumask.h new file mode 100644 index 00000000..3e97b9e5 --- /dev/null +++ b/kernel/linux/include/linux/cpumask.h @@ -0,0 +1,33 @@ +#ifndef __LINUX_CPUMASK_H +#define __LINUX_CPUMASK_H + +struct cpumask; + +/** + * cpumask_bits - get the bits in a cpumask + * @maskp: the struct cpumask * + * + * You should only assume nr_cpu_ids bits of this mask are valid. This is + * a macro so it's const-correct. + */ +#define cpumask_bits(maskp) ((maskp)->bits) + +#define num_online_cpus() cpumask_weight(cpu_online_mask) +#define num_possible_cpus() cpumask_weight(cpu_possible_mask) +#define num_present_cpus() cpumask_weight(cpu_present_mask) +#define num_active_cpus() cpumask_weight(cpu_active_mask) +#define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask) +#define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask) +#define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask) +#define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask) + +/** + * cpumask_weight - Count of bits in *srcp + * @srcp: the cpumask to count bits (< nr_cpu_ids) in. + */ +static inline unsigned int cpumask_weight(const struct cpumask *srcp) +{ + return bitmap_weight(cpumask_bits(srcp), nr_cpumask_bits); +} + +#endif \ No newline at end of file diff --git a/kernel/linux/include/linux/elf-em.h b/kernel/linux/include/linux/elf-em.h new file mode 100644 index 00000000..4aa90d85 --- /dev/null +++ b/kernel/linux/include/linux/elf-em.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_ELF_EM_H +#define _LINUX_ELF_EM_H + +/* These constants define the various ELF target machines */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ +/* Next two are historical and binaries and + modules of these types will be rejected by + Linux. */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC64 */ +#define EM_SPU 23 /* Cell BE SPU */ +#define EM_ARM 40 /* ARM 32 bit */ +#define EM_SH 42 /* SuperH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_H8_300 46 /* Renesas H8/300 */ +#define EM_IA_64 50 /* HP/Intel IA-64 */ +#define EM_X86_64 62 /* AMD x86-64 */ +#define EM_S390 22 /* IBM S/390 */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_M32R 88 /* Renesas M32R */ +#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARCOMPACT 93 /* ARCompact processor */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_BLACKFIN 106 /* ADI Blackfin Processor */ +#define EM_UNICORE 110 /* UniCore-32 */ +#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */ +#define EM_TI_C6000 140 /* TI C6X DSPs */ +#define EM_HEXAGON 164 /* QUALCOMM Hexagon */ +#define EM_NDS32 \ + 167 /* Andes Technology compact code size + embedded RISC processor family */ +#define EM_AARCH64 183 /* ARM 64 bit */ +#define EM_TILEPRO 188 /* Tilera TILEPro */ +#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ +#define EM_TILEGX 191 /* Tilera TILE-Gx */ +#define EM_ARCV2 195 /* ARCv2 Cores */ +#define EM_RISCV 243 /* RISC-V */ +#define EM_BPF 247 /* Linux BPF - in-kernel virtual machine */ +#define EM_CSKY 252 /* C-SKY */ +#define EM_FRV 0x5441 /* Fujitsu FR-V */ + +/* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ +#define EM_ALPHA 0x9026 + +/* Bogus old m32r magic number, used by old tools. */ +#define EM_CYGNUS_M32R 0x9041 +/* This is the old interim value for S/390 architecture */ +#define EM_S390_OLD 0xA390 +/* Also Panasonic/MEI MN10300, AM33 */ +#define EM_CYGNUS_MN10300 0xbeef + +#endif /* _LINUX_ELF_EM_H */ diff --git a/kernel/linux/include/linux/elf.h b/kernel/linux/include/linux/elf.h new file mode 100644 index 00000000..753d96a4 --- /dev/null +++ b/kernel/linux/include/linux/elf.h @@ -0,0 +1,475 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_ELF_H +#define _UAPI_LINUX_ELF_H + +#include +#include "elf-em.h" + +/* 32-bit ELF base types. */ +typedef __u32 Elf32_Addr; +typedef __u16 Elf32_Half; +typedef __u32 Elf32_Off; +typedef __s32 Elf32_Sword; +typedef __u32 Elf32_Word; + +/* 64-bit ELF base types. */ +typedef __u64 Elf64_Addr; +typedef __u16 Elf64_Half; +typedef __s16 Elf64_SHalf; +typedef __u64 Elf64_Off; +typedef __s32 Elf64_Sword; +typedef __u32 Elf64_Word; +typedef __u64 Elf64_Xword; +typedef __s64 Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_GNU_PROPERTY 0x6474e553 + +#define PT_GNU_STACK (PT_LOOS + 0x474e551) + +/* + * Extended Numbering + * + * If the real number of program header table entries is larger than + * or equal to PN_XNUM(0xffff), it is set to sh_info field of the + * section header at index 0, and PN_XNUM is set to e_phnum + * field. Otherwise, the section header at index 0 is zero + * initialized, if it exists. + * + * Specifications are available in: + * + * - Oracle: Linker and Libraries. + * Part No: 817–1984–19, August 2011. + * https://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf + * + * - System V ABI AMD64 Architecture Processor Supplement + * Draft Version 0.99.4, + * January 13, 2010. + * http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf + */ +#define PN_XNUM 0xffff + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +typedef struct dynamic +{ + Elf32_Sword d_tag; + union + { + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* entry tag value */ + union + { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + +typedef struct elf32_rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym +{ + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + +#define EI_NIDENT 16 + +typedef struct elf32_hdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr +{ + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_RELA_LIVEPATCH 0x00100000 +#define SHF_RO_AFTER_INIT 0x00200000 +#define SHF_MASKPROC 0xf0000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_LIVEPATCH 0xff20 +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +typedef struct elf32_shdr +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr +{ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 + +#ifndef ELF_OSABI +#define ELF_OSABI ELFOSABI_NONE +#endif + +/* + * Notes used in ET_CORE. Architectures export some of the arch register sets + * using the corresponding note types via the PTRACE_GETREGSET and + * PTRACE_SETREGSET requests. + * The note name for all these is "LINUX". + */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +/* + * Note to userspace developers: size of NT_SIGINFO note may increase + * in the future to accomodate more fields, don't assume it is fixed! + */ +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_PPC_TAR 0x103 /* Target Address Register */ +#define NT_PPC_PPR 0x104 /* Program Priority Register */ +#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */ +#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */ +#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */ +#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ +#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ +#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ +#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ +#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ +#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address Register */ +#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority Register */ +#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control Register */ +#define NT_PPC_PKEY 0x110 /* Memory Protection Keys registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ +#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ +#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ +#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */ +#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ +#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */ +#define NT_S390_GS_BC 0x30c /* s390 guarded storage broadcast control block */ +#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation */ +#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ +#define NT_ARM_TLS 0x401 /* ARM TLS register */ +#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ +#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ +#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ +#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */ +#define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */ +#define NT_ARM_PACA_KEYS 0x407 /* ARM pointer authentication address keys */ +#define NT_ARM_PACG_KEYS 0x408 /* ARM pointer authentication generic key */ +#define NT_ARM_TAGGED_ADDR_CTRL 0x409 /* arm64 tagged address control (prctl()) */ +#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ +#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ +#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ +#define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode */ +#define NT_MIPS_MSA 0x802 /* MIPS SIMD registers */ + +/* Note types with note name "GNU" */ +#define NT_GNU_PROPERTY_TYPE_0 5 + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note +{ + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note +{ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; + +/* .note.gnu.property types for EM_AARCH64: */ +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 + +/* Bits for GNU_PROPERTY_AARCH64_FEATURE_1_BTI */ +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0) + +#endif /* _UAPI_LINUX_ELF_H */ \ No newline at end of file diff --git a/kernel/linux/include/linux/errno.h b/kernel/linux/include/linux/errno.h index c5d6e1e2..56b57612 100644 --- a/kernel/linux/include/linux/errno.h +++ b/kernel/linux/include/linux/errno.h @@ -1,6 +1,8 @@ #ifndef _LINUX_ERRNO_H #define _LINUX_ERRNO_H +#include + #define ERESTARTSYS 512 #define ERESTARTNOINTR 513 #define ERESTARTNOHAND 514 /* restart if no handler.. */ diff --git a/kernel/linux/include/linux/fs.h b/kernel/linux/include/linux/fs.h index bd4d4921..467f964a 100644 --- a/kernel/linux/include/linux/fs.h +++ b/kernel/linux/include/linux/fs.h @@ -3,6 +3,8 @@ #include #include +#include +#include #define MAY_EXEC 0x00000001 #define MAY_WRITE 0x00000002 @@ -224,8 +226,8 @@ extern void kfunc_def(drop_nlink)(struct inode *inode); extern void kfunc_def(clear_nlink)(struct inode *inode); extern void kfunc_def(set_nlink)(struct inode *inode, unsigned int nlink); -extern int kfunc_def(kernel_read)(struct file *, loff_t, char *, unsigned long); -extern ssize_t kfunc_def(kernel_write)(struct file *, const char *, size_t, loff_t); +extern ssize_t kfunc_def(kernel_read)(struct file *file, void *buf, size_t count, loff_t *pos); +extern ssize_t kfunc_def(kernel_write)(struct file *file, const void *buf, size_t count, loff_t *pos); extern ssize_t kfunc_def(__kernel_write)(struct file *, const char *, size_t, loff_t *); extern struct file *kfunc_def(open_exec)(const char *); @@ -238,6 +240,8 @@ extern int kfunc_def(filp_close)(struct file *, fl_owner_t id); extern struct filename *kfunc_def(getname)(const char __user *); extern struct filename *kfunc_def(getname_kernel)(const char *); +extern loff_t kfunc_def(vfs_llseek)(struct file *file, loff_t offset, int whence); + // static inline void inc_nlink(struct inode *inode) @@ -264,18 +268,48 @@ static inline void set_nlink(struct inode *inode, unsigned int nlink) kfunc_not_found(); } -static inline int kernel_read(struct file *file, loff_t offset, char *addr, unsigned long count) +static inline ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) { - kfunc_call(kernel_read, file, offset, addr, count); - kfunc_not_found(); - return 0; + ssize_t ret = 0; + if (kfunc(kernel_read)) { + if (kver < VERSION(4, 14, 0)) { + loff_t offset = pos ? *pos : 0; + int (*kernel_read_legacy)(struct file *file, loff_t offset, char *addr, unsigned long count) = + (typeof(kernel_read_legacy))kfunc(kernel_read); + int rc = kernel_read_legacy(file, offset, (char *)buf, count); + if (pos && rc > 0) { + *pos = offset + rc; + } + ret = rc; + } else { + ret = kfunc(kernel_read)(file, buf, count, pos); + } + } else { + kfunc_not_found(); + } + return ret; } -static inline ssize_t kernel_write(struct file *file, const char *buf, size_t count, loff_t pos) +static inline ssize_t kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) { - kfunc_call(kernel_write, file, buf, count, pos); - kfunc_not_found(); - return 0; + ssize_t ret = 0; + if (kfunc(kernel_write)) { + if (kver < VERSION(4, 14, 0)) { + ssize_t (*kernel_write_legacy)(struct file *file, const char *buf, size_t count, loff_t pos) = + (typeof(kernel_write_legacy))kfunc(kernel_write); + loff_t offset = pos ? *pos : 0; + ssize_t result = kernel_write_legacy(file, buf, count, offset); + if (pos && result > 0) { + *pos = offset + result; + } + ret = result; + } else { + kfunc(kernel_write)(file, buf, count, pos); + } + } else { + kfunc_not_found(); + } + return ret; } static inline struct file *open_exec(const char *name) @@ -335,4 +369,11 @@ static inline struct filename *getname_kernel(const char *filename) return 0; } +static inline loff_t vfs_llseek(struct file *file, loff_t offset, int whence) +{ + kfunc_call(vfs_llseek, file, offset, whence); + kfunc_not_found(); + return 0; +} + #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/gfp.h b/kernel/linux/include/linux/gfp.h index cc429507..aab144d2 100644 --- a/kernel/linux/include/linux/gfp.h +++ b/kernel/linux/include/linux/gfp.h @@ -42,6 +42,7 @@ #define GFP_ATOMIC (__GFP_HIGH | __GFP_ATOMIC | __GFP_KSWAPD_RECLAIM) #define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) + #define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT) #define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) #define GFP_NOIO (__GFP_RECLAIM) diff --git a/kernel/linux/include/linux/include/linux/export.h b/kernel/linux/include/linux/include/linux/export.h new file mode 100644 index 00000000..1e852edd --- /dev/null +++ b/kernel/linux/include/linux/include/linux/export.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _LINUX_EXPORT_H +#define _LINUX_EXPORT_H + +/* + * Export symbols from the kernel to modules. Forked from module.h + * to reduce the amount of pointless cruft we feed to gcc when only + * exporting a simple symbol or two. + * + * Try not to add #includes here. It slows compilation and makes kernel + * hackers place grumpy comments in header files. + */ + +#ifndef __ASSEMBLY__ +#ifdef MODULE +extern struct module __this_module; +#define THIS_MODULE (&__this_module) +#else +#define THIS_MODULE ((struct module *)0) +#endif + +#ifdef CONFIG_MODVERSIONS +/* Mark the CRC weak since genksyms apparently decides not to + * generate a checksums for some symbols */ +#if defined(CONFIG_MODULE_REL_CRCS) +#define __CRC_SYMBOL(sym, sec) \ + asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ + " .weak __crc_" #sym " \n" \ + " .long __crc_" #sym " - . \n" \ + " .previous \n") +#else +#define __CRC_SYMBOL(sym, sec) \ + asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ + " .weak __crc_" #sym " \n" \ + " .long __crc_" #sym " \n" \ + " .previous \n") +#endif +#else +#define __CRC_SYMBOL(sym, sec) +#endif + +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS +#include +/* + * Emit the ksymtab entry as a pair of relative references: this reduces + * the size by half on 64-bit architectures, and eliminates the need for + * absolute relocations that require runtime processing on relocatable + * kernels. + */ +#define __KSYMTAB_ENTRY(sym, sec) \ + __ADDRESSABLE(sym) \ + asm(" .section \"___ksymtab" sec "+" #sym "\", \"a\" \n" \ + " .balign 4 \n" \ + "__ksymtab_" #sym ": \n" \ + " .long " #sym "- . \n" \ + " .long __kstrtab_" #sym "- . \n" \ + " .long __kstrtabns_" #sym "- . \n" \ + " .previous \n") + +struct kernel_symbol +{ + int value_offset; + int name_offset; + int namespace_offset; +}; +#else +#define __KSYMTAB_ENTRY(sym, sec) \ + static const struct kernel_symbol __ksymtab_##sym __attribute__((section("___ksymtab" sec "+" #sym), used)) \ + __aligned(sizeof(void *)) = { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym } + +struct kernel_symbol +{ + unsigned long value; + const char *name; + const char *namespace; +}; +#endif + +#ifdef __GENKSYMS__ + +#define ___EXPORT_SYMBOL(sym, sec, ns) __GENKSYMS_EXPORT_SYMBOL(sym) + +#else + +/* + * For every exported symbol, do the following: + * + * - If applicable, place a CRC entry in the __kcrctab section. + * - Put the name of the symbol and namespace (empty string "" for none) in + * __ksymtab_strings. + * - Place a struct kernel_symbol entry in the __ksymtab section. + * + * note on .section use: we specify progbits since usage of the "M" (SHF_MERGE) + * section flag requires it. Use '%progbits' instead of '@progbits' since the + * former apparently works on all arches according to the binutils source. + */ +#define ___EXPORT_SYMBOL(sym, sec, ns) \ + extern typeof(sym) sym; \ + extern const char __kstrtab_##sym[]; \ + extern const char __kstrtabns_##sym[]; \ + __CRC_SYMBOL(sym, sec); \ + asm(" .section \"__ksymtab_strings\",\"aMS\",%progbits,1 \n" \ + "__kstrtab_" #sym ": \n" \ + " .asciz \"" #sym "\" \n" \ + "__kstrtabns_" #sym ": \n" \ + " .asciz \"" ns "\" \n" \ + " .previous \n"); \ + __KSYMTAB_ENTRY(sym, sec) + +#endif + +#if !defined(CONFIG_MODULES) || defined(__DISABLE_EXPORTS) + +/* + * Allow symbol exports to be disabled completely so that C code may + * be reused in other execution contexts such as the UEFI stub or the + * decompressor. + */ +#define __EXPORT_SYMBOL(sym, sec, ns) + +#elif defined(CONFIG_TRIM_UNUSED_KSYMS) + +#include + +/* + * For fine grained build dependencies, we want to tell the build system + * about each possible exported symbol even if they're not actually exported. + * We use a symbol pattern __ksym_marker_ that the build system filters + * from the $(NM) output (see scripts/gen_ksymdeps.sh). These symbols are + * discarded in the final link stage. + */ +#define __ksym_marker(sym) static int __ksym_marker_##sym[0] __section(".discard.ksym") __used + +#define __EXPORT_SYMBOL(sym, sec, ns) \ + __ksym_marker(sym); \ + __cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym)) +#define __cond_export_sym(sym, sec, ns, conf) ___cond_export_sym(sym, sec, ns, conf) +#define ___cond_export_sym(sym, sec, ns, enabled) __cond_export_sym_##enabled(sym, sec, ns) +#define __cond_export_sym_1(sym, sec, ns) ___EXPORT_SYMBOL(sym, sec, ns) +#define __cond_export_sym_0(sym, sec, ns) /* nothing */ + +#else + +#define __EXPORT_SYMBOL(sym, sec, ns) ___EXPORT_SYMBOL(sym, sec, ns) + +#endif /* CONFIG_MODULES */ + +#ifdef DEFAULT_SYMBOL_NAMESPACE +#include +#define _EXPORT_SYMBOL(sym, sec) __EXPORT_SYMBOL(sym, sec, __stringify(DEFAULT_SYMBOL_NAMESPACE)) +#else +#define _EXPORT_SYMBOL(sym, sec) __EXPORT_SYMBOL(sym, sec, "") +#endif + +#define EXPORT_SYMBOL(sym) _EXPORT_SYMBOL(sym, "") +#define EXPORT_SYMBOL_GPL(sym) _EXPORT_SYMBOL(sym, "_gpl") +#define EXPORT_SYMBOL_GPL_FUTURE(sym) _EXPORT_SYMBOL(sym, "_gpl_future") +#define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", #ns) +#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", #ns) + +#ifdef CONFIG_UNUSED_SYMBOLS +#define EXPORT_UNUSED_SYMBOL(sym) _EXPORT_SYMBOL(sym, "_unused") +#define EXPORT_UNUSED_SYMBOL_GPL(sym) _EXPORT_SYMBOL(sym, "_unused_gpl") +#else +#define EXPORT_UNUSED_SYMBOL(sym) +#define EXPORT_UNUSED_SYMBOL_GPL(sym) +#endif + +#endif /* !__ASSEMBLY__ */ + +#endif /* _LINUX_EXPORT_H */ \ No newline at end of file diff --git a/kernel/linux/include/linux/include/linux/smp.h b/kernel/linux/include/linux/include/linux/smp.h new file mode 100644 index 00000000..f13d89e2 --- /dev/null +++ b/kernel/linux/include/linux/include/linux/smp.h @@ -0,0 +1,9 @@ +#ifndef __LINUX_SMP_H +#define __LINUX_SMP_H + +typedef void (*smp_call_func_t)(void *info); + +void kick_all_cpus_sync(void); +void wake_up_all_idle_cpus(void); + +#endif \ No newline at end of file diff --git a/kernel/linux/include/linux/kernel.h b/kernel/linux/include/linux/kernel.h index 9401d004..ce9f4436 100644 --- a/kernel/linux/include/linux/kernel.h +++ b/kernel/linux/include/linux/kernel.h @@ -2,7 +2,59 @@ #define _LINUX_KERNEL_H #include +#include +#include -// void do_exit(long error_code) __noreturn; +extern int kfunc_def(sprintf)(char *buf, const char *fmt, ...); +extern int kfunc_def(vsprintf)(char *buf, const char *fmt, va_list args); +extern int kfunc_def(snprintf)(char *buf, size_t size, const char *fmt, ...); +extern int kfunc_def(vsnprintf)(char *buf, size_t size, const char *fmt, va_list args); +extern int kfunc_def(scnprintf)(char *buf, size_t size, const char *fmt, ...); +extern int kfunc_def(vscnprintf)(char *buf, size_t size, const char *fmt, va_list args); +extern char *kfunc_def(kasprintf)(gfp_t gfp, const char *fmt, ...); +extern char *kfunc_def(kvasprintf)(gfp_t gfp, const char *fmt, va_list args); +extern int kfunc_def(sscanf)(const char *buf, const char *fmt, ...); +extern int kfunc_def(vsscanf)(const char *buf, const char *fmt, va_list args); + +#define sprintf(buf, fmt, ...) kfunc(sprintf)(buf, fmt, ##__VA_ARGS__) +#define snprintf(buf, size, fmt, ...) kfunc(snprintf)(buf, size, fmt, ##__VA_ARGS__) +#define scnprintf(buf, size, fmt, ...) kfunc(scnprintf)(buf, size, fmt, ##__VA_ARGS__) +#define kasprintf(buf, fmt, ...) kfunc(kasprintf)(buf, fmt, ##__VA_ARGS__) +#define sscanf(buf, fmt, ...) kfunc(kasprintf)(buf, fmt, ##__VA_ARGS__) + +static inline int vsprintf(char *buf, const char *fmt, va_list args) +{ + kfunc_call(vsprintf, buf, fmt, args); + kfunc_not_found(); + return 0; +} + +static inline int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + kfunc_call(vsnprintf, buf, size, fmt, args); + kfunc_not_found(); + return 0; +} + +static inline int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + kfunc_call(vscnprintf, buf, size, fmt, args); + kfunc_not_found(); + return 0; +} + +static inline char *kvasprintf(gfp_t gfp, const char *fmt, va_list args) +{ + kfunc_call(kvasprintf, gfp, fmt, args); + kfunc_not_found(); + return 0; +} + +static inline int vsscanf(const char *buf, const char *fmt, va_list args) +{ + kfunc_call(vsscanf, buf, fmt, args); + kfunc_not_found(); + return 0; +} #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/list.h b/kernel/linux/include/linux/list.h index 47384c89..bf76599e 100644 --- a/kernel/linux/include/linux/list.h +++ b/kernel/linux/include/linux/list.h @@ -16,7 +16,6 @@ * generate better code by using them directly rather than * using the generic single-entry routines. */ - #define LIST_HEAD_INIT(name) \ { \ &(name), &(name) \ @@ -59,8 +58,7 @@ static inline bool __list_del_entry_valid(struct list_head *entry) */ static inline void __list_add(struct list_head *_new, struct list_head *prev, struct list_head *next) { - if (!__list_add_valid(_new, prev, next)) - return; + if (!__list_add_valid(_new, prev, next)) return; next->prev = _new; _new->next = next; @@ -123,8 +121,7 @@ static inline void __list_del_clearprev(struct list_head *entry) static inline void __list_del_entry(struct list_head *entry) { - if (!__list_del_entry_valid(entry)) - return; + if (!__list_del_entry_valid(entry)) return; __list_del(entry->prev, entry->next); } @@ -181,8 +178,7 @@ static inline void list_swap(struct list_head *entry1, struct list_head *entry2) list_del(entry2); list_replace(entry1, entry2); - if (pos == entry1) - pos = entry2; + if (pos == entry1) pos = entry2; list_add(entry1, pos); } @@ -372,10 +368,8 @@ static inline void __list_cut_position(struct list_head *list, struct list_head */ static inline void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { - if (list_empty(head)) - return; - if (list_is_singular(head) && (head->next != entry && head != entry)) - return; + if (list_empty(head)) return; + if (list_is_singular(head) && (head->next != entry && head != entry)) return; if (entry == head) INIT_LIST_HEAD(list); else @@ -429,8 +423,7 @@ static inline void __list_splice(const struct list_head *list, struct list_head */ static inline void list_splice(const struct list_head *list, struct list_head *head) { - if (!list_empty(list)) - __list_splice(list, head, head->next); + if (!list_empty(list)) __list_splice(list, head, head->next); } /** @@ -440,8 +433,7 @@ static inline void list_splice(const struct list_head *list, struct list_head *h */ static inline void list_splice_tail(struct list_head *list, struct list_head *head) { - if (!list_empty(list)) - __list_splice(list, head->prev, head); + if (!list_empty(list)) __list_splice(list, head->prev, head); } /** @@ -784,8 +776,7 @@ static inline void __hlist_del(struct hlist_node *n) struct hlist_node **pprev = n->pprev; WRITE_ONCE(*pprev, next); - if (next) - WRITE_ONCE(next->pprev, pprev); + if (next) WRITE_ONCE(next->pprev, pprev); } /** @@ -828,8 +819,7 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; WRITE_ONCE(n->next, first); - if (first) - WRITE_ONCE(first->pprev, &n->next); + if (first) WRITE_ONCE(first->pprev, &n->next); WRITE_ONCE(h->first, n); WRITE_ONCE(n->pprev, &h->first); } @@ -858,8 +848,7 @@ static inline void hlist_add_behind(struct hlist_node *n, struct hlist_node *pre WRITE_ONCE(prev->next, n); WRITE_ONCE(n->pprev, &prev->next); - if (n->next) - WRITE_ONCE(n->next->pprev, &n->next); + if (n->next) WRITE_ONCE(n->next->pprev, &n->next); } /** @@ -908,8 +897,7 @@ static inline bool hlist_is_singular_node(struct hlist_node *n, struct hlist_hea static inline void hlist_move_list(struct hlist_head *old, struct hlist_head *_new) { _new->first = old->first; - if (_new->first) - _new->first->pprev = &_new->first; + if (_new->first) _new->first->pprev = &_new->first; old->first = 0; } diff --git a/kernel/linux/include/linux/panic.h b/kernel/linux/include/linux/panic.h new file mode 100644 index 00000000..1afa1704 --- /dev/null +++ b/kernel/linux/include/linux/panic.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_PANIC_H +#define _LINUX_PANIC_H + +#include +#include + +extern void kfunc_def(panic)(const char *fmt, ...) __noreturn __cold; + +#define panic(fmt, ...) kfunc(panic)(fmt, ##__VA_ARGS__) + +#endif \ No newline at end of file diff --git a/kernel/linux/include/linux/rculist.h b/kernel/linux/include/linux/rculist.h new file mode 100644 index 00000000..e69de29b diff --git a/kernel/linux/include/linux/rcupdate.h b/kernel/linux/include/linux/rcupdate.h index d687979a..e6119379 100644 --- a/kernel/linux/include/linux/rcupdate.h +++ b/kernel/linux/include/linux/rcupdate.h @@ -22,7 +22,6 @@ void get_completed_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp); void __rcu_read_lock(void); void __rcu_read_unlock(void); - void rcu_read_unlock_strict(void); /* Internal to kernel */ @@ -47,32 +46,15 @@ void exit_tasks_rcu_start(void); void exit_tasks_rcu_stop(void); void exit_tasks_rcu_finish(void); -/* - * Helper functions for rcu_dereference_check(), rcu_dereference_protected() - * and rcu_assign_pointer(). Some of these could be folded into their - * callers, but they are left separate in order to ease introduction of - * multiple pointers markings to match different RCU implementations - * (e.g., __srcu), should this make sense in the future. - */ - -#ifdef __CHECKER__ #define rcu_check_sparse(p, space) ((void)(((typeof(*p) space *)p) == p)) -#else /* #ifdef __CHECKER__ */ -#define rcu_check_sparse(p, space) -#endif /* #else #ifdef __CHECKER__ */ + #define __unrcu_pointer(p, local) \ ({ \ typeof(*p) *local = (typeof(*p) *__force)(p); \ rcu_check_sparse(p, __rcu); \ ((typeof(*p) __force __kernel *)(local)); \ }) -/** - * unrcu_pointer - mark a pointer as not being RCU protected - * @p: pointer needing to lose its __rcu property - * - * Converts @p from an __rcu pointer to a __kernel pointer. - * This allows an __rcu pointer to be used with xchg() and friends. - */ + #define unrcu_pointer(p) __unrcu_pointer(p, __UNIQUE_ID(rcu)) #define __rcu_access_pointer(p, local, space) \ @@ -233,8 +215,7 @@ static inline bool rcu_head_after_call_rcu(struct rcu_head *rhp, rcu_callback_t { rcu_callback_t func = READ_ONCE(rhp->func); - if (func == f) - return true; + if (func == f) return true; WARN_ON_ONCE(func != (rcu_callback_t)~0L); return false; } diff --git a/kernel/linux/include/linux/sched.h b/kernel/linux/include/linux/sched.h index fd557a8e..3fda1dac 100644 --- a/kernel/linux/include/linux/sched.h +++ b/kernel/linux/include/linux/sched.h @@ -7,6 +7,7 @@ #include #include #include +#include #include struct task_struct; // __randomize_layout @@ -48,6 +49,7 @@ struct task_struct_offset int16_t ptracer_cred_offset; int16_t real_cred_offset; int16_t cred_offset; + int16_t comm_offset; int16_t fs_offset; int16_t files_offset; int16_t loginuid_offset; @@ -55,13 +57,56 @@ struct task_struct_offset int16_t seccomp_offset; int16_t security_offset; int16_t stack_offset; + int16_t tasks_offset; }; extern struct task_struct_offset task_struct_offset; +static inline struct list_head *get_task_tasks_p(struct task_struct *task) +{ + struct list_head *head = (struct list_head *)(((uintptr_t)task) + task_struct_offset.tasks_offset); + return head; +} + +static inline const char *get_task_comm(struct task_struct *task) +{ + return (const char *)(((uintptr_t)task) + task_struct_offset.comm_offset); +} + extern struct mm_struct *kvar(init_mm); extern struct pid_namespace *kvar(init_pid_ns); +#define tasklist_empty() list_empty(get_task_tasks_p(kvar(init_task))) + +// todo: list_entry_rcu +static inline struct task_struct *next_task(struct task_struct *task) +{ + struct list_head *head = get_task_tasks_p(task); + struct list_head *next = head->next; + struct task_struct *next_task = (struct task_struct *)(next - task_struct_offset.tasks_offset); + return next_task; +} + +#define for_each_process(p) for (p = kvar(init_task); (p = next_task(p)) != kvar(init_task);) + +/* + * Careful: do_each_thread/while_each_thread is a double loop so + * 'break' will not work as expected - use goto instead. + */ +#define do_each_thread(g, t) \ + struct task_struct *__init_task = kvar(init_task); \ + for (g = t = __init_task; (g = t = next_task(g)) != __init_task;) \ + do + +#define while_each_thread(g, t) while ((t = next_thread(t)) != g) + +#define __for_each_thread(signal, t) list_for_each_entry_rcu(t, &(signal)->thread_head, thread_node) + +#define for_each_thread(p, t) __for_each_thread((p)->signal, t) + +/* Careful: this is a double loop, 'break' won't work as expected. */ +#define for_each_process_thread(p, t) for_each_process(p) for_each_thread(p, t) + extern int cpuset_cpumask_can_shrink(const struct cpumask *cur, const struct cpumask *trial); extern int task_can_attach(struct task_struct *p, const struct cpumask *cs_effective_cpus); extern void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask); diff --git a/kernel/linux/include/linux/seq_buf.h b/kernel/linux/include/linux/seq_buf.h index 0ddf315b..30404e61 100644 --- a/kernel/linux/include/linux/seq_buf.h +++ b/kernel/linux/include/linux/seq_buf.h @@ -29,6 +29,7 @@ extern int kfunc_def(seq_buf_putmem)(struct seq_buf *s, const void *mem, unsigne extern int kfunc_def(seq_buf_putmem_hex)(struct seq_buf *s, const void *mem, unsigned int len); extern int kfunc_def(seq_buf_bitmask)(struct seq_buf *s, const unsigned long *maskp, int nmaskbits); +// todo: static inline int seq_buf_printf(struct seq_buf *s, const char *fmt, ...) { if (!kfunc(seq_buf_printf)) { @@ -78,13 +79,4 @@ static inline int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp, return 0; } -static inline int seq_buf_copy_to_user(void __user *to, const void *from, int n) -{ - struct seq_buf seq_buf; - seq_buf_clear(&seq_buf); - seq_buf.buffer = (void *)from; - seq_buf.len = n; - return seq_buf_to_user(&seq_buf, to, n); -} - #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/slab.h b/kernel/linux/include/linux/slab.h index 6be8aa7a..0f05abe2 100644 --- a/kernel/linux/include/linux/slab.h +++ b/kernel/linux/include/linux/slab.h @@ -2,20 +2,52 @@ #define _LINUX_SLAB_H #include +#include +#include +#include // todo +struct kmem_cache; +struct list_lru; + +extern void *kfunc_def(__kmalloc)(size_t size, gfp_t flags); +extern void *kfunc_def(kmalloc)(size_t size, gfp_t flags); +extern void kfunc_def(kfree)(const void *); void *__must_check krealloc(const void *, size_t, gfp_t); -void kfree(const void *); void kfree_sensitive(const void *); size_t __ksize(const void *); size_t ksize(const void *); +void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags); +void *kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru, gfp_t gfpflags); +void kmem_cache_free(struct kmem_cache *s, void *objp); +void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p); +int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, void **p); + +void *__kmalloc_node(size_t size, gfp_t flags, int node); +void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node); +void *kmalloc_trace(struct kmem_cache *s, gfp_t flags, size_t size); +void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags, int node, size_t size); +void *kmalloc_large(size_t size, gfp_t flags); +void *kmalloc_large_node(size_t size, gfp_t flags, int node); + +static __always_inline void kfree_bulk(size_t size, void **p) +{ + kmem_cache_free_bulk(0, size, p); +} -void *__kmalloc(size_t size, gfp_t flags); -void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags); -void kmem_cache_free(struct kmem_cache *, void *); +static inline void *kmalloc(size_t size, gfp_t flags) +{ + kfunc_call(kmalloc, size, flags); + kfunc_call(__kmalloc, size, flags); + kfunc_not_found(); + return 0; +} -void kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); -int kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); +static inline void kfree(const void *objp) +{ + kfunc_call(kfree, objp); + kfunc_not_found(); +} #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/socket.h b/kernel/linux/include/linux/socket.h index 74e8d3e8..c1e1fe61 100644 --- a/kernel/linux/include/linux/socket.h +++ b/kernel/linux/include/linux/socket.h @@ -152,8 +152,7 @@ static inline struct cmsghdr *__cmsg_nxthdr(void *__ctl, __kernel_size_t __size, struct cmsghdr *__ptr; __ptr = (struct cmsghdr *)(((unsigned char *)__cmsg) + CMSG_ALIGN(__cmsg->cmsg_len)); - if ((unsigned long)((char *)(__ptr + 1) - (char *)__ctl) > __size) - return (struct cmsghdr *)0; + if ((unsigned long)((char *)(__ptr + 1) - (char *)__ctl) > __size) return (struct cmsghdr *)0; return __ptr; } diff --git a/kernel/linux/include/linux/stacktrace.h b/kernel/linux/include/linux/stacktrace.h new file mode 100644 index 00000000..95d42eb1 --- /dev/null +++ b/kernel/linux/include/linux/stacktrace.h @@ -0,0 +1,51 @@ +#ifndef __LINUX_STACKTRACE_H +#define __LINUX_STACKTRACE_H + +#include + +struct pt_regs; + +struct stack_trace +{ + unsigned int nr_entries, max_entries; + unsigned long *entries; + int skip; /* input argument: How many entries to skip */ +}; + +extern void kfunc_def(save_stack_trace)(struct stack_trace *trace); +extern void kfunc_def(save_stack_trace_regs)(struct pt_regs *regs, struct stack_trace *trace); +extern void kfunc_def(save_stack_trace_tsk)(struct task_struct *tsk, struct stack_trace *trace); +extern void kfunc_def(print_stack_trace)(struct stack_trace *trace, int spaces); +extern void kfunc_def(save_stack_trace_user)(struct stack_trace *trace); + +static inline void save_stack_trace(struct stack_trace *trace) +{ + kfunc_call_void(save_stack_trace, trace); + kfunc_not_found() +} + +static inline void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) +{ + kfunc_call_void(save_stack_trace_regs, regs, trace); + kfunc_not_found() +} + +static inline void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + kfunc_call_void(save_stack_trace_tsk, tsk, trace); + kfunc_not_found() +} + +static inline void print_stack_trace(struct stack_trace *trace, int spaces) +{ + kfunc_call_void(print_stack_trace, trace, spaces); + kfunc_not_found() +} + +static inline void save_stack_trace_user(struct stack_trace *trace) +{ + kfunc_call_void(save_stack_trace_user, trace); + kfunc_not_found() +} + +#endif \ No newline at end of file diff --git a/kernel/linux/include/linux/stop_machine.h b/kernel/linux/include/linux/stop_machine.h index 1d025787..f26aa72b 100644 --- a/kernel/linux/include/linux/stop_machine.h +++ b/kernel/linux/include/linux/stop_machine.h @@ -8,6 +8,40 @@ typedef int (*cpu_stop_fn_t)(void *arg); struct cpumask; +extern bool kvar_def(stop_machine_initialized); +extern const struct cpumask *kvar_def(cpu_online_mask); + +/** + * stop_machine: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr for the @fn() + * @cpus: the cpus to run the @fn() on (NULL = any online cpu) + * + * Description: This causes a thread to be scheduled on every cpu, + * each of which disables interrupts. The result is that no one is + * holding a spinlock or inside any other preempt-disabled region when + * @fn() runs. + * + * This can be thought of as a very heavy write lock, equivalent to + * grabbing every spinlock in the kernel. + * + * Protects against CPU hotplug. + * + */ extern int kfunc_def(stop_machine)(int (*fn)(void *), void *data, const struct cpumask *cpus); +static inline int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus) +{ + kfunc_call(stop_machine, fn, data, cpus); + // todo: + // unsigned long flags; + // int ret; + // local_irq_save(flags); + // ret = fn(data); + // local_irq_restore(flags); + // return ret; + kfunc_not_found(); + return 0; +} + #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/string.h b/kernel/linux/include/linux/string.h index 2625fdb9..8d548389 100644 --- a/kernel/linux/include/linux/string.h +++ b/kernel/linux/include/linux/string.h @@ -8,6 +8,7 @@ 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); @@ -59,373 +60,379 @@ 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); -inline void kfree_const(const void *x) +static inline void kfree_const(const void *x) { kfunc_call(kfree_const, x); kfunc_not_found(); - ; } -inline char *kstrdup(const char *s, gfp_t gfp) + +static inline char *kstrdup(const char *s, gfp_t gfp) { kfunc_call(kstrdup, s, gfp); kfunc_not_found(); return 0; - ; } -inline const char *kstrdup_const(const char *s, gfp_t gfp) + +static inline const char *kstrdup_const(const char *s, gfp_t gfp) { kfunc_call(kstrdup_const, s, gfp); kfunc_not_found(); return 0; - ; } -inline char *kstrndup(const char *s, size_t len, gfp_t gfp) + +static inline char *kstrndup(const char *s, size_t len, gfp_t gfp) { kfunc_call(kstrndup, s, len, gfp); kfunc_not_found(); return 0; - ; } -inline void *kmemdup(const void *src, size_t len, gfp_t gfp) + +static inline void *kmemdup(const void *src, size_t len, gfp_t gfp) { kfunc_call(kmemdup, src, len, gfp); kfunc_not_found(); return 0; - ; } -inline char *kmemdup_nul(const char *s, size_t len, gfp_t gfp) + +static inline char *kmemdup_nul(const char *s, size_t len, gfp_t gfp) { kfunc_call(kmemdup_nul, s, len, gfp); kfunc_not_found(); return 0; - ; } -inline char **argv_split(gfp_t gfp, const char *str, int *argcp) + +static inline void *memdup_user(const void __user *src, size_t len) +{ + kfunc_call(memdup_user, src, len); + kfunc_not_found(); + return 0; +} + +static inline char **argv_split(gfp_t gfp, const char *str, int *argcp) { kfunc_call(argv_split, gfp, str, argcp); kfunc_not_found(); return 0; - ; } -inline void argv_free(char **argv) + +static inline void argv_free(char **argv) { kfunc_call(argv_free, argv); kfunc_not_found(); - ; } -inline int kstrtobool(const char *s, bool *res) + +static inline int kstrtobool(const char *s, bool *res) { kfunc_call(kstrtobool, s, res); kfunc_not_found(); return 0; - ; } -inline int strncasecmp(const char *s1, const char *s2, size_t len) + +static inline int strncasecmp(const char *s1, const char *s2, size_t len) { kfunc_call(strncasecmp, s1, s2, len); kfunc_not_found(); return 0; - ; } -inline int strcasecmp(const char *s1, const char *s2) + +static inline int strcasecmp(const char *s1, const char *s2) { kfunc_call(strcasecmp, s1, s2); kfunc_not_found(); return 0; - ; } -inline char *strcpy(char *dest, const char *src) + +static inline char *strcpy(char *dest, const char *src) { kfunc_call(strcpy, dest, src); kfunc_not_found(); return 0; - ; } -inline char *strncpy(char *dest, const char *src, size_t count) + +static inline char *strncpy(char *dest, const char *src, size_t count) { kfunc_call(strncpy, dest, src, count); kfunc_not_found(); return 0; - ; } -inline size_t strlcpy(char *dest, const char *src, size_t size) + +static inline size_t strlcpy(char *dest, const char *src, size_t size) { kfunc_call(strlcpy, dest, src, size); kfunc_not_found(); return 0; - ; } -inline ssize_t strscpy(char *dest, const char *src, size_t count) + +static inline ssize_t strscpy(char *dest, const char *src, size_t count) { kfunc_call(strscpy, dest, src, count); kfunc_not_found(); return 0; - ; } -inline ssize_t strscpy_pad(char *dest, const char *src, size_t count) + +static inline ssize_t strscpy_pad(char *dest, const char *src, size_t count) { kfunc_call(strscpy_pad, dest, src, count); kfunc_not_found(); return 0; - ; } -inline char *stpcpy(char *__restrict__ dest, const char *__restrict__ src) + +static inline char *stpcpy(char *__restrict__ dest, const char *__restrict__ src) { kfunc_call(stpcpy, dest, src); kfunc_not_found(); return 0; - ; } -inline char *strcat(char *dest, const char *src) + +static inline char *strcat(char *dest, const char *src) { kfunc_call(strcat, dest, src); kfunc_not_found(); return 0; - ; } -inline char *strncat(char *dest, const char *src, size_t count) + +static inline char *strncat(char *dest, const char *src, size_t count) { kfunc_call(strncat, dest, src, count); kfunc_not_found(); return 0; - ; } -inline size_t strlcat(char *dest, const char *src, size_t count) + +static inline size_t strlcat(char *dest, const char *src, size_t count) { kfunc_call(strlcat, dest, src, count); kfunc_not_found(); return 0; - ; } -inline int strcmp(const char *cs, const char *ct) + +static inline int strcmp(const char *cs, const char *ct) { kfunc_call(strcmp, cs, ct); kfunc_not_found(); return 0; - ; } -inline int strncmp(const char *cs, const char *ct, size_t count) + +static inline int strncmp(const char *cs, const char *ct, size_t count) { kfunc_call(strncmp, cs, ct, count); kfunc_not_found(); return 0; - ; } -inline char *strchr(const char *s, int c) + +static inline char *strchr(const char *s, int c) { kfunc_call(strchr, s, c); kfunc_not_found(); return 0; - ; } -inline char *strchrnul(const char *s, int c) + +static inline char *strchrnul(const char *s, int c) { kfunc_call(strchrnul, s, c); kfunc_not_found(); return 0; - ; } -inline char *strnchrnul(const char *s, size_t count, int c) + +static inline char *strnchrnul(const char *s, size_t count, int c) { kfunc_call(strnchrnul, s, count, c); kfunc_not_found(); return 0; - ; } -inline char *strrchr(const char *s, int c) + +static inline char *strrchr(const char *s, int c) { kfunc_call(strrchr, s, c); kfunc_not_found(); return 0; - ; } -inline char *strnchr(const char *s, size_t count, int c) + +static inline char *strnchr(const char *s, size_t count, int c) { kfunc_call(strnchr, s, count, c); kfunc_not_found(); return 0; - ; } -inline char *skip_spaces(const char *str) + +static inline char *skip_spaces(const char *str) { kfunc_call(skip_spaces, str); kfunc_not_found(); return 0; - ; } -inline char *strim(char *s) + +static inline char *strim(char *s) { kfunc_call(strim, s); kfunc_not_found(); return 0; - ; } -inline size_t strlen(const char *s) + +static inline size_t strlen(const char *s) { kfunc_call(strlen, s); kfunc_not_found(); return 0; - ; } -inline size_t strnlen(const char *s, size_t count) + +static inline size_t strnlen(const char *s, size_t count) { kfunc_call(strnlen, s, count); kfunc_not_found(); return 0; - ; } -inline size_t strspn(const char *s, const char *accept) + +static inline size_t strspn(const char *s, const char *accept) { kfunc_call(strspn, s, accept); kfunc_not_found(); return 0; - ; } -inline size_t strcspn(const char *s, const char *reject) + +static inline size_t strcspn(const char *s, const char *reject) { kfunc_call(strcspn, s, reject); kfunc_not_found(); return 0; - ; } -inline char *strpbrk(const char *cs, const char *ct) + +static inline char *strpbrk(const char *cs, const char *ct) { kfunc_call(strpbrk, cs, ct); kfunc_not_found(); return 0; - ; } -inline char *strsep(char **s, const char *ct) + +static inline char *strsep(char **s, const char *ct) { kfunc_call(strsep, s, ct); kfunc_not_found(); return 0; - ; } -inline bool sysfs_streq(const char *s1, const char *s2) + +static inline bool sysfs_streq(const char *s1, const char *s2) { kfunc_call(sysfs_streq, s1, s2); kfunc_not_found(); return 0; - ; } -inline int match_string(const char *const *array, size_t n, const char *string) + +static inline int match_string(const char *const *array, size_t n, const char *string) { kfunc_call(match_string, array, n, string); kfunc_not_found(); return 0; - ; } -inline int __sysfs_match_string(const char *const *array, size_t n, const char *str) + +static inline int __sysfs_match_string(const char *const *array, size_t n, const char *str) { kfunc_call(__sysfs_match_string, array, n, str); kfunc_not_found(); return 0; - ; } -inline void *memset(void *s, int c, size_t count) + +static inline void *memset(void *s, int c, size_t count) { kfunc_call(memset, s, c, count); kfunc_not_found(); return 0; - ; } -inline void *memset16(uint16_t *s, uint16_t v, size_t count) + +static inline void *memset16(uint16_t *s, uint16_t v, size_t count) { kfunc_call(memset16, s, v, count); kfunc_not_found(); return 0; - ; } -inline void *memset32(uint32_t *s, uint32_t v, size_t count) + +static inline void *memset32(uint32_t *s, uint32_t v, size_t count) { kfunc_call(memset32, s, v, count); kfunc_not_found(); return 0; - ; } -inline void *memset64(uint64_t *s, uint64_t v, size_t count) + +static inline void *memset64(uint64_t *s, uint64_t v, size_t count) { kfunc_call(memset64, s, v, count); kfunc_not_found(); return 0; - ; } -inline void *memcpy(void *dest, const void *src, size_t count) + +static inline void *memcpy(void *dest, const void *src, size_t count) { kfunc_call(memcpy, dest, src, count); kfunc_not_found(); return 0; - ; } -inline void *memmove(void *dest, const void *src, size_t count) + +static inline void *memmove(void *dest, const void *src, size_t count) { kfunc_call(memmove, dest, src, count); kfunc_not_found(); return 0; - ; } -inline int memcmp(const void *cs, const void *ct, size_t count) + +static inline int memcmp(const void *cs, const void *ct, size_t count) { kfunc_call(memcmp, cs, ct, count); kfunc_not_found(); return 0; - ; } -inline int bcmp(const void *a, const void *b, size_t len) + +static inline int bcmp(const void *a, const void *b, size_t len) { kfunc_call(bcmp, a, b, len); kfunc_not_found(); return 0; - ; } -inline void *memscan(void *addr, int c, size_t size) + +static inline void *memscan(void *addr, int c, size_t size) { kfunc_call(memscan, addr, c, size); kfunc_not_found(); return 0; - ; } -inline char *strstr(const char *s1, const char *s2) + +static inline char *strstr(const char *s1, const char *s2) { kfunc_call(strstr, s1, s2); kfunc_not_found(); return 0; - ; } -inline char *strnstr(const char *s1, const char *s2, size_t len) + +static inline char *strnstr(const char *s1, const char *s2, size_t len) { kfunc_call(strnstr, s1, s2, len); kfunc_not_found(); return 0; - ; } -inline void *memchr(const void *s, int c, size_t n) + +static inline void *memchr(const void *s, int c, size_t n) { kfunc_call(memchr, s, c, n); kfunc_not_found(); return 0; - ; } -inline void *memchr_inv(const void *start, int c, size_t bytes) + +static inline void *memchr_inv(const void *start, int c, size_t bytes) { kfunc_call(memchr_inv, start, c, bytes); kfunc_not_found(); return 0; - ; } -inline char *strreplace(char *s, char old, char new) + +static inline char *strreplace(char *s, char old, char new) { kfunc_call(strreplace, s, old, new); kfunc_not_found(); return 0; - ; } -inline void fortify_panic(const char *name) + +static inline void fortify_panic(const char *name) { kfunc_call(fortify_panic, name); kfunc_not_found(); - ; } #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/syscall.h b/kernel/linux/include/linux/syscall.h index a4b064d7..8a9d494a 100644 --- a/kernel/linux/include/linux/syscall.h +++ b/kernel/linux/include/linux/syscall.h @@ -1,11 +1,8 @@ #ifndef _LINUX_SYSCALLS_H #define _LINUX_SYSCALLS_H -// todo: remove typedef struct - #include -typedef struct aio_context_t aio_context_t; struct iocb; struct io_event; struct __kernel_timespec; @@ -13,11 +10,9 @@ struct __aio_sigset; struct io_uring_params; struct old_timespec32; struct epoll_event; -typedef struct sigset_t sigset_t; struct statfs; struct statfs64; struct open_how; -typedef struct qid_t qid_t; struct linux_dirent64; struct iovec; struct pollfd; @@ -25,20 +20,16 @@ struct stat; struct stat64; struct __kernel_itimerspec; struct old_itimerspec32; -typedef struct cap_user_header_t cap_user_header_t; -typedef struct cap_user_data_t cap_user_data_t; struct siginfo; struct rusage; struct robust_list_head; struct futex_waitv; struct __kernel_old_itimerval; struct kexec_segment; -typedef struct clockid_t clockid_t; struct sigevent; struct sched_param; struct sigaltstack; struct sigaction; -typedef struct siginfo_t siginfo_t; struct tms; struct new_utsname; struct rlimit; @@ -48,7 +39,6 @@ struct timezone; struct __kernel_timex; struct old_timex32; struct sysinfo; -typedef struct umode_t umode_t; struct mq_attr; struct msqid_ds; struct msgbuf; @@ -56,7 +46,6 @@ struct sembuf; struct shmid_ds; struct sockaddr; struct user_msghdr; -typedef struct key_serial_t key_serial_t; struct clone_args; struct perf_event_attr; struct mmsghdr; @@ -70,17 +59,11 @@ struct rseq; struct mount_attr; struct landlock_ruleset_attr; enum landlock_rule_type; -typedef struct __kernel_old_time_t __kernel_old_time_t; -typedef struct old_time32_t old_time32_t; struct utimbuf; struct old_utimbuf32; struct old_timeval32; struct linux_dirent; struct old_sigaction; -typedef struct old_sigset_t old_sigset_t; -typedef struct __sighandler_t __sighandler_t; -typedef struct old_uid_t old_uid_t; -typedef struct old_gid_t old_gid_t; struct __old_kernel_stat; struct sel_arg_struct; struct old_linux_dirent; @@ -91,755 +74,4 @@ struct sembuf; struct timespec64; struct ipc_namespace; -asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t __user *ctx); -asmlinkage long sys_io_destroy(aio_context_t ctx); -asmlinkage long sys_io_submit(aio_context_t, long, struct iocb __user *__user *); -asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, struct io_event __user *result); -asmlinkage long sys_io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user *events, - struct __kernel_timespec __user *timeout); -asmlinkage long sys_io_getevents_time32(u32 ctx_id, s32 min_nr, s32 nr, struct io_event __user *events, - struct old_timespec32 __user *timeout); -asmlinkage long sys_io_pgetevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user *events, - struct __kernel_timespec __user *timeout, const struct __aio_sigset *sig); -asmlinkage long sys_io_pgetevents_time32(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user *events, - struct old_timespec32 __user *timeout, const struct __aio_sigset *sig); -asmlinkage long sys_io_uring_setup(u32 entries, struct io_uring_params __user *p); -asmlinkage long sys_io_uring_enter(unsigned int fd, u32 to_submit, u32 min_complete, u32 flags, const void __user *argp, - size_t argsz); -asmlinkage long sys_io_uring_register(unsigned int fd, unsigned int op, void __user *arg, unsigned int nr_args); - -/* fs/xattr.c */ -asmlinkage long sys_setxattr(const char __user *path, const char __user *name, const void __user *value, size_t size, - int flags); -asmlinkage long sys_lsetxattr(const char __user *path, const char __user *name, const void __user *value, size_t size, - int flags); -asmlinkage long sys_fsetxattr(int fd, const char __user *name, const void __user *value, size_t size, int flags); -asmlinkage long sys_getxattr(const char __user *path, const char __user *name, void __user *value, size_t size); -asmlinkage long sys_lgetxattr(const char __user *path, const char __user *name, void __user *value, size_t size); -asmlinkage long sys_fgetxattr(int fd, const char __user *name, void __user *value, size_t size); -asmlinkage long sys_listxattr(const char __user *path, char __user *list, size_t size); -asmlinkage long sys_llistxattr(const char __user *path, char __user *list, size_t size); -asmlinkage long sys_flistxattr(int fd, char __user *list, size_t size); -asmlinkage long sys_removexattr(const char __user *path, const char __user *name); -asmlinkage long sys_lremovexattr(const char __user *path, const char __user *name); -asmlinkage long sys_fremovexattr(int fd, const char __user *name); - -/* fs/dcache.c */ -asmlinkage long sys_getcwd(char __user *buf, unsigned long size); - -/* fs/cookies.c */ -asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user *buf, size_t len); - -/* fs/eventfd.c */ -asmlinkage long sys_eventfd2(unsigned int count, int flags); - -/* fs/eventpoll.c */ -asmlinkage long sys_epoll_create1(int flags); -asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event); -asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, int maxevents, int timeout, - const sigset_t __user *sigmask, size_t sigsetsize); -asmlinkage long sys_epoll_pwait2(int epfd, struct epoll_event __user *events, int maxevents, - const struct __kernel_timespec __user *timeout, const sigset_t __user *sigmask, - size_t sigsetsize); - -/* fs/fcntl.c */ -asmlinkage long sys_dup(unsigned int fildes); -asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags); -asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); -asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg); - -/* fs/inotify_user.c */ -asmlinkage long sys_inotify_init1(int flags); -asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask); -asmlinkage long sys_inotify_rm_watch(int fd, s32 wd); - -/* fs/ioctl.c */ -asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); - -/* fs/ioprio.c */ -asmlinkage long sys_ioprio_set(int which, int who, int ioprio); -asmlinkage long sys_ioprio_get(int which, int who); - -/* fs/locks.c */ -asmlinkage long sys_flock(unsigned int fd, unsigned int cmd); - -/* fs/namei.c */ -asmlinkage long sys_mknodat(int dfd, const char __user *filename, umode_t mode, unsigned dev); -asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, umode_t mode); -asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag); -asmlinkage long sys_symlinkat(const char __user *oldname, int newdfd, const char __user *newname); -asmlinkage long sys_linkat(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, int flags); -asmlinkage long sys_renameat(int olddfd, const char __user *oldname, int newdfd, const char __user *newname); - -/* fs/namespace.c */ -asmlinkage long sys_umount(char __user *name, int flags); -asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name, char __user *type, unsigned long flags, - void __user *data); -asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *put_old); - -/* fs/nfsctl.c */ - -/* fs/open.c */ -asmlinkage long sys_statfs(const char __user *path, struct statfs __user *buf); -asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf); -asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user *buf); -asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf); -asmlinkage long sys_truncate(const char __user *path, long length); -asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length); -#if BITS_PER_LONG == 32 -asmlinkage long sys_truncate64(const char __user *path, loff_t length); -asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length); -#endif -asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); -asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode); -asmlinkage long sys_faccessat2(int dfd, const char __user *filename, int mode, int flags); -asmlinkage long sys_chdir(const char __user *filename); -asmlinkage long sys_fchdir(unsigned int fd); -asmlinkage long sys_chroot(const char __user *filename); -asmlinkage long sys_fchmod(unsigned int fd, umode_t mode); -asmlinkage long sys_fchmodat(int dfd, const char __user *filename, umode_t mode); -asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, int flag); -asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group); -asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, umode_t mode); -asmlinkage long sys_openat2(int dfd, const char __user *filename, struct open_how *how, size_t size); -asmlinkage long sys_close(unsigned int fd); -asmlinkage long sys_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags); -asmlinkage long sys_vhangup(void); - -/* fs/pipe.c */ -asmlinkage long sys_pipe2(int __user *fildes, int flags); - -/* fs/quota.c */ -asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr); -asmlinkage long sys_quotactl_fd(unsigned int fd, unsigned int cmd, qid_t id, void __user *addr); - -/* fs/readdir.c */ -asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count); - -/* fs/read_write.c */ -asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t __user *result, - unsigned int whence); -asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int whence); -asmlinkage long sys_read(unsigned int fd, char __user *buf, size_t count); -asmlinkage long sys_write(unsigned int fd, const char __user *buf, size_t count); -asmlinkage long sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen); -asmlinkage long sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen); -asmlinkage long sys_pread64(unsigned int fd, char __user *buf, size_t count, loff_t pos); -asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf, size_t count, loff_t pos); -asmlinkage long sys_preadv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, - unsigned long pos_h); -asmlinkage long sys_pwritev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, - unsigned long pos_h); - -/* fs/sendfile.c */ -asmlinkage long sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count); - -/* fs/select.c */ -asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *, fd_set __user *, struct __kernel_timespec __user *, - void __user *); -asmlinkage long sys_pselect6_time32(int, fd_set __user *, fd_set __user *, fd_set __user *, - struct old_timespec32 __user *, void __user *); -asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int, struct __kernel_timespec __user *, - const sigset_t __user *, size_t); -asmlinkage long sys_ppoll_time32(struct pollfd __user *, unsigned int, struct old_timespec32 __user *, - const sigset_t __user *, size_t); - -/* fs/signalfd.c */ -asmlinkage long sys_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask, int flags); - -/* fs/splice.c */ -asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov, unsigned long nr_segs, unsigned int flags); -asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, int fd_out, loff_t __user *off_out, size_t len, - unsigned int flags); -asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags); - -/* fs/stat.c */ -asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf, int bufsiz); -asmlinkage long sys_newfstatat(int dfd, const char __user *filename, struct stat __user *statbuf, int flag); -asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf); -asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf); -asmlinkage long sys_fstatat64(int dfd, const char __user *filename, struct stat64 __user *statbuf, int flag); - -/* fs/sync.c */ -asmlinkage long sys_sync(void); -asmlinkage long sys_fsync(unsigned int fd); -asmlinkage long sys_fdatasync(unsigned int fd); -asmlinkage long sys_sync_file_range2(int fd, unsigned int flags, loff_t offset, loff_t nbytes); -asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, unsigned int flags); - -/* fs/timerfd.c */ -asmlinkage long sys_timerfd_create(int clockid, int flags); -asmlinkage long sys_timerfd_settime(int ufd, int flags, const struct __kernel_itimerspec __user *utmr, - struct __kernel_itimerspec __user *otmr); -asmlinkage long sys_timerfd_gettime(int ufd, struct __kernel_itimerspec __user *otmr); -asmlinkage long sys_timerfd_gettime32(int ufd, struct old_itimerspec32 __user *otmr); -asmlinkage long sys_timerfd_settime32(int ufd, int flags, const struct old_itimerspec32 __user *utmr, - struct old_itimerspec32 __user *otmr); - -/* fs/utimes.c */ -asmlinkage long sys_utimensat(int dfd, const char __user *filename, struct __kernel_timespec __user *utimes, int flags); -asmlinkage long sys_utimensat_time32(unsigned int dfd, const char __user *filename, struct old_timespec32 __user *t, - int flags); - -/* kernel/acct.c */ -asmlinkage long sys_acct(const char __user *name); - -/* kernel/capability.c */ -asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr); -asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data); - -/* kernel/exec_domain.c */ -asmlinkage long sys_personality(unsigned int personality); - -/* kernel/exit.c */ -asmlinkage long sys_exit(int error_code); -asmlinkage long sys_exit_group(int error_code); -asmlinkage long sys_waitid(int which, pid_t pid, struct siginfo __user *infop, int options, struct rusage __user *ru); - -/* kernel/fork.c */ -asmlinkage long sys_set_tid_address(int __user *tidptr); -asmlinkage long sys_unshare(unsigned long unshare_flags); - -/* kernel/futex/syscalls.c */ -asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val, const struct __kernel_timespec __user *utime, - u32 __user *uaddr2, u32 val3); -asmlinkage long sys_futex_time32(u32 __user *uaddr, int op, u32 val, const struct old_timespec32 __user *utime, - u32 __user *uaddr2, u32 val3); -asmlinkage long sys_get_robust_list(int pid, struct robust_list_head __user *__user *head_ptr, size_t __user *len_ptr); -asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len); - -asmlinkage long sys_futex_waitv(struct futex_waitv *waiters, unsigned int nr_futexes, unsigned int flags, - struct __kernel_timespec __user *timeout, clockid_t clockid); - -/* kernel/hrtimer.c */ -asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp, struct __kernel_timespec __user *rmtp); -asmlinkage long sys_nanosleep_time32(struct old_timespec32 __user *rqtp, struct old_timespec32 __user *rmtp); - -/* kernel/itimer.c */ -asmlinkage long sys_getitimer(int which, struct __kernel_old_itimerval __user *value); -asmlinkage long sys_setitimer(int which, struct __kernel_old_itimerval __user *value, - struct __kernel_old_itimerval __user *ovalue); - -/* kernel/kexec.c */ -asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, - unsigned long flags); - -/* kernel/module.c */ -asmlinkage long sys_init_module(void __user *umod, unsigned long len, const char __user *uargs); -asmlinkage long sys_delete_module(const char __user *name_user, unsigned int flags); - -/* kernel/posix-timers.c */ -asmlinkage long sys_timer_create(clockid_t which_clock, struct sigevent __user *timer_event_spec, - timer_t __user *created_timer_id); -asmlinkage long sys_timer_gettime(timer_t timer_id, struct __kernel_itimerspec __user *setting); -asmlinkage long sys_timer_getoverrun(timer_t timer_id); -asmlinkage long sys_timer_settime(timer_t timer_id, int flags, const struct __kernel_itimerspec __user *new_setting, - struct __kernel_itimerspec __user *old_setting); -asmlinkage long sys_timer_delete(timer_t timer_id); -asmlinkage long sys_clock_settime(clockid_t which_clock, const struct __kernel_timespec __user *tp); -asmlinkage long sys_clock_gettime(clockid_t which_clock, struct __kernel_timespec __user *tp); -asmlinkage long sys_clock_getres(clockid_t which_clock, struct __kernel_timespec __user *tp); -asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags, const struct __kernel_timespec __user *rqtp, - struct __kernel_timespec __user *rmtp); -asmlinkage long sys_timer_gettime32(timer_t timer_id, struct old_itimerspec32 __user *setting); -asmlinkage long sys_timer_settime32(timer_t timer_id, int flags, struct old_itimerspec32 __user *new, - struct old_itimerspec32 __user *old); -asmlinkage long sys_clock_settime32(clockid_t which_clock, struct old_timespec32 __user *tp); -asmlinkage long sys_clock_gettime32(clockid_t which_clock, struct old_timespec32 __user *tp); -asmlinkage long sys_clock_getres_time32(clockid_t which_clock, struct old_timespec32 __user *tp); -asmlinkage long sys_clock_nanosleep_time32(clockid_t which_clock, int flags, struct old_timespec32 __user *rqtp, - struct old_timespec32 __user *rmtp); - -/* kernel/printk.c */ -asmlinkage long sys_syslog(int type, char __user *buf, int len); - -/* kernel/ptrace.c */ -asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data); -/* kernel/sched/core.c */ - -asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param); -asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param); -asmlinkage long sys_sched_getscheduler(pid_t pid); -asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param); -asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr); -asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr); -asmlinkage long sys_sched_yield(void); -asmlinkage long sys_sched_get_priority_max(int policy); -asmlinkage long sys_sched_get_priority_min(int policy); -asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct __kernel_timespec __user *interval); -asmlinkage long sys_sched_rr_get_interval_time32(pid_t pid, struct old_timespec32 __user *interval); - -/* kernel/signal.c */ -asmlinkage long sys_restart_syscall(void); -asmlinkage long sys_kill(pid_t pid, int sig); -asmlinkage long sys_tkill(pid_t pid, int sig); -asmlinkage long sys_tgkill(pid_t tgid, pid_t pid, int sig); -asmlinkage long sys_sigaltstack(const struct sigaltstack __user *uss, struct sigaltstack __user *uoss); -asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize); - -#ifndef CONFIG_ODD_RT_SIGACTION -asmlinkage long sys_rt_sigaction(int, const struct sigaction __user *, struct sigaction __user *, size_t); -#endif - -asmlinkage long sys_rt_sigprocmask(int how, sigset_t __user *set, sigset_t __user *oset, size_t sigsetsize); -asmlinkage long sys_rt_sigpending(sigset_t __user *set, size_t sigsetsize); -asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese, siginfo_t __user *uinfo, - const struct __kernel_timespec __user *uts, size_t sigsetsize); -asmlinkage long sys_rt_sigtimedwait_time32(const sigset_t __user *uthese, siginfo_t __user *uinfo, - const struct old_timespec32 __user *uts, size_t sigsetsize); -asmlinkage long sys_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t __user *uinfo); - -/* kernel/sys.c */ -asmlinkage long sys_setpriority(int which, int who, int niceval); -asmlinkage long sys_getpriority(int which, int who); -asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user *arg); -asmlinkage long sys_setregid(gid_t rgid, gid_t egid); -asmlinkage long sys_setgid(gid_t gid); -asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); -asmlinkage long sys_setuid(uid_t uid); -asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); -asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid); -asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); -asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid); -asmlinkage long sys_setfsuid(uid_t uid); -asmlinkage long sys_setfsgid(gid_t gid); -asmlinkage long sys_times(struct tms __user *tbuf); -asmlinkage long sys_setpgid(pid_t pid, pid_t pgid); -asmlinkage long sys_getpgid(pid_t pid); -asmlinkage long sys_getsid(pid_t pid); -asmlinkage long sys_setsid(void); -asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist); -asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist); -asmlinkage long sys_newuname(struct new_utsname __user *name); -asmlinkage long sys_sethostname(char __user *name, int len); -asmlinkage long sys_setdomainname(char __user *name, int len); -asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim); -asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim); -asmlinkage long sys_getrusage(int who, struct rusage __user *ru); -asmlinkage long sys_umask(int mask); -asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); -asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); - -/* kernel/time.c */ -asmlinkage long sys_gettimeofday(struct __kernel_old_timeval __user *tv, struct timezone __user *tz); -asmlinkage long sys_settimeofday(struct __kernel_old_timeval __user *tv, struct timezone __user *tz); -asmlinkage long sys_adjtimex(struct __kernel_timex __user *txc_p); -asmlinkage long sys_adjtimex_time32(struct old_timex32 __user *txc_p); - -/* kernel/sys.c */ -asmlinkage long sys_getpid(void); -asmlinkage long sys_getppid(void); -asmlinkage long sys_getuid(void); -asmlinkage long sys_geteuid(void); -asmlinkage long sys_getgid(void); -asmlinkage long sys_getegid(void); -asmlinkage long sys_gettid(void); -asmlinkage long sys_sysinfo(struct sysinfo __user *info); - -/* ipc/mqueue.c */ -asmlinkage long sys_mq_open(const char __user *name, int oflag, umode_t mode, struct mq_attr __user *attr); -asmlinkage long sys_mq_unlink(const char __user *name); -asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *msg_ptr, size_t msg_len, unsigned int msg_prio, - const struct __kernel_timespec __user *abs_timeout); -asmlinkage long sys_mq_timedreceive(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, - const struct __kernel_timespec __user *abs_timeout); -asmlinkage long sys_mq_notify(mqd_t mqdes, const struct sigevent __user *notification); -asmlinkage long sys_mq_getsetattr(mqd_t mqdes, const struct mq_attr __user *mqstat, struct mq_attr __user *omqstat); -asmlinkage long sys_mq_timedreceive_time32(mqd_t mqdes, char __user *u_msg_ptr, unsigned int msg_len, - unsigned int __user *u_msg_prio, - const struct old_timespec32 __user *u_abs_timeout); -asmlinkage long sys_mq_timedsend_time32(mqd_t mqdes, const char __user *u_msg_ptr, unsigned int msg_len, - unsigned int msg_prio, const struct old_timespec32 __user *u_abs_timeout); - -/* ipc/msg.c */ -asmlinkage long sys_msgget(key_t key, int msgflg); -asmlinkage long sys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf); -asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf); -asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg); -asmlinkage long sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg); - -/* ipc/sem.c */ -asmlinkage long sys_semget(key_t key, int nsems, int semflg); -asmlinkage long sys_semctl(int semid, int semnum, int cmd, unsigned long arg); -asmlinkage long sys_old_semctl(int semid, int semnum, int cmd, unsigned long arg); -asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, unsigned nsops, - const struct __kernel_timespec __user *timeout); -asmlinkage long sys_semtimedop_time32(int semid, struct sembuf __user *sops, unsigned nsops, - const struct old_timespec32 __user *timeout); -asmlinkage long sys_semop(int semid, struct sembuf __user *sops, unsigned nsops); - -/* ipc/shm.c */ -asmlinkage long sys_shmget(key_t key, size_t size, int flag); -asmlinkage long sys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); -asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg); -asmlinkage long sys_shmdt(char __user *shmaddr); - -/* net/socket.c */ -asmlinkage long sys_socket(int, int, int); -asmlinkage long sys_socketpair(int, int, int, int __user *); -asmlinkage long sys_bind(int, struct sockaddr __user *, int); -asmlinkage long sys_listen(int, int); -asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *); -asmlinkage long sys_connect(int, struct sockaddr __user *, int); -asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *); -asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); -asmlinkage long sys_sendto(int, void __user *, size_t, unsigned, struct sockaddr __user *, int); -asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *); -asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen); -asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen); -asmlinkage long sys_shutdown(int, int); -asmlinkage long sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags); -asmlinkage long sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags); - -/* mm/filemap.c */ -asmlinkage long sys_readahead(int fd, loff_t offset, size_t count); - -/* mm/nommu.c, also with MMU */ -asmlinkage long sys_brk(unsigned long brk); -asmlinkage long sys_munmap(unsigned long addr, size_t len); -asmlinkage long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, - unsigned long new_addr); - -/* security/keys/keyctl.c */ -asmlinkage long sys_add_key(const char __user *_type, const char __user *_description, const void __user *_payload, - size_t plen, key_serial_t destringid); -asmlinkage long sys_request_key(const char __user *_type, const char __user *_description, - const char __user *_callout_info, key_serial_t destringid); -asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); - -/* arch/example/kernel/sys_example.c */ -#ifdef CONFIG_CLONE_BACKWARDS -asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, unsigned long, int __user *); -#else -#ifdef CONFIG_CLONE_BACKWARDS3 -asmlinkage long sys_clone(unsigned long, unsigned long, int, int __user *, int __user *, unsigned long); -#else -asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, int __user *, unsigned long); -#endif -#endif - -asmlinkage long sys_clone3(struct clone_args __user *uargs, size_t size); - -asmlinkage long sys_execve(const char __user *filename, const char __user *const __user *argv, - const char __user *const __user *envp); - -/* mm/fadvise.c */ -asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice); - -/* mm/, CONFIG_MMU only */ -asmlinkage long sys_swapon(const char __user *specialfile, int swap_flags); -asmlinkage long sys_swapoff(const char __user *specialfile); -asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot); -asmlinkage long sys_msync(unsigned long start, size_t len, int flags); -asmlinkage long sys_mlock(unsigned long start, size_t len); -asmlinkage long sys_munlock(unsigned long start, size_t len); -asmlinkage long sys_mlockall(int flags); -asmlinkage long sys_munlockall(void); -asmlinkage long sys_mincore(unsigned long start, size_t len, unsigned char __user *vec); -asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior); -asmlinkage long sys_process_madvise(int pidfd, const struct iovec __user *vec, size_t vlen, int behavior, - unsigned int flags); -asmlinkage long sys_process_mrelease(int pidfd, unsigned int flags); -asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, - unsigned long flags); -asmlinkage long sys_mbind(unsigned long start, unsigned long len, unsigned long mode, const unsigned long __user *nmask, - unsigned long maxnode, unsigned flags); -asmlinkage long sys_get_mempolicy(int __user *policy, unsigned long __user *nmask, unsigned long maxnode, - unsigned long addr, unsigned long flags); -asmlinkage long sys_set_mempolicy(int mode, const unsigned long __user *nmask, unsigned long maxnode); -asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, const unsigned long __user *from, - const unsigned long __user *to); -asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, const void __user *__user *pages, - const int __user *nodes, int __user *status, int flags); - -asmlinkage long sys_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t __user *uinfo); -asmlinkage long sys_perf_event_open(struct perf_event_attr __user *attr_uptr, pid_t pid, int cpu, int group_fd, - unsigned long flags); -asmlinkage long sys_accept4(int, struct sockaddr __user *, int __user *, int); -asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, unsigned int vlen, unsigned flags, - struct __kernel_timespec __user *timeout); -asmlinkage long sys_recvmmsg_time32(int fd, struct mmsghdr __user *msg, unsigned int vlen, unsigned flags, - struct old_timespec32 __user *timeout); - -asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr, int options, struct rusage __user *ru); -asmlinkage long sys_prlimit64(pid_t pid, unsigned int resource, const struct rlimit64 __user *new_rlim, - struct rlimit64 __user *old_rlim); -asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags); -asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, u64 mask, int fd, const char __user *pathname); -asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name, struct file_handle __user *handle, - int __user *mnt_id, int flag); -asmlinkage long sys_open_by_handle_at(int mountdirfd, struct file_handle __user *handle, int flags); -asmlinkage long sys_clock_adjtime(clockid_t which_clock, struct __kernel_timex __user *tx); -asmlinkage long sys_clock_adjtime32(clockid_t which_clock, struct old_timex32 __user *tx); -asmlinkage long sys_syncfs(int fd); -asmlinkage long sys_setns(int fd, int nstype); -asmlinkage long sys_pidfd_open(pid_t pid, unsigned int flags); -asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg, unsigned int vlen, unsigned flags); -asmlinkage long sys_process_vm_readv(pid_t pid, const struct iovec __user *lvec, unsigned long liovcnt, - const struct iovec __user *rvec, unsigned long riovcnt, unsigned long flags); -asmlinkage long sys_process_vm_writev(pid_t pid, const struct iovec __user *lvec, unsigned long liovcnt, - const struct iovec __user *rvec, unsigned long riovcnt, unsigned long flags); -asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2); -asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); -asmlinkage long sys_sched_setattr(pid_t pid, struct sched_attr __user *attr, unsigned int flags); -asmlinkage long sys_sched_getattr(pid_t pid, struct sched_attr __user *attr, unsigned int size, unsigned int flags); -asmlinkage long sys_renameat2(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, - unsigned int flags); -asmlinkage long sys_seccomp(unsigned int op, unsigned int flags, void __user *uargs); -asmlinkage long sys_getrandom(char __user *buf, size_t count, unsigned int flags); -asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags); -asmlinkage long sys_bpf(int cmd, union bpf_attr *attr, unsigned int size); -asmlinkage long sys_execveat(int dfd, const char __user *filename, const char __user *const __user *argv, - const char __user *const __user *envp, int flags); -asmlinkage long sys_userfaultfd(int flags); -asmlinkage long sys_membarrier(int cmd, unsigned int flags, int cpu_id); -asmlinkage long sys_mlock2(unsigned long start, size_t len, int flags); -asmlinkage long sys_copy_file_range(int fd_in, loff_t __user *off_in, int fd_out, loff_t __user *off_out, size_t len, - unsigned int flags); -asmlinkage long sys_preadv2(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, - unsigned long pos_h, rwf_t flags); -asmlinkage long sys_pwritev2(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, - unsigned long pos_h, rwf_t flags); -asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len, unsigned long prot, int pkey); -asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val); -asmlinkage long sys_pkey_free(int pkey); -asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer); -asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len, int flags, uint32_t sig); -asmlinkage long sys_open_tree(int dfd, const char __user *path, unsigned flags); -asmlinkage long sys_move_mount(int from_dfd, const char __user *from_path, int to_dfd, const char __user *to_path, - unsigned int ms_flags); -asmlinkage long sys_mount_setattr(int dfd, const char __user *path, unsigned int flags, struct mount_attr __user *uattr, - size_t usize); -asmlinkage long sys_fsopen(const char __user *fs_name, unsigned int flags); -asmlinkage long sys_fsconfig(int fs_fd, unsigned int cmd, const char __user *key, const void __user *value, int aux); -asmlinkage long sys_fsmount(int fs_fd, unsigned int flags, unsigned int ms_flags); -asmlinkage long sys_fspick(int dfd, const char __user *path, unsigned int flags); -asmlinkage long sys_pidfd_send_signal(int pidfd, int sig, siginfo_t __user *info, unsigned int flags); -asmlinkage long sys_pidfd_getfd(int pidfd, int fd, unsigned int flags); -asmlinkage long sys_landlock_create_ruleset(const struct landlock_ruleset_attr __user *attr, size_t size, __u32 flags); -asmlinkage long sys_landlock_add_rule(int ruleset_fd, enum landlock_rule_type rule_type, const void __user *rule_attr, - __u32 flags); -asmlinkage long sys_landlock_restrict_self(int ruleset_fd, __u32 flags); -asmlinkage long sys_memfd_secret(unsigned int flags); -asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long len, unsigned long home_node, - unsigned long flags); - -/* - * Architecture-specific system calls - */ - -/* arch/x86/kernel/ioport.c */ -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); - -/* pciconfig: alpha, arm, arm64, ia64, sparc */ -asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, - void __user *buf); -asmlinkage long sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, - void __user *buf); -asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn); - -/* powerpc */ -asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus); -asmlinkage long sys_spu_create(const char __user *name, unsigned int flags, umode_t mode, int fd); - -/* - * Deprecated system calls which are still defined in - * include/uapi/asm-generic/unistd.h and wanted by >= 1 arch - */ - -/* __ARCH_WANT_SYSCALL_NO_AT */ -asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode); -asmlinkage long sys_link(const char __user *oldname, const char __user *newname); -asmlinkage long sys_unlink(const char __user *pathname); -asmlinkage long sys_mknod(const char __user *filename, umode_t mode, unsigned dev); -asmlinkage long sys_chmod(const char __user *filename, umode_t mode); -asmlinkage long sys_chown(const char __user *filename, uid_t user, gid_t group); -asmlinkage long sys_mkdir(const char __user *pathname, umode_t mode); -asmlinkage long sys_rmdir(const char __user *pathname); -asmlinkage long sys_lchown(const char __user *filename, uid_t user, gid_t group); -asmlinkage long sys_access(const char __user *filename, int mode); -asmlinkage long sys_rename(const char __user *oldname, const char __user *newname); -asmlinkage long sys_symlink(const char __user *old, const char __user *new); -asmlinkage long sys_stat64(const char __user *filename, struct stat64 __user *statbuf); -asmlinkage long sys_lstat64(const char __user *filename, struct stat64 __user *statbuf); - -asmlinkage long sys_pipe(int __user *fildes); -asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd); -asmlinkage long sys_epoll_create(int size); -asmlinkage long sys_inotify_init(void); -asmlinkage long sys_eventfd(unsigned int count); -asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask); - -/* __ARCH_WANT_SYSCALL_OFF_T */ -asmlinkage long sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count); -asmlinkage long sys_newstat(const char __user *filename, struct stat __user *statbuf); -asmlinkage long sys_newlstat(const char __user *filename, struct stat __user *statbuf); -asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice); - -/* __ARCH_WANT_SYSCALL_DEPRECATED */ -asmlinkage long sys_alarm(unsigned int seconds); -asmlinkage long sys_getpgrp(void); -asmlinkage long sys_pause(void); -asmlinkage long sys_time(__kernel_old_time_t __user *tloc); -asmlinkage long sys_time32(old_time32_t __user *tloc); -asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times); -asmlinkage long sys_utimes(char __user *filename, struct __kernel_old_timeval __user *utimes); -asmlinkage long sys_futimesat(int dfd, const char __user *filename, struct __kernel_old_timeval __user *utimes); -asmlinkage long sys_futimesat_time32(unsigned int dfd, const char __user *filename, struct old_timeval32 __user *t); -asmlinkage long sys_utime32(const char __user *filename, struct old_utimbuf32 __user *t); -asmlinkage long sys_utimes_time32(const char __user *filename, struct old_timeval32 __user *t); -asmlinkage long sys_creat(const char __user *pathname, umode_t mode); -asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user *dirent, unsigned int count); -asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, - struct __kernel_old_timeval __user *tvp); -asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, int timeout); -asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, int maxevents, int timeout); -asmlinkage long sys_ustat(unsigned dev, struct ustat __user *ubuf); -asmlinkage long sys_vfork(void); -asmlinkage long sys_recv(int, void __user *, size_t, unsigned); -asmlinkage long sys_send(int, void __user *, size_t, unsigned); -asmlinkage long sys_oldumount(char __user *name); -asmlinkage long sys_uselib(const char __user *library); -asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2); -asmlinkage long sys_fork(void); - -/* obsolete: kernel/time/time.c */ -asmlinkage long sys_stime(__kernel_old_time_t __user *tptr); -asmlinkage long sys_stime32(old_time32_t __user *tptr); - -/* obsolete: kernel/signal.c */ -asmlinkage long sys_sigpending(old_sigset_t __user *uset); -asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set, old_sigset_t __user *oset); -asmlinkage long sys_sigsuspend(old_sigset_t mask); - -#ifdef CONFIG_OLD_SIGSUSPEND3 -asmlinkage long sys_sigsuspend(int unused1, int unused2, old_sigset_t mask); -#endif - -asmlinkage long sys_sigaction(int, const struct old_sigaction __user *, struct old_sigaction __user *); - -asmlinkage long sys_sgetmask(void); -asmlinkage long sys_ssetmask(int newmask); -asmlinkage long sys_signal(int sig, __sighandler_t handler); - -/* obsolete: kernel/sched/core.c */ -asmlinkage long sys_nice(int increment); - -/* obsolete: kernel/kexec_file.c */ -asmlinkage long sys_kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, - const char __user *cmdline_ptr, unsigned long flags); - -/* obsolete: kernel/exit.c */ -asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options); - -/* obsolete: kernel/uid16.c */ -asmlinkage long sys_chown16(const char __user *filename, old_uid_t user, old_gid_t group); -asmlinkage long sys_lchown16(const char __user *filename, old_uid_t user, old_gid_t group); -asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group); -asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid); -asmlinkage long sys_setgid16(old_gid_t gid); -asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid); -asmlinkage long sys_setuid16(old_uid_t uid); -asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid); -asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid); -asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid); -asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid); -asmlinkage long sys_setfsuid16(old_uid_t uid); -asmlinkage long sys_setfsgid16(old_gid_t gid); -asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist); -asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist); -asmlinkage long sys_getuid16(void); -asmlinkage long sys_geteuid16(void); -asmlinkage long sys_getgid16(void); -asmlinkage long sys_getegid16(void); - -/* obsolete: net/socket.c */ -asmlinkage long sys_socketcall(int call, unsigned long __user *args); - -/* obsolete: fs/stat.c */ -asmlinkage long sys_stat(const char __user *filename, struct __old_kernel_stat __user *statbuf); -asmlinkage long sys_lstat(const char __user *filename, struct __old_kernel_stat __user *statbuf); -asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat __user *statbuf); -asmlinkage long sys_readlink(const char __user *path, char __user *buf, int bufsiz); - -/* obsolete: fs/select.c */ -asmlinkage long sys_old_select(struct sel_arg_struct __user *arg); - -/* obsolete: fs/readdir.c */ -asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int); - -/* obsolete: kernel/sys.c */ -asmlinkage long sys_gethostname(char __user *name, int len); -asmlinkage long sys_uname(struct old_utsname __user *); -asmlinkage long sys_olduname(struct oldold_utsname __user *); - -#ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT -asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim); -#endif - -/* obsolete: ipc */ -asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second, unsigned long third, void __user *ptr, - long fifth); - -/* obsolete: mm/ */ -asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg); - -/* - * Not a real system call, but a placeholder for syscalls which are - * not implemented -- see kernel/sys_ni.c - */ -asmlinkage long sys_ni_syscall(void); - -/* - * Kernel code should not call syscalls (i.e., sys_xyzyyz()) directly. - * Instead, use one of the functions which work equivalently, such as - * the ksys_xyzyyz() functions prototyped below. - */ -ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count); -int ksys_fchown(unsigned int fd, uid_t user, gid_t group); -ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count); -void ksys_sync(void); -int ksys_unshare(unsigned long unshare_flags); -int ksys_setsid(void); -int ksys_sync_file_range(int fd, loff_t offset, loff_t nbytes, unsigned int flags); -ssize_t ksys_pread64(unsigned int fd, char __user *buf, size_t count, loff_t pos); -ssize_t ksys_pwrite64(unsigned int fd, const char __user *buf, size_t count, loff_t pos); -int ksys_fallocate(int fd, int mode, loff_t offset, loff_t len); -int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice); - -unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -ssize_t ksys_readahead(int fd, loff_t offset, size_t count); -int ksys_ipc(unsigned int call, int first, unsigned long second, unsigned long third, void __user *ptr, long fifth); -int compat_ksys_ipc(u32 call, int first, int second, u32 third, u32 ptr, u32 fifth); - -long ksys_chown(const char __user *filename, uid_t user, gid_t group); -long ksys_lchown(const char __user *filename, uid_t user, gid_t group); -long ksys_ftruncate(unsigned int fd, loff_t length); -long ksys_truncate(const char __user *pathname, loff_t length); -unsigned int ksys_personality(unsigned int personality); - -/* for __ARCH_WANT_SYS_IPC */ -long ksys_semtimedop(int semid, struct sembuf __user *tsops, unsigned int nsops, - const struct __kernel_timespec __user *timeout); -long ksys_semget(key_t key, int nsems, int semflg); -long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg); -long ksys_msgget(key_t key, int msgflg); -long ksys_old_msgctl(int msqid, int cmd, struct msqid_ds __user *buf); -long ksys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg); -long ksys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg); -long ksys_shmget(key_t key, size_t size, int shmflg); -long ksys_shmdt(char __user *shmaddr); -long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); -long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, unsigned int nsops, - const struct old_timespec32 __user *timeout); -long __do_semtimedop(int semid, struct sembuf *tsems, unsigned int nsops, const struct timespec64 *timeout, - struct ipc_namespace *ns); - -int __sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen); -int __sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen); - #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/trace_seq.h b/kernel/linux/include/linux/trace_seq.h index 99f5d7dc..eddf47e4 100644 --- a/kernel/linux/include/linux/trace_seq.h +++ b/kernel/linux/include/linux/trace_seq.h @@ -5,21 +5,30 @@ #include #include -struct trace_seq -{ - // unsigned char buffer[PAGE_SIZE]; - unsigned char buffer[4096]; - unsigned int len; - unsigned int readpos; - int full; -}; +// 3.18 +// struct trace_seq +// { +// unsigned char buffer[PAGE_SIZE]; +// unsigned int len; +// unsigned int readpos; +// int full; +// }; -static inline void trace_seq_init(struct trace_seq *s) -{ - s->len = 0; - s->readpos = 0; - s->full = 0; -} +// 4.4 +// struct trace_seq { +// char buffer[PAGE_SIZE]; +// struct seq_buf seq; +// int full; +// }; + +// static inline void trace_seq_init(struct trace_seq *s) +// { +// s->len = 0; +// s->readpos = 0; +// s->full = 0; +// } + +struct trace_seq; extern int kfunc_def(trace_seq_printf)(struct trace_seq *s, const char *fmt, ...); extern int kfunc_def(trace_seq_to_user)(struct trace_seq *s, char __user *ubuf, int cnt); @@ -78,13 +87,4 @@ static inline int trace_seq_bitmask(struct trace_seq *s, const unsigned long *ma return 0; } -// todo: PAGE_SIZE -static inline int trace_seq_copy_to_user(void __user *to, const void *from, int n) -{ - struct trace_seq trace_seq; - trace_seq_init(&trace_seq); - trace_seq_putmem(&trace_seq, from, n); - return trace_seq_to_user(&trace_seq, to, n); -} - #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/uaccess.h b/kernel/linux/include/linux/uaccess.h index 308fed31..f6d3c57c 100644 --- a/kernel/linux/include/linux/uaccess.h +++ b/kernel/linux/include/linux/uaccess.h @@ -3,8 +3,6 @@ #include #include -#include -#include #define get_fs() (current_thread_info()->addr_limit) @@ -13,33 +11,46 @@ // unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n); // unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n); +// >= 5.8, On success, returns the length of the string INCLUDING the trailing NUL. +extern long kfunc_def(strncpy_from_user_nofault)(char *dst, const void __user *unsafe_addr, long count); +// >= 5.3, On success, returns the length of the string INCLUDING the trailing NUL. +extern long kfunc_def(strncpy_from_unsafe_user)(char *dst, const void __user *unsafe_addr, long count); +// all, On success, returns the length of the string (not including the trailing* NUL). extern long kfunc_def(strncpy_from_user)(char *dest, const char __user *src, long count); -extern __must_check long kfunc_def(strnlen_user)(const char __user *str, long n); -static inline long strncpy_from_user(char *dest, const char __user *src, long count) +// Unlike strnlen_user, this can be used from IRQ handler etc. because it disables pagefaults. +extern long kfunc_def(strnlen_user_nofault)(const void __user *unsafe_addr, long count); +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); + +// On success, returns the length of the string INCLUDING the trailing NUL. +static inline long strncpy_from_user_nofault(char *dest, const char __user *src, long count) { - kfunc_call(strncpy_from_user, dest, src, count); + kfunc_call(strncpy_from_user_nofault, dest, src, count); + kfunc_call(strncpy_from_unsafe_user, dest, src, count); + if (kfunc(strncpy_from_user)) { + // todo: maybe fault + long rc = kfunc(strncpy_from_user)(dest, src, count); + if (rc > 0) return rc + 1; + return rc; + } kfunc_not_found(); return 0; } -static inline __must_check long strnlen_user(const char __user *str, long n) +static inline long strnlen_user_nofault(const char __user *str, long n) { - kfunc_call(strnlen_user, str, n); + kfunc_call(strnlen_user_nofault, str, n); + kfunc_call(strnlen_unsafe_user, str, n); kfunc_not_found(); return 0; } -static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) +static inline long strnlen_user(const char __user *str, long n) { - int copy_len; - if (kfunc(seq_buf_to_user)) { - copy_len = seq_buf_copy_to_user((void *__user)to, from, n); - } else { - // todo: malloc - copy_len = trace_seq_copy_to_user((void *__user)to, from, n); - } - return copy_len; + kfunc_call(strnlen_user, str, n); + kfunc_not_found(); + return 0; } #endif \ No newline at end of file diff --git a/kernel/linux/include/linux/vmalloc.h b/kernel/linux/include/linux/vmalloc.h index db148c4f..e9cc2fcf 100644 --- a/kernel/linux/include/linux/vmalloc.h +++ b/kernel/linux/include/linux/vmalloc.h @@ -3,6 +3,8 @@ #include #include +#include +#include typedef size_t pgprot_t; @@ -28,6 +30,9 @@ struct vm_struct unsigned long size; unsigned long flags; struct page **pages; +#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC + unsigned int page_order; +#endif unsigned int nr_pages; phys_addr_t phys_addr; const void *caller; @@ -66,9 +71,11 @@ extern void *kfunc_def(vzalloc_node)(unsigned long size, int node); extern void *kfunc_def(vmalloc_32)(unsigned long size); extern void *kfunc_def(vmalloc_32_user)(unsigned long size); extern void *kfunc_def(__vmalloc)(unsigned long size, gfp_t gfp_mask); + extern void *kfunc_def(__vmalloc_node_range)(unsigned long size, unsigned long align, unsigned long start, unsigned long end, gfp_t gfp_mask, pgprot_t prot, unsigned long vm_flags, int node, const void *caller); + extern void *kfunc_def(__vmalloc_node)(unsigned long size, unsigned long align, gfp_t gfp_mask, int node, const void *caller); @@ -90,12 +97,6 @@ extern void kfunc_def(free_vm_area)(struct vm_struct *area); extern struct vm_struct *kfunc_def(remove_vm_area)(const void *addr); extern struct vm_struct *kfunc_def(find_vm_area)(const void *addr); -extern int kfunc_def(map_kernel_range_noflush)(unsigned long start, unsigned long size, pgprot_t prot, - struct page **pages); -extern int kfunc_def(map_kernel_range)(unsigned long start, unsigned long size, pgprot_t prot, struct page **pages); -extern void kfunc_def(unmap_kernel_range_noflush)(unsigned long addr, unsigned long size); -extern void kfunc_def(unmap_kernel_range)(unsigned long addr, unsigned long size); - /* for /dev/kmem */ extern long kfunc_def(vread)(char *buf, char *addr, unsigned long count); extern long kfunc_def(vwrite)(char *buf, char *addr, unsigned long count); @@ -159,20 +160,33 @@ static inline void *vmalloc_32_user(unsigned long size) kfunc_not_found(); return 0; } + static inline void *__vmalloc(unsigned long size, gfp_t gfp_mask) { kfunc_call(__vmalloc, size, gfp_mask); kfunc_not_found(); return 0; } + static inline void *__vmalloc_node_range(unsigned long size, unsigned long align, unsigned long start, unsigned long end, gfp_t gfp_mask, pgprot_t prot, unsigned long vm_flags, int node, const void *caller) { - kfunc_call(__vmalloc_node_range, size, align, start, end, gfp_mask, prot, vm_flags, node, caller); + if (likely(kver >= VERSION(4, 0, 0))) { + kfunc_call(__vmalloc_node_range, size, align, start, end, gfp_mask, prot, vm_flags, node, caller); + } else { + void *(*__vmalloc_node_range_legacy)(unsigned long size, unsigned long align, unsigned long start, + unsigned long end, gfp_t gfp_mask, pgprot_t prot, int node, + const void *caller) = + (typeof(__vmalloc_node_range_legacy))kfunc(__vmalloc_node_range); + if (__vmalloc_node_range_legacy) + return __vmalloc_node_range_legacy(size, align, start, end, gfp_mask, prot, node, caller); + } + kfunc_not_found(); return 0; } + static inline void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask, int node, const void *caller) @@ -187,6 +201,7 @@ static inline void vfree(const void *addr) kfunc_call(vfree, addr); kfunc_not_found(); } + static inline void vfree_atomic(const void *addr) { kfunc_call(vfree_atomic, addr); @@ -261,29 +276,6 @@ static inline struct vm_struct *find_vm_area(const void *addr) return 0; } -static inline int map_kernel_range_noflush(unsigned long start, unsigned long size, pgprot_t prot, struct page **pages) -{ - kfunc_call(map_kernel_range_noflush, start, size, prot, pages); - kfunc_not_found(); - return 0; -} -static inline int map_kernel_range(unsigned long start, unsigned long size, pgprot_t prot, struct page **pages) -{ - kfunc_call(map_kernel_range_noflush, start, size, prot, pages); - kfunc_not_found(); - return 0; -} -static inline void unmap_kernel_range_noflush(unsigned long addr, unsigned long size) -{ - kfunc_call(unmap_kernel_range_noflush, addr, size); - kfunc_not_found(); -} -static inline void unmap_kernel_range(unsigned long addr, unsigned long size) -{ - kfunc_call(unmap_kernel_range, addr, size); - kfunc_not_found(); -} - /* for /dev/kmem */ static inline long vread(char *buf, char *addr, unsigned long count) { diff --git a/kernel/linux/include/uapi/asm-generic/errno.h b/kernel/linux/include/uapi/asm-generic/errno.h index 754411b0..6b14a71e 100644 --- a/kernel/linux/include/uapi/asm-generic/errno.h +++ b/kernel/linux/include/uapi/asm-generic/errno.h @@ -1,7 +1,7 @@ #ifndef _ASM_GENERIC_ERRNO_H #define _ASM_GENERIC_ERRNO_H -// #include +#include #define EDEADLK 35 /* Resource deadlock would occur */ #define ENAMETOOLONG 36 /* File name too long */ diff --git a/kernel/linux/include/uapi/asm-generic/fcntl.h b/kernel/linux/include/uapi/asm-generic/fcntl.h new file mode 100644 index 00000000..6d0fd4eb --- /dev/null +++ b/kernel/linux/include/uapi/asm-generic/fcntl.h @@ -0,0 +1,225 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _ASM_GENERIC_FCNTL_H +#define _ASM_GENERIC_FCNTL_H + +#include + +/* + * FMODE_EXEC is 0x20 + * FMODE_NONOTIFY is 0x4000000 + * These cannot be used by userspace O_* until internal and external open + * flags are split. + * -Eric Paris + */ + +/* + * When introducing new O_* bits, please check its uniqueness in fcntl_init(). + */ + +#define O_ACCMODE 00000003 +#define O_RDONLY 00000000 +#define O_WRONLY 00000001 +#define O_RDWR 00000002 +#ifndef O_CREAT +#define O_CREAT 00000100 /* not fcntl */ +#endif +#ifndef O_EXCL +#define O_EXCL 00000200 /* not fcntl */ +#endif +#ifndef O_NOCTTY +#define O_NOCTTY 00000400 /* not fcntl */ +#endif +#ifndef O_TRUNC +#define O_TRUNC 00001000 /* not fcntl */ +#endif +#ifndef O_APPEND +#define O_APPEND 00002000 +#endif +#ifndef O_NONBLOCK +#define O_NONBLOCK 00004000 +#endif +#ifndef O_DSYNC +#define O_DSYNC 00010000 /* used to be O_SYNC, see below */ +#endif +#ifndef FASYNC +#define FASYNC 00020000 /* fcntl, for BSD compatibility */ +#endif +#ifndef O_DIRECT +#define O_DIRECT 00040000 /* direct disk access hint */ +#endif +#ifndef O_LARGEFILE +#define O_LARGEFILE 00100000 +#endif +#ifndef O_DIRECTORY +#define O_DIRECTORY 00200000 /* must be a directory */ +#endif +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 00400000 /* don't follow links */ +#endif +#ifndef O_NOATIME +#define O_NOATIME 01000000 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 02000000 /* set close_on_exec */ +#endif + +/* + * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using + * the O_SYNC flag. We continue to use the existing numerical value + * for O_DSYNC semantics now, but using the correct symbolic name for it. + * This new value is used to request true Posix O_SYNC semantics. It is + * defined in this strange way to make sure applications compiled against + * new headers get at least O_DSYNC semantics on older kernels. + * + * This has the nice side-effect that we can simply test for O_DSYNC + * wherever we do not care if O_DSYNC or O_SYNC is used. + * + * Note: __O_SYNC must never be used directly. + */ +#ifndef O_SYNC +#define __O_SYNC 04000000 +#define O_SYNC (__O_SYNC | O_DSYNC) +#endif + +#ifndef O_PATH +#define O_PATH 010000000 +#endif + +#ifndef __O_TMPFILE +#define __O_TMPFILE 020000000 +#endif + +/* a horrid kludge trying to make sure that this will fail on old kernels */ +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) + +#ifndef O_NDELAY +#define O_NDELAY O_NONBLOCK +#endif + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get close_on_exec */ +#define F_SETFD 2 /* set/clear close_on_exec */ +#define F_GETFL 3 /* get file->f_flags */ +#define F_SETFL 4 /* set file->f_flags */ +#ifndef F_GETLK +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 +#endif +#ifndef F_SETOWN +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ +#endif +#ifndef F_SETSIG +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ +#endif + +#if __BITS_PER_LONG == 32 || defined(__KERNEL__) +#ifndef F_GETLK64 +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 +#endif +#endif /* __BITS_PER_LONG == 32 || defined(__KERNEL__) */ + +#ifndef F_SETOWN_EX +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 +#endif + +#ifndef F_GETOWNER_UIDS +#define F_GETOWNER_UIDS 17 +#endif + +/* + * Open File Description Locks + * + * Usually record locks held by a process are released on *any* close and are + * not inherited across a fork(). + * + * These cmd values will set locks that conflict with process-associated + * record locks, but are "owned" by the open file description, not the + * process. This means that they are inherited across fork() like BSD (flock) + * locks, and they are only released automatically when the last reference to + * the the open file against which they were acquired is put. + */ +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_OWNER_TID 0 +#define F_OWNER_PID 1 +#define F_OWNER_PGRP 2 + +struct f_owner_ex +{ + int type; + __kernel_pid_t pid; +}; + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#ifndef F_RDLCK +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 +#endif + +/* for old implementation of bsd flock () */ +#ifndef F_EXLCK +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ +#endif + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB \ + 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +/* + * LOCK_MAND support has been removed from the kernel. We leave the symbols + * here to not break legacy builds, but these should not be used in new code. + */ +#define LOCK_MAND 32 /* This is a mandatory flock ... */ +#define LOCK_READ 64 /* which allows concurrent read operations */ +#define LOCK_WRITE 128 /* which allows concurrent write operations */ +#define LOCK_RW 192 /* which allows concurrent read & write ops */ + +#define F_LINUX_SPECIFIC_BASE 1024 + +#ifndef HAVE_ARCH_STRUCT_FLOCK +struct flock +{ + short l_type; + short l_whence; + __kernel_off_t l_start; + __kernel_off_t l_len; + __kernel_pid_t l_pid; +#ifdef __ARCH_FLOCK_EXTRA_SYSID + __ARCH_FLOCK_EXTRA_SYSID +#endif +#ifdef __ARCH_FLOCK_PAD + __ARCH_FLOCK_PAD +#endif +}; + +struct flock64 +{ + short l_type; + short l_whence; + __kernel_loff_t l_start; + __kernel_loff_t l_len; + __kernel_pid_t l_pid; +#ifdef __ARCH_FLOCK64_PAD + __ARCH_FLOCK64_PAD +#endif +}; +#endif /* HAVE_ARCH_STRUCT_FLOCK */ + +#endif /* _ASM_GENERIC_FCNTL_H */ \ No newline at end of file diff --git a/kernel/linux/include/uapi/linux/capability.h b/kernel/linux/include/uapi/linux/capability.h index 6a43b30a..1c58c31f 100644 --- a/kernel/linux/include/uapi/linux/capability.h +++ b/kernel/linux/include/uapi/linux/capability.h @@ -392,6 +392,6 @@ struct vfs_ns_cap_data */ #define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */ -#define CAP_TO_MASK(x) (1U << ((x)&31)) /* mask for indexed __u32 */ +#define CAP_TO_MASK(x) (1U << ((x) & 31)) /* mask for indexed __u32 */ #endif \ No newline at end of file diff --git a/kernel/linux/include/uapi/linux/elf.h b/kernel/linux/include/uapi/linux/elf.h new file mode 100644 index 00000000..8e30e8db --- /dev/null +++ b/kernel/linux/include/uapi/linux/elf.h @@ -0,0 +1,475 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_ELF_H +#define _UAPI_LINUX_ELF_H + +#include +#include + +/* 32-bit ELF base types. */ +typedef __u32 Elf32_Addr; +typedef __u16 Elf32_Half; +typedef __u32 Elf32_Off; +typedef __s32 Elf32_Sword; +typedef __u32 Elf32_Word; + +/* 64-bit ELF base types. */ +typedef __u64 Elf64_Addr; +typedef __u16 Elf64_Half; +typedef __s16 Elf64_SHalf; +typedef __u64 Elf64_Off; +typedef __s32 Elf64_Sword; +typedef __u32 Elf64_Word; +typedef __u64 Elf64_Xword; +typedef __s64 Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_GNU_PROPERTY 0x6474e553 + +#define PT_GNU_STACK (PT_LOOS + 0x474e551) + +/* + * Extended Numbering + * + * If the real number of program header table entries is larger than + * or equal to PN_XNUM(0xffff), it is set to sh_info field of the + * section header at index 0, and PN_XNUM is set to e_phnum + * field. Otherwise, the section header at index 0 is zero + * initialized, if it exists. + * + * Specifications are available in: + * + * - Oracle: Linker and Libraries. + * Part No: 817–1984–19, August 2011. + * https://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf + * + * - System V ABI AMD64 Architecture Processor Supplement + * Draft Version 0.99.4, + * January 13, 2010. + * http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf + */ +#define PN_XNUM 0xffff + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +typedef struct dynamic +{ + Elf32_Sword d_tag; + union + { + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* entry tag value */ + union + { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + +typedef struct elf32_rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym +{ + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + +#define EI_NIDENT 16 + +typedef struct elf32_hdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr +{ + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_RELA_LIVEPATCH 0x00100000 +#define SHF_RO_AFTER_INIT 0x00200000 +#define SHF_MASKPROC 0xf0000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_LIVEPATCH 0xff20 +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +typedef struct elf32_shdr +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr +{ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 + +#ifndef ELF_OSABI +#define ELF_OSABI ELFOSABI_NONE +#endif + +/* + * Notes used in ET_CORE. Architectures export some of the arch register sets + * using the corresponding note types via the PTRACE_GETREGSET and + * PTRACE_SETREGSET requests. + * The note name for all these is "LINUX". + */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +/* + * Note to userspace developers: size of NT_SIGINFO note may increase + * in the future to accomodate more fields, don't assume it is fixed! + */ +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_PPC_TAR 0x103 /* Target Address Register */ +#define NT_PPC_PPR 0x104 /* Program Priority Register */ +#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */ +#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */ +#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */ +#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ +#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ +#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ +#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ +#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ +#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address Register */ +#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority Register */ +#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control Register */ +#define NT_PPC_PKEY 0x110 /* Memory Protection Keys registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ +#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ +#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ +#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */ +#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ +#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */ +#define NT_S390_GS_BC 0x30c /* s390 guarded storage broadcast control block */ +#define NT_S390_RI_CB 0x30d /* s390 runtime instrumentation */ +#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ +#define NT_ARM_TLS 0x401 /* ARM TLS register */ +#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ +#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ +#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ +#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */ +#define NT_ARM_PAC_MASK 0x406 /* ARM pointer authentication code masks */ +#define NT_ARM_PACA_KEYS 0x407 /* ARM pointer authentication address keys */ +#define NT_ARM_PACG_KEYS 0x408 /* ARM pointer authentication generic key */ +#define NT_ARM_TAGGED_ADDR_CTRL 0x409 /* arm64 tagged address control (prctl()) */ +#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */ +#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */ +#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */ +#define NT_MIPS_FP_MODE 0x801 /* MIPS floating-point mode */ +#define NT_MIPS_MSA 0x802 /* MIPS SIMD registers */ + +/* Note types with note name "GNU" */ +#define NT_GNU_PROPERTY_TYPE_0 5 + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note +{ + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note +{ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; + +/* .note.gnu.property types for EM_AARCH64: */ +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 + +/* Bits for GNU_PROPERTY_AARCH64_FEATURE_1_BTI */ +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0) + +#endif /* _UAPI_LINUX_ELF_H */ \ No newline at end of file diff --git a/kernel/linux/include/uapi/linux/fs.h b/kernel/linux/include/uapi/linux/fs.h new file mode 100644 index 00000000..cd2b82bc --- /dev/null +++ b/kernel/linux/include/uapi/linux/fs.h @@ -0,0 +1,282 @@ +#ifndef _UAPI_LINUX_FS_H +#define _UAPI_LINUX_FS_H + +#include + +/* Fixed constants first: */ +#undef NR_OPEN +#define INR_OPEN_CUR 1024 /* Initial setting for nfile rlimits */ +#define INR_OPEN_MAX 4096 /* Hard limit for nfile rlimits */ + +#define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1 << BLOCK_SIZE_BITS) + +#define SEEK_SET 0 /* seek relative to beginning of file */ +#define SEEK_CUR 1 /* seek relative to current file position */ +#define SEEK_END 2 /* seek relative to end of file */ +#define SEEK_DATA 3 /* seek to the next data */ +#define SEEK_HOLE 4 /* seek to the next hole */ +#define SEEK_MAX SEEK_HOLE + +#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */ +#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ +#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */ + +struct file_clone_range +{ + __s64 src_fd; + __u64 src_offset; + __u64 src_length; + __u64 dest_offset; +}; + +struct fstrim_range +{ + __u64 start; + __u64 len; + __u64 minlen; +}; + +/* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */ +#define FILE_DEDUPE_RANGE_SAME 0 +#define FILE_DEDUPE_RANGE_DIFFERS 1 + +/* from struct btrfs_ioctl_file_extent_same_info */ +struct file_dedupe_range_info +{ + __s64 dest_fd; /* in - destination file */ + __u64 dest_offset; /* in - start of extent in destination */ + __u64 bytes_deduped; /* out - total # of bytes we were able + * to dedupe from this file. */ + /* status of this dedupe operation: + * < 0 for error + * == FILE_DEDUPE_RANGE_SAME if dedupe succeeds + * == FILE_DEDUPE_RANGE_DIFFERS if data differs + */ + __s32 status; /* out - see above description */ + __u32 reserved; /* must be zero */ +}; + +/* from struct btrfs_ioctl_file_extent_same_args */ +struct file_dedupe_range +{ + __u64 src_offset; /* in - start of extent in source */ + __u64 src_length; /* in - length of extent */ + __u16 dest_count; /* in - total elements in info array */ + __u16 reserved1; /* must be zero */ + __u32 reserved2; /* must be zero */ + struct file_dedupe_range_info info[]; +}; + +/* And dynamically-tunable limits and defaults: */ +struct files_stat_struct +{ + unsigned long nr_files; /* read only */ + unsigned long nr_free_files; /* read only */ + unsigned long max_files; /* tunable */ +}; + +struct inodes_stat_t +{ + long nr_inodes; + long nr_unused; + long dummy[5]; /* padding for sysctl ABI compatibility */ +}; + +#define NR_FILE 8192 /* this can well be larger on a larger system */ + +/* + * Structure for FS_IOC_FSGETXATTR[A] and FS_IOC_FSSETXATTR. + */ +struct fsxattr +{ + __u32 fsx_xflags; /* xflags field value (get/set) */ + __u32 fsx_extsize; /* extsize field value (get/set)*/ + __u32 fsx_nextents; /* nextents field value (get) */ + __u32 fsx_projid; /* project identifier (get/set) */ + __u32 fsx_cowextsize; /* CoW extsize field value (get/set)*/ + unsigned char fsx_pad[8]; +}; + +/* + * Flags for the fsx_xflags field + */ +#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ +#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ +#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ +#define FS_XFLAG_APPEND 0x00000010 /* all writes append */ +#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ +#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */ +#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ +#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ +#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ +#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ +#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ +#define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ +#define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ +#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ +#define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */ +#define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */ +#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ + +/* the read-only stuff doesn't really belong here, but any other place is + probably as bad and I don't want to create yet another include file. */ + +#define BLKROSET _IO(0x12, 93) /* set device read-only (0 = read-write) */ +#define BLKROGET _IO(0x12, 94) /* get read-only status (0 = read_write) */ +#define BLKRRPART _IO(0x12, 95) /* re-read partition table */ +#define BLKGETSIZE _IO(0x12, 96) /* return device size /512 (long *arg) */ +#define BLKFLSBUF _IO(0x12, 97) /* flush buffer cache */ +#define BLKRASET _IO(0x12, 98) /* set read ahead for block device */ +#define BLKRAGET _IO(0x12, 99) /* get current read ahead setting */ +#define BLKFRASET _IO(0x12, 100) /* set filesystem (mm/filemap.c) read-ahead */ +#define BLKFRAGET _IO(0x12, 101) /* get filesystem (mm/filemap.c) read-ahead */ +#define BLKSECTSET _IO(0x12, 102) /* set max sectors per request (ll_rw_blk.c) */ +#define BLKSECTGET _IO(0x12, 103) /* get max sectors per request (ll_rw_blk.c) */ +#define BLKSSZGET _IO(0x12, 104) /* get block device sector size */ +#if 0 +#define BLKPG _IO(0x12, 105) /* See blkpg.h */ + +/* Some people are morons. Do not use sizeof! */ + +#define BLKELVGET _IOR(0x12, 106, size_t) /* elevator get */ +#define BLKELVSET _IOW(0x12, 107, size_t) /* elevator set */ +/* This was here just to show that the number is taken - + probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ +#endif +/* A jump here: 108-111 have been used for various private purposes. */ +#define BLKBSZGET _IOR(0x12, 112, size_t) +#define BLKBSZSET _IOW(0x12, 113, size_t) +#define BLKGETSIZE64 _IOR(0x12, 114, size_t) /* return device size in bytes (u64 *arg) */ +#define BLKTRACESETUP _IOWR(0x12, 115, struct blk_user_trace_setup) +#define BLKTRACESTART _IO(0x12, 116) +#define BLKTRACESTOP _IO(0x12, 117) +#define BLKTRACETEARDOWN _IO(0x12, 118) +#define BLKDISCARD _IO(0x12, 119) +#define BLKIOMIN _IO(0x12, 120) +#define BLKIOOPT _IO(0x12, 121) +#define BLKALIGNOFF _IO(0x12, 122) +#define BLKPBSZGET _IO(0x12, 123) +#define BLKDISCARDZEROES _IO(0x12, 124) +#define BLKSECDISCARD _IO(0x12, 125) +#define BLKROTATIONAL _IO(0x12, 126) +#define BLKZEROOUT _IO(0x12, 127) +#define BLKGETDISKSEQ _IOR(0x12, 128, __u64) +/* + * A jump here: 130-136 are reserved for zoned block devices + * (see uapi/linux/blkzoned.h) + */ + +#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ +#define FIBMAP _IO(0x00, 1) /* bmap access */ +#define FIGETBSZ _IO(0x00, 2) /* get the block size used for bmap */ +#define FIFREEZE _IOWR('X', 119, int) /* Freeze */ +#define FITHAW _IOWR('X', 120, int) /* Thaw */ +#define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */ +#define FICLONE _IOW(0x94, 9, int) +#define FICLONERANGE _IOW(0x94, 13, struct file_clone_range) +#define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range) + +#define FSLABEL_MAX 256 /* Max chars for the interface; each fs may differ */ + +#define FS_IOC_GETFLAGS _IOR('f', 1, long) +#define FS_IOC_SETFLAGS _IOW('f', 2, long) +#define FS_IOC_GETVERSION _IOR('v', 1, long) +#define FS_IOC_SETVERSION _IOW('v', 2, long) +#define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap) +#define FS_IOC32_GETFLAGS _IOR('f', 1, int) +#define FS_IOC32_SETFLAGS _IOW('f', 2, int) +#define FS_IOC32_GETVERSION _IOR('v', 1, int) +#define FS_IOC32_SETVERSION _IOW('v', 2, int) +#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) +#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) +#define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX]) +#define FS_IOC_SETFSLABEL _IOW(0x94, 50, char[FSLABEL_MAX]) + +/* + * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS) + * + * Note: for historical reasons, these flags were originally used and + * defined for use by ext2/ext3, and then other file systems started + * using these flags so they wouldn't need to write their own version + * of chattr/lsattr (which was shipped as part of e2fsprogs). You + * should think twice before trying to use these flags in new + * contexts, or trying to assign these flags, since they are used both + * as the UAPI and the on-disk encoding for ext2/3/4. Also, we are + * almost out of 32-bit flags. :-) + * + * We have recently hoisted FS_IOC_FSGETXATTR / FS_IOC_FSSETXATTR from + * XFS to the generic FS level interface. This uses a structure that + * has padding and hence has more room to grow, so it may be more + * appropriate for many new use cases. + * + * Please do not change these flags or interfaces before checking with + * linux-fsdevel@vger.kernel.org and linux-api@vger.kernel.org. + */ +#define FS_SECRM_FL 0x00000001 /* Secure deletion */ +#define FS_UNRM_FL 0x00000002 /* Undelete */ +#define FS_COMPR_FL 0x00000004 /* Compress file */ +#define FS_SYNC_FL 0x00000008 /* Synchronous updates */ +#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define FS_APPEND_FL 0x00000020 /* writes to file may only append */ +#define FS_NODUMP_FL 0x00000040 /* do not dump file */ +#define FS_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define FS_DIRTY_FL 0x00000100 +#define FS_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define FS_NOCOMP_FL 0x00000400 /* Don't compress */ +/* End compression flags --- maybe not all used */ +#define FS_ENCRYPT_FL 0x00000800 /* Encrypted file */ +#define FS_BTREE_FL 0x00001000 /* btree format dir */ +#define FS_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define FS_IMAGIC_FL 0x00002000 /* AFS directory */ +#define FS_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ +#define FS_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define FS_HUGE_FILE_FL 0x00040000 /* Reserved for ext4 */ +#define FS_EXTENT_FL 0x00080000 /* Extents */ +#define FS_VERITY_FL 0x00100000 /* Verity protected inode */ +#define FS_EA_INODE_FL 0x00200000 /* Inode used for large EA */ +#define FS_EOFBLOCKS_FL 0x00400000 /* Reserved for ext4 */ +#define FS_NOCOW_FL 0x00800000 /* Do not cow file */ +#define FS_DAX_FL 0x02000000 /* Inode is DAX */ +#define FS_INLINE_DATA_FL 0x10000000 /* Reserved for ext4 */ +#define FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ +#define FS_CASEFOLD_FL 0x40000000 /* Folder is case insensitive */ +#define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define FS_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ + +#define SYNC_FILE_RANGE_WAIT_BEFORE 1 +#define SYNC_FILE_RANGE_WRITE 2 +#define SYNC_FILE_RANGE_WAIT_AFTER 4 +#define SYNC_FILE_RANGE_WRITE_AND_WAIT \ + (SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WAIT_AFTER) + +/* + * Flags for preadv2/pwritev2: + */ + +typedef int __bitwise __kernel_rwf_t; + +/* high priority request, poll if possible */ +#define RWF_HIPRI ((__force __kernel_rwf_t)0x00000001) + +/* per-IO O_DSYNC */ +#define RWF_DSYNC ((__force __kernel_rwf_t)0x00000002) + +/* per-IO O_SYNC */ +#define RWF_SYNC ((__force __kernel_rwf_t)0x00000004) + +/* per-IO, return -EAGAIN if operation would block */ +#define RWF_NOWAIT ((__force __kernel_rwf_t)0x00000008) + +/* per-IO O_APPEND */ +#define RWF_APPEND ((__force __kernel_rwf_t)0x00000010) + +/* mask of flags supported by the kernel */ +#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT | RWF_APPEND) + +#endif \ No newline at end of file diff --git a/kernel/linux/security/selinux/include/security.h b/kernel/linux/security/selinux/include/security.h index 1e9f6d0d..a1c07ee0 100644 --- a/kernel/linux/security/selinux/include/security.h +++ b/kernel/linux/security/selinux/include/security.h @@ -79,8 +79,8 @@ struct av_decision #define XPERMS_AUDITALLOW 2 #define XPERMS_DONTAUDIT 4 -#define security_xperm_set(perms, x) ((perms)[(x) >> 5] |= 1 << ((x)&0x1f)) -#define security_xperm_test(perms, x) (1 & ((perms)[(x) >> 5] >> ((x)&0x1f))) +#define security_xperm_set(perms, x) ((perms)[(x) >> 5] |= 1 << ((x) & 0x1f)) +#define security_xperm_test(perms, x) (1 & ((perms)[(x) >> 5] >> ((x) & 0x1f))) struct extended_perms_data { diff --git a/kernel/linux/tools/arch/arm64/include/asm/barrier.h b/kernel/linux/tools/arch/arm64/include/asm/barrier.h index ea717b2a..3388b099 100644 --- a/kernel/linux/tools/arch/arm64/include/asm/barrier.h +++ b/kernel/linux/tools/arch/arm64/include/asm/barrier.h @@ -2,75 +2,6 @@ #ifndef _TOOLS_LINUX_ASM_AARCH64_BARRIER_H #define _TOOLS_LINUX_ASM_AARCH64_BARRIER_H -#define mb() asm volatile("dmb ish" ::: "memory") -#define wmb() asm volatile("dmb ishst" ::: "memory") -#define rmb() asm volatile("dmb ishld" ::: "memory") - -/* - * Kernel uses dmb variants on arm64 for smp_*() barriers. Pretty much the same - * implementation as above mb()/wmb()/rmb(), though for the latter kernel uses - * dsb. In any case, should above mb()/wmb()/rmb() change, make sure the below - * smp_*() don't. - */ -#define smp_mb() asm volatile("dmb ish" ::: "memory") -#define smp_wmb() asm volatile("dmb ishst" ::: "memory") -#define smp_rmb() asm volatile("dmb ishld" ::: "memory") - -#define smp_store_release(p, v) \ - do { \ - union \ - { \ - typeof(*p) __val; \ - char __c[1]; \ - } __u = { .__val = (v) }; \ - \ - switch (sizeof(*p)) { \ - case 1: \ - asm volatile("stlrb %w1, %0" : "=Q"(*p) : "r"(*(u8 *)__u.__c) : "memory"); \ - break; \ - case 2: \ - asm volatile("stlrh %w1, %0" : "=Q"(*p) : "r"(*(u16 *)__u.__c) : "memory"); \ - break; \ - case 4: \ - asm volatile("stlr %w1, %0" : "=Q"(*p) : "r"(*(u32 *)__u.__c) : "memory"); \ - break; \ - case 8: \ - asm volatile("stlr %1, %0" : "=Q"(*p) : "r"(*(u64 *)__u.__c) : "memory"); \ - break; \ - default: \ - /* Only to shut up gcc ... */ \ - mb(); \ - break; \ - } \ - } while (0) - -#define smp_load_acquire(p) \ - ({ \ - union \ - { \ - typeof(*p) __val; \ - char __c[1]; \ - } __u = { .__c = { 0 } }; \ - \ - switch (sizeof(*p)) { \ - case 1: \ - asm volatile("ldarb %w0, %1" : "=r"(*(u8 *)__u.__c) : "Q"(*p) : "memory"); \ - break; \ - case 2: \ - asm volatile("ldarh %w0, %1" : "=r"(*(u16 *)__u.__c) : "Q"(*p) : "memory"); \ - break; \ - case 4: \ - asm volatile("ldar %w0, %1" : "=r"(*(u32 *)__u.__c) : "Q"(*p) : "memory"); \ - break; \ - case 8: \ - asm volatile("ldar %0, %1" : "=r"(*(u64 *)__u.__c) : "Q"(*p) : "memory"); \ - break; \ - default: \ - /* Only to shut up gcc ... */ \ - mb(); \ - break; \ - } \ - __u.__val; \ - }) +#include #endif /* _TOOLS_LINUX_ASM_AARCH64_BARRIER_H */ \ No newline at end of file diff --git a/kernel/minc/print.c b/kernel/minc/print.c index 39a1da12..5bf732f2 100644 --- a/kernel/minc/print.c +++ b/kernel/minc/print.c @@ -477,8 +477,7 @@ static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, const #if defined(PRINTF_SUPPORT_FLOAT) case 'f': case 'F': - if (*format == 'F') - flags |= FLAGS_UPPERCASE; + if (*format == 'F') flags |= FLAGS_UPPERCASE; idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); format++; break; @@ -487,10 +486,8 @@ static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, const case 'E': case 'g': case 'G': - if ((*format == 'g') || (*format == 'G')) - flags |= FLAGS_ADAPT_EXP; - if ((*format == 'E') || (*format == 'G')) - flags |= FLAGS_UPPERCASE; + if ((*format == 'g') || (*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E') || (*format == 'G')) flags |= FLAGS_UPPERCASE; idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); format++; break; diff --git a/kernel/minc/stdlib.c b/kernel/minc/stdlib.c index 85397275..b1604351 100644 --- a/kernel/minc/stdlib.c +++ b/kernel/minc/stdlib.c @@ -60,8 +60,7 @@ uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n) n--; nptr++; } - if (endptr) - *endptr = (char *)nptr; + if (endptr) *endptr = (char *)nptr; return minus ? -v : v; } @@ -87,8 +86,7 @@ void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, min_ const void *midobj = (const char *)base + mididx * size; int diff = cmp(key, midobj); - if (diff == 0) - return (void *)midobj; + if (diff == 0) return (void *)midobj; if (diff > 0) { base = (const char *)midobj + size; @@ -103,11 +101,9 @@ void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, min_ static inline size_t newgap(size_t gap) { gap = (gap * 10) / 13; - if (gap == 9 || gap == 10) - gap = 11; + if (gap == 9 || gap == 10) gap = 11; - if (gap < 1) - gap = 1; + if (gap < 1) gap = 1; return gap; } @@ -118,8 +114,7 @@ void qsort(void *base, size_t nmemb, size_t size, min_comparefunc_t cmp) char *p1, *p2; int swapped; - if (!nmemb) - return; + if (!nmemb) return; do { gap = newgap(gap); diff --git a/kernel/minc/string.c b/kernel/minc/string.c index bc0665d8..a89bb97e 100644 --- a/kernel/minc/string.c +++ b/kernel/minc/string.c @@ -10,8 +10,7 @@ void *min_memccpy(void *dst, const void *src, int c, size_t n) char ch; while (n--) { *q++ = ch = *p++; - if (ch == (char)c) - return q; + if (ch == (char)c) return q; } return 0; } @@ -20,8 +19,7 @@ void *min_memchr(const void *s, int c, size_t n) { const unsigned char *sp = s; while (n--) { - if (*sp == (unsigned char)c) - return (void *)sp; + if (*sp == (unsigned char)c) return (void *)sp; sp++; } return 0; @@ -33,13 +31,12 @@ int min_memcmp(const void *s1, const void *s2, size_t n) int d = 0; while (n--) { d = (int)*c1++ - (int)*c2++; - if (d) - break; + if (d) break; } return d; } -void *min_memcpy(void *dst, const void *src, size_t n) +void *memcpy(void *dst, const void *src, size_t n) { const char *p = src; char *q = dst; @@ -56,8 +53,7 @@ void *min_memmem(const void *haystack, size_t n, const void *needle, size_t m) size_t j, k, l; - if (m > n || !m || !n) - return 0; + if (m > n || !m || !n) return 0; if (1 != m) { if (x[0] == x[1]) { @@ -73,15 +69,13 @@ void *min_memmem(const void *haystack, size_t n, const void *needle, size_t m) if (x[1] != y[j + 1]) { j += k; } else { - if (!min_memcmp(x + 2, y + j + 2, m - 2) && x[0] == y[j]) - return (void *)&y[j]; + if (!min_memcmp(x + 2, y + j + 2, m - 2) && x[0] == y[j]) return (void *)&y[j]; j += l; } } } else do { - if (*y == *x) - return (void *)y; + if (*y == *x) return (void *)y; y++; } while (--n); return 0; @@ -111,8 +105,7 @@ void *min_memrchr(const void *s, int c, size_t n) const unsigned char *sp = (const unsigned char *)s + n - 1; while (n--) { - if (*sp == (unsigned char)c) - return (void *)sp; + if (*sp == (unsigned char)c) return (void *)sp; sp--; } @@ -152,8 +145,7 @@ int min_strcasecmp(const char *s1, const char *s2) int d = 0; while (1) { d = min_toupper(ch = *c1++) - min_toupper(*c2++); - if (d || !ch) - break; + if (d || !ch) break; } return d; } @@ -167,8 +159,7 @@ char *min_strcat(char *dst, const char *src) char *min_strchr(const char *s, int c) { while (*s != (char)c) { - if (!*s) - return 0; + if (!*s) return 0; s++; } return (char *)s; @@ -182,8 +173,7 @@ int min_strcmp(const char *s1, const char *s2) int d = 0; while (1) { d = (int)(ch = *c1++) - (int)*c2++; - if (d || !ch) - break; + if (d || !ch) break; } return d; } @@ -210,12 +200,10 @@ size_t min_strlcat(char *dst, const char *src, size_t size) q++; bytes++; } - if (bytes == size) - return (bytes + min_strlen(src)); + if (bytes == size) return (bytes + min_strlen(src)); while ((ch = *p++)) { - if (bytes + 1 < size) - *q++ = ch; + if (bytes + 1 < size) *q++ = ch; bytes++; } @@ -231,13 +219,11 @@ size_t min_strlcpy(char *dst, const char *src, size_t size) char ch; while ((ch = *p++)) { - if (bytes + 1 < size) - *q++ = ch; + if (bytes + 1 < size) *q++ = ch; bytes++; } - if (size) - *q = '\0'; + if (size) *q = '\0'; return bytes; } @@ -257,8 +243,7 @@ int min_strncasecmp(const char *s1, const char *s2, size_t n) int d = 0; while (n--) { d = min_toupper(ch = *c1++) - min_toupper(*c2++); - if (d || !ch) - break; + if (d || !ch) break; } return d; } @@ -270,8 +255,7 @@ char *min_strncat(char *dst, const char *src, size_t n) char ch; while (n--) { *q++ = ch = *p++; - if (!ch) - return dst; + if (!ch) return dst; } *q = '\0'; return dst; @@ -285,8 +269,7 @@ int min_strncmp(const char *s1, const char *s2, size_t n) int d = 0; while (n--) { d = (int)(ch = *c1++) - (int)*c2++; - if (d || !ch) - break; + if (d || !ch) break; } return d; } @@ -299,8 +282,7 @@ char *min_strncpy(char *dst, const char *src, size_t n) while (n) { n--; *q++ = ch = *p++; - if (!ch) - break; + if (!ch) break; } min_memset(q, 0, n); return dst; @@ -319,19 +301,15 @@ size_t min_strnlen(const char *s, size_t maxlen) char *min_strpbrk(const char *s1, const char *s2) { const char *c = s2; - if (!*s1) - return (char *)0; + if (!*s1) return (char *)0; while (*s1) { for (c = s2; *c; c++) { - if (*s1 == *c) - break; + if (*s1 == *c) break; } - if (*c) - break; + if (*c) break; s1++; } - if (*c == '\0') - s1 = 0; + if (*c == '\0') s1 = 0; return (char *)s1; } @@ -339,8 +317,7 @@ char *min_strrchr(const char *s, int c) { const char *found = 0; while (*s) { - if (*s == (char)c) - found = s; + if (*s == (char)c) found = s; s++; } return (char *)found; @@ -350,11 +327,9 @@ char *min_strsep(char **stringp, const char *delim) { char *s = *stringp; char *e; - if (!s) - return 0; + if (!s) return 0; e = min_strpbrk(s, delim); - if (e) - *e++ = '\0'; + if (e) *e++ = '\0'; *stringp = e; return s; } @@ -365,11 +340,9 @@ size_t min_strspn(const char *s1, const char *s2) const char *c; while (*s1) { for (c = s2; *c; c++) { - if (*s1 == *c) - break; + if (*s1 == *c) break; } - if (*c == '\0') - break; + if (*c == '\0') break; s1++; } return s1 - s; @@ -388,8 +361,7 @@ char *min_strtok(char *s, const char *delim) char *min_strtok_r(char *s, const char *delim, char **holder) { - if (s) - *holder = s; + if (s) *holder = s; do { s = min_strsep(holder, delim); } while (s && !*s); diff --git a/kernel/module/hello/Makefile b/kernel/module/hello/Makefile deleted file mode 100644 index 3a5f9b70..00000000 --- a/kernel/module/hello/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -ifndef TARGET_COMPILE - $(error TARGET_COMPILE is not set) -endif - -CC = $(TARGET_COMPILE)gcc -LD = $(TARGET_COMPILE)ld - -CFLAGS = -std=c11 -Wall - -objs := hello.O - -all: kpm_hello - -kpm_hello: hello.o ${objs} - ${CC} -fpic -shared -o $@ $^ - -%.o : %.c - $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ - -.PHONY: clean -clean: - rm -rf kpm_hello - find . -name "*.o" | xargs rm -f \ No newline at end of file diff --git a/kernel/module/hello/hello.c b/kernel/module/hello/hello.c deleted file mode 100644 index a00433ba..00000000 --- a/kernel/module/hello/hello.c +++ /dev/null @@ -1,11 +0,0 @@ - - -int kpm_init() -{ - return 0; -} - -int kpm_uninit() -{ - return 0; -} \ No newline at end of file diff --git a/kernel/module/module.c b/kernel/module/module.c deleted file mode 100644 index 8ec530e3..00000000 --- a/kernel/module/module.c +++ /dev/null @@ -1 +0,0 @@ -#include "module.h" \ No newline at end of file diff --git a/kernel/module/module.h b/kernel/module/module.h deleted file mode 100644 index 07c43f9c..00000000 --- a/kernel/module/module.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _KP_MODULE_H_ -#define _KP_MODULE_H_ - -#define Elf_Shdr Elf64_Shdr -#define Elf_Phdr Elf64_Phdr -#define Elf_Sym Elf64_Sym -#define Elf_Dyn Elf64_Dyn -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Addr Elf64_Addr -#ifdef CONFIG_MODULES_USE_ELF_REL -#define Elf_Rel Elf64_Rel -#endif -#ifdef CONFIG_MODULES_USE_ELF_RELA -#define Elf_Rela Elf64_Rela -#endif -#define ELF_R_TYPE(X) ELF64_R_TYPE(X) -#define ELF_R_SYM(X) ELF64_R_SYM(X) - -#endif \ No newline at end of file diff --git a/kernel/patch/accctl/selinuxhook.c b/kernel/patch/accctl/selinuxhook.c deleted file mode 100644 index 8751e34f..00000000 --- a/kernel/patch/accctl/selinuxhook.c +++ /dev/null @@ -1,187 +0,0 @@ -#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_AVC_RET_ZERO_BEFORE() \ - struct task_ext *ext = get_current_task_ext(); \ - if (task_ext_valid(ext) && ext->selinux_allow) { \ - return 0; \ - } -// #define HOOK_AVC_RET_ZERO_BEFORE() - -#include - -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; -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) -{ - int rc = hook_call_backup(avc_has_perm_noaudit, state, ssid, tsid, tclass, requested, flags, avd); - struct task_ext *ext = get_current_task_ext(); - if (task_ext_valid(ext) && ext->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; - } - rc = 0; - } - return rc; -} - -int hook_backup(avc_has_perm)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, void *requested, - struct common_audit_data *auditdata) = 0; -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; -} - -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; -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 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); -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; -} - -int hook_backup(avc_denied)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, void *requested, - void *driver, void *xperm, void *flags, struct av_decision *avd) = 0; - -int hook_replace(avc_denied)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, void *requested, - void *driver, void *xperm, void *flags, struct av_decision *avd) -{ - HOOK_AVC_RET_ZERO_BEFORE(); - int rc = hook_call_backup(avc_denied, state, ssid, tsid, tclass, requested, driver, xperm, flags, avd); - return rc; -} - -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 -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 (task_ext_valid(ext) && ext->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)); - } - } -} - -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 -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 (task_ext_valid(ext) && ext->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)); - } -} - -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 -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 (task_ext_valid(ext) && ext->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() -{ - hook_kfunc(avc_has_perm_noaudit); - hook_kfunc(avc_has_perm); - hook_kfunc(avc_has_perm_flags); - hook_kfunc(avc_has_extended_perms); - // hook_kfunc(avc_denied); - - 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/accctl/supercall.c b/kernel/patch/accctl/supercall.c deleted file mode 100644 index 010030f9..00000000 --- a/kernel/patch/accctl/supercall.c +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_KEY_LEN 127 - -static inline long call_hello() -{ - logki("KernelPatch Supercall Hello!\n"); - return SUPERCALL_HELLO_MAGIC; -} - -static inline long call_get_kernel_version() -{ - return kver; -} - -static inline long call_get_kp_version() -{ - return kpver; -} - -static long call_load_kpm(const char *path, long len) -{ - return SUPERCALL_RES_NOT_IMPL; -} - -static long call_unload_kpm(const char *path, long len) -{ - return SUPERCALL_RES_NOT_IMPL; -} - -static inline long call_su(const char *sctx) -{ - int ret = commit_su(1, sctx); - return ret; -} - -static long call_thread_su(pid_t pid, const char *sctx) -{ - int ret = SUPERCALL_RES_SUCCEED; - ret = thread_su(pid, sctx); - return ret; -} - -static long call_thread_unsu(pid_t pid) -{ - return SUPERCALL_RES_NOT_IMPL; -} - -static long supercall(long cmd, void *__user arg1, void *__user arg2, void *__user arg3) -{ - logkd("SuperCall with cmd: %x\n", cmd); - - long ret = SUPERCALL_RES_NOT_IMPL; - - if (cmd == SUPERCALL_HELLO) { - ret = call_hello(); - } else if (cmd == SUPERCALL_GET_KERNEL_VERSION) { - ret = kver; - } else if (cmd == SUPERCALL_GET_KP_VERSION) { - ret = kpver; - } else if (cmd == SUPERCALL_LOAD_KPM) { - ret = call_load_kpm(0, 0); - } else if (cmd == SUPERCALL_UNLOAD_KPM) { - ret = call_unload_kpm(0, 0); - } else if (cmd == SUPERCALL_SU) { - char sctx[SUPERCALL_SCONTEXT_LEN + 1]; - sctx[SUPERCALL_SCONTEXT_LEN] = 0; - long len = strncpy_from_user(sctx, (const char *)arg1, SUPERCALL_SCONTEXT_LEN); - ret = call_su(len > 0 ? sctx : 0); - } else if (cmd == SUPERCALL_THREAD_SU) { - pid_t pid = (pid_t)(uintptr_t)arg1; - char sctx[SUPERCALL_SCONTEXT_LEN + 1]; - sctx[SUPERCALL_SCONTEXT_LEN] = 0; - long len = strncpy_from_user(sctx, (const char *)arg2, SUPERCALL_SCONTEXT_LEN); - ret = call_thread_su(pid, len > 0 ? sctx : 0); - } else if (cmd == SUPERCALL_THREAD_UNSU) { - pid_t pid = (pid_t)(uintptr_t)arg1; - ret = call_thread_unsu(pid); - } else { -#ifdef ANDROID - ret = supercall_android(cmd, arg1, arg2, arg3); -#else - ret = SUPERCALL_RES_NOT_IMPL; -#endif - } - return ret; -} - -HOOK_SYSCALL_DEFINE6(__NR_supercall, const char __user *, ukey, long, hash, long, cmd, void *, a1, void *, a2, void *, - a3) -{ - char key[MAX_KEY_LEN + 1] = { '\0' }; - long len = strncpy_from_user(key, ukey, MAX_KEY_LEN); - - if (len <= 0) { - goto ori_call; - } - - if (cmd >= SUPERCALL_MAX || cmd < SUPERCALL_HELLO) { - goto ori_call; - } - - if (superkey_auth(key, len)) { - goto ori_call; - } - - if (hash_key(key) != hash) { - goto ori_call; - } - - return supercall(cmd, a1, a2, a3); - -ori_call: - return HOOK_SYSCALL_CALL_ORIGIN(__NR_supercall, ukey, hash, cmd, a1, a2, a3); -} - -int supercall_install() -{ - // REPLACE_SYSCALL_INSTALL(__NR_supercall); - INLINE_SYSCALL_INSTALL(__NR_supercall); - return 0; -} diff --git a/kernel/patch/android/kpuserd.c b/kernel/patch/android/kpuserd.c new file mode 100644 index 00000000..508bdfad --- /dev/null +++ b/kernel/patch/android/kpuserd.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct module *find_module(const char *name); + +static void load_kpuserd_config() +{ + // todo: private allow + set_selinx_allow(current, 1); + + patch_config_t *config = get_preset_patch_cfg(); + const char *su_config_path = config->su_config_file; + const char *kpm_path = config->test_kpm_file; + + log_boot("config path: %s\n", su_config_path); + log_boot("module path: %s\n", kpm_path); + + // struct file *filp = filp_open(kpm_path, O_RDONLY, 0); + // if (IS_ERR(filp)) { + // log_boot("open: %s error: %d\n", kpm_path, PTR_ERR(filp)); + // goto out; + // } + + // filp_close(filp, 0); + // out: + set_selinx_allow(current, 0); +} + +static void on_post_fs_data() +{ + static bool done = false; + if (done) { + logkw("on_post_fs_data already done\n"); + return; + } + done = true; + load_kpuserd_config(); +} + +#define CONFIG_COMPAT + +struct user_arg_ptr +{ +#ifdef CONFIG_COMPAT + bool is_compat; +#endif + union + { + const char __user *const __user *native; +#ifdef CONFIG_COMPAT + const compat_uptr_t __user *compat; +#endif + } ptr; +}; +static const char __user *get_user_arg_ptr(void *a0, void *a1, int nr) +{ + 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) { + native = (char __user *const __user *)((unsigned long)a1 >> 32); + size = 4; + } + } + native = (char __user *const __user *)((unsigned long)native + nr * size); + char __user **upptr = memdup_user(native, size); + if (IS_ERR(upptr)) { + return ERR_PTR((long)upptr); + } + char __user *uptr; + if (size == 8) { + uptr = *upptr; + } else { + uptr = (char __user *)(unsigned long)*(int32_t *)upptr; + } + kfree(upptr); + return uptr; +} + +/* +Copied and modified from KernelSU, GPLv2 +https://github.com/tiann/KernelSU +*/ + +// int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) +// int __do_execve_file(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags, +// struct file *file); +// static int do_execve_common(struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp) +static void before_do_execve(hook_fargs8_t *args, void *udata) +{ + int filename_index = 0; + if ((((uintptr_t)args->arg0) & 0xF000000000000000) != 0xF000000000000000) { + filename_index = 1; + } + struct filename *filename = (struct filename *)args->args[filename_index]; + + if (!filename || IS_ERR(filename)) return; + + static const char app_process[] = "/system/bin/app_process"; + static bool first_app_process = true; + + /* This applies to versions Android 10+ */ + static const char system_bin_init[] = "/system/bin/init"; + /* This applies to versions between Android 6 ~ 9 */ + static const char old_system_init[] = "/init"; + static bool init_second_stage_executed = false; + + if (!memcmp(filename->name, system_bin_init, sizeof(system_bin_init) - 1) || + !memcmp(filename->name, old_system_init, sizeof(old_system_init) - 1)) { + for (int i = 1; i < 0x7FFFFFFF; i++) { + const char __user *p1 = + get_user_arg_ptr((void *)args->args[filename_index + 1], (void *)args->args[filename_index + 2], i); + + if (p1 && !IS_ERR(p1)) { + char arg[16] = { '\0' }; + if (strncpy_from_user_nofault(arg, p1, sizeof(arg)) <= 0) { + break; + } + if (!min_strcmp(arg, "second_stage")) { + logkd("exec %s second_stage\n", filename->name); + init_second_stage_executed = true; + // apply_kernelsu_rules(); + // ksu_android_ns_fs_check(); + } + } + } + + if (!init_second_stage_executed) { + int envp_index = filename_index + (has_config_compat ? 3 : 2); + for (int i = 0; i < 0x7FFFFFFF; i++) { + const char __user *up = + get_user_arg_ptr((void *)args->args[envp_index], (void *)args->args[envp_index + 1], i); + if (!up || IS_ERR(up)) break; + char env[256]; + if (strncpy_from_user_nofault(env, up, sizeof(env)) <= 0) { + break; + } + // Parsing environment variable names and values + char *env_name = env; + char *env_value = min_strchr(env, '='); + if (env_value) { + // Replace equal sign with string terminator + *env_value = '\0'; + env_value++; + // Check if the environment variable name and value are matching + if (!strcmp(env_name, "INIT_SECOND_STAGE") && + (!strcmp(env_value, "1") || !strcmp(env_value, "true"))) { + logkd("exec %s second_stage\n", filename->name); + init_second_stage_executed = true; + // apply_kernelsu_rules(); + // ksu_android_ns_fs_check(); + } + } + } + } + } + + if (unlikely(first_app_process && !memcmp(filename->name, app_process, sizeof(app_process) - 1))) { + first_app_process = false; + logkd("exec app_process, /data prepared, second_stage: %d\n", init_second_stage_executed); + on_post_fs_data(); + remove_execv_hook(before_do_execve, 0); + } +} + +int kpuserd_init() +{ + int rc = 0; + hook_err_t err = add_execv_hook(before_do_execve, 0, 0); + if (err) { + log_boot("hook add execv error: %d\n", err); + rc = err; + goto out; + } +out: + return rc; +} \ No newline at end of file diff --git a/kernel/patch/android/sucompat.c b/kernel/patch/android/sucompat.c index 47571b00..248bb6d9 100644 --- a/kernel/patch/android/sucompat.c +++ b/kernel/patch/android/sucompat.c @@ -2,10 +2,9 @@ #include #include #include -#include +#include #include #include -#include #include #include #include @@ -16,29 +15,36 @@ #include #include #include +#include #include #include #include +#include #include +#include +#include + +/* +Copy and modified from KernelSU, GPLv2 +https://github.com/tiann/KernelSU +*/ #define INVALID_ALLOW_UID ((uid_t)-1) static char android_su_path[] = "/system/bin/kp"; static const char android_sh_path[] = "/system/bin/sh"; -static const char android_sh_dir[] = "/system/bin/"; static uid_t su_allow_list[32]; static int is_su_allow(uid_t uid) { for (int i = 0; i < SUPERCALL_SU_ALLOW_UID_MAX; i++) { - if (su_allow_list[i] == uid) - return 1; + if (su_allow_list[i] == uid) return 1; } return 0; } -int add_allow_uid(uid_t uid) +int su_add_allow_uid(uid_t uid) { for (int i = 0; i < SUPERCALL_SU_ALLOW_UID_MAX; i++) { if (su_allow_list[i] == INVALID_ALLOW_UID || su_allow_list[i] == uid) { @@ -46,89 +52,71 @@ int add_allow_uid(uid_t uid) return 0; } } - return ERR_CAP_FULL; + return -ENOMEM; } -int remove_allow_uid(uid_t uid) +int su_remove_allow_uid(uid_t uid) { for (int i = 0; i < SUPERCALL_SU_ALLOW_UID_MAX; i++) { if (su_allow_list[i] == uid) { su_allow_list[i] = INVALID_ALLOW_UID; } } - return ERR_NO_ERR; -} - -int reset_su_cmd(const char cmd[3]) -{ - if (cmd[2]) { - return ERR_CAP_FULL; - } - android_su_path[sizeof(android_sh_dir) - 1] = cmd[0]; - android_su_path[sizeof(android_sh_dir)] = cmd[1]; - logkd("reset su to: %s\n", android_su_path); return 0; } -static int list_allow_uids_compat(uid_t __user *uids, size_t __user *size) +int su_allow_uid_nums() { - // uids - struct trace_seq trace_seq; - trace_seq_init(&trace_seq); - size_t num = 0; + int num = 0; for (int i = 0; i < SUPERCALL_SU_ALLOW_UID_MAX; i++) { uid_t uid = su_allow_list[i]; if (uid != INVALID_ALLOW_UID) { - trace_seq_putmem(&trace_seq, &uid, sizeof(uid_t)); num++; } } - trace_seq_to_user(&trace_seq, (char *)uids, num * sizeof(uid_t)); - // size - trace_seq_init(&trace_seq); - trace_seq_putmem(&trace_seq, (void *)&num, sizeof(num)); - trace_seq_to_user(&trace_seq, (char *)size, sizeof(size_t)); - return ERR_NO_ERR; + return num; } -int list_allow_uids(uid_t __user *uids, size_t __user *size) +int su_list_allow_uids(uid_t __user *uids, int num) { - if (!kfunc(seq_buf_to_user)) { - return list_allow_uids_compat(uids, size); - } - // uids - struct seq_buf seq_buf; - seq_buf_clear(&seq_buf); - char buffer[SUPERCALL_SU_ALLOW_UID_MAX * sizeof(uid_t)]; - seq_buf.buffer = buffer; - seq_buf.size = sizeof(seq_buf); - size_t num = 0; + uid_t buf[SUPERCALL_SU_ALLOW_UID_MAX]; + int bufi = 0; + for (int i = 0; i < SUPERCALL_SU_ALLOW_UID_MAX; i++) { uid_t uid = su_allow_list[i]; if (uid != INVALID_ALLOW_UID) { - ((uid_t *)buffer)[num++] = uid; - seq_buf.len = num * sizeof(uid_t); + buf[bufi++] = uid; } } - int rc = 0; - if (num > 0) { - rc = seq_buf_to_user(&seq_buf, (char *)uids, seq_buf.len); - if (rc != seq_buf.len) { - logkfe("copy to user uid error\n"); - return ERR_COPY_TO_USER; - } + + int max_num = num < bufi ? num : bufi; + + int len = seq_copy_to_user(uids, buf, max_num * sizeof(uid_t)); + if (len != max_num * sizeof(uid_t)) { + logke("su allow to user error: %d\n", len); + return len; } - // size - seq_buf_clear(&seq_buf); - *(size_t *)buffer = num; - seq_buf.len = sizeof(size_t); - rc = seq_buf_to_user(&seq_buf, (char *)size, seq_buf.len); - if (rc != sizeof(size_t)) { - logkfe("copy to user uid error\n"); - return ERR_COPY_TO_USER; + return bufi; +} + +// todo: +int su_reset_path(const char *cmd) +{ + if (strnlen(cmd, sizeof(android_su_path)) >= sizeof(android_su_path)) { + return -ENOMEM; } - return ERR_NO_ERR; + strlcpy(android_su_path, cmd, sizeof(android_su_path)); + dsb(ishst); + logki("reset su to: %s\n", cmd); + return 0; +} + +int su_get_path(char *__user cmd, int arg2) +{ + int len = strnlen(android_su_path, sizeof(android_su_path)); + if (arg2 <= len) return -ENOMEM; + return seq_copy_to_user(cmd, android_su_path, len); } // todo: rcu_dereference_protected @@ -147,7 +135,7 @@ static void *__user copy_to_user_stack(void *data, size_t len) addr &= 0xFFFFFFFFFFFFFFF0; // sometimes, to avoid userspace -fstack-protector addr -= 10; - copy_to_user((void *)addr, data, len); + seq_copy_to_user((void *)addr, data, len); return (void *)addr; } @@ -169,7 +157,7 @@ static void log_user_string(const char *tag, const char *__user ustring) { if (is_su_allow(current_uid())) { char buf[64] = { '\0' }; - strncpy_from_user(buf, ustring, 63); + strncpy_from_user_nofault(buf, ustring, 64); logkd("tag: %s, ustring: %s\n", tag, buf); } } @@ -182,13 +170,11 @@ static inline void log_user_string(const char *tag, const char *__user filename) // int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) // int __do_execve_file(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags, // struct file *file); -// 3.18: static int do_execve(struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp); +// static int do_execve_common(struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp) void before_do_execve(hook_fargs8_t *args, void *udata) { uid_t uid = current_uid(); - if (!is_su_allow(uid)) - return; - + if (!is_su_allow(uid)) return; struct filename *filename; if ((((uintptr_t)args->arg0) & 0xF000000000000000) == 0xF000000000000000) { filename = (struct filename *)args->arg0; @@ -196,10 +182,9 @@ void before_do_execve(hook_fargs8_t *args, void *udata) filename = (struct filename *)args->arg1; } // logkd("exec su uid: %d, %s\n", uid, filename->name); - dsb(ishst); // todo - if (!IS_ERR(filename)) { - if (!min_strcmp(filename->name, android_su_path)) { - logkd("exec su uid: %d\n", uid); + if (filename && !IS_ERR(filename)) { + if (!strcmp(filename->name, android_su_path)) { + logkd("su exec uid: %d\n", uid); commit_su(0, 0); min_strcpy((char *)filename->name, android_sh_path); } @@ -211,15 +196,14 @@ void before_do_execve(hook_fargs8_t *args, void *udata) void before_faccessat(hook_fargs4_t *args, void *udata) { uid_t uid = current_uid(); - if (!is_su_allow(uid)) - return; + if (!is_su_allow(uid)) return; char __user *filename = (char __user *)args->arg1; - char buf[sizeof(android_su_path) + 1] = { '\0' }; - strncpy_from_user(buf, filename, sizeof(android_su_path)); + char buf[sizeof(android_su_path)] = { '\0' }; + strncpy_from_user_nofault(buf, filename, sizeof(android_su_path)); - if (!min_strcmp(buf, android_su_path)) { - logkd("access: uid: %d\n", uid); + if (!strcmp(buf, android_su_path)) { + logkd("su access uid: %d\n", uid); args->ret = 0; args->early_ret = 1; } @@ -236,22 +220,23 @@ void before_stat(hook_fargs8_t *args, void *udata) args->local.data[0] = change_flag; uid_t uid = current_uid(); - if (!is_su_allow(uid)) - return; + if (!is_su_allow(uid)) return; if ((((uintptr_t)args->arg1) & 0xF000000000000000) == 0xF000000000000000) { struct filename *filename = (struct filename *)args->arg1; - if (!min_strcmp(filename->name, android_su_path)) { - logkd("stat0: uid: %d\n", uid); + if (!strcmp(filename->name, android_su_path)) { + logkd("su stat0 uid: %d\n", uid); min_strcpy((char *)filename->name, android_sh_path); } } else { - char buf[sizeof(android_su_path) + 1] = { '\0' }; - strncpy_from_user(buf, (char *)args->arg1, sizeof(android_su_path)); - if (!min_strcmp(buf, android_su_path)) { - logkd("stat1: uid: %d\n", uid); - copy_to_user((void *)args->arg1 + sizeof(android_sh_dir) - 1, android_sh_path + sizeof(android_sh_dir) - 1, - 3); + char buf[sizeof(android_su_path)] = { '\0' }; + strncpy_from_user_nofault(buf, (char *)args->arg1, sizeof(android_su_path)); + if (!strcmp(buf, android_su_path)) { + logkd("su stat1 uid: %d\n", uid); + int sz = seq_copy_to_user((void *)args->arg1, android_sh_path, sizeof(android_sh_path)); + if (sz != sizeof(android_sh_path)) { + logke("seq_copy_to_user error: %d\n", sz); + } change_flag = 1; } } @@ -262,34 +247,24 @@ void after_stat(hook_fargs8_t *args, void *udata) { int change_flag = args->local.data[0]; if (change_flag) { - copy_to_user((void *)args->arg1 + sizeof(android_sh_dir) - 1, android_su_path + sizeof(android_sh_dir) - 1, 3); - } -} - -static int hook_execv_compat(void *data, const char *name, struct module *, unsigned long addr) -{ - if (min_strncmp("do_execve_common", name, min_strlen("do_execve_common"))) { - return 0; - } - logkd("Find do_execve_common symbol: %s\n", name); - hook_err_t err = hook_wrap8((void *)addr, before_do_execve, 0, 0); - if (err) { - logke("Hook %s error: %d\n", name, err); - return err; + int len = min_strlen(android_su_path) + 1; + int sz = seq_copy_to_user((void *)args->arg1, android_su_path, len); + if (sz != len) { + logke("seq_copy_to_user error: %d\n", sz); + } } - return 1; } int su_compat_init() { + int rc = 0; + for (int i = 0; i < SUPERCALL_SU_ALLOW_UID_MAX; i++) { su_allow_list[i] = INVALID_ALLOW_UID; } // todo: su_allow_list[0] = 2000; - hook_err_t err = HOOK_NO_ERR; - // state unsigned long vfs_stat_addr = kallsyms_lookup_name("vfs_statx"); if (!vfs_stat_addr) { @@ -299,14 +274,16 @@ int su_compat_init() vfs_stat_addr = kallsyms_lookup_name("vfs_fstatat"); } if (!vfs_stat_addr) { - logke("Can't find symbol vfs_fstatat, do_statx or vfs_statx\n"); - return ERR_NO_SUCH_SYMBOL; - } - - err = hook_wrap8((void *)vfs_stat_addr, before_stat, after_stat, 0); - if (err) { - logke("Hook vfs_fstatat error: %d\n", err); - return err; + log_boot("no symbol vfs_fstatat, do_statx or vfs_statx\n"); + rc = -ENOENT; + goto out; + } else { + hook_err_t err = hook_wrap8((void *)vfs_stat_addr, before_stat, after_stat, 0); + if (err) { + log_boot("hook vfs_fstatat error: %d\n", err); + rc = err; + goto out; + } } // access @@ -315,28 +292,26 @@ int su_compat_init() faccessat_addr = kallsyms_lookup_name("sys_faccessat"); } if (!faccessat_addr) { - logke("Can't find symbol do_faccessat or sys_faccessat\n"); - return ERR_NO_SUCH_SYMBOL; - } - err = hook_wrap4((void *)faccessat_addr, before_faccessat, 0, 0); - if (err) { - logke("Hook do_faccessat error: %d\n", err); - return err; - } - - // execv - unsigned long execve_addr = kallsyms_lookup_name("__do_execve_file"); - if (!execve_addr) - execve_addr = kallsyms_lookup_name("do_execveat_common"); - if (!execve_addr) { - kallsyms_on_each_symbol(hook_execv_compat, 0); + log_boot("no symbol do_faccessat or sys_faccessat\n"); + rc = -ENOENT; + goto out; } else { - err = hook_wrap8((void *)execve_addr, before_do_execve, 0, 0); + hook_err_t err = hook_wrap4((void *)faccessat_addr, before_faccessat, 0, 0); if (err) { - logke("Hook __do_execve_file or do_execveat_common error: %d\n", err); - return err; + log_boot("hook do_faccessat error: %d\n", err); + rc = err; + goto out; } } - return 0; + // execv + hook_err_t err = add_execv_hook(before_do_execve, 0, 0); + if (err) { + log_boot("hook add execv error: %d\n", err); + rc = err; + goto out; + } + +out: + return rc; } \ No newline at end of file diff --git a/kernel/patch/android/supercall.c b/kernel/patch/android/supercall.c index 539aebe4..04ea54fc 100644 --- a/kernel/patch/android/supercall.c +++ b/kernel/patch/android/supercall.c @@ -9,46 +9,32 @@ #include #include #include +#include -static long call_grant_su(uid_t uid) -{ - return add_allow_uid(uid); -} - -static long call_revoke_su(uid_t uid) -{ - return remove_allow_uid(uid); -} - -static long call_list_su_allow(uid_t *__user uids, size_t *__user size) -{ - return list_allow_uids(uids, size); -} - -static long call_reset_su_cmd(const char cmd[3]) -{ - return reset_su_cmd(cmd); -} - -long supercall_android(long cmd, void *__user arg1, void *__user arg2, void *__user arg3) +long supercall_android(long cmd, long arg1, long arg2, long arg3) { long ret; if (cmd == SUPERCALL_GRANT_SU) { uid_t uid = (uid_t)(uintptr_t)arg1; - ret = call_grant_su(uid); + ret = su_add_allow_uid(uid); } else if (cmd == SUPERCALL_REVOKE_SU) { uid_t uid = (uid_t)(uintptr_t)arg1; - ret = call_revoke_su(uid); + ret = su_remove_allow_uid(uid); + } else if (cmd == SUPERCALL_SU_ALLOW_NUM) { + ret = su_allow_uid_nums(); } else if (cmd == SUPERCALL_LIST_SU_ALLOW) { uid_t *uids = (uid_t *)arg1; - size_t *size = (size_t *)arg2; - ret = call_list_su_allow(uids, size); - } else if (cmd == SUPERCALL_RESET_SU_CMD) { - char cmd[3] = { '\0' }; - strncpy_from_user(cmd, (char *__user)arg1, 2); - ret = call_reset_su_cmd(cmd); + int num = (int)arg2; + ret = su_list_allow_uids(uids, num); + } else if (cmd == SUPERCALL_SU_RESET_PATH) { + char cmd[SUPERCALL_SU_PATH_LEN] = { '\0' }; + strncpy_from_user_nofault(cmd, (char *__user)arg1, sizeof(cmd)); + ret = su_reset_path(cmd); + } else if (cmd == SUPERCALL_SU_GET_PATH) { + int size = (int)arg2; + ret = su_get_path((char *)arg1, size); } else { - ret = SUPERCALL_RES_NOT_IMPL; + ret = -ENOSYS; } return ret; } diff --git a/kernel/patch/accctl/accctl.c b/kernel/patch/common/accctl.c similarity index 60% rename from kernel/patch/accctl/accctl.c rename to kernel/patch/common/accctl.c index 057b40f4..d3bd548a 100644 --- a/kernel/patch/accctl/accctl.c +++ b/kernel/patch/common/accctl.c @@ -10,8 +10,20 @@ #include #include #include -#include #include +#include + +int set_selinx_allow(struct task_struct *task, int val) +{ + struct task_ext *ext = get_task_ext(task); + if (unlikely(!task_ext_valid(ext))) { + logkfe("dirty task_ext, pid(maybe dirty): %d\n", ext->pid); + goto out; + } + ext->selinux_allow = val; +out: + return 0; +} static void make_cred_su(struct cred *cred, const char *sctx) { @@ -32,35 +44,38 @@ static void make_cred_su(struct cred *cred, const char *sctx) *(uid_t *)((uintptr_t)cred + cred_offset.sgid_offset) = 0; } -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; +// 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_def(security_cred_getsecid)) { - kfunc_def(security_cred_getsecid)(old, &secid); - set_security_override(new, secid); - } - commit_creds(new); +// 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); +// } +// // todo: +// commit_creds(new); -out: - return rc; -} +// out: +// return rc; +// } int commit_su(int super, const char *sctx) { int rc = 0; + int scontext_changed = 0; struct task_struct *task = current; struct task_ext *ext = get_task_ext(task); + if (!task_ext_valid(ext)) { logkfe("dirty task_ext, pid(maybe dirty): %d\n", ext->pid); - rc = ERR_DIRTY_EXT; + rc = -ENOMEM; goto out; } ext->super = super; @@ -68,34 +83,44 @@ int commit_su(int super, const char *sctx) struct cred *new = prepare_creds(); make_cred_su(new, sctx); + if (sctx && sctx[0]) { - ext->selinux_allow = !!set_security_override_from_ctx(new, sctx); + scontext_changed = !set_security_override_from_ctx(new, sctx); + if (!scontext_changed) rc = -EINVAL; + ext->selinux_allow = !scontext_changed; } + commit_creds(new); - // todo: ranchu-4.4.302, ranchu-4.14.175, and ..., BUG: recent printk recursion! - // logkfi("pid: %d, tgid: %d\n", ext->pid, ext->tgid); + out: + logkfi("pid: %d, tgid: %d, sctx: %s, changed: %d\n", ext->pid, ext->tgid, sctx, scontext_changed); return rc; } int effect_su_unsafe(const char *sctx) { int rc = 0; + int scontext_changed = 0; struct task_struct *task = current; struct task_ext *ext = get_task_ext(task); if (!task_ext_valid(ext)) { logkfe("dirty task_ext, pid(maybe dirty): %d\n", ext->pid); - rc = ERR_DIRTY_EXT; + rc = -ENOMEM; goto out; } + ext->selinux_allow = 1; struct cred *cred = *(struct cred **)((uintptr_t)task + task_struct_offset.cred_offset); make_cred_su(cred, sctx); + if (sctx && sctx[0]) { - ext->selinux_allow = !!set_security_override_from_ctx(cred, sctx); + scontext_changed = !set_security_override_from_ctx(cred, sctx); + if (!scontext_changed) rc = -EINVAL; + ext->selinux_allow = !scontext_changed; } - // logkfi("pid: %d, tgid: %d\n", ext->pid, ext->tgid); + out: + logkfi("pid: %d, tgid: %d, sctx: %s, changed: %d\n", ext->pid, ext->tgid, sctx, scontext_changed); return rc; } @@ -103,32 +128,37 @@ int effect_su_unsafe(const char *sctx) int thread_su(pid_t vpid, const char *sctx) { int rc = 0; + int scontext_changed = 0; struct task_struct *task = find_get_task_by_vpid(vpid); if (!task) { - rc = ERR_NO_SUCH_ID; + logkfe("no such pid: %d\n", vpid); + rc = -ENOENT; goto out; } struct task_ext *ext = get_task_ext(task); if (!task_ext_valid(ext)) { logkfe("dirty task_ext, pid(maybe dirty): %d\n", ext->pid); - rc = ERR_DIRTY_EXT; + rc = -ENOMEM; goto out; } struct cred *cred = *(struct cred **)((uintptr_t)task + task_struct_offset.cred_offset); make_cred_su(cred, sctx); - if (sctx && sctx[0]) { - ext->selinux_allow = set_security_override_from_ctx(cred, sctx); - } + + if (sctx && sctx[0]) scontext_changed = !set_security_override_from_ctx(cred, sctx); + struct cred *real_cred = *(struct cred **)((uintptr_t)task + task_struct_offset.real_cred_offset); if (cred != real_cred) { make_cred_su(real_cred, sctx); - if (sctx && sctx[0]) { - ext->selinux_allow = set_security_override_from_ctx(real_cred, sctx); - } + if (sctx && sctx[0]) scontext_changed = scontext_changed && !set_security_override_from_ctx(real_cred, sctx); } - // logkfi("pid: %d, tgid: %d\n", ext->pid, ext->tgid); + + ext->selinux_allow = !scontext_changed; + if (!scontext_changed) rc = -EINVAL; + + logkfi("pid: %d, tgid: %d, sctx: %s, changed: %d\n", ext->pid, ext->tgid, sctx, scontext_changed); + out: __put_task_struct(task); return rc; diff --git a/kernel/patch/common/hotpatch.c b/kernel/patch/common/hotpatch.c new file mode 100644 index 00000000..26a3d88f --- /dev/null +++ b/kernel/patch/common/hotpatch.c @@ -0,0 +1,82 @@ +#include + +#include +#include +#include +#include +#include +#include + +#define MAX_STACK_TRACE_DEPTH 64 +// static unsigned long stack_entries[MAX_STACK_TRACE_DEPTH]; +// static struct stack_trace trace = { 0 }; + +// static int backtrace_address_verify(unsigned long address, bool replace) +// { +// return 0; +// } + +/* + * https://github.com/dynup/kpatch/blob/922cd458091915b0dad8c1892d7a609addd4afd7/kmod/core/core.c#L274C20-L274C20 + * Verify activeness safety, i.e. that none of the to-be-patched functions are on the stack of any task. + */ +int patch_verify_safety() +{ + // if (task_struct_offset.tasks_offset < 0) { + // return -1; + // } + int ret = 0; + + // trace.max_entries = sizeof(stack_entries) / sizeof(stack_entries[0]); + // trace.entries = &stack_entries[0]; + + // struct task_struct *g, *t; + + // do_each_thread(p) + // { + // logkd("ggg: %llx\n", p); + // trace.nr_entries = 0; + // save_stack_trace_tsk(t, &trace); + + // if (trace.nr_entries >= trace.max_entries) { + // logke("more than %u trace entries!\n", trace.max_entries); + // ret = -EBUSY; + // goto out; + // } + + // for (int i = 0; i < trace.nr_entries; i++) { + // if (trace.entries[i] == ULONG_MAX) + // break; + // ret = backtrace_address_verify(trace.entries[i], 0); + // if (ret) + // goto out; + // } + // } + + // out: + // if (ret) { + // // pid_t pid = + // logke("Comm: %.20s\n", get_task_comm(t)); + // for (int i = 0; i < trace.nr_entries; i++) { + // if (trace.entries[i] == ULONG_MAX) + // break; + // logke(" [<%pK>] %pB\n", (void *)trace.entries[i], (void *)trace.entries[i]); + // } + // } + + return ret; +} + +// static int check_all_task(void *data) +// { +// hook_t *hook = (hook_t *)data; +// logkd("check_all_task data: %llx\n", hook); +// return 0; +// } + +int hot_patch_text() +{ + // int rc = stop_machine(check_all_task, &data, 0); + // logkd("stop_machine rc: %d\n", rc); + return 0; +} diff --git a/kernel/patch/common/secpass.c b/kernel/patch/common/secpass.c new file mode 100644 index 00000000..8ff8382a --- /dev/null +++ b/kernel/patch/common/secpass.c @@ -0,0 +1,82 @@ + +#include +#include +#include +#include +#include + +struct pt_regs; + +static inline bool should_cfi_pass(unsigned long target) +{ + return is_kp_text_area(target) || is_kp_hook_area(target) || is_kpm_rox_area(target); +} + +enum bug_trap_type +{ + BUG_TRAP_TYPE_NONE = 0, + BUG_TRAP_TYPE_WARN = 1, + BUG_TRAP_TYPE_BUG = 2, +}; + +static enum bug_trap_type (*backup_report_cfi_failure)(struct pt_regs *regs, unsigned long addr, unsigned long *target, + u32 type) = 0; +static enum bug_trap_type replace_report_cfi_failure(struct pt_regs *regs, unsigned long addr, unsigned long *target, + u32 type) +{ + if (should_cfi_pass(*target)) { + return BUG_TRAP_TYPE_WARN; + } + enum bug_trap_type rc = backup_report_cfi_failure(regs, addr, target, type); + return rc; +} + +typedef void (*cfi_check_fn)(uint64_t id, void *ptr, void *diag); + +static void (*backup__cfi_slowpath)(uint64_t id, void *ptr, void *diag) = 0; +static void replace__cfi_slowpath(uint64_t id, void *ptr, void *diag) +{ + if (should_cfi_pass((unsigned long)ptr)) return; + backup__cfi_slowpath(id, ptr, diag); +} + +int bypass_kcfi() +{ + int rc = 0; + + // 6.1.0 + // todo: Is there more elegant way? + unsigned long report_cfi_failure_addr = kallsyms_lookup_name("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); + if (err) { + log_boot("hook report_cfi_failure: %llx, error: %d\n", report_cfi_failure_addr, err); + rc = err; + goto out; + } + } + + // todo: direct modify cfi_shadow, __cfi_check? + unsigned long __cfi_slowpath_addr = kallsyms_lookup_name("__cfi_slowpath_diag"); + if (!__cfi_slowpath_addr) { + __cfi_slowpath_addr = kallsyms_lookup_name("__cfi_slowpath"); + } + if (__cfi_slowpath_addr) { + hook_err_t err = + hook((void *)__cfi_slowpath_addr, (void *)replace__cfi_slowpath, (void **)&backup__cfi_slowpath); + if (err) { + log_boot("hook __cfi_slowpath_diag: %llx, error: %d\n", __cfi_slowpath_addr, err); + rc = err; + goto out; + } + } + + if (!report_cfi_failure_addr && !__cfi_slowpath_addr) { + // not error + log_boot("no symbol for pass kcfi\n"); + } + +out: + return rc; +} \ No newline at end of file diff --git a/kernel/patch/common/selinuxhook.c b/kernel/patch/common/selinuxhook.c new file mode 100644 index 00000000..2776a887 --- /dev/null +++ b/kernel/patch/common/selinuxhook.c @@ -0,0 +1,222 @@ +#include "accctl.h" + +#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)) { \ + return 0; \ + } + +static 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)) { + 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 int hook_backup(avc_denied)(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 hook_replace(avc_denied)(struct selinux_state *state, void *ssid, void *tsid, void *tclass, void *requested, + void *driver, void *xperm, void *flags, struct av_decision *avd) +{ + HOOK_AVC_RET_ZERO_BEFORE(); + int rc = hook_call_backup(avc_denied, state, ssid, tsid, tclass, requested, driver, xperm, flags, avd); + return rc; +} + +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)) { + 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)) { + 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)) { + 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() +{ + hook_kfunc(avc_has_perm_noaudit); + hook_kfunc(avc_has_perm); + hook_kfunc(avc_has_perm_flags); + hook_kfunc(avc_has_extended_perms); + + hook_kfunc(avc_denied); + + 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/supercall.c b/kernel/patch/common/supercall.c new file mode 100644 index 00000000..03402df7 --- /dev/null +++ b/kernel/patch/common/supercall.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_KEY_LEN 127 + +static inline long call_hello() +{ + logki("KernelPatch Supercall Hello!\n"); + return SUPERCALL_HELLO_MAGIC; +} + +static inline long call_get_kernel_version() +{ + return kver; +} + +static inline long call_get_kp_version() +{ + return kpver; +} + +static long call_load_kpm(const char __user *arg1, const char *__user arg2) +{ + char path[512], args[512]; + long pathlen = strncpy_from_user_nofault(path, arg1, sizeof(path)); + if (pathlen <= 0) return EINVAL; + long arglen = strncpy_from_user_nofault(args, arg2, sizeof(args)); + return load_module_path(path, arglen <= 0 ? 0 : args); +} + +static long call_unload_kpm(const char *__user arg1) +{ + char name[512]; + long len = strncpy_from_user_nofault(name, arg1, sizeof(name)); + if (len <= 0) return EINVAL; + return unload_module(name); +} + +static long call_kpm_nums() +{ + return get_module_nums(); +} + +static long call_kpm_info(int index, char *__user out_info, int out_len) +{ + if (index < 0) return 0; + if (out_len <= 0) return 0; + char buf[1024]; + int sz = get_module_info(index, buf, sizeof(buf)); + if (sz <= 0) return sz; + if (sz > out_len) return -ENOMEM; + sz = seq_copy_to_user(out_info, buf, sz); + return sz; +} + +static inline long call_su(const char *sctx) +{ + int ret = commit_su(1, sctx); + return ret; +} + +static long call_thread_su(pid_t pid, const char *sctx) +{ + int ret = SUPERCALL_RES_SUCCEED; + ret = thread_su(pid, sctx); + return ret; +} + +static long call_thread_unsu(pid_t pid) +{ + return -ENOSYS; +} + +static long supercall(long cmd, long arg1, long arg2, long arg3) +{ + logkd("supercall with cmd: %x\n", cmd); + + long ret = -ENOSYS; + + if (cmd == SUPERCALL_HELLO) { + ret = call_hello(); + } else if (cmd == SUPERCALL_GET_KERNEL_VERSION) { + ret = kver; + } else if (cmd == SUPERCALL_GET_KP_VERSION) { + ret = kpver; + } else if (cmd == SUPERCALL_LOAD_KPM) { + ret = call_load_kpm((const char *__user)arg1, (const char *__user)arg2); + } else if (cmd == SUPERCALL_UNLOAD_KPM) { + ret = call_unload_kpm((const char *__user)arg1); + } else if (cmd == SUPERCALL_KPM_NUMS) { + return call_kpm_nums(); + } else if (cmd == SUPERCALL_KPM_INFO) { + return call_kpm_info((long)arg1, (char *__user)arg2, (long)arg3); + } else if (cmd == SUPERCALL_SU) { + char sctx[SUPERCALL_SCONTEXT_LEN]; + long len = strncpy_from_user_nofault(sctx, (const char *)arg1, SUPERCALL_SCONTEXT_LEN); + ret = call_su(len > 0 ? sctx : 0); + } else if (cmd == SUPERCALL_THREAD_SU) { + pid_t pid = (pid_t)(uintptr_t)arg1; + char sctx[SUPERCALL_SCONTEXT_LEN]; + long len = strncpy_from_user_nofault(sctx, (char *)arg2, SUPERCALL_SCONTEXT_LEN); + ret = call_thread_su(pid, len > 0 ? sctx : 0); + } else if (cmd == SUPERCALL_THREAD_UNSU) { + pid_t pid = (pid_t)(uintptr_t)arg1; + ret = call_thread_unsu(pid); + } else { +#ifdef ANDROID + ret = supercall_android(cmd, arg1, arg2, arg3); +#else + ret = -ENOSYS; +#endif + } + return ret; +} + +void before(hook_fargs6_t *args, void *udata) +{ + const char *__user ukey; + long hash; + long cmd; + long a1; + long a2; + long a3; + + if (syscall_has_wrapper) { + const struct pt_regs *regs = (const struct pt_regs *)args->arg0; + ukey = (const char *__user)regs->regs[0]; + hash = (long)regs->regs[1]; + cmd = (long)regs->regs[2]; + a1 = (long)regs->regs[3]; + a2 = (long)regs->regs[4]; + a3 = (long)regs->regs[5]; + } else { + ukey = (const char *__user)args->arg0; + hash = (long)args->arg1; + cmd = (long)args->arg2; + a1 = (long)args->arg3; + a2 = (long)args->arg4; + a3 = (long)args->arg5; + } + + char key[MAX_KEY_LEN + 1]; + long len = strncpy_from_user_nofault(key, ukey, MAX_KEY_LEN + 1); + + if (len <= 0) return; + if (cmd >= SUPERCALL_MAX || cmd < SUPERCALL_HELLO) return; + if (superkey_auth(key, len - 1)) return; + if (hash_key(key) != hash) return; + + args->early_ret = 1; + args->ret = supercall(cmd, a1, a2, a3); +} + +int supercall_install() +{ + int rc = 0; + // hook_err_t err = inline_hook_syscalln(__NR_supercall, 6, before, 0, 0); + hook_err_t err = fp_hook_syscalln(__NR_supercall, 6, before, 0, 0); + if (err) { + log_boot("install supercall hook error: %d\n", err); + rc = err; + goto out; + } +out: + return rc; +} diff --git a/kernel/patch/extend/syscall.c b/kernel/patch/common/syscall.c similarity index 56% rename from kernel/patch/extend/syscall.c rename to kernel/patch/common/syscall.c index 32332423..13491f56 100644 --- a/kernel/patch/extend/syscall.c +++ b/kernel/patch/common/syscall.c @@ -5,53 +5,20 @@ #include #include #include +#include +#include -bool syscall_has_wrapper = false; -uintptr_t syscall_table_addr = 0; -uintptr_t compat_syscall_table_addr = 0; - -void inline_syscall_with(long nr, uintptr_t *old, uintptr_t new) -{ - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - uint64_t func = *(uintptr_t *)addr; - hook((void *)func, (void *)new, (void **)old); -} +uintptr_t kvar_def(sys_call_table) = 0; +KP_EXPORT_SYMBOL(kvar(sys_call_table)); -void inline_compat_syscall_with(long nr, uintptr_t *old, uintptr_t new) -{ - uintptr_t addr = compat_syscall_table_addr + nr * sizeof(uintptr_t); - uint64_t func = *(uintptr_t *)addr; - hook((void *)func, (void *)new, (void **)old); -} +uintptr_t kvar_def(compat_sys_call_table) = 0; +KP_EXPORT_SYMBOL(kvar(compat_sys_call_table)); -// todo: Control Flow Integrity, CONFIG_LTO_CLANG=y CONFIG_CFI_CLANG=y -void replace_syscall_with(long nr, uintptr_t *old, uintptr_t new) -{ - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - *old = *(uintptr_t *)addr; - uintptr_t *pte = pgtable_entry_kernel(addr); - uintptr_t ori_prot = *pte; - *pte = (ori_prot | PTE_DBM) & ~PTE_RDONLY; - flush_tlb_kernel_page(addr); - *(uintptr_t *)addr = new; - // flush_icache_all(); - *pte = ori_prot; - flush_tlb_kernel_page(addr); -} +bool syscall_has_wrapper = false; +KP_EXPORT_SYMBOL(syscall_has_wrapper); -void replace_compat_syscall_with(long nr, uintptr_t *old, uintptr_t new) -{ - uintptr_t addr = compat_syscall_table_addr + nr * sizeof(uintptr_t); - *old = *(uintptr_t *)addr; - uintptr_t *pte = pgtable_entry_kernel(addr); - uintptr_t ori_prot = *pte; - *pte = (ori_prot | PTE_DBM) & ~PTE_RDONLY; - flush_tlb_kernel_page(addr); - *(uintptr_t *)addr = new; - // flush_icache_all(); - *pte = ori_prot; - flush_tlb_kernel_page(addr); -} +bool has_config_compat = false; +KP_EXPORT_SYMBOL(has_config_compat); typedef long (*warp_raw_syscall_f)(const struct pt_regs *regs); typedef long (*raw_syscall0_f)(); @@ -64,10 +31,8 @@ typedef long (*raw_syscall6_f)(long arg0, long arg1, long arg2, long arg3, long long raw_syscall0(long nr) { - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - addr = *(uintptr_t *)addr; + uintptr_t addr = kvar(sys_call_table)[nr]; if (syscall_has_wrapper) { - // todo: struct pt_regs regs; memset(®s, 0, sizeof(regs)); return ((warp_raw_syscall_f)addr)(®s); @@ -78,8 +43,7 @@ long raw_syscall0(long nr) long raw_syscall1(long nr, long arg0) { - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - addr = *(uintptr_t *)addr; + uintptr_t addr = kvar(sys_call_table)[nr]; if (syscall_has_wrapper) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); @@ -90,8 +54,7 @@ long raw_syscall1(long nr, long arg0) long raw_syscall2(long nr, long arg0, long arg1) { - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - addr = *(uintptr_t *)addr; + uintptr_t addr = kvar(sys_call_table)[nr]; if (syscall_has_wrapper) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); @@ -104,8 +67,7 @@ long raw_syscall2(long nr, long arg0, long arg1) long raw_syscall3(long nr, long arg0, long arg1, long arg2) { - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - addr = *(uintptr_t *)addr; + uintptr_t addr = kvar(sys_call_table)[nr]; if (syscall_has_wrapper) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); @@ -119,8 +81,7 @@ long raw_syscall3(long nr, long arg0, long arg1, long arg2) long raw_syscall4(long nr, long arg0, long arg1, long arg2, long arg3) { - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - addr = *(uintptr_t *)addr; + uintptr_t addr = kvar(sys_call_table)[nr]; if (syscall_has_wrapper) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); @@ -135,8 +96,7 @@ long raw_syscall4(long nr, long arg0, long arg1, long arg2, long arg3) long raw_syscall5(long nr, long arg0, long arg1, long arg2, long arg3, long arg4) { - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - addr = *(uintptr_t *)addr; + uintptr_t addr = kvar(sys_call_table)[nr]; if (syscall_has_wrapper) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); @@ -152,8 +112,7 @@ long raw_syscall5(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) { - uintptr_t addr = syscall_table_addr + nr * sizeof(uintptr_t); - addr = *(uintptr_t *)addr; + uintptr_t addr = kvar(sys_call_table)[nr]; if (syscall_has_wrapper) { struct pt_regs regs; memset(®s, 0, sizeof(regs)); @@ -170,8 +129,21 @@ long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 int syscall_init() { - compat_syscall_table_addr = kallsyms_lookup_name("compat_sys_call_table"); - syscall_table_addr = kallsyms_lookup_name("sys_call_table"); - syscall_has_wrapper = kallsyms_lookup_name("__arm64_sys_openat") ? true : false; - return 0; + int rc = 0; + kvar(sys_call_table) = (typeof(kvar(sys_call_table)))kallsyms_lookup_name("sys_call_table"); + if (!kvar(sys_call_table)) { + rc = -ENOENT; + log_boot("no symbol sys_call_table\n"); + goto out; + } + kvar(compat_sys_call_table) = (typeof(kvar(compat_sys_call_table)))kallsyms_lookup_name("compat_sys_call_table"); + + has_config_compat = !!kvar(compat_sys_call_table); + log_boot("syscall config_compat: %d\n", has_config_compat); + + syscall_has_wrapper = !!kallsyms_lookup_name("__arm64_sys_openat"); + log_boot("syscall has_wrapper: %d\n", syscall_has_wrapper); + +out: + return rc; } diff --git a/kernel/patch/common/taskob.c b/kernel/patch/common/taskob.c new file mode 100644 index 00000000..5fc69990 --- /dev/null +++ b/kernel/patch/common/taskob.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void prepare_init_ext(struct task_struct *task) +{ + struct task_ext *ext = get_task_ext(task); + ext->magic = TASK_EXT_MAGIC; + ext->pid = 0; + ext->tgid = 0; + ext->super = 0; + ext->selinux_allow = 0; +} + +static void prepare_task_ext(struct task_struct *new, struct task_struct *old) +{ + struct task_ext *old_ext = get_task_ext(old); + if (unlikely(!task_ext_valid(old_ext))) { + logkfe("dirty task_ext, pid(maybe dirty): %d\n", old_ext->pid); + return; + } + struct task_ext *new_ext = get_task_ext(new); + 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->super = 0; + new_ext->selinux_allow = old_ext->selinux_allow; + + dsb(ishst); +} + +static struct task_struct *(*backup_copy_process)(void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, + void *a7) = 0; + +struct task_struct *replace_copy_process(void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7) +{ + struct task_struct *new = backup_copy_process(a0, a1, a2, a3, a4, a5, a6, a7); + if (unlikely(IS_ERR_VALUE(new))) return new; + prepare_task_ext(new, current); + return new; +} + +static void (*backup_cgroup_post_fork)(struct task_struct *p, void *a1) = 0; + +void replace_cgroup_post_fork(struct task_struct *p, void *a1) +{ + struct task_struct *new = p; + backup_cgroup_post_fork(p, a1); + prepare_task_ext(new, current); +} + +unsigned long execv_hook_addr = 0; + +static int hook_execv_compat(void *data, const char *name, struct module *, unsigned long addr) +{ + if (min_strncmp("do_execve_common", name, min_strlen("do_execve_common"))) { + return 0; + } + execv_hook_addr = addr; + return 1; +} + +// int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) +// int __do_execve_file(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags, +// struct file *file); +// static int do_execve_common(struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp) +hook_err_t add_execv_hook(hook_chain8_callback before, hook_chain8_callback after, void *udata) +{ + return hook_wrap8((void *)execv_hook_addr, before, after, udata); +} + +void remove_execv_hook(hook_chain8_callback before, hook_chain8_callback after) +{ + hook_unwrap((void *)execv_hook_addr, before, after); +} + +int task_observer() +{ + int rc = 0; + + prepare_init_ext(kvar(init_task)); + + unsigned long copy_process_addr = kallsyms_lookup_name("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; + } + } else { + log_boot("no symbol copy_process, try cgroup_post_fork\n"); + unsigned long cgroup_post_fork_addr = kallsyms_lookup_name("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; + } + } + + // hook execv + execv_hook_addr = kallsyms_lookup_name("__do_execve_file"); + if (!execv_hook_addr) execv_hook_addr = kallsyms_lookup_name("do_execveat_common"); + if (!execv_hook_addr) { + kallsyms_on_each_symbol(hook_execv_compat, 0); + } + + if (!execv_hook_addr) { + log_boot("no symbol for execv hook\n"); + rc = -ENOENT; + goto out; + } else { + hook_err_t err = hook_wrap8((void *)execv_hook_addr, 0, 0, 0); + if (err) { + log_boot("hook execv: %llx, error: %d\n", execv_hook_addr, err); + rc = err; + goto out; + } + } + +out: + return rc; +} \ No newline at end of file diff --git a/kernel/patch/common/utils.c b/kernel/patch/common/utils.c new file mode 100644 index 00000000..f2fa89c5 --- /dev/null +++ b/kernel/patch/common/utils.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +int trace_seq_copy_to_user(void __user *to, const void *from, int n) +{ + unsigned char trace_seq_data[page_size + 0x20]; + struct trace_seq *trace_seq = (struct trace_seq *)trace_seq_data; + int *fp = (int *)(((uintptr_t)trace_seq) + page_size); + int *plen = fp; + int *preadpos = fp + 1; + int *pfull = fp + 2; + unsigned char *pbuffer = (unsigned char *)trace_seq; + *plen = n; + *preadpos = 0; + *pfull = 0; + if (n > page_size) { + return 0; + } + memcpy(pbuffer, from, n); + int sz = trace_seq_to_user(trace_seq, to, n); + return sz; +} + +int seq_buf_copy_to_user(void __user *to, const void *from, int n) +{ + struct seq_buf seq_buf; + seq_buf.size = n; + seq_buf.len = n; + seq_buf.readpos = 0; + seq_buf.buffer = (void *)from; + return seq_buf_to_user(&seq_buf, to, n); +} + +int __must_check seq_copy_to_user(void __user *to, const void *from, int n) +{ + int copy_len; + if (kfunc(seq_buf_to_user)) { + copy_len = seq_buf_copy_to_user((void *__user)to, from, n); + } else { + copy_len = trace_seq_copy_to_user((void *__user)to, from, n); + } + return copy_len; +} \ No newline at end of file diff --git a/kernel/patch/extend/lsmext.c b/kernel/patch/extend/lsmext.c deleted file mode 100644 index 440d21c1..00000000 --- a/kernel/patch/extend/lsmext.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static uint8_t *secid_fast_table = 0; -static struct selinux_policy policy_list = { 0 }; - -struct selinux_policy *selinux_secid_policies(u32 secid) -{ - if (is_secid_fast(secid)) { - if (secid_fast_table[secid] == FAST_TABLE_ELEM_INVALID) { - return 0; - }; - } - - char *secctx = 0; - u32 seclen = 0; - if (security_sid_to_context(secid, &secctx, &seclen)) { - return 0; - } - struct selinux_policy *find = 0; - struct selinux_policy *policy; - list_for_each_entry(policy, &policy_list.list, list) - { - if (!min_strncmp(secctx, policy->scontext, seclen)) { - find = policy; - break; - } - } - - if (!find) { - if (is_secid_fast(secid)) - secid_fast_table[secid] = FAST_TABLE_ELEM_INVALID; - } - return find; -} - -int add_secctx_policy(const char *secctx, const char *tcontext, const char *tclass, const char *perms) -{ - return 0; -} - -int del_secctx_policy(const char *secctx, struct lsm_pair *pairs, int npair) -{ - return 0; -} - -int lsm_ext_init() -{ - INIT_LIST_HEAD(&policy_list.list); - - secid_fast_table = (typeof(secid_fast_table))vmalloc(SECID_FAST_TABLE_NUM * sizeof(uint8_t)); - for (int i = 0; i < SECID_FAST_TABLE_NUM; i++) - secid_fast_table[i] = FAST_TABLE_ELEM_UNKNOWN; - -#ifdef ANDROID - // add_secctx_policy("u:r:logd:s0", "", "dir", "search"); - // add_secctx_policy("u:r:logd:s0", "", "file", "read,open,getattr"); -#endif - - return 0; -} diff --git a/kernel/patch/extend/taskob.c b/kernel/patch/extend/taskob.c deleted file mode 100644 index 5d677d50..00000000 --- a/kernel/patch/extend/taskob.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static inline void prepare_init_ext(struct task_struct *task) -{ - struct task_ext *ext = get_task_ext(task); - ext->magic = TASK_EXT_MAGIC; - ext->pid = 0; - ext->tgid = 0; - ext->super = 0; - ext->selinux_allow = 0; -} - -static inline void prepare_task_ext(struct task_struct *new, struct task_struct *old) -{ - struct task_ext *old_ext = get_task_ext(old); - if (!task_ext_valid(old_ext)) { - logkfe("dirty task_ext, pid(maybe dirty): %d\n", old_ext->pid); - return; - } - struct task_ext *new_ext = get_task_ext(new); - 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->super = 0; - new_ext->selinux_allow = old_ext->selinux_allow; -} - -static struct task_struct *(*backup_copy_process)(void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, - void *a7) = 0; - -struct task_struct *replace_copy_process(void *a0, void *a1, void *a2, void *a3, void *a4, void *a5, void *a6, void *a7) -{ - struct task_struct *new = backup_copy_process(a0, a1, a2, a3, a4, a5, a6, a7); - if (IS_ERR_VALUE(new)) - return new; - prepare_task_ext(new, current); - return new; -} - -static void (*backup_cgroup_post_fork)(struct task_struct *p, void *a1) = 0; - -void replace_cgroup_post_fork(struct task_struct *p, void *a1) -{ - struct task_struct *new = p; - backup_cgroup_post_fork(p, a1); - prepare_task_ext(new, current); -} - -int task_observer() -{ - prepare_init_ext(kvar(init_task)); - - hook_err_t err = HOOK_NO_ERR; - unsigned long copy_process_addr = kallsyms_lookup_name("copy_process"); - if (copy_process_addr) { - err = hook((void *)copy_process_addr, (void *)replace_copy_process, (void **)&backup_copy_process); - if (err) { - logke("Hook copy_process error: %d\n", err); - } - } else { - logkw("Can't find symbol copy_process, try cgroup_post_fork\n"); - unsigned long cgroup_post_fork_addr = kallsyms_lookup_name("cgroup_post_fork"); - if (!cgroup_post_fork_addr) { - logke("Can't find symbol cgroup_post_fork\n"); - return ERR_NO_SUCH_SYMBOL; - } - err = hook((void *)cgroup_post_fork_addr, (void *)replace_cgroup_post_fork, (void **)&backup_cgroup_post_fork); - if (err != HOOK_NO_ERR) { - logke("Hook cgroup_post_fork error: %d\n", err); - return err; - } - } - - return 0; -} \ No newline at end of file diff --git a/kernel/patch/include/accctl.h b/kernel/patch/include/accctl.h index 314f1d6b..cc42711b 100644 --- a/kernel/patch/include/accctl.h +++ b/kernel/patch/include/accctl.h @@ -8,6 +8,7 @@ #define SU_ALLOW_MAX +int set_selinx_allow(struct task_struct *task, int val); int commit_kernel_cred(); int effect_su_unsafe(const char *sctx); int commit_su(int super, const char *sctx); @@ -17,12 +18,15 @@ int selinux_hook_install(); int supercall_install(); #ifdef ANDROID +int kpuserd_init(); int su_compat_init(); -int add_allow_uid(uid_t uid); -int remove_allow_uid(uid_t uid); -int list_allow_uids(uid_t *uids, size_t *size); -int reset_su_cmd(const char path[3]); -long supercall_android(long cmd, void *__user arg1, void *__user arg2, void *__user arg3); +int su_add_allow_uid(uid_t uid); +int su_remove_allow_uid(uid_t uid); +int su_allow_uid_nums(); +int su_list_allow_uids(uid_t *__user uids, int num); +int su_reset_path(const char *path); +int su_get_path(char *__user cmd, int size); +long supercall_android(long cmd, long arg1, long arg2, long arg3); #endif #endif \ No newline at end of file diff --git a/kernel/patch/include/hotpatch.h b/kernel/patch/include/hotpatch.h new file mode 100644 index 00000000..59503a2c --- /dev/null +++ b/kernel/patch/include/hotpatch.h @@ -0,0 +1,8 @@ +#ifndef _KP_HOTPATCH_H_ +#define _KP_HOTPATCH_H_ + +#include + +int patch_verify_safety(); + +#endif \ No newline at end of file diff --git a/kernel/patch/include/kconfig.h b/kernel/patch/include/kconfig.h new file mode 100644 index 00000000..8dc9aced --- /dev/null +++ b/kernel/patch/include/kconfig.h @@ -0,0 +1,8 @@ +#ifndef _KP_KCONFIG_H_ +#define _KP_KCONFIG_H_ + +// todo: move config to here + +extern bool has_config_compat; + +#endif \ No newline at end of file diff --git a/kernel/patch/include/kputils.h b/kernel/patch/include/kputils.h new file mode 100644 index 00000000..bc08c389 --- /dev/null +++ b/kernel/patch/include/kputils.h @@ -0,0 +1,9 @@ +#ifndef _KP_UTILS_H_ +#define _KP_UTILS_H_ + +#include +#include + +int __must_check seq_copy_to_user(void __user *to, const void *from, int n); + +#endif \ No newline at end of file diff --git a/kernel/patch/include/ksyms.h b/kernel/patch/include/ksyms.h index 644a23d3..b2c483b6 100644 --- a/kernel/patch/include/ksyms.h +++ b/kernel/patch/include/ksyms.h @@ -1,5 +1,5 @@ -#ifndef _KSYMS_H -#define _KSYMS_H +#ifndef _KP_KSYMS_H +#define _KP_KSYMS_H #include #include @@ -14,42 +14,16 @@ #define kvar_match(var, name, addr) kv_##var = (typeof(kv_##var))kallsyms_lookup_name(#var) #define kfunc_match(func, name, addr) kf_##func = (typeof(kf_##func))kallsyms_lookup_name(#func) +#define kfunc_match_cfi(func, name, addr) \ + kf_##func = (typeof(kf_##func))kallsyms_lookup_name(#func ".cfi_jt"); \ + if (!kf_##func) kf_##func = (typeof(kf_##func))kallsyms_lookup_name(#func); #define kfunc_call(func, ...) \ - if (kf_##func) \ - return kf_##func(__VA_ARGS__); + if (kf_##func) return kf_##func(__VA_ARGS__); #define kfunc_call_void(func, ...) \ - if (kf_##func) \ - kf_##func(__VA_ARGS__); + if (kf_##func) kf_##func(__VA_ARGS__); // todo #define kfunc_not_found() logke("kfunc: %s not found\n", __func__); -#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) { \ - logke("hook: %s, ret: %d\n", #func, err_##func); \ - } \ - } else { \ - logkw("hook: %s not found\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) { \ - logke("hook: %s, ret: %d\n", #func, err_##func); \ - } \ - } else { \ - logkw("hook: %s not found\n", #func); \ - } - #endif diff --git a/kernel/patch/include/lsmext.h b/kernel/patch/include/lsmext.h deleted file mode 100644 index 05b63295..00000000 --- a/kernel/patch/include/lsmext.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _KP_LSMEXT_H_ -#define _KP_LSMEXT_H_ - -#include -#include -#include - -#define FAST_TABLE_ELEM_UNKNOWN 1 -#define FAST_TABLE_ELEM_INVALID 2 - -#define SECID_FAST_TABLE_NUM 4096 - -struct lsm_pair -{ - LSM_TYPE type; - LSM_VAL val; -}; - -struct task_selinux_rule -{ - u32 tsid; - u16 tclass; - u32 allowed; -}; - -struct selinux_policy -{ - struct list_head list; - const char *scontext; - const char *tcontext; - const char *tclass; - const char *perms; -}; - -static inline bool is_secid_fast(u32 secid) -{ - return secid >= 0 && secid < SECID_FAST_TABLE_NUM; -} - -int lsm_ext_init(); - -#endif \ No newline at end of file diff --git a/kernel/patch/include/module.h b/kernel/patch/include/module.h new file mode 100644 index 00000000..c400fd73 --- /dev/null +++ b/kernel/patch/include/module.h @@ -0,0 +1,56 @@ +#ifndef _KP_LOADER_H_ +#define _KP_LOADER_H_ + +#include +#include + +struct load_info +{ + struct + { + const char *base; + unsigned long size; + const char *name, *version, *license, *author, *description; + } info; + Elf_Ehdr *hdr; + unsigned long len; + Elf_Shdr *sechdrs; + char *secstrings, *strtab; + unsigned long symoffs, stroffs; + struct + { + unsigned int sym, str, mod, info; + } index; +}; + +struct module +{ + struct + { + const char *base, *name, *version, *license, *author, *description; + } info; + + char *args; + initcall_t *init; + exitcall_t *exit; + + unsigned int size; + unsigned int text_size; + unsigned int ro_size; + + void *start; + + struct list_head list; +}; + +int load_module(void *data, int len, const char *args); +int load_module_path(const char *path, const char *args); +int unload_module(const char *name); +struct module *find_module(const char *name); + +int get_module_nums(); +int get_module_info(int index, char *info, int size); + +int module_init(); + +#endif \ No newline at end of file diff --git a/kernel/patch/include/syscall.h b/kernel/patch/include/syscall.h index 546a0adb..397bf059 100644 --- a/kernel/patch/include/syscall.h +++ b/kernel/patch/include/syscall.h @@ -2,116 +2,14 @@ #define _KP_SYSCALL_H_ #include +#include +#include #include #include -#define SYS_CALL_MAX_NR 512 - -#define __MAP0(m, ...) -#define __MAP1(m, t, a, ...) m(t, a) -#define __MAP2(m, t, a, ...) m(t, a), __MAP1(m, __VA_ARGS__) -#define __MAP3(m, t, a, ...) m(t, a), __MAP2(m, __VA_ARGS__) -#define __MAP4(m, t, a, ...) m(t, a), __MAP3(m, __VA_ARGS__) -#define __MAP5(m, t, a, ...) m(t, a), __MAP4(m, __VA_ARGS__) -#define __MAP6(m, t, a, ...) m(t, a), __MAP5(m, __VA_ARGS__) -#define __MAP(n, ...) __MAP##n(__VA_ARGS__) - -#define __SC_DECL(t, a) t a -#define __SC_ARGS(t, a) a -#define __SC_EMPTY(t, a) 0 - -#define ARM64_REGS_TO_ARGS(x, ...) \ - __MAP(x, __SC_ARGS, , regs->regs[0], , regs->regs[1], , regs->regs[2], , regs->regs[3], , regs->regs[4], , \ - regs->regs[5]) - -#define __REGS_ASSIGN0(n, ...) -#define __REGS_ASSIGN1(n, t, a, ...) \ - a = (t)(regs->regs[n - 1]); \ - __REGS_ASSIGN0(n, __VA_ARGS__) -#define __REGS_ASSIGN2(n, t, a, ...) \ - a = (t)(regs->regs[n - 2]); \ - __REGS_ASSIGN1(n, __VA_ARGS__) -#define __REGS_ASSIGN3(n, t, a, ...) \ - a = (t)(regs->regs[n - 3]); \ - __REGS_ASSIGN2(n, __VA_ARGS__) -#define __REGS_ASSIGN4(n, t, a, ...) \ - a = (t)(regs->regs[n - 4]); \ - __REGS_ASSIGN3(n, __VA_ARGS__) -#define __REGS_ASSIGN5(n, t, a, ...) \ - a = (t)(regs->regs[n - 5]); \ - __REGS_ASSIGN4(n, __VA_ARGS__) -#define __REGS_ASSIGN6(n, t, a, ...) \ - a = (t)(regs->regs[n - 6]); \ - __REGS_ASSIGN5(n, __VA_ARGS__) -#define __REGS_ASSIGN(n, ...) __REGS_ASSIGN##n(n, __VA_ARGS__) - -#define HOOK_SYSCALL_DEFINE(x, nr, ...) \ - static long (*__hook_sys_backup_##nr)(__MAP(x, __SC_DECL, __VA_ARGS__)) = 0; \ - static long (*__hook_sys_wrap_backup_##nr)(const struct pt_regs *regs) = 0; \ - static long __hook_sys_bridge_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)); \ - static long __hook_sys_common_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)); \ - long __attribute__((__noinline__)) __hook_sys_##nr(__MAP(x, __SC_DECL, __VA_ARGS__)) \ - { \ - return __hook_sys_bridge_##nr(0, __MAP(x, __SC_ARGS, __VA_ARGS__)); \ - } \ - long __attribute__((__noinline__)) __hook_sys_wrap_##nr(const struct pt_regs *regs) \ - { \ - return __hook_sys_bridge_##nr(regs, __MAP(x, __SC_EMPTY, __VA_ARGS__)); \ - } \ - static long inline __hook_sys_bridge_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)) \ - { \ - if (regs) { \ - __REGS_ASSIGN(x, __VA_ARGS__); \ - } \ - return __hook_sys_common_##nr(regs, __MAP(x, __SC_ARGS, __VA_ARGS__)); \ - } \ - static long inline __hook_sys_common_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)) - -#define HOOK_SYSCALL_DEFINE0(nr, ...) HOOK_SYSCALL_DEFINE(0, nr, __VA_ARGS__) -#define HOOK_SYSCALL_DEFINE1(nr, ...) HOOK_SYSCALL_DEFINE(1, nr, __VA_ARGS__) -#define HOOK_SYSCALL_DEFINE2(nr, ...) HOOK_SYSCALL_DEFINE(2, nr, __VA_ARGS__) -#define HOOK_SYSCALL_DEFINE3(nr, ...) HOOK_SYSCALL_DEFINE(3, nr, __VA_ARGS__) -#define HOOK_SYSCALL_DEFINE4(nr, ...) HOOK_SYSCALL_DEFINE(4, nr, __VA_ARGS__) -#define HOOK_SYSCALL_DEFINE5(nr, ...) HOOK_SYSCALL_DEFINE(5, nr, __VA_ARGS__) -#define HOOK_SYSCALL_DEFINE6(nr, ...) HOOK_SYSCALL_DEFINE(6, nr, __VA_ARGS__) - -#define __HOOK_SYSCALL_CALL_ORIGIN(nr, ...) \ - (syscall_has_wrapper ? __hook_sys_wrap_backup_##nr(regs) : __hook_sys_backup_##nr(__VA_ARGS__)); - -#define HOOK_SYSCALL_CALL_ORIGIN(nr, ...) __HOOK_SYSCALL_CALL_ORIGIN(nr, __VA_ARGS__) - -#define __REPLACE_SYSCALL_INSTALL(nr) \ - if (syscall_has_wrapper) { \ - replace_syscall_with(nr, (uintptr_t *)&__hook_sys_wrap_backup_##nr, (uintptr_t)__hook_sys_wrap_##nr); \ - } else { \ - replace_syscall_with(nr, (uintptr_t *)&__hook_sys_backup_##nr, (uintptr_t)__hook_sys_##nr); \ - } -#define REPLACE_SYSCALL_INSTALL(nr) __REPLACE_SYSCALL_INSTALL(nr) - -#define __INLINE_SYSCALL_INSTALL(nr) \ - if (syscall_has_wrapper) { \ - inline_syscall_with(nr, (uintptr_t *)&__hook_sys_wrap_backup_##nr, (uintptr_t)__hook_sys_wrap_##nr); \ - } else { \ - inline_syscall_with(nr, (uintptr_t *)&__hook_sys_backup_##nr, (uintptr_t)__hook_sys_##nr); \ - } -#define INLINE_SYSCALL_INSTALL(nr) __INLINE_SYSCALL_INSTALL(nr) - -#define _ARGS_TO_REGS(regs, idx, val, ...) \ - do { \ - regs.regs[idx] = val; \ - ARGS_TO_REGS(regs, idx + 1, __VA_ARGS__); \ - } while (0) - -#define ARGS_TO_REGS(regs, ...) _ARGS_TO_REGS(regs, 0, __VA_ARGS__) - +extern uintptr_t kvar_def(sys_call_table); +extern uintptr_t kvar_def(compat_sys_call_table); extern bool syscall_has_wrapper; -extern uintptr_t syscall_table_addr; -extern uintptr_t compat_syscall_table_addr; - -void inline_syscall_with(long nr, uintptr_t *old, uintptr_t new); -void inline_compat_syscall_with(long nr, uintptr_t *old, uintptr_t new); -void replace_syscall_with(long nr, uintptr_t *old, uintptr_t newsc); -void replace_compat_syscall_with(long nr, uintptr_t *old, uintptr_t newsc); long raw_syscall0(long nr); long raw_syscall1(long nr, long arg0); @@ -123,6 +21,45 @@ long raw_syscall6(long nr, long arg0, long arg1, long arg2, long arg3, long arg4 #define raw_syscall(f) raw_syscall##f +static inline uint64_t *syscall_args(void *hook_fargs) +{ + uint64_t *args; + if (syscall_has_wrapper) + args = ((struct pt_regs *)((hook_fargs0_t *)hook_fargs)->args[0])->regs; + else + args = ((hook_fargs0_t *)hook_fargs)->args; + return args; +} + +static inline uint64_t syscall_argn(void *fdata_args, int n) +{ + return syscall_args(fdata_args)[n]; +} + +static inline hook_err_t fp_hook_syscalln(int nr, int narg, void *before, void *after, void *udata) +{ + uintptr_t fp_addr = (uintptr_t)(kvar(sys_call_table) + nr); + return fp_hook_wrap(fp_addr, narg, before, after, udata); +} + +static inline void fp_unhook_syscall(int nr, void *before, void *after) +{ + uintptr_t fp_addr = (uintptr_t)(kvar(sys_call_table) + nr); + fp_hook_unwrap(fp_addr, before, after); +} + +static inline hook_err_t inline_hook_syscalln(int nr, int narg, void *before, void *after, void *udata) +{ + uintptr_t fp = kvar(sys_call_table)[nr]; + return hook_wrap((void *)fp, narg, before, after, udata); +} + +static inline void inline_unhook_syscall(int nr, void *before, void *after) +{ + uintptr_t fp = kvar(sys_call_table)[nr]; + hook_unwrap((void *)fp, before, after); +} + int syscall_init(); #endif \ No newline at end of file diff --git a/kernel/patch/include/taskext.h b/kernel/patch/include/taskext.h index c4a7f547..37cfc5fe 100644 --- a/kernel/patch/include/taskext.h +++ b/kernel/patch/include/taskext.h @@ -20,7 +20,7 @@ struct task_ext static inline int task_ext_valid(struct task_ext *ext) { - return ext->magic == TASK_EXT_MAGIC; + return ext && (ext->magic == TASK_EXT_MAGIC); } #endif diff --git a/kernel/patch/include/taskob.h b/kernel/patch/include/taskob.h index 0a1491d6..fa74b976 100644 --- a/kernel/patch/include/taskob.h +++ b/kernel/patch/include/taskob.h @@ -1,4 +1,9 @@ #ifndef _KP_TASKOB_H_ #define _KP_TASKOB_H_ +#include + +hook_err_t add_execv_hook(hook_chain8_callback before, hook_chain8_callback after, void *udata); +void remove_execv_hook(hook_chain8_callback before, hook_chain8_callback after); + #endif \ No newline at end of file diff --git a/kernel/patch/include/uapi/lsmdef.h b/kernel/patch/include/uapi/lsmdef.h deleted file mode 100644 index fb4d5dd6..00000000 --- a/kernel/patch/include/uapi/lsmdef.h +++ /dev/null @@ -1,303 +0,0 @@ -#ifndef _KP_LSMDEF_H_ -#define _KP_LSMDEF_H_ - -// /include/linux/lsm_hooks.h - -typedef unsigned char LSM_VAL; - -#define LSM_VAL_IGNORE 0 -#define LSM_VAL_ALL 0xff - -typedef enum LSM_TYPE -{ - LSM_TYPE_MIN = 0, - LSM_TYPE_security_binder_set_context_mgr, - LSM_TYPE_security_binder_transaction, - LSM_TYPE_security_binder_transfer_binder, - LSM_TYPE_security_binder_transfer_file, - LSM_TYPE_security_ptrace_access_check, - LSM_TYPE_security_ptrace_traceme, - LSM_TYPE_security_capget, - LSM_TYPE_security_capset, - LSM_TYPE_security_capable, - LSM_TYPE_security_quotactl, - LSM_TYPE_security_quota_on, - LSM_TYPE_security_syslog, - LSM_TYPE_security_settime64, - LSM_TYPE_security_vm_enough_memory_mm, - LSM_TYPE_security_bprm_creds_for_exec, - LSM_TYPE_security_bprm_creds_from_file, - LSM_TYPE_security_bprm_check, - LSM_TYPE_security_bprm_committing_creds, - LSM_TYPE_security_bprm_committed_creds, - LSM_TYPE_security_fs_context_dup, - LSM_TYPE_security_fs_context_parse_param, - LSM_TYPE_security_sb_alloc, - LSM_TYPE_security_sb_delete, - LSM_TYPE_security_sb_free, - LSM_TYPE_security_free_mnt_opts, - LSM_TYPE_security_sb_eat_lsm_opts, - LSM_TYPE_security_sb_remount, - LSM_TYPE_security_sb_kern_mount, - LSM_TYPE_security_sb_show_options, - LSM_TYPE_security_sb_statfs, - LSM_TYPE_security_sb_mount, - LSM_TYPE_security_sb_umount, - LSM_TYPE_security_sb_pivotroot, - LSM_TYPE_security_sb_set_mnt_opts, - LSM_TYPE_security_sb_clone_mnt_opts, - LSM_TYPE_security_add_mnt_opt, - LSM_TYPE_security_move_mount, - LSM_TYPE_security_dentry_init_security, - LSM_TYPE_security_dentry_create_files_as, - - //config_security_path - LSM_TYPE_security_path_unlink, - LSM_TYPE_security_path_mkdir, - LSM_TYPE_security_path_rmdir, - LSM_TYPE_security_path_mknod, - LSM_TYPE_security_path_truncate, - LSM_TYPE_security_path_symlink, - LSM_TYPE_security_path_link, - LSM_TYPE_security_path_rename, - LSM_TYPE_security_path_chmod, - LSM_TYPE_security_path_chown, - LSM_TYPE_security_path_chroot, - /* config_security_path */ - - /* needed for inode based security check */ - LSM_TYPE_security_path_notify, - LSM_TYPE_security_inode_alloc, - LSM_TYPE_security_inode_free, - LSM_TYPE_security_inode_init_security, - LSM_TYPE_security_old_inode_init_security, - LSM_TYPE_security_inode_create, - LSM_TYPE_security_inode_link, - LSM_TYPE_security_inode_unlink, - LSM_TYPE_security_inode_symlink, - LSM_TYPE_security_inode_mkdir, - LSM_TYPE_security_inode_rmdir, - LSM_TYPE_security_inode_mknod, - LSM_TYPE_security_inode_rename, - LSM_TYPE_security_inode_readlink, - LSM_TYPE_security_inode_follow_link, - LSM_TYPE_security_inode_permission, - LSM_TYPE_security_inode_setattr, - LSM_TYPE_security_inode_getattr, - LSM_TYPE_security_inode_setxattr, - LSM_TYPE_security_inode_post_setxattr, - LSM_TYPE_security_inode_getxattr, - LSM_TYPE_security_inode_listxattr, - LSM_TYPE_security_inode_removexattr, - LSM_TYPE_security_inode_set_acl, - LSM_TYPE_security_inode_get_acl, - LSM_TYPE_security_inode_remove_acl, - LSM_TYPE_security_inode_need_killpriv, - LSM_TYPE_security_inode_killpriv, - LSM_TYPE_security_inode_getsecurity, - LSM_TYPE_security_inode_setsecurity, - LSM_TYPE_security_inode_listsecurity, - LSM_TYPE_security_inode_getsecid, - LSM_TYPE_security_inode_copy_up, - LSM_TYPE_security_inode_copy_up_xattr, - LSM_TYPE_security_kernfs_init_security, - LSM_TYPE_security_file_permission, - LSM_TYPE_security_file_alloc, - LSM_TYPE_security_file_free, - LSM_TYPE_security_file_ioctl, - LSM_TYPE_security_mmap_addr, - LSM_TYPE_security_mmap_file, - LSM_TYPE_security_file_mprotect, - LSM_TYPE_security_file_lock, - LSM_TYPE_security_file_fcntl, - LSM_TYPE_security_file_set_fowner, - LSM_TYPE_security_file_send_sigiotask, - LSM_TYPE_security_file_receive, - LSM_TYPE_security_file_open, - LSM_TYPE_security_file_truncate, - LSM_TYPE_security_task_alloc, - LSM_TYPE_security_task_free, - LSM_TYPE_security_cred_alloc_blank, - LSM_TYPE_security_cred_free, - LSM_TYPE_security_prepare_creds, - LSM_TYPE_security_transfer_creds, - LSM_TYPE_security_cred_getsecid, - LSM_TYPE_security_kernel_act_as, - LSM_TYPE_security_kernel_create_files_as, - LSM_TYPE_security_kernel_module_request, - LSM_TYPE_security_kernel_load_data, - LSM_TYPE_security_kernel_post_load_data, - LSM_TYPE_security_kernel_read_file, - LSM_TYPE_security_kernel_post_read_file, - LSM_TYPE_security_task_fix_setuid, - LSM_TYPE_security_task_fix_setgid, - LSM_TYPE_security_task_fix_setgroups, - LSM_TYPE_security_task_setpgid, - LSM_TYPE_security_task_getpgid, - LSM_TYPE_security_task_getsid, - LSM_TYPE_security_current_getsecid_subj, - LSM_TYPE_security_task_getsecid_obj, - LSM_TYPE_security_task_getsecid, - LSM_TYPE_security_task_setnice, - LSM_TYPE_security_task_setioprio, - LSM_TYPE_security_task_getioprio, - LSM_TYPE_security_task_prlimit, - LSM_TYPE_security_task_setrlimit, - LSM_TYPE_security_task_setscheduler, - LSM_TYPE_security_task_getscheduler, - LSM_TYPE_security_task_movememory, - LSM_TYPE_security_task_kill, - LSM_TYPE_security_task_prctl, - LSM_TYPE_security_task_to_inode, - LSM_TYPE_security_create_user_ns, - LSM_TYPE_security_ipc_permission, - LSM_TYPE_security_ipc_getsecid, - LSM_TYPE_security_msg_msg_alloc, - LSM_TYPE_security_msg_msg_free, - LSM_TYPE_security_msg_queue_alloc, - LSM_TYPE_security_msg_queue_free, - LSM_TYPE_security_msg_queue_associate, - LSM_TYPE_security_msg_queue_msgctl, - LSM_TYPE_security_msg_queue_msgsnd, - LSM_TYPE_security_msg_queue_msgrcv, - LSM_TYPE_security_shm_alloc, - LSM_TYPE_security_shm_free, - LSM_TYPE_security_shm_associate, - LSM_TYPE_security_shm_shmctl, - LSM_TYPE_security_shm_shmat, - LSM_TYPE_security_sem_alloc, - LSM_TYPE_security_sem_free, - LSM_TYPE_security_sem_associate, - LSM_TYPE_security_sem_semctl, - LSM_TYPE_security_sem_semop, - LSM_TYPE_security_d_instantiate, - LSM_TYPE_security_getprocattr, - LSM_TYPE_security_setprocattr, - LSM_TYPE_security_netlink_send, - LSM_TYPE_security_ismaclabel, - LSM_TYPE_security_secid_to_secctx, - LSM_TYPE_security_secctx_to_secid, - LSM_TYPE_security_release_secctx, - LSM_TYPE_security_inode_invalidate_secctx, - LSM_TYPE_security_inode_notifysecctx, - LSM_TYPE_security_inode_setsecctx, - LSM_TYPE_security_inode_getsecctx, - - // config_watch_queue - LSM_TYPE_security_post_notification, - - // config_key_notifications - LSM_TYPE_security_watch_key, - - // config_security_network - LSM_TYPE_security_unix_stream_connect, - LSM_TYPE_security_unix_may_send, - LSM_TYPE_security_socket_create, - LSM_TYPE_security_socket_post_create, - LSM_TYPE_security_socket_socketpair, - LSM_TYPE_security_socket_bind, - LSM_TYPE_security_socket_connect, - LSM_TYPE_security_socket_listen, - LSM_TYPE_security_socket_accept, - LSM_TYPE_security_socket_sendmsg, - LSM_TYPE_security_socket_recvmsg, - LSM_TYPE_security_socket_getsockname, - LSM_TYPE_security_socket_getpeername, - LSM_TYPE_security_socket_getsockopt, - LSM_TYPE_security_socket_setsockopt, - LSM_TYPE_security_socket_shutdown, - LSM_TYPE_security_sock_rcv_skb, - LSM_TYPE_security_socket_getpeersec_stream, - LSM_TYPE_security_socket_getpeersec_dgram, - LSM_TYPE_security_sk_alloc, - LSM_TYPE_security_sk_free, - LSM_TYPE_security_sk_clone, - LSM_TYPE_security_sk_classify_flow, - LSM_TYPE_security_req_classify_flow, - LSM_TYPE_security_sock_graft, - LSM_TYPE_security_inet_conn_request, - LSM_TYPE_security_inet_csk_clone, - LSM_TYPE_security_inet_conn_established, - LSM_TYPE_security_secmark_relabel_packet, - LSM_TYPE_security_secmark_refcount_inc, - LSM_TYPE_security_secmark_refcount_dec, - LSM_TYPE_security_tun_dev_alloc_security, - LSM_TYPE_security_tun_dev_free_security, - LSM_TYPE_security_tun_dev_create, - LSM_TYPE_security_tun_dev_attach_queue, - LSM_TYPE_security_tun_dev_attach, - LSM_TYPE_security_tun_dev_open, - LSM_TYPE_security_sctp_assoc_request, - LSM_TYPE_security_sctp_bind_connect, - LSM_TYPE_security_sctp_sk_clone, - LSM_TYPE_security_sctp_assoc_established, - - // config_security_infiniband - LSM_TYPE_security_ib_pkey_access, - LSM_TYPE_security_ib_endport_manage_subnet, - LSM_TYPE_security_ib_alloc_security, - LSM_TYPE_security_ib_free_security, - - // config_security_network_xfrm - LSM_TYPE_security_xfrm_policy_alloc, - LSM_TYPE_security_xfrm_policy_clone, - LSM_TYPE_security_xfrm_policy_free, - LSM_TYPE_security_xfrm_policy_delete, - LSM_TYPE_security_xfrm_state_alloc, - LSM_TYPE_security_xfrm_state_alloc_acquire, - LSM_TYPE_security_xfrm_state_delete, - LSM_TYPE_security_xfrm_state_free, - LSM_TYPE_security_xfrm_policy_lookup, - LSM_TYPE_security_xfrm_state_pol_flow_match, - LSM_TYPE_security_xfrm_decode_session, - LSM_TYPE_security_skb_classify_flow, - - /* key management security hooks */ - // config_keys - LSM_TYPE_security_key_alloc, - LSM_TYPE_security_key_free, - LSM_TYPE_security_key_permission, - LSM_TYPE_security_key_getsecurity, - - // config_audit - LSM_TYPE_security_audit_rule_init, - LSM_TYPE_security_audit_rule_known, - LSM_TYPE_security_audit_rule_free, - LSM_TYPE_security_audit_rule_match, - - // config_bpf_syscall - LSM_TYPE_security_bpf, - LSM_TYPE_security_bpf_map, - LSM_TYPE_security_bpf_prog, - LSM_TYPE_security_bpf_map_alloc, - LSM_TYPE_security_bpf_prog_alloc, - LSM_TYPE_security_bpf_map_free, - LSM_TYPE_security_bpf_prog_free, - // config_bpf_syscall - - LSM_TYPE_security_locked_down, - - // config_perf_events - LSM_TYPE_security_perf_event_open, - LSM_TYPE_security_perf_event_alloc, - LSM_TYPE_security_perf_event_free, - LSM_TYPE_security_perf_event_read, - LSM_TYPE_security_perf_event_write, - - // config_io_uring - LSM_TYPE_security_uring_override_creds, - LSM_TYPE_security_uring_sqpoll, - LSM_TYPE_security_uring_cmd, - - // - LSM_TYPE_MAX, -} LSM_TYPE; - -#define LSM_TYPE_INVALID LSM_TYPE_MAX - -static inline int lsm_type_valid(LSM_TYPE type) -{ - return type > LSM_TYPE_MIN && type < LSM_TYPE_MAX; -} - -#endif diff --git a/kernel/patch/include/uapi/scdefs.h b/kernel/patch/include/uapi/scdefs.h index ba3aab39..0a5d4fe8 100644 --- a/kernel/patch/include/uapi/scdefs.h +++ b/kernel/patch/include/uapi/scdefs.h @@ -16,30 +16,34 @@ static inline long hash_key(const char *key) #define SUPERCALL_HELLO 0x1000 #define SUPERCALL_GET_KERNEL_VERSION 0x1001 #define SUPERCALL_GET_KP_VERSION 0x1002 -#define SUPERCALL_LOAD_KPM 0x1003 -#define SUPERCALL_UNLOAD_KPM 0x1004 -#define SUPERCALL_SU 0x1005 -#define SUPERCALL_THREAD_SU 0x1006 -#define SUPERCALL_THREAD_UNSU 0x1007 + +#define SUPERCALL_LOAD_KPM 0x1010 +#define SUPERCALL_UNLOAD_KPM 0x1011 +#define SUPERCALL_KPM_NUMS 0x1012 +#define SUPERCALL_KPM_INFO 0x1013 +#define SUPERCALL_SU 0x1020 +#define SUPERCALL_THREAD_SU 0x1021 +#define SUPERCALL_THREAD_UNSU 0x1022 + +#define SUPERCALL_KEY_MAX_LEN 64 +#define SUPERCALL_SCONTEXT_LEN 64 #ifdef ANDROID -#define SUPERCALL_GRANT_SU 0x1020 -#define SUPERCALL_REVOKE_SU 0x1021 -#define SUPERCALL_LIST_SU_ALLOW 0x1022 -#define SUPERCALL_RESET_SU_CMD 0x1023 +#define SUPERCALL_GRANT_SU 0x1100 +#define SUPERCALL_REVOKE_SU 0x1101 +#define SUPERCALL_SU_ALLOW_NUM 0x1102 +#define SUPERCALL_LIST_SU_ALLOW 0x1103 +#define SUPERCALL_SU_RESET_PATH 0x1104 +#define SUPERCALL_SU_GET_PATH 0x1105 #define SUPERCALL_SU_ALLOW_UID_MAX 32 -#define SUPERCALL_SU_CMD_LEN 14 +#define SUPERCALL_SU_PATH_LEN 15 #endif -#define SUPERCALL_MAX 0x1100 +#define SUPERCALL_MAX 0x1200 #define SUPERCALL_RES_SUCCEED 0 -#define SUPERCALL_RES_FAILED 1 -#define SUPERCALL_RES_NOT_IMPL 2 #define SUPERCALL_HELLO_MAGIC 0x1158 -#define SUPERCALL_SCONTEXT_LEN 64 - #endif diff --git a/kernel/patch/ksyms/libs.c b/kernel/patch/ksyms/libs.c new file mode 100644 index 00000000..1ae73931 --- /dev/null +++ b/kernel/patch/ksyms/libs.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include + +// lib/dump_stack.c +void kfunc_def(dump_stack_lvl)(const char *log_lvl) = 0; +KP_EXPORT_SYMBOL(kfunc(dump_stack_lvl)); +void kfunc_def(dump_stack)(void) = 0; +KP_EXPORT_SYMBOL(kfunc(dump_stack)); + +static void _linux_lib_dump_stack_sym_match() +{ + kfunc_match(dump_stack_lvl, name, addr); + kfunc_match(dump_stack, name, addr); +} + +#include + +long kfunc_def(strncpy_from_user_nofault)(char *dst, const void __user *unsafe_addr, long count) = 0; +KP_EXPORT_SYMBOL(kfunc(strncpy_from_user_nofault)); +long kfunc_def(strncpy_from_unsafe_user)(char *dst, const void __user *unsafe_addr, long count) = 0; +KP_EXPORT_SYMBOL(kfunc(strncpy_from_unsafe_user)); +long kfunc_def(strncpy_from_user)(char *dest, const char __user *src, long count) = 0; +KP_EXPORT_SYMBOL(kfunc(strncpy_from_user)); +long kfunc_def(strnlen_user_nofault)(const void __user *unsafe_addr, long count) = 0; +KP_EXPORT_SYMBOL(kfunc(strnlen_user_nofault)); +long kfunc_def(strnlen_unsafe_user)(const void __user *unsafe_addr, long count) = 0; +KP_EXPORT_SYMBOL(kfunc(strnlen_unsafe_user)); +long kfunc_def(strnlen_user)(const char __user *str, long n); +KP_EXPORT_SYMBOL(kfunc(strnlen_user)); + +static void _linux_lib_strncpy_from_user_sym_match() +{ + kfunc_match(strncpy_from_user_nofault, name, addr); + if (!kfunc(strncpy_from_user_nofault)) { + kfunc_match(strncpy_from_unsafe_user, name, addr); + } + kfunc_match(strncpy_from_user, name, addr); + + kfunc_match(strnlen_user_nofault, name, addr); + if (!kfunc(strnlen_user_nofault)) { + kfunc_match(strnlen_unsafe_user, name, addr); + } + kfunc_match(strnlen_user, name, addr); +} + +// lib/string.c +#include + +int kfunc_def(strncasecmp)(const char *s1, const char *s2, size_t len) = 0; +KP_EXPORT_SYMBOL(kfunc(strncasecmp)); +int kfunc_def(strcasecmp)(const char *s1, const char *s2) = 0; +KP_EXPORT_SYMBOL(kfunc(strcasecmp)); +char *kfunc_def(strcpy)(char *dest, const char *src) = 0; +KP_EXPORT_SYMBOL(kfunc(strcpy)); +char *kfunc_def(strncpy)(char *dest, const char *src, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(strncpy)); +size_t kfunc_def(strlcpy)(char *dest, const char *src, size_t size) = 0; +KP_EXPORT_SYMBOL(kfunc(strlcpy)); +ssize_t kfunc_def(strscpy)(char *dest, const char *src, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(strscpy)); +ssize_t kfunc_def(strscpy_pad)(char *dest, const char *src, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(strscpy_pad)); +char *kfunc_def(stpcpy)(char *__restrict__ dest, const char *__restrict__ src) = 0; +KP_EXPORT_SYMBOL(kfunc(stpcpy)); +char *kfunc_def(strcat)(char *dest, const char *src) = 0; +KP_EXPORT_SYMBOL(kfunc(strcat)); +char *kfunc_def(strncat)(char *dest, const char *src, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(strncat)); +size_t kfunc_def(strlcat)(char *dest, const char *src, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(strlcat)); +int kfunc_def(strcmp)(const char *cs, const char *ct) = 0; +KP_EXPORT_SYMBOL(kfunc(strcmp)); +int kfunc_def(strncmp)(const char *cs, const char *ct, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(strncmp)); +char *kfunc_def(strchr)(const char *s, int c) = 0; +KP_EXPORT_SYMBOL(kfunc(strchr)); +char *kfunc_def(strchrnul)(const char *s, int c) = 0; +KP_EXPORT_SYMBOL(kfunc(strchrnul)); +char *kfunc_def(strnchrnul)(const char *s, size_t count, int c) = 0; +KP_EXPORT_SYMBOL(kfunc(strnchrnul)); +char *kfunc_def(strrchr)(const char *s, int c) = 0; +KP_EXPORT_SYMBOL(kfunc(strrchr)); +char *kfunc_def(strnchr)(const char *s, size_t count, int c) = 0; +KP_EXPORT_SYMBOL(kfunc(strnchr)); +char *kfunc_def(skip_spaces)(const char *str) = 0; +KP_EXPORT_SYMBOL(kfunc(skip_spaces)); +char *kfunc_def(strim)(char *s) = 0; +KP_EXPORT_SYMBOL(kfunc(strim)); +size_t kfunc_def(strlen)(const char *s) = 0; +KP_EXPORT_SYMBOL(kfunc(strlen)); +size_t kfunc_def(strnlen)(const char *s, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(strnlen)); +size_t kfunc_def(strspn)(const char *s, const char *accept) = 0; +KP_EXPORT_SYMBOL(kfunc(strspn)); +size_t kfunc_def(strcspn)(const char *s, const char *reject) = 0; +KP_EXPORT_SYMBOL(kfunc(strcspn)); +char *kfunc_def(strpbrk)(const char *cs, const char *ct) = 0; +KP_EXPORT_SYMBOL(kfunc(strpbrk)); +char *kfunc_def(strsep)(char **s, const char *ct) = 0; +KP_EXPORT_SYMBOL(kfunc(strsep)); +bool kfunc_def(sysfs_streq)(const char *s1, const char *s2) = 0; +KP_EXPORT_SYMBOL(kfunc(sysfs_streq)); +int kfunc_def(match_string)(const char *const *array, size_t n, const char *string) = 0; +KP_EXPORT_SYMBOL(kfunc(match_string)); +int kfunc_def(__sysfs_match_string)(const char *const *array, size_t n, const char *str) = 0; +KP_EXPORT_SYMBOL(kfunc(__sysfs_match_string)); +void *kfunc_def(memset)(void *s, int c, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(memset)); +void *kfunc_def(memset16)(uint16_t *s, uint16_t v, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(memset16)); +void *kfunc_def(memset32)(uint32_t *s, uint32_t v, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(memset32)); +void *kfunc_def(memset64)(uint64_t *s, uint64_t v, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(memset64)); +void *kfunc_def(memcpy)(void *dest, const void *src, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(memcpy)); +void *kfunc_def(memmove)(void *dest, const void *src, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(memmove)); +int kfunc_def(memcmp)(const void *cs, const void *ct, size_t count) = 0; +KP_EXPORT_SYMBOL(kfunc(memcmp)); +int kfunc_def(bcmp)(const void *a, const void *b, size_t len) = 0; +KP_EXPORT_SYMBOL(kfunc(bcmp)); +void *kfunc_def(memscan)(void *addr, int c, size_t size) = 0; +KP_EXPORT_SYMBOL(kfunc(memscan)); +char *kfunc_def(strstr)(const char *s1, const char *s2) = 0; +KP_EXPORT_SYMBOL(kfunc(strstr)); +char *kfunc_def(strnstr)(const char *s1, const char *s2, size_t len) = 0; +KP_EXPORT_SYMBOL(kfunc(strnstr)); +void *kfunc_def(memchr)(const void *s, int c, size_t n) = 0; +KP_EXPORT_SYMBOL(kfunc(memchr)); +void *kfunc_def(memchr_inv)(const void *start, int c, size_t bytes) = 0; +KP_EXPORT_SYMBOL(kfunc(memchr_inv)); +char *kfunc_def(strreplace)(char *s, char old, char new) = 0; +KP_EXPORT_SYMBOL(kfunc(strreplace)); +void kfunc_def(fortify_panic)(const char *name) = 0; +KP_EXPORT_SYMBOL(kfunc(fortify_panic)); + +static void _linux_lib_string_sym_match() +{ + kfunc_match(strncasecmp, name, addr); + kfunc_match(strcasecmp, name, addr); + kfunc_match(strcpy, name, addr); + kfunc_match(strncpy, name, addr); + kfunc_match(strlcpy, name, addr); + kfunc_match(strscpy, name, addr); + kfunc_match(strscpy_pad, name, addr); + kfunc_match(stpcpy, name, addr); + kfunc_match(strcat, name, addr); + kfunc_match(strncat, name, addr); + kfunc_match(strlcat, name, addr); + kfunc_match(strcmp, name, addr); + kfunc_match(strncmp, name, addr); + kfunc_match(strchr, name, addr); + kfunc_match(strchrnul, name, addr); + kfunc_match(strnchrnul, name, addr); + kfunc_match(strrchr, name, addr); + kfunc_match(strnchr, name, addr); + kfunc_match(skip_spaces, name, addr); + kfunc_match(strim, name, addr); + kfunc_match(strlen, name, addr); + kfunc_match(strnlen, name, addr); + kfunc_match(strspn, name, addr); + kfunc_match(strcspn, name, addr); + kfunc_match(strpbrk, name, addr); + kfunc_match(strsep, name, addr); + // kfunc_match(sysfs_streq, name, addr); + kfunc_match(match_string, name, addr); + // kfunc_match(__sysfs_match_string, name, addr); + kfunc_match(memset, name, addr); + // kfunc_match(memset16, name, addr); + // kfunc_match(memset32, name, addr); + // kfunc_match(memset64, name, addr); + kfunc_match(memcpy, name, addr); + kfunc_match(memmove, name, addr); + kfunc_match(memcmp, name, addr); + kfunc_match(bcmp, name, addr); + kfunc_match(memscan, name, addr); + kfunc_match(strstr, name, addr); + kfunc_match(strnstr, name, addr); + kfunc_match(memchr, name, addr); + kfunc_match(memchr_inv, name, addr); + kfunc_match(strreplace, name, addr); + // kfunc_match(fortify_panic, name, addr); +} + +// lib/argv_split.c +void kfunc_def(argv_free)(char **argv) = 0; +KP_EXPORT_SYMBOL(kfunc(argv_free)); +char **kfunc_def(argv_split)(gfp_t gfp, const char *str, int *argcp) = 0; +KP_EXPORT_SYMBOL(kfunc(argv_split)); + +static void _linux_lib_argv_split_sym_match() +{ + kfunc_match(argv_free, name, addr); + kfunc_match(argv_split, name, addr); +} + +#include +#include + +int kfunc_def(seq_buf_printf)(struct seq_buf *s, const char *fmt, ...) = 0; +KP_EXPORT_SYMBOL(kfunc(seq_buf_printf)); +int kfunc_def(seq_buf_to_user)(struct seq_buf *s, char __user *ubuf, int cnt) = 0; +KP_EXPORT_SYMBOL(kfunc(seq_buf_to_user)); +int kfunc_def(seq_buf_puts)(struct seq_buf *s, const char *str) = 0; +KP_EXPORT_SYMBOL(kfunc(seq_buf_puts)); +int kfunc_def(seq_buf_putc)(struct seq_buf *s, unsigned char c) = 0; +KP_EXPORT_SYMBOL(kfunc(seq_buf_putc)); +int kfunc_def(seq_buf_putmem)(struct seq_buf *s, const void *mem, unsigned int len) = 0; +KP_EXPORT_SYMBOL(kfunc(seq_buf_putmem)); +int kfunc_def(seq_buf_putmem_hex)(struct seq_buf *s, const void *mem, unsigned int len) = 0; +KP_EXPORT_SYMBOL(kfunc(seq_buf_putmem_hex)); +int kfunc_def(seq_buf_bitmask)(struct seq_buf *s, const unsigned long *maskp, int nmaskbits) = 0; +KP_EXPORT_SYMBOL(kfunc(seq_buf_bitmask)); + +int kfunc_def(trace_seq_printf)(struct trace_seq *s, const char *fmt, ...) = 0; +KP_EXPORT_SYMBOL(kfunc(trace_seq_printf)); +int kfunc_def(trace_seq_to_user)(struct trace_seq *s, char __user *ubuf, int cnt) = 0; +KP_EXPORT_SYMBOL(kfunc(trace_seq_to_user)); +int kfunc_def(trace_seq_puts)(struct trace_seq *s, const char *str) = 0; +KP_EXPORT_SYMBOL(kfunc(trace_seq_puts)); +int kfunc_def(trace_seq_putc)(struct trace_seq *s, unsigned char c) = 0; +KP_EXPORT_SYMBOL(kfunc(trace_seq_putc)); +int kfunc_def(trace_seq_putmem)(struct trace_seq *s, const void *mem, unsigned int len) = 0; +KP_EXPORT_SYMBOL(kfunc(trace_seq_putmem)); +int kfunc_def(trace_seq_putmem_hex)(struct trace_seq *s, const void *mem, unsigned int len) = 0; +KP_EXPORT_SYMBOL(kfunc(trace_seq_putmem_hex)); +int kfunc_def(trace_seq_bitmask)(struct trace_seq *s, const unsigned long *maskp, int nmaskbits) = 0; +KP_EXPORT_SYMBOL(kfunc(trace_seq_bitmask)); + +static void _linux_lib_seq_buf_sym_match() +{ + kfunc_match(seq_buf_to_user, name, addr); + if (kfunc(seq_buf_to_user)) { + kfunc_match(seq_buf_printf, name, addr); + kfunc_match(seq_buf_puts, name, addr); + // kfunc_match(seq_buf_putc, name, addr); + kfunc_match(seq_buf_putmem, name, addr); + // kfunc_match(seq_buf_putmem_hex, name, addr); + // kfunc_match(seq_buf_bitmask, name, addr); + } else { + kfunc_match(trace_seq_printf, name, addr); + kfunc_match(trace_seq_to_user, name, addr); + kfunc_match(trace_seq_puts, name, addr); + // kfunc_match(trace_seq_putc, name, addr); + kfunc_match(trace_seq_putmem, name, addr); + // kfunc_match(trace_seq_putmem_hex, name, addr); + // kfunc_match(trace_seq_bitmask, name, addr); + } +} + +// linux/include/kernel.h +int kfunc_def(sprintf)(char *buf, const char *fmt, ...) = 0; +KP_EXPORT_SYMBOL(kfunc(sprintf)); +int kfunc_def(vsprintf)(char *buf, const char *fmt, va_list args) = 0; +KP_EXPORT_SYMBOL(kfunc(vsprintf)); +int kfunc_def(snprintf)(char *buf, size_t size, const char *fmt, ...) = 0; +KP_EXPORT_SYMBOL(kfunc(snprintf)); +int kfunc_def(vsnprintf)(char *buf, size_t size, const char *fmt, va_list args) = 0; +KP_EXPORT_SYMBOL(kfunc(vsnprintf)); +int kfunc_def(scnprintf)(char *buf, size_t size, const char *fmt, ...) = 0; +KP_EXPORT_SYMBOL(kfunc(scnprintf)); +int kfunc_def(vscnprintf)(char *buf, size_t size, const char *fmt, va_list args) = 0; +KP_EXPORT_SYMBOL(kfunc(vscnprintf)); +char *kfunc_def(kasprintf)(gfp_t gfp, const char *fmt, ...) = 0; +KP_EXPORT_SYMBOL(kfunc(kasprintf)); +char *kfunc_def(kvasprintf)(gfp_t gfp, const char *fmt, va_list args) = 0; +KP_EXPORT_SYMBOL(kfunc(kvasprintf)); +int kfunc_def(sscanf)(const char *buf, const char *fmt, ...) = 0; +KP_EXPORT_SYMBOL(kfunc(sscanf)); +int kfunc_def(vsscanf)(const char *buf, const char *fmt, va_list args) = 0; +KP_EXPORT_SYMBOL(kfunc(vsscanf)); + +static void _linux_include_kernel_sym_match() +{ + kfunc_match(sprintf, name, addr); + kfunc_match(vsprintf, name, addr); + kfunc_match(snprintf, name, addr); + kfunc_match(vsnprintf, name, addr); + kfunc_match(scnprintf, name, addr); + kfunc_match(vscnprintf, name, addr); + kfunc_match(kasprintf, name, addr); + kfunc_match(kvasprintf, name, addr); + kfunc_match(sscanf, name, addr); + kfunc_match(vsscanf, name, addr); +} + +int linux_libs_symbol_init() +{ + int rc = 0; + _linux_lib_dump_stack_sym_match(); + _linux_lib_strncpy_from_user_sym_match(); + _linux_lib_string_sym_match(); + _linux_lib_argv_split_sym_match(); + _linux_lib_seq_buf_sym_match(); + _linux_include_kernel_sym_match(); + return rc; +} diff --git a/kernel/patch/ksyms/misc.c b/kernel/patch/ksyms/misc.c index d750cddd..49d67631 100644 --- a/kernel/patch/ksyms/misc.c +++ b/kernel/patch/ksyms/misc.c @@ -1,24 +1,14 @@ #include #include +#include +#include +#include #include #include #include -#include // init/init_task.c kernel/cred.c -struct task_struct *kvar(init_task) = 0; -union thread_union *kvar(init_thread_union) = 0; - -void _linux_init_task_sym_match() -{ - kvar_match(init_task, name, addr); - kvar_match(init_thread_union, name, addr); -} - -struct cred *kvar(init_cred) = 0; -struct group_info *kvar(init_groups) = 0; - void kfunc_def(__put_cred)(struct cred *) = 0; void kfunc_def(exit_creds)(struct task_struct *) = 0; int kfunc_def(copy_creds)(struct task_struct *, unsigned long) = 0; @@ -41,8 +31,6 @@ bool kfunc_def(creds_are_invalid)(const struct cred *cred) = 0; void _linux_kernel_cred_sym_match() { - kvar_match(init_cred, name, addr); - kvar_match(init_groups, name, addr); kfunc_match(__put_cred, name, addr); // kfunc_match(exit_creds, name, addr); kfunc_match(copy_creds, name, addr); @@ -157,7 +145,7 @@ int kfunc_def(unshare_fd)(unsigned long unshare_flags, unsigned int max_fds, str int kfunc_def(ksys_unshare)(unsigned long unshare_flags) = 0; int kfunc_def(unshare_files)(struct files_struct **displaced) = 0; -void _linux_kernel_fork_sym_match() +static void _linux_kernel_fork_sym_match() { // kfunc_match(pidfd_pid, name, addr); // kfunc_match(get_mm_exe_file, name, addr); @@ -246,166 +234,17 @@ void _linux_kernel_pid_sym_match() // kernel/stop_machine.c #include +bool kvar_def(stop_machine_initialized) = 0; +const struct cpumask *kvar_def(cpu_online_mask) = 0; int kfunc_def(stop_machine)(int (*fn)(void *), void *data, const struct cpumask *cpus) = 0; -void _linux_kernel_stop_machine_sym_match() +static void _linux_kernel_stop_machine_sym_match() { + kvar_match(stop_machine_initialized, name, addr); + kvar_match(cpu_online_mask, name, addr); kfunc_match(stop_machine, name, addr); } -// lib/argv_split.c - -void kfunc_def(argv_free)(char **argv) = 0; -char **kfunc_def(argv_split)(gfp_t gfp, const char *str, int *argcp) = 0; - -void _linux_lib_argv_split_sym_match() -{ - // kfunc_match(argv_free, name, addr); - // kfunc_match(argv_split, name, addr); -} - -// lib/kstrtox.c -int kfunc_def(kstrtoull)(const char *s, unsigned int base, unsigned long long *res) = 0; -int kfunc_def(kstrtoll)(const char *s, unsigned int base, long long *res) = 0; -int kfunc_def(kstrtouint)(const char *s, unsigned int base, unsigned int *res) = 0; -int kfunc_def(kstrtoint)(const char *s, unsigned int base, int *res) = 0; -int kfunc_def(kstrtou16)(const char *s, unsigned int base, u16 *res) = 0; -int kfunc_def(kstrtos16)(const char *s, unsigned int base, s16 *res) = 0; -int kfunc_def(kstrtou8)(const char *s, unsigned int base, u8 *res) = 0; -int kfunc_def(kstrtos8)(const char *s, unsigned int base, s8 *res) = 0; -int kfunc_def(kstrtobool)(const char *s, bool *res) = 0; -int kfunc_def(kstrtobool_from_user)(const char __user *s, size_t count, bool *res) = 0; - -void _linxu_lib_kstrtox_sym_match() -{ - // kfunc_match(kstrtoull, name, addr); - // kfunc_match(kstrtoll, name, addr); - // kfunc_match(kstrtouint, name, addr); - // kfunc_match(kstrtoint, name, addr); - // kfunc_match(kstrtou16, name, addr); - // kfunc_match(kstrtos16, name, addr); - // kfunc_match(kstrtou8, name, addr); - // kfunc_match(kstrtos8, name, addr); - // kfunc_match(kstrtobool, name, addr); - // kfunc_match(kstrtobool_from_user, name, addr); -} - -// lib/string.c -#include - -int kfunc_def(strncasecmp)(const char *s1, const char *s2, size_t len) = 0; -int kfunc_def(strcasecmp)(const char *s1, const char *s2) = 0; -char *kfunc_def(strcpy)(char *dest, const char *src) = 0; -char *kfunc_def(strncpy)(char *dest, const char *src, size_t count) = 0; -size_t kfunc_def(strlcpy)(char *dest, const char *src, size_t size) = 0; -ssize_t kfunc_def(strscpy)(char *dest, const char *src, size_t count) = 0; -ssize_t kfunc_def(strscpy_pad)(char *dest, const char *src, size_t count) = 0; -char *kfunc_def(stpcpy)(char *__restrict__ dest, const char *__restrict__ src) = 0; -char *kfunc_def(strcat)(char *dest, const char *src) = 0; -char *kfunc_def(strncat)(char *dest, const char *src, size_t count) = 0; -size_t kfunc_def(strlcat)(char *dest, const char *src, size_t count) = 0; -int kfunc_def(strcmp)(const char *cs, const char *ct) = 0; -int kfunc_def(strncmp)(const char *cs, const char *ct, size_t count) = 0; -char *kfunc_def(strchr)(const char *s, int c) = 0; -char *kfunc_def(strchrnul)(const char *s, int c) = 0; -char *kfunc_def(strnchrnul)(const char *s, size_t count, int c) = 0; -char *kfunc_def(strrchr)(const char *s, int c) = 0; -char *kfunc_def(strnchr)(const char *s, size_t count, int c) = 0; -char *kfunc_def(skip_spaces)(const char *str) = 0; -char *kfunc_def(strim)(char *s) = 0; -size_t kfunc_def(strlen)(const char *s) = 0; -size_t kfunc_def(strnlen)(const char *s, size_t count) = 0; -size_t kfunc_def(strspn)(const char *s, const char *accept) = 0; -size_t kfunc_def(strcspn)(const char *s, const char *reject) = 0; -char *kfunc_def(strpbrk)(const char *cs, const char *ct) = 0; -char *kfunc_def(strsep)(char **s, const char *ct) = 0; -bool kfunc_def(sysfs_streq)(const char *s1, const char *s2) = 0; -int kfunc_def(match_string)(const char *const *array, size_t n, const char *string) = 0; -int kfunc_def(__sysfs_match_string)(const char *const *array, size_t n, const char *str) = 0; -void *kfunc_def(memset)(void *s, int c, size_t count) = 0; -void *kfunc_def(memset16)(uint16_t *s, uint16_t v, size_t count) = 0; -void *kfunc_def(memset32)(uint32_t *s, uint32_t v, size_t count) = 0; -void *kfunc_def(memset64)(uint64_t *s, uint64_t v, size_t count) = 0; -void *kfunc_def(memcpy)(void *dest, const void *src, size_t count) = 0; -void *kfunc_def(memmove)(void *dest, const void *src, size_t count) = 0; -int kfunc_def(memcmp)(const void *cs, const void *ct, size_t count) = 0; -int kfunc_def(bcmp)(const void *a, const void *b, size_t len) = 0; -void *kfunc_def(memscan)(void *addr, int c, size_t size) = 0; -char *kfunc_def(strstr)(const char *s1, const char *s2) = 0; -char *kfunc_def(strnstr)(const char *s1, const char *s2, size_t len) = 0; -void *kfunc_def(memchr)(const void *s, int c, size_t n) = 0; -void *kfunc_def(memchr_inv)(const void *start, int c, size_t bytes) = 0; -char *kfunc_def(strreplace)(char *s, char old, char new) = 0; -void kfunc_def(fortify_panic)(const char *name) = 0; - -void _linux_lib_string_sym_match() -{ - kfunc_match(strncasecmp, name, addr); - kfunc_match(strcasecmp, name, addr); - kfunc_match(strcpy, name, addr); - kfunc_match(strncpy, name, addr); - // kfunc_match(strlcpy, name, addr); - // kfunc_match(strscpy, name, addr); - // kfunc_match(strscpy_pad, name, addr); - kfunc_match(stpcpy, name, addr); - kfunc_match(strcat, name, addr); - kfunc_match(strncat, name, addr); - kfunc_match(strlcat, name, addr); - kfunc_match(strcmp, name, addr); - kfunc_match(strncmp, name, addr); - // kfunc_match(strchr, name, addr); - // kfunc_match(strchrnul, name, addr); - // kfunc_match(strnchrnul, name, addr); - // kfunc_match(strrchr, name, addr); - // kfunc_match(strnchr, name, addr); - // kfunc_match(skip_spaces, name, addr); - // kfunc_match(strim, name, addr); - kfunc_match(strlen, name, addr); - kfunc_match(strnlen, name, addr); - // kfunc_match(strspn, name, addr); - // kfunc_match(strcspn, name, addr); - // kfunc_match(strpbrk, name, addr); - // kfunc_match(strsep, name, addr); - // kfunc_match(sysfs_streq, name, addr); - // kfunc_match(match_string, name, addr); - // kfunc_match(__sysfs_match_string, name, addr); - kfunc_match(memset, name, addr); - // kfunc_match(memset16, name, addr); - // kfunc_match(memset32, name, addr); - // kfunc_match(memset64, name, addr); - kfunc_match(memcpy, name, addr); - kfunc_match(memmove, name, addr); - kfunc_match(memcmp, name, addr); - // kfunc_match(bcmp, name, addr); - // kfunc_match(memscan, name, addr); - // kfunc_match(strstr, name, addr); - // kfunc_match(strnstr, name, addr); - // kfunc_match(memchr, name, addr); - // kfunc_match(memchr_inv, name, addr); - // kfunc_match(strreplace, name, addr); - // kfunc_match(fortify_panic, name, addr); -} - -// lib/strncpy_from_user.c -#include - -long kfunc_def(strncpy_from_user)(char *dst, const char __user *src, long count) = 0; - -void _linux_lib_strncpy_from_user_sym_match() -{ - kfunc_match(strncpy_from_user, name, addr); -} - -// lib/strnlen_user.c -#include - -long kfunc_def(strnlen_user)(const char __user *str, long count) = 0; - -void _linxu_lib_strnlen_user_sym_match() -{ - kfunc_match(strnlen_user, name, addr); -} - // mm/util.c struct file; struct page; @@ -434,11 +273,15 @@ int kfunc_def(__page_mapcount)(struct page *page) = 0; unsigned long kfunc_def(vm_memory_committed)(void) = 0; int kfunc_def(get_cmdline)(struct task_struct *task, char *buffer, int buflen) = 0; // not exported -void _linux_mm_utils_sym_match() +void *kfunc_def(__kmalloc)(size_t size, gfp_t flags) = 0; +void *kfunc_def(kmalloc)(size_t size, gfp_t flags) = 0; +void kfunc_def(kfree)(const void *) = 0; + +static void _linux_mm_utils_sym_match() { - // kfunc_match(kfree_const, name, addr); + kfunc_match(kfree_const, name, addr); kfunc_match(kstrdup, name, addr); - // kfunc_match(kstrdup_const, name, addr); + kfunc_match(kstrdup_const, name, addr); kfunc_match(kstrndup, name, addr); kfunc_match(kmemdup, name, addr); kfunc_match(kmemdup_nul, name, addr); @@ -456,16 +299,10 @@ void _linux_mm_utils_sym_match() // kfunc_match(__page_mapcount, name, addr); // kfunc_match(vm_memory_committed, name, addr); // kfunc_match(get_cmdline, name, addr); -} -// lib/dump_stack.c -void kfunc_def(dump_stack_lvl)(const char *log_lvl) = 0; -void kfunc_def(dump_stack)(void) = 0; - -void _linux_lib_dump_stack_sym_match() -{ - kfunc_match(dump_stack_lvl, name, addr); - kfunc_match(dump_stack, name, addr); + kfunc_match(__kmalloc, name, addr); + kfunc_match(kmalloc, name, addr); + kfunc_match(kfree, name, addr); } // mm/vmalloc.c @@ -516,7 +353,7 @@ void kfunc_def(unmap_kernel_range)(unsigned long addr, unsigned long size) = 0; long kfunc_def(vread)(char *buf, char *addr, unsigned long count) = 0; long kfunc_def(vwrite)(char *buf, char *addr, unsigned long count) = 0; -void _linux_mm_vmalloc_sym_match() +static void _linux_mm_vmalloc_sym_match() { // kfunc_match(vm_unmap_ram, name, addr); // kfunc_match(vm_map_ram, name, addr); @@ -530,7 +367,7 @@ void _linux_mm_vmalloc_sym_match() // kfunc_match(vmalloc_32, name, addr); // kfunc_match(vmalloc_32_user, name, addr); kfunc_match(__vmalloc, name, addr); - // kfunc_match(__vmalloc_node_range, name, addr); + kfunc_match(__vmalloc_node_range, name, addr); // kfunc_match(__vmalloc_node, name, addr); kfunc_match(vfree, name, addr); @@ -558,50 +395,6 @@ void _linux_mm_vmalloc_sym_match() // kfunc_match(vwrite, name, addr); } -// lib/seq_buf.c, - -#include -#include - -int kfunc_def(seq_buf_printf)(struct seq_buf *s, const char *fmt, ...) = 0; -int kfunc_def(seq_buf_to_user)(struct seq_buf *s, char __user *ubuf, int cnt) = 0; -int kfunc_def(seq_buf_puts)(struct seq_buf *s, const char *str) = 0; -int kfunc_def(seq_buf_putc)(struct seq_buf *s, unsigned char c) = 0; -int kfunc_def(seq_buf_putmem)(struct seq_buf *s, const void *mem, unsigned int len) = 0; -int kfunc_def(seq_buf_putmem_hex)(struct seq_buf *s, const void *mem, unsigned int len) = 0; -int kfunc_def(seq_buf_bitmask)(struct seq_buf *s, const unsigned long *maskp, int nmaskbits) = 0; - -int kfunc_def(trace_seq_printf)(struct trace_seq *s, const char *fmt, ...) = 0; -int kfunc_def(trace_seq_to_user)(struct trace_seq *s, char __user *ubuf, int cnt) = 0; -int kfunc_def(trace_seq_puts)(struct trace_seq *s, const char *str) = 0; -int kfunc_def(trace_seq_putc)(struct trace_seq *s, unsigned char c) = 0; -int kfunc_def(trace_seq_putmem)(struct trace_seq *s, const void *mem, unsigned int len) = 0; -int kfunc_def(trace_seq_putmem_hex)(struct trace_seq *s, const void *mem, unsigned int len) = 0; -int kfunc_def(trace_seq_bitmask)(struct trace_seq *s, const unsigned long *maskp, int nmaskbits) = 0; - -void _linux_lib_seq_buf_sym_match() -{ - kfunc_match(seq_buf_to_user, name, addr); - if (kfunc(seq_buf_to_user)) { - kfunc_match(seq_buf_printf, name, addr); - // kfunc_match(seq_buf_to_user, name, addr); - kfunc_match(seq_buf_puts, name, addr); - // kfunc_match(seq_buf_putc, name, addr); - kfunc_match(seq_buf_putmem, name, addr); - // kfunc_match(seq_buf_putmem_hex, name, addr); - // kfunc_match(seq_buf_bitmask, name, addr); - } else { - kfunc_match(trace_seq_printf, name, addr); - kfunc_match(trace_seq_to_user, name, addr); - kfunc_match(trace_seq_puts, name, addr); - // kfunc_match(trace_seq_putc, name, addr); - kfunc_match(trace_seq_putmem, name, addr); - // kfunc_match(trace_seq_putmem_hex, name, addr); - // kfunc_match(trace_seq_bitmask, name, addr); - } -} - -// #include void kfunc_def(inc_nlink)(struct inode *inode) = 0; @@ -609,8 +402,8 @@ void kfunc_def(drop_nlink)(struct inode *inode) = 0; void kfunc_def(clear_nlink)(struct inode *inode) = 0; void kfunc_def(set_nlink)(struct inode *inode, unsigned int nlink) = 0; -int kfunc_def(kernel_read)(struct file *, loff_t, char *, unsigned long) = 0; -ssize_t kfunc_def(kernel_write)(struct file *, const char *, size_t, loff_t) = 0; +ssize_t kfunc_def(kernel_read)(struct file *file, void *buf, size_t count, loff_t *pos) = 0; +ssize_t kfunc_def(kernel_write)(struct file *file, const void *buf, size_t count, loff_t *pos) = 0; struct file *kfunc_def(open_exec)(const char *) = 0; struct file *kfunc_def(file_open_name)(struct filename *, int, umode_t) = 0; @@ -622,7 +415,9 @@ int kfunc_def(filp_close)(struct file *, fl_owner_t id) = 0; struct filename *kfunc_def(getname)(const char __user *) = 0; struct filename *kfunc_def(getname_kernel)(const char *) = 0; -void _linux_fs_sym_match() +loff_t kfunc_def(vfs_llseek)(struct file *file, loff_t offset, int whence) = 0; + +static void _linux_fs_sym_match() { // kfunc_match(inc_nlink, name, addr); // kfunc_match(drop_nlink, name, addr); @@ -638,4 +433,253 @@ void _linux_fs_sym_match() kfunc_match(filp_close, name, addr); // kfunc_match(getname, name, addr); // kfunc_match(getname_kernel, name, addr); -} \ No newline at end of file + kfunc_match(vfs_llseek, name, addr); +} + +#include + +void kfunc_def(save_stack_trace)(struct stack_trace *trace) = 0; +void kfunc_def(save_stack_trace_regs)(struct pt_regs *regs, struct stack_trace *trace) = 0; +void kfunc_def(save_stack_trace_tsk)(struct task_struct *tsk, struct stack_trace *trace) = 0; +void kfunc_def(print_stack_trace)(struct stack_trace *trace, int spaces) = 0; +void kfunc_def(save_stack_trace_user)(struct stack_trace *trace) = 0; + +static void _linux_stacktrace_sym_match() +{ + // kfunc_match(save_stack_trace, name, addr); + // kfunc_match(save_stack_trace_regs, name, addr); + kfunc_match(save_stack_trace_tsk, name, addr); + // kfunc_match(print_stack_trace, name, addr); + // kfunc_match(save_stack_trace_user, name, addr); +} + +#include + +int kfunc_def(avc_denied)(u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 xperm, unsigned int flags, + struct av_decision *avd) = 0; +int kfunc_def(avc_has_perm_noaudit)(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, + struct av_decision *avd) = 0; +int kfunc_def(avc_has_perm)(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata) = 0; +int kfunc_def(avc_has_perm_flags)(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata, + int flags) = 0; +int kfunc_def(avc_has_extended_perms)(u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 perm, + struct common_audit_data *ad) = 0; + +static void _linux_security_selinux_avc_sym_match() +{ + kfunc_match(avc_denied, name, addr); + kfunc_match(avc_has_perm_noaudit, name, addr); + kfunc_match(avc_has_perm, name, addr); + kfunc_match(avc_has_perm_flags, name, addr); + kfunc_match(avc_has_extended_perms, name, addr); +} + +#include +#include + +int kvar_def(selinux_enabled_boot) = 0; +int kvar_def(selinux_enabled) = 0; +struct selinux_state kvar_def(selinux_state) = 0; +struct security_class_mapping kvar_def(secclass_map)[] = 0; + +int kfunc_def(security_mls_enabled)(void) = 0; +int kfunc_def(security_load_policy)(void *data, size_t len, struct selinux_load_state *load_state) = 0; +void kfunc_def(selinux_policy_commit)(struct selinux_load_state *load_state) = 0; +void kfunc_def(selinux_policy_cancel)(struct selinux_load_state *load_state) = 0; +int kfunc_def(security_read_policy)(void **data, size_t *len) = 0; +int kfunc_def(security_read_state_kernel)(void **data, size_t *len) = 0; +int kfunc_def(security_policycap_supported)(unsigned int req_cap) = 0; +void kfunc_def(security_compute_av)(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, + struct extended_perms *xperms) = 0; +void kfunc_def(security_compute_xperms_decision)(u32 ssid, u32 tsid, u16 tclass, u8 driver, + struct extended_perms_decision *xpermd) = 0; +void kfunc_def(security_compute_av_user)(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) = 0; +int kfunc_def(security_transition_sid)(u32 ssid, u32 tsid, u16 tclass, const struct qstr *qstr, u32 *out_sid) = 0; +int kfunc_def(security_transition_sid_user)(u32 ssid, u32 tsid, u16 tclass, const char *objname, u32 *out_sid) = 0; +int kfunc_def(security_member_sid)(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) = 0; +int kfunc_def(security_change_sid)(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) = 0; +int kfunc_def(security_sid_to_context)(u32 sid, char **scontext, u32 *scontext_len) = 0; +int kfunc_def(security_sid_to_context_force)(u32 sid, char **scontext, u32 *scontext_len) = 0; +int kfunc_def(security_sid_to_context_inval)(u32 sid, char **scontext, u32 *scontext_len) = 0; +int kfunc_def(security_context_to_sid)(const char *scontext, u32 scontext_len, u32 *out_sid, gfp_t gfp) = 0; +int kfunc_def(security_context_str_to_sid)(const char *scontext, u32 *out_sid, gfp_t gfp) = 0; +int kfunc_def(security_context_to_sid_default)(const char *scontext, u32 scontext_len, u32 *out_sid, u32 def_sid, + gfp_t gfp_flags) = 0; +int kfunc_def(security_context_to_sid_force)(const char *scontext, u32 scontext_len, u32 *sid) = 0; +int kfunc_def(security_get_user_sids)(u32 callsid, char *username, u32 **sids, u32 *nel) = 0; +int kfunc_def(security_port_sid)(u8 protocol, u16 port, u32 *out_sid) = 0; +int kfunc_def(security_ib_pkey_sid)(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) = 0; +int kfunc_def(security_ib_endport_sid)(const char *dev_name, u8 port_num, u32 *out_sid) = 0; +int kfunc_def(security_netif_sid)(char *name, u32 *if_sid) = 0; +int kfunc_def(security_node_sid)(u16 domain, void *addr, u32 addrlen, u32 *out_sid) = 0; +int kfunc_def(security_validate_transition)(u32 oldsid, u32 newsid, u32 tasksid, u16 tclass) = 0; +int kfunc_def(security_validate_transition_user)(u32 oldsid, u32 newsid, u32 tasksid, u16 tclass) = 0; +int kfunc_def(security_bounded_transition)(u32 oldsid, u32 newsid) = 0; +int kfunc_def(security_sid_mls_copy)(u32 sid, u32 mls_sid, u32 *new_sid) = 0; +int kfunc_def(security_net_peersid_resolve)(u32 nlbl_sid, u32 nlbl_type, u32 xfrm_sid, u32 *peer_sid) = 0; +int kfunc_def(security_get_classes)(struct selinux_policy *policy, char ***classes, int *nclasses) = 0; +int kfunc_def(security_get_permissions)(struct selinux_policy *policy, char *class, char ***perms, int *nperms) = 0; +int kfunc_def(security_get_reject_unknown)(void) = 0; +int kfunc_def(security_get_allow_unknown)(void) = 0; + +int kfunc_def(security_fs_use)(struct super_block *sb) = 0; +int kfunc_def(security_genfs_sid)(const char *fstype, const char *path, u16 sclass, u32 *sid) = 0; +int kfunc_def(selinux_policy_genfs_sid)(struct selinux_policy *policy, const char *fstype, const char *path, u16 sclass, + u32 *sid) = 0; +int kfunc_def(security_netlbl_secattr_to_sid)(struct netlbl_lsm_secattr *secattr, u32 *sid) = 0; +int kfunc_def(security_netlbl_sid_to_secattr)(u32 sid, struct netlbl_lsm_secattr *secattr) = 0; +const char *kfunc_def(security_get_initial_sid_context)(u32 sid) = 0; + +void kfunc_def(selinux_status_update_setenforce)(int enforcing) = 0; +void kfunc_def(selinux_status_update_policyload)(int seqno) = 0; +void kfunc_def(selinux_complete_init)(void) = 0; +void kfunc_def(exit_sel_fs)(void) = 0; +void kfunc_def(selnl_notify_setenforce)(int val) = 0; +void kfunc_def(selnl_notify_policyload)(u32 seqno) = 0; +int kfunc_def(selinux_nlmsg_lookup)(u16 sclass, u16 nlmsg_type, u32 *perm) = 0; + +void kfunc_def(avtab_cache_init)(void) = 0; +void kfunc_def(ebitmap_cache_init)(void) = 0; +void kfunc_def(hashtab_cache_init)(void) = 0; +int kfunc_def(security_sidtab_hash_stats)(char *page) = 0; + +static void _linux_security_selinux_sym_match() +{ + // kvar_match(selinux_enabled_boot, name, addr); + kvar_match(selinux_enabled, name, addr); + kvar_match(selinux_state, name, addr); + // kvar_match(secclass_map, name, addr); + // kfunc_match(security_mls_enabled, name, addr); + // kfunc_match(security_load_policy, name, addr); + // kfunc_match(selinux_policy_commit, name, addr); + // kfunc_match(selinux_policy_cancel, name, addr); + // kfunc_match(security_read_policy, name, addr); + // kfunc_match(security_read_state_kernel, name, addr); + // kfunc_match(security_policycap_supported, name, addr); + kfunc_match(security_compute_av, name, addr); + kfunc_match(security_compute_xperms_decision, name, addr); + kfunc_match(security_compute_av_user, name, addr); + // kfunc_match(security_transition_sid, name, addr); + // kfunc_match(security_transition_sid_user, name, addr); + // kfunc_match(security_member_sid, name, addr); + // kfunc_match(security_change_sid, name, addr); + // kfunc_match(security_sid_to_context, name, addr); + // kfunc_match(security_sid_to_context_force, name, addr); + // kfunc_match(security_sid_to_context_inval, name, addr); + // kfunc_match(security_context_to_sid, name, addr); + // kfunc_match(security_context_str_to_sid, name, addr); + // kfunc_match(security_context_to_sid_default, name, addr); + // kfunc_match(security_context_to_sid_force, name, addr); + // kfunc_match(security_get_user_sids, name, addr); + // kfunc_match(security_port_sid, name, addr); + // kfunc_match(security_ib_pkey_sid, name, addr); + // kfunc_match(security_ib_endport_sid, name, addr); + // kfunc_match(security_netif_sid, name, addr); + // kfunc_match(security_node_sid, name, addr); + // kfunc_match(security_validate_transition, name, addr); + // kfunc_match(security_validate_transition_user, name, addr); + // kfunc_match(security_bounded_transition, name, addr); + // kfunc_match(security_sid_mls_copy, name, addr); + // kfunc_match(security_net_peersid_resolve, name, addr); + // kfunc_match(security_get_classes, name, addr); + // kfunc_match(security_get_permissions, name, addr); + // kfunc_match(security_get_reject_unknown, name, addr); + // kfunc_match(security_get_allow_unknown, name, addr); + + // kfunc_match(security_fs_use, name, addr); + // kfunc_match(security_genfs_sid, name, addr); + // kfunc_match(selinux_policy_genfs_sid, name, addr); + // kfunc_match(security_netlbl_secattr_to_sid, name, addr); + // kfunc_match(security_netlbl_sid_to_secattr, name, addr); + // kfunc_match(security_get_initial_sid_context, name, addr); + + // kfunc_match(selinux_status_update_setenforce, name, addr); + // kfunc_match(selinux_status_update_policyload, name, addr); + // kfunc_match(selinux_complete_init, name, addr); + // kfunc_match(exit_sel_fs, name, addr); + // kfunc_match(selnl_notify_setenforce, name, addr); + // kfunc_match(selnl_notify_policyload, name, addr); + // kfunc_match(selinux_nlmsg_lookup, name, addr); + + // kfunc_match(avtab_cache_init, name, addr); + // kfunc_match(ebitmap_cache_init, name, addr); + // kfunc_match(hashtab_cache_init, name, addr); + // kfunc_match(security_sidtab_hash_stats, name, addr); +} + +#include + +int kfunc_def(cap_capable)(const struct cred *cred, struct user_namespace *ns, int cap, unsigned int opts) = 0; +int kfunc_def(cap_settime)(const struct timespec64 *ts, const struct timezone *tz) = 0; +int kfunc_def(cap_ptrace_access_check)(struct task_struct *child, unsigned int mode) = 0; +int kfunc_def(cap_ptrace_traceme)(struct task_struct *parent) = 0; +int kfunc_def(cap_capget)(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, + kernel_cap_t *permitted) = 0; +int kfunc_def(cap_capset)(struct cred *new, const struct cred *old, const kernel_cap_t *effective, + const kernel_cap_t *inheritable, const kernel_cap_t *permitted) = 0; +int kfunc_def(cap_bprm_creds_from_file)(struct linux_binprm *bprm, struct file *file) = 0; +int kfunc_def(cap_inode_setxattr)(struct dentry *dentry, const char *name, const void *value, size_t size, + int flags) = 0; +int kfunc_def(cap_inode_removexattr)(struct dentry *dentry, const char *name) = 0; +int kfunc_def(cap_inode_need_killpriv)(struct dentry *dentry) = 0; +int kfunc_def(cap_inode_killpriv)(struct dentry *dentry) = 0; +int kfunc_def(cap_inode_getsecurity)(struct inode *inode, const char *name, void **buffer, bool alloc) = 0; +int kfunc_def(cap_mmap_addr)(unsigned long addr) = 0; +int kfunc_def(cap_mmap_file)(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) = 0; +int kfunc_def(cap_task_fix_setuid)(struct cred *new, const struct cred *old, int flags) = 0; +int kfunc_def(cap_task_prctl)(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, + unsigned long arg5) = 0; +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; + +kernel_cap_t full_cap = { 0 }; + +static void _linux_security_commoncap_sym_match() +{ + kfunc_match(cap_capable, name, addr); + // kfunc_match(cap_settime, name, addr); + // kfunc_match(cap_ptrace_access_check, name, addr); + // kfunc_match(cap_ptrace_traceme, name, addr); + kfunc_match(cap_capget, name, addr); + kfunc_match(cap_capset, name, addr); + // kfunc_match(cap_bprm_creds_from_file, name, addr); + // kfunc_match(cap_inode_setxattr, name, addr); + // kfunc_match(cap_inode_removexattr, name, addr); + // kfunc_match(cap_inode_need_killpriv, name, addr); + // kfunc_match(cap_inode_killpriv, name, addr); + // kfunc_match(cap_inode_getsecurity, name, addr); + // kfunc_match(cap_mmap_addr, name, addr); + // kfunc_match(cap_mmap_file, name, addr); + // kfunc_match(cap_task_fix_setuid, name, addr); + kfunc_match(cap_task_prctl, name, addr); + // 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); +} + +void kfunc_def(panic)(const char *fmt, ...) __noreturn __cold = 0; + +static void _linux_include_linux_panic_sym_match() +{ + kfunc_match(panic, name, addr); +} + +int linux_misc_symbol_init() +{ + _linux_kernel_cred_sym_match(); + _linux_kernel_pid_sym_match(); + _linux_kernel_stop_machine_sym_match(); + _linux_mm_utils_sym_match(); + _linux_mm_vmalloc_sym_match(); + _linux_fs_sym_match(); + _linux_stacktrace_sym_match(); + _linux_security_selinux_sym_match(); + _linux_security_commoncap_sym_match(); + _linux_include_linux_panic_sym_match(); + _linux_security_selinux_avc_sym_match(); + _linux_kernel_fork_sym_match(); + return 0; +} diff --git a/kernel/patch/ksyms/misc_len.c b/kernel/patch/ksyms/misc_len.c index 6cba43d3..d3218525 100644 --- a/kernel/patch/ksyms/misc_len.c +++ b/kernel/patch/ksyms/misc_len.c @@ -7,33 +7,55 @@ #include #include #include +#include #include +struct task_struct *kvar(init_task) = 0; +union thread_union *kvar(init_thread_union) = 0; +struct cred *kvar(init_cred) = 0; +struct group_info *kvar(init_groups) = 0; + int kvlen(init_task) = -1; int kvlen(init_cred) = -1; int kvlen(init_thread_union) = -1; -void linux_sybmol_len_init() +int linux_sybmol_len_init() { + int rc = 0; + + kvar_match(init_task, name, addr); + kvar_match(init_thread_union, name, addr); + kvar_match(init_cred, name, addr); + kvar_match(init_groups, name, addr); + + if (!kvar(init_task) || !kvar(init_thread_union) || !kvar(init_cred) || !kvar(init_groups)) { + rc = -ENOENT; + log_boot("no symbol init_task or init_thread_union or init_cred or init_groups\n"); + goto out; + } + unsigned long offset = 0; unsigned long size = 0; char mod[16] = { '\0' }; char name[16] = { '\0' }; - logkd("struct size:\n"); + log_boot("struct size: \n"); lookup_symbol_attrs((unsigned long)kvar(init_cred), &size, &offset, mod, name); kvlen(init_cred) = size; - logkd(" init_cred: %d\n", size); + log_boot(" init_cred: %x\n", size); lookup_symbol_attrs((unsigned long)kvar(init_task), &size, &offset, mod, name); kvlen(init_task) = size; - logkd(" init_task: %d\n", size); + log_boot(" init_task: %x\n", size); lookup_symbol_attrs((unsigned long)kvar(init_thread_union), &size, &offset, mod, name); kvlen(init_thread_union) = size; thread_size = size; - logkd(" thread_size: %d\n", size); + log_boot(" thread_union: %x\n", size); + +out: + return rc; } #endif \ No newline at end of file diff --git a/kernel/patch/struct/task_cred.c b/kernel/patch/ksyms/task_cred.c similarity index 70% rename from kernel/patch/struct/task_cred.c rename to kernel/patch/ksyms/task_cred.c index d96f46c9..28f2e1ae 100644 --- a/kernel/patch/struct/task_cred.c +++ b/kernel/patch/ksyms/task_cred.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -11,11 +10,12 @@ #include #include #include +#include #include +#include #include -#include #include -#include +#include struct task_struct_offset task_struct_offset = { .pid_offset = -1, @@ -31,13 +31,14 @@ struct task_struct_offset task_struct_offset = { .seccomp_offset = -1, .security_offset = -1, .stack_offset = -1, + .tasks_offset = -1, }; +KP_EXPORT_SYMBOL(task_struct_offset); struct cred_offset cred_offset = { .usage_offset = -1, .subscribers_offset = -1, .magic_offset = -1, - .uid_offset = -1, .gid_offset = -1, .suid_offset = -1, @@ -67,18 +68,34 @@ struct cred_offset cred_offset = { .rcu_offset = -1, }; +KP_EXPORT_SYMBOL(cred_offset); int thread_size = -1; +KP_EXPORT_SYMBOL(thread_size); + bool thread_info_in_task = false; +KP_EXPORT_SYMBOL(thread_info_in_task); + bool task_is_sp_el0 = false; +KP_EXPORT_SYMBOL(task_is_sp_el0); + bool thread_info_is_sp_el0 = false; +KP_EXPORT_SYMBOL(thread_info_is_sp_el0); + bool thread_info_is_sp = false; +KP_EXPORT_SYMBOL(thread_info_is_sp); + int task_in_thread_info_offset = -1; +KP_EXPORT_SYMBOL(task_in_thread_info_offset); + int stack_in_task_offset = -1; +KP_EXPORT_SYMBOL(stack_in_task_offset); + int stack_end_offset = 0x90; -int thread_info_size = 0x90; +KP_EXPORT_SYMBOL(stack_end_offset); -struct task_struct *task = 0; +int thread_info_size = 0x90; +KP_EXPORT_SYMBOL(thread_info_size); static int16_t *bl_list = 0; static int bl_cap = 0; @@ -94,17 +111,15 @@ static void reinit_bllist(int num) static void uninit_bllist() { - vfree(bl_list); bl_cap = 0; + vfree(bl_list); } static bool is_bl(int16_t off) { for (int i = 0; i < bl_cap; i++) { - if (bl_list[i] < 0) - break; - if (bl_list[i] == off) - return true; + if (bl_list[i] < 0) break; + if (bl_list[i] == off) return true; } return false; } @@ -114,30 +129,26 @@ static void add_bll(int16_t off, int16_t size) for (int i = 0; i < bl_cap; i++) { if (bl_list[i] < 0) { bl_list[i] = off; - if (size == 8) - bl_list[i + 1] = off + 4; + if (size == 8) bl_list[i + 1] = off + 4; break; } } } // todo: -int build_cred_offset() +int resolve_cred_offset() { int cred_len = kvlen(init_cred); int task_len = kvlen(init_task); - logkd("struct cred: \n"); + log_boot("struct cred: \n"); - if (task_len <= 0 || cred_len <= 0) { - logke("init_task or init_cred length unknown\n"); - return -1; - } reinit_bllist(128); - struct cred *cred = cred_alloc_blank(); struct cred *cred1 = cred_alloc_blank(); + unsigned char _task[task_len]; + struct task_struct *task = (struct task_struct *)_task; memcpy(task, kvar(init_task), task_len); memcpy(cred, kvar(init_cred), cred_len); memcpy(cred1, kvar(init_cred), cred_len); @@ -170,9 +181,9 @@ int build_cred_offset() add_bll(i, sizeof(uintptr_t)); } } - logkd(" user offset: %d\n", cred_offset.user_offset); - logkd(" user_ns offset: %d\n", cred_offset.user_ns_offset); - logkd(" group_info offset: %d\n", cred_offset.group_info_offset); + log_boot(" user offset: %x\n", cred_offset.user_offset); + log_boot(" user_ns offset: %x\n", cred_offset.user_ns_offset); + log_boot(" group_info offset: %x\n", cred_offset.group_info_offset); for (int16_t i = 0; i < cred_len; i += sizeof(unsigned)) { unsigned int val = *(unsigned int *)((uintptr_t)kvar(init_cred) + i); @@ -189,20 +200,19 @@ int build_cred_offset() add_bll(i, sizeof(unsigned)); } } - logkd(" usage offset: %d\n", cred_offset.usage_offset); + log_boot(" usage offset: %x\n", cred_offset.usage_offset); // cap_inheritable, cap_permitted, cap_effective kernel_cap_t effective, inheritable, permitted; cap_capget(task, &effective, &inheritable, &permitted); full_cap.val = effective.val; - logkd(" full_cap capability: %llx\n", full_cap.val); + log_boot(" full_cap capability: %x\n", full_cap.val); kernel_cap_t new_cap_e = { 0xff }, new_cap_i = { 0xf }, new_cap_p = { 0xfff }; cap_capset(cred1, cred, &new_cap_e, &new_cap_i, &new_cap_p); for (int16_t i = 0; i < cred_len; i += sizeof(kernel_cap_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; kernel_cap_t cap = *(kernel_cap_t *)((uintptr_t)cred + i); kernel_cap_t cap1 = *(kernel_cap_t *)((uintptr_t)cred1 + i); if (cap.val == effective.val && cap1.val == new_cap_e.val) { @@ -224,23 +234,21 @@ int build_cred_offset() // cap_bset for (int16_t i = 0; i < cred_len; i += sizeof(kernel_cap_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; kernel_cap_t cap1 = *(kernel_cap_t *)((uintptr_t)cred1 + i); if (cap1.val == effective.val) { cred_offset.cap_bset_offset = i; add_bll(i, sizeof(kernel_cap_t)); } } - logkd(" cap_effective offset: %d\n", cred_offset.cap_effective_offset); - logkd(" cap_inheritable offset: %d\n", cred_offset.cap_inheritable_offset); - logkd(" cap_permitted offset: %d\n", cred_offset.cap_permitted_offset); - logkd(" cap_bset offset: %d\n", cred_offset.cap_bset_offset); + log_boot(" cap_effective offset: %x\n", cred_offset.cap_effective_offset); + log_boot(" cap_inheritable offset: %x\n", cred_offset.cap_inheritable_offset); + log_boot(" cap_permitted offset: %x\n", cred_offset.cap_permitted_offset); + log_boot(" cap_bset offset: %x\n", cred_offset.cap_bset_offset); // securebits for (int i = 0; i < cred_len; i += sizeof(unsigned)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; unsigned *sbitsp = (unsigned *)((uintptr_t)cred + i); unsigned oribits = *sbitsp; *sbitsp = 1158; @@ -254,15 +262,13 @@ int build_cred_offset() add_bll(i, sizeof(unsigned)); break; } - logkd(" securebits offset: %d\n", cred_offset.securebits_offset); + log_boot(" securebits offset: %x\n", cred_offset.securebits_offset); // euid, uid, egid, gid for (int i = 0; i < cred_len; i += sizeof(uid_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; uid_t *uidp = (uid_t *)((uintptr_t)cred + i); - if (*uidp) - continue; + if (*uidp) continue; *uidp = 1158; if (raw_syscall0(__NR_geteuid) == 1158) { cred_offset.euid_offset = i; @@ -279,15 +285,14 @@ int build_cred_offset() *uidp = 0; add_bll(i, sizeof(uid_t)); } - logkd(" uid offset: %d\n", cred_offset.uid_offset); - logkd(" euid offset: %d\n", cred_offset.euid_offset); - logkd(" gid offset: %d\n", cred_offset.gid_offset); - logkd(" egid offset: %d\n", cred_offset.egid_offset); + log_boot(" uid offset: %x\n", cred_offset.uid_offset); + log_boot(" euid offset: %x\n", cred_offset.euid_offset); + log_boot(" gid offset: %x\n", cred_offset.gid_offset); + log_boot(" egid offset: %x\n", cred_offset.egid_offset); // fsuid for (int i = 0; i < cred_len; i += sizeof(uid_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; uid_t *uidp = (uid_t *)((uintptr_t)cred + i); uid_t backup = *uidp; *uidp = 1158; @@ -299,13 +304,12 @@ int build_cred_offset() break; } } - logkd(" fsuid offset: %d\n", cred_offset.fsuid_offset); + log_boot(" fsuid offset: %x\n", cred_offset.fsuid_offset); // fsgid struct cred *new_cred = *(struct cred **)((uintptr_t)task + task_struct_offset.cred_offset); for (int i = 0; i < cred_len; i += sizeof(gid_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; gid_t *gidp = (gid_t *)((uintptr_t)new_cred + i); gid_t backup = *gidp; *gidp = 1158; @@ -317,14 +321,13 @@ int build_cred_offset() break; } } - logkd(" fsgid offset: %d\n", cred_offset.fsgid_offset); + log_boot(" fsgid offset: %x\n", cred_offset.fsgid_offset); // suid raw_syscall3(__NR_setresuid, 0, 0, 1158); new_cred = *(struct cred **)((uintptr_t)task + task_struct_offset.cred_offset); for (int i = 0; i < cred_len; i += sizeof(uid_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; uid_t *uidp = (uid_t *)((uintptr_t)new_cred + i); if (*uidp == 1158) { cred_offset.suid_offset = i; @@ -333,14 +336,13 @@ int build_cred_offset() break; } } - logkd(" suid offset: %d\n", cred_offset.suid_offset); + log_boot(" suid offset: %x\n", cred_offset.suid_offset); // sgid raw_syscall3(__NR_setresgid, 0, 0, 1158); new_cred = *(struct cred **)((uintptr_t)task + task_struct_offset.cred_offset); for (int i = 0; i < cred_len; i += sizeof(gid_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; gid_t *uidp = (gid_t *)((uintptr_t)new_cred + i); if (*uidp == 1158) { cred_offset.sgid_offset = i; @@ -349,7 +351,7 @@ int build_cred_offset() break; } } - logkd(" sgid offset: %d\n", cred_offset.sgid_offset); + log_boot(" sgid offset: %x\n", cred_offset.sgid_offset); // cap_ambient new_cred = *(struct cred **)((uintptr_t)task + task_struct_offset.cred_offset); @@ -360,8 +362,7 @@ int build_cred_offset() cap_task_prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, 0xf, 0, 0); new_cred = *(struct cred **)((uintptr_t)task + task_struct_offset.cred_offset); for (int16_t i = 0; i < cred_len; i += sizeof(kernel_cap_t)) { - if (is_bl(i)) - continue; + if (is_bl(i)) continue; kernel_cap_t cap = *(kernel_cap_t *)((uintptr_t)cred + i); kernel_cap_t new_cap = *(kernel_cap_t *)((uintptr_t)new_cred + i); if (!cap.val && new_cap.val == (1 << 0xf)) { @@ -369,7 +370,7 @@ int build_cred_offset() add_bll(i, sizeof(kernel_cap_t)); } } - logkd(" cap_ambient offset: %d\n", cred_offset.cap_ambient_offset); + log_boot(" cap_ambient offset: %x\n", cred_offset.cap_ambient_offset); // todo: put cred // __put_cred(new_cred); @@ -379,12 +380,14 @@ int build_cred_offset() return 0; } -int build_task_offset() +int resolve_task_offset() { - logkd("struct task: \n"); + log_boot("struct task: \n"); int cred_len = kvlen(init_cred); int task_len = kvlen(init_task); + unsigned char _task[task_len]; + struct task_struct *task = (struct task_struct *)_task; memcpy(task, kvar(init_task), task_len); uintptr_t start = (uintptr_t)task; @@ -403,10 +406,10 @@ int build_task_offset() cand[ci++] = i - start; } } - if (ci != 2) - return ERR_STRUCT_LAYOUT; - // - struct cred *flag = (struct cred *)vmalloc(kvlen(init_cred)); + if (ci != 2) return -EINVAL; + + unsigned char _flag[kvlen(init_cred)]; + struct cred *flag = (struct cred *)_flag; memcpy(flag, kvar(init_cred), cred_len); *(uintptr_t *)(start + cand[0]) = (uintptr_t)flag; @@ -418,10 +421,9 @@ int build_task_offset() task_struct_offset.real_cred_offset = cand[1]; task_struct_offset.cred_offset = cand[0]; } - vfree(flag); - logkd(" cred offset: %d\n", task_struct_offset.cred_offset); - logkd(" read_cred offset: %d\n", task_struct_offset.real_cred_offset); + log_boot(" cred offset: %x\n", task_struct_offset.cred_offset); + log_boot(" read_cred offset: %x\n", task_struct_offset.real_cred_offset); // stack uintptr_t stack_base = (uintptr_t)kvar(init_thread_union); @@ -433,14 +435,65 @@ int build_task_offset() break; } } - logkd(" stack offset: %d\n", task_struct_offset.stack_offset); + log_boot(" stack offset: %x\n", task_struct_offset.stack_offset); + + // list_head + // for (uintptr_t i = start; i < end; i += sizeof(uintptr_t)) { + // uintptr_t val = *(uintptr_t *)i; + // uintptr_t val1 = *(uintptr_t *)(i + 8); + // uintptr_t task_addr = (uintptr_t)kvar(init_task) + (i - start); + // if (val == task_addr && val1 == task_addr) { + // list_heads[j++] = i - start; + // } + // } + + // comm + for (uintptr_t i = start; i < end; i += sizeof(uintptr_t)) { + const char *comm = (const char *)i; + // swapper + if (!strncmp("swapper", comm, 7)) { + task_struct_offset.comm_offset = i - start; + } + } + log_boot(" comm offset: %x\n", task_struct_offset.comm_offset); return 0; } +// static int dynamic_resolve_times = 0; +// static bool dynamic_resolve_struct_done = false; + +// int dynamic_resolve_struct(struct task_struct *new, struct task_struct *old) +// { +// if (likely(dynamic_resolve_struct_done) || dynamic_resolve_times++ > 10) return 0; + +// static bool first_fork = true; + +// if (first_fork) { +// first_fork = false; +// // tasks, // copy_process, list_add_tail_rcu(&p->tasks, &init_task.tasks); +// for (int i = 0; i < CAND_MAX; i++) { +// int16_t cand = tasks_cands[i]; +// if (!cand) continue; +// uintptr_t old_next = *(uintptr_t *)((uintptr_t)old + cand + sizeof(uintptr_t)); +// uintptr_t new_prev = *(uintptr_t *)((uintptr_t) new + cand); +// if (old_next == (uintptr_t) new + cand && new_prev == (uintptr_t)old + cand) { +// task_struct_offset.tasks_offset = cand; +// log_boot(" task offset: %x\n", task_struct_offset.tasks_offset); +// } +// } +// } + +// if (task_struct_offset.tasks_offset != -1) { +// dynamic_resolve_struct_done = true; +// } + +// return 0; +// } + int resolve_current() { - logkd("current: \n"); + log_boot("current: \n"); int err = 0; uintptr_t sp_el0; @@ -460,20 +513,20 @@ int resolve_current() break; } } - logkd(" stack end offset stack: %d\n", stack_end_offset); - logkd(" thread_info_in_task: %d\n", thread_info_in_task); + log_boot(" stack end offset stack: %x\n", stack_end_offset); + log_boot(" thread_info_in_task: %x\n", thread_info_in_task); // where is task if (sp_el0 == (uint64_t)kvar(init_task)) { task_is_sp_el0 = true; - logkd(" current is sp_el0\n"); + log_boot(" current is sp_el0\n"); } else { if (sp_el0 == init_thread_union_addr) { thread_info_is_sp_el0 = true; - logkd(" current_thread_info is sp_el0\n"); + log_boot(" current_thread_info is sp_el0\n"); } else { thread_info_is_sp = true; - logkd(" current_thread_info is sp\n"); + log_boot(" current_thread_info is sp\n"); } // task_in_thread_info_offset @@ -485,34 +538,21 @@ int resolve_current() break; } } - logkd(" task offset of thread_info: %d\n", task_in_thread_info_offset); + log_boot(" task offset of thread_info: %x\n", task_in_thread_info_offset); } return err; } -int build_struct() +int resolve_struct() { - if (kvlen(init_task) <= 0 || kvlen(init_cred) <= 0) { - logke("init_task or init_cred length unknown\n"); - return ERR_STRUCT_LAYOUT; - } - if (thread_size <= 0) { - thread_size = 16384; - } - + if (thread_size <= 0) thread_size = 0x4000; full_cap = CAP_FULL_SET; - task = (struct task_struct *)vmalloc(kvlen(init_task)); int err = 0; - if ((err = build_task_offset())) - goto out; - if ((err = resolve_current())) - goto out; - if ((err = build_cred_offset())) - goto out; - + if ((err = resolve_task_offset())) goto out; + if ((err = resolve_current())) goto out; + if ((err = resolve_cred_offset())) goto out; out: - vfree(task); return err; -} \ No newline at end of file +} diff --git a/kernel/patch/module/insn.c b/kernel/patch/module/insn.c new file mode 100644 index 00000000..852ec1a8 --- /dev/null +++ b/kernel/patch/module/insn.c @@ -0,0 +1,926 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "insn.h" + +#define BUG() \ + do { \ + printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ + do { \ + } while (0); \ + panic("BUG INSN!"); \ + } while (0) + +#define BUG_ON(condition) \ + do { \ + if (unlikely(condition)) BUG(); \ + } while (0) + +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) + +#define SZ_1 0x00000001 +#define SZ_2 0x00000002 +#define SZ_4 0x00000004 +#define SZ_8 0x00000008 +#define SZ_16 0x00000010 +#define SZ_32 0x00000020 +#define SZ_64 0x00000040 +#define SZ_128 0x00000080 +#define SZ_256 0x00000100 +#define SZ_512 0x00000200 + +#define SZ_1K 0x00000400 +#define SZ_2K 0x00000800 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_32K 0x00008000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +/* + * Create a contiguous bitmask starting at bit position @l and ending at + * position @h. For example + * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. + */ +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#define GENMASK_ULL(h, l) (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) + +/* + * #imm16 values used for BRK instruction generation + * Allowed values for kgbd are 0x400 - 0x7ff + * 0x100: for triggering a fault on purpose (reserved) + * 0x400: for dynamic BRK instruction + * 0x401: for compile time BRK instruction + */ +#define FAULT_BRK_IMM 0x100 +#define KGDB_DYN_DBG_BRK_IMM 0x400 +#define KGDB_COMPILED_DBG_BRK_IMM 0x401 + +/* + * BRK instruction encoding + * The #imm16 value should be placed at bits[20:5] within BRK ins + */ +#define AARCH64_BREAK_MON 0xd4200000 + +/* + * BRK instruction for provoking a fault on purpose + * Unlike kgdb, #imm16 value with unallocated handler is used for faulting. + */ +#define AARCH64_BREAK_FAULT (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5)) + +#define AARCH64_INSN_SF_BIT BIT(31) +#define AARCH64_INSN_N_BIT BIT(22) + +static int aarch64_insn_encoding_class[] = { + AARCH64_INSN_CLS_UNKNOWN, AARCH64_INSN_CLS_UNKNOWN, AARCH64_INSN_CLS_UNKNOWN, AARCH64_INSN_CLS_UNKNOWN, + AARCH64_INSN_CLS_LDST, AARCH64_INSN_CLS_DP_REG, AARCH64_INSN_CLS_LDST, AARCH64_INSN_CLS_DP_FPSIMD, + AARCH64_INSN_CLS_DP_IMM, AARCH64_INSN_CLS_DP_IMM, AARCH64_INSN_CLS_BR_SYS, AARCH64_INSN_CLS_BR_SYS, + AARCH64_INSN_CLS_LDST, AARCH64_INSN_CLS_DP_REG, AARCH64_INSN_CLS_LDST, AARCH64_INSN_CLS_DP_FPSIMD, +}; + +enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn) +{ + return aarch64_insn_encoding_class[(insn >> 25) & 0xf]; +} + +/* NOP is an alias of HINT */ +bool aarch64_insn_is_nop(u32 insn) +{ + if (!aarch64_insn_is_hint(insn)) return false; + + switch (insn & 0xFE0) { + case AARCH64_INSN_HINT_YIELD: + case AARCH64_INSN_HINT_WFE: + case AARCH64_INSN_HINT_WFI: + case AARCH64_INSN_HINT_SEV: + case AARCH64_INSN_HINT_SEVL: + return false; + default: + return true; + } +} + +void aarch64_insn_read(void *addr, u32 *insnp) +{ + u32 val = *(u32 *)addr; + *insnp = le32_to_cpu(val); +} + +void aarch64_insn_write(void *addr, u32 insn) +{ + insn = cpu_to_le32(insn); + *(u32 *)addr = le32_to_cpu(insn); +} + +static bool __aarch64_insn_hotpatch_safe(u32 insn) +{ + if (aarch64_get_insn_class(insn) != AARCH64_INSN_CLS_BR_SYS) return false; + + return aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn) || aarch64_insn_is_svc(insn) || + aarch64_insn_is_hvc(insn) || aarch64_insn_is_smc(insn) || aarch64_insn_is_brk(insn) || + aarch64_insn_is_nop(insn); +} + +/* + * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a + * Section B2.6.5 "Concurrent modification and execution of instructions": + * Concurrent modification and execution of instructions can lead to the + * resulting instruction performing any behavior that can be achieved by + * executing any sequence of instructions that can be executed from the + * same Exception level, except where the instruction before modification + * and the instruction after modification is a B, BL, NOP, BKPT, SVC, HVC, + * or SMC instruction. + */ +bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn) +{ + return __aarch64_insn_hotpatch_safe(old_insn) && __aarch64_insn_hotpatch_safe(new_insn); +} + +int aarch64_insn_patch_text_nosync(void *addr, u32 insn) +{ + u32 *tp = addr; + int ret; + if ((uintptr_t)tp & 0x3) return -EINVAL; + aarch64_insn_write(tp, insn); + flush_icache_range((uintptr_t)tp, (uintptr_t)tp + AARCH64_INSN_SIZE); + return ret; +} + +struct aarch64_insn_patch +{ + void **text_addrs; + u32 *new_insns; + int insn_cnt; + atomic_t cpu_count; +}; + +static int aarch64_insn_patch_text_cb(void *arg) +{ + int i, ret = 0; + struct aarch64_insn_patch *pp = arg; + + /* The first CPU becomes master */ + if (atomic_inc_return(&pp->cpu_count) == 1) { + for (i = 0; ret == 0 && i < pp->insn_cnt; i++) + ret = aarch64_insn_patch_text_nosync(pp->text_addrs[i], pp->new_insns[i]); + /* + * aarch64_insn_patch_text_nosync() calls flush_icache_range(), + * which ends with "dsb; isb" pair guaranteeing global + * visibility. + */ + /* Notify other processors with an additional increment. */ + atomic_inc(&pp->cpu_count); + } else { + // while (atomic_read(&pp->cpu_count) <= num_online_cpus()) + // cpu_relax(); + // isb(); + } + + return ret; +} + +int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt) +{ + struct aarch64_insn_patch patch = { + .text_addrs = addrs, + .new_insns = insns, + .insn_cnt = cnt, + .cpu_count = ATOMIC_INIT(0), + }; + + if (cnt <= 0) return -EINVAL; + + // return stop_machine(aarch64_insn_patch_text_cb, &patch, cpu_online_mask); + return stop_machine(aarch64_insn_patch_text_cb, &patch, 0); +} + +int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt) +{ + int ret; + u32 insn; + + /* Unsafe to patch multiple instructions without synchronizaiton */ + if (cnt == 1) { + aarch64_insn_read(addrs[0], &insn); + if (aarch64_insn_hotpatch_safe(insn, insns[0])) { + /* + * ARMv8 architecture doesn't guarantee all CPUs see + * the new instruction after returning from function + * aarch64_insn_patch_text_nosync(). So send IPIs to + * all other CPUs to achieve instruction + * synchronization. + */ + ret = aarch64_insn_patch_text_nosync(addrs[0], insns[0]); + // kick_all_cpus_sync(); + return ret; + } + } + + return aarch64_insn_patch_text_sync(addrs, insns, cnt); +} + +u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, u32 insn, u64 imm) +{ + u32 immlo, immhi, lomask, himask, mask; + int shift; + + switch (type) { + case AARCH64_INSN_IMM_ADR: + lomask = 0x3; + himask = 0x7ffff; + immlo = imm & lomask; + imm >>= 2; + immhi = imm & himask; + imm = (immlo << 24) | (immhi); + mask = (lomask << 24) | (himask); + shift = 5; + break; + case AARCH64_INSN_IMM_26: + mask = BIT(26) - 1; + shift = 0; + break; + case AARCH64_INSN_IMM_19: + mask = BIT(19) - 1; + shift = 5; + break; + case AARCH64_INSN_IMM_16: + mask = BIT(16) - 1; + shift = 5; + break; + case AARCH64_INSN_IMM_14: + mask = BIT(14) - 1; + shift = 5; + break; + case AARCH64_INSN_IMM_12: + mask = BIT(12) - 1; + shift = 10; + break; + case AARCH64_INSN_IMM_9: + mask = BIT(9) - 1; + shift = 12; + break; + case AARCH64_INSN_IMM_7: + mask = BIT(7) - 1; + shift = 15; + break; + case AARCH64_INSN_IMM_6: + case AARCH64_INSN_IMM_S: + mask = BIT(6) - 1; + shift = 10; + break; + case AARCH64_INSN_IMM_R: + mask = BIT(6) - 1; + shift = 16; + break; + default: + logke("aarch64_insn_encode_immediate: unknown immediate encoding %d\n", type); + return 0; + } + + /* Update the immediate field. */ + insn &= ~(mask << shift); + insn |= (imm & mask) << shift; + + return insn; +} + +static u32 aarch64_insn_encode_register(enum aarch64_insn_register_type type, u32 insn, enum aarch64_insn_register reg) +{ + int shift; + + if (reg < AARCH64_INSN_REG_0 || reg > AARCH64_INSN_REG_SP) { + logke("%s: unknown register encoding %d\n", __func__, reg); + return 0; + } + + switch (type) { + case AARCH64_INSN_REGTYPE_RT: + case AARCH64_INSN_REGTYPE_RD: + shift = 0; + break; + case AARCH64_INSN_REGTYPE_RN: + shift = 5; + break; + case AARCH64_INSN_REGTYPE_RT2: + case AARCH64_INSN_REGTYPE_RA: + shift = 10; + break; + case AARCH64_INSN_REGTYPE_RM: + shift = 16; + break; + default: + logke("%s: unknown register type encoding %d\n", __func__, type); + return 0; + } + + insn &= ~(GENMASK(4, 0) << shift); + insn |= reg << shift; + + return insn; +} + +static u32 aarch64_insn_encode_ldst_size(enum aarch64_insn_size_type type, u32 insn) +{ + u32 size; + + switch (type) { + case AARCH64_INSN_SIZE_8: + size = 0; + break; + case AARCH64_INSN_SIZE_16: + size = 1; + break; + case AARCH64_INSN_SIZE_32: + size = 2; + break; + case AARCH64_INSN_SIZE_64: + size = 3; + break; + default: + logke("%s: unknown size encoding %d\n", __func__, type); + return 0; + } + + insn &= ~GENMASK(31, 30); + insn |= size << 30; + + return insn; +} + +static inline long branch_imm_common(unsigned long pc, unsigned long addr, long range) +{ + long offset; + /* + * PC: A 64-bit Program Counter holding the address of the current + * instruction. A64 instructions must be word-aligned. + */ + BUG_ON((pc & 0x3) || (addr & 0x3)); + + offset = ((long)addr - (long)pc); + BUG_ON(offset < -range || offset >= range); + + return offset; +} + +u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, enum aarch64_insn_branch_type type) +{ + u32 insn; + long offset; + + /* + * B/BL support [-128M, 128M) offset + * ARM64 virtual address arrangement guarantees all kernel and module + * texts are within +/-128M. + */ + offset = branch_imm_common(pc, addr, SZ_128M); + + switch (type) { + case AARCH64_INSN_BRANCH_LINK: + insn = aarch64_insn_get_bl_value(); + break; + case AARCH64_INSN_BRANCH_NOLINK: + insn = aarch64_insn_get_b_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn, offset >> 2); +} + +u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr, enum aarch64_insn_register reg, + enum aarch64_insn_variant variant, enum aarch64_insn_branch_type type) +{ + u32 insn; + long offset; + + offset = branch_imm_common(pc, addr, SZ_1M); + + switch (type) { + case AARCH64_INSN_BRANCH_COMP_ZERO: + insn = aarch64_insn_get_cbz_value(); + break; + case AARCH64_INSN_BRANCH_COMP_NONZERO: + insn = aarch64_insn_get_cbnz_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg); + + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn, offset >> 2); +} + +u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr, enum aarch64_insn_condition cond) +{ + u32 insn; + long offset; + + offset = branch_imm_common(pc, addr, SZ_1M); + + insn = aarch64_insn_get_bcond_value(); + + BUG_ON(cond < AARCH64_INSN_COND_EQ || cond > AARCH64_INSN_COND_AL); + insn |= cond; + + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_19, insn, offset >> 2); +} + +u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op) +{ + return aarch64_insn_get_hint_value() | op; +} + +u32 aarch64_insn_gen_nop(void) +{ + return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP); +} + +u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg, enum aarch64_insn_branch_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_BRANCH_NOLINK: + insn = aarch64_insn_get_br_value(); + break; + case AARCH64_INSN_BRANCH_LINK: + insn = aarch64_insn_get_blr_value(); + break; + case AARCH64_INSN_BRANCH_RETURN: + insn = aarch64_insn_get_ret_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, reg); +} + +u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg, enum aarch64_insn_register base, + enum aarch64_insn_register offset, enum aarch64_insn_size_type size, + enum aarch64_insn_ldst_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_LDST_LOAD_REG_OFFSET: + insn = aarch64_insn_get_ldr_reg_value(); + break; + case AARCH64_INSN_LDST_STORE_REG_OFFSET: + insn = aarch64_insn_get_str_reg_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_ldst_size(size, insn); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, base); + + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, offset); +} + +u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1, enum aarch64_insn_register reg2, + enum aarch64_insn_register base, int offset, enum aarch64_insn_variant variant, + enum aarch64_insn_ldst_type type) +{ + u32 insn; + int shift; + + switch (type) { + case AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX: + insn = aarch64_insn_get_ldp_pre_value(); + break; + case AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX: + insn = aarch64_insn_get_stp_pre_value(); + break; + case AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX: + insn = aarch64_insn_get_ldp_post_value(); + break; + case AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX: + insn = aarch64_insn_get_stp_post_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + /* offset must be multiples of 4 in the range [-256, 252] */ + BUG_ON(offset & 0x3); + BUG_ON(offset < -256 || offset > 252); + shift = 2; + break; + case AARCH64_INSN_VARIANT_64BIT: + /* offset must be multiples of 8 in the range [-512, 504] */ + BUG_ON(offset & 0x7); + BUG_ON(offset < -512 || offset > 504); + shift = 3; + insn |= AARCH64_INSN_SF_BIT; + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT, insn, reg1); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RT2, insn, reg2); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, base); + + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_7, insn, offset >> shift); +} + +u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst, enum aarch64_insn_register src, int imm, + enum aarch64_insn_variant variant, enum aarch64_insn_adsb_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_ADSB_ADD: + insn = aarch64_insn_get_add_imm_value(); + break; + case AARCH64_INSN_ADSB_SUB: + insn = aarch64_insn_get_sub_imm_value(); + break; + case AARCH64_INSN_ADSB_ADD_SETFLAGS: + insn = aarch64_insn_get_adds_imm_value(); + break; + case AARCH64_INSN_ADSB_SUB_SETFLAGS: + insn = aarch64_insn_get_subs_imm_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + BUG_ON(imm & ~(SZ_4K - 1)); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src); + + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, imm); +} + +u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst, enum aarch64_insn_register src, int immr, int imms, + enum aarch64_insn_variant variant, enum aarch64_insn_bitfield_type type) +{ + u32 insn; + u32 mask; + + switch (type) { + case AARCH64_INSN_BITFIELD_MOVE: + insn = aarch64_insn_get_bfm_value(); + break; + case AARCH64_INSN_BITFIELD_MOVE_UNSIGNED: + insn = aarch64_insn_get_ubfm_value(); + break; + case AARCH64_INSN_BITFIELD_MOVE_SIGNED: + insn = aarch64_insn_get_sbfm_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + mask = GENMASK(4, 0); + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT | AARCH64_INSN_N_BIT; + mask = GENMASK(5, 0); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + BUG_ON(immr & ~mask); + BUG_ON(imms & ~mask); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src); + + insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_R, insn, immr); + + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_S, insn, imms); +} + +u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst, int imm, int shift, enum aarch64_insn_variant variant, + enum aarch64_insn_movewide_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_MOVEWIDE_ZERO: + insn = aarch64_insn_get_movz_value(); + break; + case AARCH64_INSN_MOVEWIDE_KEEP: + insn = aarch64_insn_get_movk_value(); + break; + case AARCH64_INSN_MOVEWIDE_INVERSE: + insn = aarch64_insn_get_movn_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + BUG_ON(imm & ~(SZ_64K - 1)); + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + BUG_ON(shift != 0 && shift != 16); + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + BUG_ON(shift != 0 && shift != 16 && shift != 32 && shift != 48); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn |= (shift >> 4) << 21; + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm); +} + +u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg, int shift, enum aarch64_insn_variant variant, + enum aarch64_insn_adsb_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_ADSB_ADD: + insn = aarch64_insn_get_add_value(); + break; + case AARCH64_INSN_ADSB_SUB: + insn = aarch64_insn_get_sub_value(); + break; + case AARCH64_INSN_ADSB_ADD_SETFLAGS: + insn = aarch64_insn_get_adds_value(); + break; + case AARCH64_INSN_ADSB_SUB_SETFLAGS: + insn = aarch64_insn_get_subs_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + BUG_ON(shift & ~(SZ_32 - 1)); + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + BUG_ON(shift & ~(SZ_64 - 1)); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src); + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg); + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift); +} + +u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_variant variant, enum aarch64_insn_data1_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_DATA1_REVERSE_16: + insn = aarch64_insn_get_rev16_value(); + break; + case AARCH64_INSN_DATA1_REVERSE_32: + insn = aarch64_insn_get_rev32_value(); + break; + case AARCH64_INSN_DATA1_REVERSE_64: + BUG_ON(variant != AARCH64_INSN_VARIANT_64BIT); + insn = aarch64_insn_get_rev64_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src); +} + +u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg, enum aarch64_insn_variant variant, + enum aarch64_insn_data2_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_DATA2_UDIV: + insn = aarch64_insn_get_udiv_value(); + break; + case AARCH64_INSN_DATA2_SDIV: + insn = aarch64_insn_get_sdiv_value(); + break; + case AARCH64_INSN_DATA2_LSLV: + insn = aarch64_insn_get_lslv_value(); + break; + case AARCH64_INSN_DATA2_LSRV: + insn = aarch64_insn_get_lsrv_value(); + break; + case AARCH64_INSN_DATA2_ASRV: + insn = aarch64_insn_get_asrv_value(); + break; + case AARCH64_INSN_DATA2_RORV: + insn = aarch64_insn_get_rorv_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src); + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg); +} + +u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg1, enum aarch64_insn_register reg2, + enum aarch64_insn_variant variant, enum aarch64_insn_data3_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_DATA3_MADD: + insn = aarch64_insn_get_madd_value(); + break; + case AARCH64_INSN_DATA3_MSUB: + insn = aarch64_insn_get_msub_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RA, insn, src); + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, reg1); + return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg2); +} + +u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg, int shift, enum aarch64_insn_variant variant, + enum aarch64_insn_logic_type type) +{ + u32 insn; + + switch (type) { + case AARCH64_INSN_LOGIC_AND: + insn = aarch64_insn_get_and_value(); + break; + case AARCH64_INSN_LOGIC_BIC: + insn = aarch64_insn_get_bic_value(); + break; + case AARCH64_INSN_LOGIC_ORR: + insn = aarch64_insn_get_orr_value(); + break; + case AARCH64_INSN_LOGIC_ORN: + insn = aarch64_insn_get_orn_value(); + break; + case AARCH64_INSN_LOGIC_EOR: + insn = aarch64_insn_get_eor_value(); + break; + case AARCH64_INSN_LOGIC_EON: + insn = aarch64_insn_get_eon_value(); + break; + case AARCH64_INSN_LOGIC_AND_SETFLAGS: + insn = aarch64_insn_get_ands_value(); + break; + case AARCH64_INSN_LOGIC_BIC_SETFLAGS: + insn = aarch64_insn_get_bics_value(); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + switch (variant) { + case AARCH64_INSN_VARIANT_32BIT: + BUG_ON(shift & ~(SZ_32 - 1)); + break; + case AARCH64_INSN_VARIANT_64BIT: + insn |= AARCH64_INSN_SF_BIT; + BUG_ON(shift & ~(SZ_64 - 1)); + break; + default: + BUG_ON(1); + return AARCH64_BREAK_FAULT; + } + + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst); + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src); + insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, reg); + return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift); +} \ No newline at end of file diff --git a/kernel/patch/module/insn.h b/kernel/patch/module/insn.h new file mode 100644 index 00000000..c077ddc4 --- /dev/null +++ b/kernel/patch/module/insn.h @@ -0,0 +1,330 @@ +#ifndef __ASM_INSN_H +#define __ASM_INSN_H + +#include + +/* A64 instructions are always 32 bits. */ +#define AARCH64_INSN_SIZE 4 + +/* + * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a + * Section C3.1 "A64 instruction index by encoding": + * AArch64 main encoding table + * Bit position + * 28 27 26 25 Encoding Group + * 0 0 - - Unallocated + * 1 0 0 - Data processing, immediate + * 1 0 1 - Branch, exception generation and system instructions + * - 1 - 0 Loads and stores + * - 1 0 1 Data processing - register + * 0 1 1 1 Data processing - SIMD and floating point + * 1 1 1 1 Data processing - SIMD and floating point + * "-" means "don't care" + */ +enum aarch64_insn_encoding_class +{ + AARCH64_INSN_CLS_UNKNOWN, /* UNALLOCATED */ + AARCH64_INSN_CLS_DP_IMM, /* Data processing - immediate */ + AARCH64_INSN_CLS_DP_REG, /* Data processing - register */ + AARCH64_INSN_CLS_DP_FPSIMD, /* Data processing - SIMD and FP */ + AARCH64_INSN_CLS_LDST, /* Loads and stores */ + AARCH64_INSN_CLS_BR_SYS, /* Branch, exception generation and + * system instructions */ +}; + +enum aarch64_insn_hint_op +{ + AARCH64_INSN_HINT_NOP = 0x0 << 5, + AARCH64_INSN_HINT_YIELD = 0x1 << 5, + AARCH64_INSN_HINT_WFE = 0x2 << 5, + AARCH64_INSN_HINT_WFI = 0x3 << 5, + AARCH64_INSN_HINT_SEV = 0x4 << 5, + AARCH64_INSN_HINT_SEVL = 0x5 << 5, +}; + +enum aarch64_insn_imm_type +{ + AARCH64_INSN_IMM_ADR, + AARCH64_INSN_IMM_26, + AARCH64_INSN_IMM_19, + AARCH64_INSN_IMM_16, + AARCH64_INSN_IMM_14, + AARCH64_INSN_IMM_12, + AARCH64_INSN_IMM_9, + AARCH64_INSN_IMM_7, + AARCH64_INSN_IMM_6, + AARCH64_INSN_IMM_S, + AARCH64_INSN_IMM_R, + AARCH64_INSN_IMM_MAX +}; + +enum aarch64_insn_register_type +{ + AARCH64_INSN_REGTYPE_RT, + AARCH64_INSN_REGTYPE_RN, + AARCH64_INSN_REGTYPE_RT2, + AARCH64_INSN_REGTYPE_RM, + AARCH64_INSN_REGTYPE_RD, + AARCH64_INSN_REGTYPE_RA, +}; + +enum aarch64_insn_register +{ + AARCH64_INSN_REG_0 = 0, + AARCH64_INSN_REG_1 = 1, + AARCH64_INSN_REG_2 = 2, + AARCH64_INSN_REG_3 = 3, + AARCH64_INSN_REG_4 = 4, + AARCH64_INSN_REG_5 = 5, + AARCH64_INSN_REG_6 = 6, + AARCH64_INSN_REG_7 = 7, + AARCH64_INSN_REG_8 = 8, + AARCH64_INSN_REG_9 = 9, + AARCH64_INSN_REG_10 = 10, + AARCH64_INSN_REG_11 = 11, + AARCH64_INSN_REG_12 = 12, + AARCH64_INSN_REG_13 = 13, + AARCH64_INSN_REG_14 = 14, + AARCH64_INSN_REG_15 = 15, + AARCH64_INSN_REG_16 = 16, + AARCH64_INSN_REG_17 = 17, + AARCH64_INSN_REG_18 = 18, + AARCH64_INSN_REG_19 = 19, + AARCH64_INSN_REG_20 = 20, + AARCH64_INSN_REG_21 = 21, + AARCH64_INSN_REG_22 = 22, + AARCH64_INSN_REG_23 = 23, + AARCH64_INSN_REG_24 = 24, + AARCH64_INSN_REG_25 = 25, + AARCH64_INSN_REG_26 = 26, + AARCH64_INSN_REG_27 = 27, + AARCH64_INSN_REG_28 = 28, + AARCH64_INSN_REG_29 = 29, + AARCH64_INSN_REG_FP = 29, /* Frame pointer */ + AARCH64_INSN_REG_30 = 30, + AARCH64_INSN_REG_LR = 30, /* Link register */ + AARCH64_INSN_REG_ZR = 31, /* Zero: as source register */ + AARCH64_INSN_REG_SP = 31 /* Stack pointer: as load/store base reg */ +}; + +enum aarch64_insn_variant +{ + AARCH64_INSN_VARIANT_32BIT, + AARCH64_INSN_VARIANT_64BIT +}; + +enum aarch64_insn_condition +{ + AARCH64_INSN_COND_EQ = 0x0, /* == */ + AARCH64_INSN_COND_NE = 0x1, /* != */ + AARCH64_INSN_COND_CS = 0x2, /* unsigned >= */ + AARCH64_INSN_COND_CC = 0x3, /* unsigned < */ + AARCH64_INSN_COND_MI = 0x4, /* < 0 */ + AARCH64_INSN_COND_PL = 0x5, /* >= 0 */ + AARCH64_INSN_COND_VS = 0x6, /* overflow */ + AARCH64_INSN_COND_VC = 0x7, /* no overflow */ + AARCH64_INSN_COND_HI = 0x8, /* unsigned > */ + AARCH64_INSN_COND_LS = 0x9, /* unsigned <= */ + AARCH64_INSN_COND_GE = 0xa, /* signed >= */ + AARCH64_INSN_COND_LT = 0xb, /* signed < */ + AARCH64_INSN_COND_GT = 0xc, /* signed > */ + AARCH64_INSN_COND_LE = 0xd, /* signed <= */ + AARCH64_INSN_COND_AL = 0xe, /* always */ +}; + +enum aarch64_insn_branch_type +{ + AARCH64_INSN_BRANCH_NOLINK, + AARCH64_INSN_BRANCH_LINK, + AARCH64_INSN_BRANCH_RETURN, + AARCH64_INSN_BRANCH_COMP_ZERO, + AARCH64_INSN_BRANCH_COMP_NONZERO, +}; + +enum aarch64_insn_size_type +{ + AARCH64_INSN_SIZE_8, + AARCH64_INSN_SIZE_16, + AARCH64_INSN_SIZE_32, + AARCH64_INSN_SIZE_64, +}; + +enum aarch64_insn_ldst_type +{ + AARCH64_INSN_LDST_LOAD_REG_OFFSET, + AARCH64_INSN_LDST_STORE_REG_OFFSET, + AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX, + AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX, + AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX, + AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX, +}; + +enum aarch64_insn_adsb_type +{ + AARCH64_INSN_ADSB_ADD, + AARCH64_INSN_ADSB_SUB, + AARCH64_INSN_ADSB_ADD_SETFLAGS, + AARCH64_INSN_ADSB_SUB_SETFLAGS +}; + +enum aarch64_insn_movewide_type +{ + AARCH64_INSN_MOVEWIDE_ZERO, + AARCH64_INSN_MOVEWIDE_KEEP, + AARCH64_INSN_MOVEWIDE_INVERSE +}; + +enum aarch64_insn_bitfield_type +{ + AARCH64_INSN_BITFIELD_MOVE, + AARCH64_INSN_BITFIELD_MOVE_UNSIGNED, + AARCH64_INSN_BITFIELD_MOVE_SIGNED +}; + +enum aarch64_insn_data1_type +{ + AARCH64_INSN_DATA1_REVERSE_16, + AARCH64_INSN_DATA1_REVERSE_32, + AARCH64_INSN_DATA1_REVERSE_64, +}; + +enum aarch64_insn_data2_type +{ + AARCH64_INSN_DATA2_UDIV, + AARCH64_INSN_DATA2_SDIV, + AARCH64_INSN_DATA2_LSLV, + AARCH64_INSN_DATA2_LSRV, + AARCH64_INSN_DATA2_ASRV, + AARCH64_INSN_DATA2_RORV, +}; + +enum aarch64_insn_data3_type +{ + AARCH64_INSN_DATA3_MADD, + AARCH64_INSN_DATA3_MSUB, +}; + +enum aarch64_insn_logic_type +{ + AARCH64_INSN_LOGIC_AND, + AARCH64_INSN_LOGIC_BIC, + AARCH64_INSN_LOGIC_ORR, + AARCH64_INSN_LOGIC_ORN, + AARCH64_INSN_LOGIC_EOR, + AARCH64_INSN_LOGIC_EON, + AARCH64_INSN_LOGIC_AND_SETFLAGS, + AARCH64_INSN_LOGIC_BIC_SETFLAGS +}; + +#define __AARCH64_INSN_FUNCS(abbr, mask, val) \ + static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ + { \ + return (code & (mask)) == (val); \ + } \ + static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \ + { \ + return (val); \ + } + +__AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800) +__AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800) +__AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000) +__AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000) +__AARCH64_INSN_FUNCS(stp_pre, 0x7FC00000, 0x29800000) +__AARCH64_INSN_FUNCS(ldp_pre, 0x7FC00000, 0x29C00000) +__AARCH64_INSN_FUNCS(add_imm, 0x7F000000, 0x11000000) +__AARCH64_INSN_FUNCS(adds_imm, 0x7F000000, 0x31000000) +__AARCH64_INSN_FUNCS(sub_imm, 0x7F000000, 0x51000000) +__AARCH64_INSN_FUNCS(subs_imm, 0x7F000000, 0x71000000) +__AARCH64_INSN_FUNCS(movn, 0x7F800000, 0x12800000) +__AARCH64_INSN_FUNCS(sbfm, 0x7F800000, 0x13000000) +__AARCH64_INSN_FUNCS(bfm, 0x7F800000, 0x33000000) +__AARCH64_INSN_FUNCS(movz, 0x7F800000, 0x52800000) +__AARCH64_INSN_FUNCS(ubfm, 0x7F800000, 0x53000000) +__AARCH64_INSN_FUNCS(movk, 0x7F800000, 0x72800000) +__AARCH64_INSN_FUNCS(add, 0x7F200000, 0x0B000000) +__AARCH64_INSN_FUNCS(adds, 0x7F200000, 0x2B000000) +__AARCH64_INSN_FUNCS(sub, 0x7F200000, 0x4B000000) +__AARCH64_INSN_FUNCS(subs, 0x7F200000, 0x6B000000) +__AARCH64_INSN_FUNCS(madd, 0x7FE08000, 0x1B000000) +__AARCH64_INSN_FUNCS(msub, 0x7FE08000, 0x1B008000) +__AARCH64_INSN_FUNCS(udiv, 0x7FE0FC00, 0x1AC00800) +__AARCH64_INSN_FUNCS(sdiv, 0x7FE0FC00, 0x1AC00C00) +__AARCH64_INSN_FUNCS(lslv, 0x7FE0FC00, 0x1AC02000) +__AARCH64_INSN_FUNCS(lsrv, 0x7FE0FC00, 0x1AC02400) +__AARCH64_INSN_FUNCS(asrv, 0x7FE0FC00, 0x1AC02800) +__AARCH64_INSN_FUNCS(rorv, 0x7FE0FC00, 0x1AC02C00) +__AARCH64_INSN_FUNCS(rev16, 0x7FFFFC00, 0x5AC00400) +__AARCH64_INSN_FUNCS(rev32, 0x7FFFFC00, 0x5AC00800) +__AARCH64_INSN_FUNCS(rev64, 0x7FFFFC00, 0x5AC00C00) +__AARCH64_INSN_FUNCS(and, 0x7F200000, 0x0A000000) +__AARCH64_INSN_FUNCS(bic, 0x7F200000, 0x0A200000) +__AARCH64_INSN_FUNCS(orr, 0x7F200000, 0x2A000000) +__AARCH64_INSN_FUNCS(orn, 0x7F200000, 0x2A200000) +__AARCH64_INSN_FUNCS(eor, 0x7F200000, 0x4A000000) +__AARCH64_INSN_FUNCS(eon, 0x7F200000, 0x4A200000) +__AARCH64_INSN_FUNCS(ands, 0x7F200000, 0x6A000000) +__AARCH64_INSN_FUNCS(bics, 0x7F200000, 0x6A200000) +__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000) +__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000) +__AARCH64_INSN_FUNCS(cbz, 0xFE000000, 0x34000000) +__AARCH64_INSN_FUNCS(cbnz, 0xFE000000, 0x35000000) +__AARCH64_INSN_FUNCS(bcond, 0xFF000010, 0x54000000) +__AARCH64_INSN_FUNCS(svc, 0xFFE0001F, 0xD4000001) +__AARCH64_INSN_FUNCS(hvc, 0xFFE0001F, 0xD4000002) +__AARCH64_INSN_FUNCS(smc, 0xFFE0001F, 0xD4000003) +__AARCH64_INSN_FUNCS(brk, 0xFFE0001F, 0xD4200000) +__AARCH64_INSN_FUNCS(hint, 0xFFFFF01F, 0xD503201F) +__AARCH64_INSN_FUNCS(br, 0xFFFFFC1F, 0xD61F0000) +__AARCH64_INSN_FUNCS(blr, 0xFFFFFC1F, 0xD63F0000) +__AARCH64_INSN_FUNCS(ret, 0xFFFFFC1F, 0xD65F0000) + +#undef __AARCH64_INSN_FUNCS + +bool aarch64_insn_is_nop(u32 insn); + +void aarch64_insn_read(void *addr, u32 *insnp); +void aarch64_insn_write(void *addr, u32 insn); +enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn); +u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, u32 insn, u64 imm); +u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, enum aarch64_insn_branch_type type); +u32 aarch64_insn_gen_comp_branch_imm(unsigned long pc, unsigned long addr, enum aarch64_insn_register reg, + enum aarch64_insn_variant variant, enum aarch64_insn_branch_type type); +u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr, enum aarch64_insn_condition cond); +u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op); +u32 aarch64_insn_gen_nop(void); +u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg, enum aarch64_insn_branch_type type); +u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg, enum aarch64_insn_register base, + enum aarch64_insn_register offset, enum aarch64_insn_size_type size, + enum aarch64_insn_ldst_type type); +u32 aarch64_insn_gen_load_store_pair(enum aarch64_insn_register reg1, enum aarch64_insn_register reg2, + enum aarch64_insn_register base, int offset, enum aarch64_insn_variant variant, + enum aarch64_insn_ldst_type type); +u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst, enum aarch64_insn_register src, int imm, + enum aarch64_insn_variant variant, enum aarch64_insn_adsb_type type); +u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst, enum aarch64_insn_register src, int immr, int imms, + enum aarch64_insn_variant variant, enum aarch64_insn_bitfield_type type); +u32 aarch64_insn_gen_movewide(enum aarch64_insn_register dst, int imm, int shift, enum aarch64_insn_variant variant, + enum aarch64_insn_movewide_type type); +u32 aarch64_insn_gen_add_sub_shifted_reg(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg, int shift, enum aarch64_insn_variant variant, + enum aarch64_insn_adsb_type type); +u32 aarch64_insn_gen_data1(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_variant variant, enum aarch64_insn_data1_type type); +u32 aarch64_insn_gen_data2(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg, enum aarch64_insn_variant variant, + enum aarch64_insn_data2_type type); +u32 aarch64_insn_gen_data3(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg1, enum aarch64_insn_register reg2, + enum aarch64_insn_variant variant, enum aarch64_insn_data3_type type); +u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst, enum aarch64_insn_register src, + enum aarch64_insn_register reg, int shift, enum aarch64_insn_variant variant, + enum aarch64_insn_logic_type type); + +bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); + +int aarch64_insn_patch_text_nosync(void *addr, u32 insn); +int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt); +int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); + +#endif \ No newline at end of file diff --git a/kernel/patch/module/module.c b/kernel/patch/module/module.c new file mode 100644 index 00000000..fef48ae1 --- /dev/null +++ b/kernel/patch/module/module.c @@ -0,0 +1,585 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "relo.h" + +#define SZ_128M 0x08000000 + +#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a)-1) + +#define align(X) ALIGN(X, page_size) + +#define elf_check_arch(x) ((x)->e_machine == EM_AARCH64) + +#define ARCH_SHF_SMALL 0 + +static inline bool strstarts(const char *str, const char *prefix) +{ + return strncmp(str, prefix, strlen(prefix)) == 0; +} + +static char *next_string(char *string, unsigned long *secsize) +{ + while (string[0]) { + string++; + if ((*secsize)-- <= 1) return 0; + } + while (!string[0]) { + string++; + if ((*secsize)-- <= 1) return 0; + } + return string; +} + +/* 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; + *size = ret + sechdr->sh_size; + return ret; +} + +static char *get_next_modinfo(const struct load_info *info, const char *tag, char *prev) +{ + char *p; + unsigned int taglen = strlen(tag); + Elf_Shdr *infosec = &info->sechdrs[info->index.info]; + unsigned long size = infosec->sh_size; + char *modinfo = (char *)info->hdr + infosec->sh_offset; + if (prev) { + size -= prev - modinfo; + modinfo = next_string(prev, &size); + } + for (p = modinfo; p; p = next_string(p, &size)) { + if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') return p + taglen + 1; + } + return 0; +} + +static char *get_modinfo(const struct load_info *info, const char *tag) +{ + return get_next_modinfo(info, tag, 0); +} + +static int find_sec(const struct load_info *info, const char *name) +{ + for (int i = 1; i < info->hdr->e_shnum; i++) { + Elf_Shdr *shdr = &info->sechdrs[i]; + if ((shdr->sh_flags & SHF_ALLOC) && strcmp(info->secstrings + shdr->sh_name, name) == 0) return i; + } + return 0; +} + +static void *get_sh_base(struct load_info *info, const char *secname) +{ + int idx = find_sec(info, secname); + if (!idx) return 0; + Elf_Shdr *infosec = &info->sechdrs[idx]; + void *addr = (void *)info->hdr + infosec->sh_offset; + return addr; +} + +static unsigned long get_sh_size(struct load_info *info, const char *secname) +{ + int idx = find_sec(info, secname); + if (!idx) return 0; + Elf_Shdr *infosec = &info->sechdrs[idx]; + return infosec->sh_entsize; +} + +static void layout_sections(struct module *mod, struct load_info *info) +{ + static unsigned long const masks[][2] = { + /* NOTE: all executable code must be the first section in this array; otherwise modify the text_size finder in the two loops below */ + { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, + { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, + { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, + { ARCH_SHF_SMALL | SHF_ALLOC, 0 } + }; + + for (int i = 0; i < info->hdr->e_shnum; i++) + info->sechdrs[i].sh_entsize = ~0UL; + + // todo: tslf alloc all rwx and not page aligned + for (int m = 0; m < sizeof(masks) / sizeof(masks[0]); ++m) { + for (int i = 0; i < info->hdr->e_shnum; ++i) { + Elf_Shdr *s = &info->sechdrs[i]; + if ((s->sh_flags & masks[m][0]) != masks[m][0] || (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL) + continue; + s->sh_entsize = get_offset(mod, &mod->size, s, i); + // const char *sname = info->secstrings + s->sh_name; + } + switch (m) { + case 0: /* executable */ + mod->size = align(mod->size); + mod->text_size = mod->size; + break; + case 1: /* RO: text and ro-data */ + mod->size = align(mod->size); + mod->ro_size = mod->size; + break; + case 2: + break; + case 3: /* whole */ + mod->size = align(mod->size); + break; + } + } +} + +static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs, unsigned int shnum) +{ + const Elf_Shdr *sec; + if (src->st_shndx == SHN_UNDEF || src->st_shndx >= shnum || !src->st_name) return false; + sec = sechdrs + src->st_shndx; + if (!(sec->sh_flags & SHF_ALLOC) || !(sec->sh_flags & SHF_EXECINSTR)) return false; + return true; +} + +/* Change all symbols so that st_value encodes the pointer directly. */ +static int simplify_symbols(struct module *mod, const struct load_info *info) +{ + Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; + Elf_Sym *sym = (void *)symsec->sh_addr; + unsigned long secbase; + unsigned int i; + int ret = 0; + + for (i = 1; i < symsec->sh_size / sizeof(Elf_Sym); i++) { + const char *name = info->strtab + sym[i].st_name; + switch (sym[i].st_shndx) { + case SHN_COMMON: + if (!strncmp(name, "__gnu_lto", 9)) { + logkd("Please compile with -fno-common\n"); + ret = -ENOEXEC; + } + break; + case SHN_ABS: + break; + case SHN_UNDEF: + unsigned long addr = symbol_lookup_name(name); + // cause overflow in relocation + // if (!addr) addr = kallsyms_lookup_name(name); + if (!addr) { + logke("Unknown symbol: %s\n", name); + ret = -ENOENT; + break; + } + sym[i].st_value = addr; + break; + default: + secbase = info->sechdrs[sym[i].st_shndx].sh_addr; + sym[i].st_value += secbase; + break; + } + } + return ret; +} + +static int apply_relocations(struct module *mod, const struct load_info *info) +{ + int err = 0; + unsigned int i; + for (i = 1; i < info->hdr->e_shnum; i++) { + unsigned int infosec = info->sechdrs[i].sh_info; + if (infosec >= info->hdr->e_shnum) continue; + if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC)) continue; + if (info->sechdrs[i].sh_type == SHT_REL) { + err = apply_relocate(info->sechdrs, info->strtab, info->index.sym, i, mod); + } else if (info->sechdrs[i].sh_type == SHT_RELA) { + err = apply_relocate_add(info->sechdrs, info->strtab, info->index.sym, i, mod); + } + if (err < 0) break; + } + return err; +} + +// todo: free .strtab and .symtab after relocation +static void layout_symtab(struct module *mod, struct load_info *info) +{ + Elf_Shdr *symsect = info->sechdrs + info->index.sym; + Elf_Shdr *strsect = info->sechdrs + info->index.str; + const Elf_Sym *src; + unsigned int i, nsrc, ndst, strtab_size = 0; + + /* Put symbol section at end of module. */ + symsect->sh_flags |= SHF_ALLOC; + symsect->sh_entsize = get_offset(mod, &mod->size, symsect, info->index.sym); + + src = (void *)info->hdr + symsect->sh_offset; + nsrc = symsect->sh_size / sizeof(*src); + + /* strtab always starts with a nul, so offset 0 is the empty string. */ + strtab_size = 1; + /* Compute total space required for the core symbols' strtab. */ + for (ndst = i = 0; i < nsrc; i++) { + if (i == 0 || is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum)) { + strtab_size += strlen(&info->strtab[src[i].st_name]) + 1; + ndst++; + } + } + + /* Append room for core symbols at end. */ + info->symoffs = ALIGN(mod->size, symsect->sh_addralign ?: 1); + info->stroffs = mod->size = info->symoffs + ndst * sizeof(Elf_Sym); + mod->size += strtab_size; + + /* Put string table section at end of module. */ + strsect->sh_flags |= SHF_ALLOC; + strsect->sh_entsize = get_offset(mod, &mod->size, strsect, info->index.str); +} + +static int license_is_gpl_compatible(const char *license) +{ + return (strcmp(license, "GPL") == 0 || strcmp(license, "GPL v2") == 0 || + strcmp(license, "GPL and additional rights") == 0 || strcmp(license, "Dual BSD/GPL") == 0 || + strcmp(license, "Dual MIT/GPL") == 0 || strcmp(license, "Dual MPL/GPL") == 0); +} + +static int rewrite_section_headers(struct load_info *info) +{ + info->sechdrs[0].sh_addr = 0; + for (int i = 1; i < info->hdr->e_shnum; i++) { + Elf_Shdr *shdr = &info->sechdrs[i]; + if (shdr->sh_type != SHT_NOBITS && info->len < shdr->sh_offset + shdr->sh_size) { + return -ENOEXEC; + } + /* Mark all sections sh_addr with their address in the temporary image. */ + shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset; + } + return 0; +} + +static int move_module(struct module *mod, struct load_info *info) +{ + // todo: + logki("alloc module size: %llx\n", mod->size); + mod->start = kp_malloc_exec(mod->size); + if (!mod->start) { + return -ENOMEM; + } + memset(mod->start, 0, mod->size); + + /* Transfer each section which specifies SHF_ALLOC */ + logkd("final section addresses:\n"); + + for (int i = 1; i < info->hdr->e_shnum; i++) { + void *dest; + Elf_Shdr *shdr = &info->sechdrs[i]; + if (!(shdr->sh_flags & SHF_ALLOC)) continue; + + dest = mod->start + shdr->sh_entsize; + const char *sname = info->secstrings + shdr->sh_name; + + logkd(" %s %llx %llx\n", sname, dest, shdr->sh_size); + + if (shdr->sh_type != SHT_NOBITS) { + memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size); + } + + shdr->sh_addr = (unsigned long)dest; + + if (!mod->init && !strcmp(".kpm.init", sname)) { + mod->init = (initcall_t *)dest; + } + if (!mod->exit && !strcmp(".kpm.exit", sname)) { + mod->exit = (exitcall_t *)dest; + } + if (!mod->info.base && !strcmp(".kpm.info", sname)) { + mod->info.base = (const char *)dest; + } + } + mod->info.name = info->info.name - info->info.base + mod->info.base; + mod->info.version = info->info.version - info->info.base + mod->info.base; + mod->info.license = info->info.license - info->info.base + mod->info.base; + if (info->info.author) mod->info.author = info->info.author - info->info.base + mod->info.base; + if (info->info.description) mod->info.description = info->info.description - info->info.base + mod->info.base; + + return 0; +} + +static int setup_load_info(struct load_info *info) +{ + int err = 0; + info->sechdrs = (void *)info->hdr + info->hdr->e_shoff; + info->secstrings = (void *)info->hdr + info->sechdrs[info->hdr->e_shstrndx].sh_offset; + + if ((err = rewrite_section_headers(info))) { + logke("rewrite section error\n"); + return err; + } + + if (!find_sec(info, ".kpm.init") || !find_sec(info, ".kpm.exit")) { + logke("no .kpm.init or .kpm.exit section\n"); + return -ENOEXEC; + } + + info->index.info = find_sec(info, ".kpm.info"); + if (!info->index.info) { + logke("no .kpm.info section\n"); + return -ENOEXEC; + } + info->info.base = get_sh_base(info, ".kpm.info"); + info->info.size = get_sh_size(info, ".kpm.info"); + + const char *name = get_modinfo(info, "name"); + if (!name) { + logke("module name not found\n"); + return -ENOEXEC; + } + info->info.name = name; + logkd("loading module: \n"); + logkd(" name: %s\n", name); + + const char *version = get_modinfo(info, "version"); + if (!version) { + logkd("module version not found\n"); + return -ENOEXEC; + } + info->info.version = version; + logkd(" version: %s\n", version); + + const char *license = get_modinfo(info, "license"); + if (!license || !license_is_gpl_compatible(license)) { + logkd("module license incompatible\n"); + return -ENOEXEC; + } + info->info.license = license; + logkd(" license: %s\n", license); + + const char *author = get_modinfo(info, "author"); + info->info.author = author; + logkd(" author: %s\n", author); + const char *description = get_modinfo(info, "description"); + info->info.description = description; + logkd(" description: %s\n", description); + + for (int i = 1; i < info->hdr->e_shnum; i++) { + if (info->sechdrs[i].sh_type == SHT_SYMTAB) { + info->index.sym = i; + info->index.str = info->sechdrs[i].sh_link; + info->strtab = (char *)info->hdr + info->sechdrs[info->index.str].sh_offset; + break; + } + } + + if (info->index.sym == 0) { + logkd("module has no symbols (stripped?)\n"); + return -ENOEXEC; + } + return 0; +} + +static int elf_header_check(struct load_info *info) +{ + if (info->len <= sizeof(*(info->hdr))) return -ENOEXEC; + if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) || info->hdr->e_type != ET_REL || !elf_check_arch(info->hdr) || + info->hdr->e_shentsize != sizeof(Elf_Shdr)) + return -ENOEXEC; + if (info->hdr->e_shoff >= info->len || (info->hdr->e_shnum * sizeof(Elf_Shdr) > info->len - info->hdr->e_shoff)) + return -ENOEXEC; + return 0; +} + +struct module modules = { 0 }; + +int load_module(void *data, int len, const char *args) +{ + struct load_info load_info = { .len = len, .hdr = data }; + struct load_info *info = &load_info; + + int err = 0; + if ((err = elf_header_check(info))) { + goto out; + } + if ((err = setup_load_info(info))) { + goto out; + } + + if (find_module(info->info.name)) { + logkd("module: %s exist\n", info->info.name); + err = -EEXIST; + goto out; + } + + struct module *mod = (struct module *)kp_malloc(sizeof(struct module)); + if (!mod) return -ENOMEM; + memset(mod, 0, sizeof(struct module)); + + if (args) { + mod->args = kp_malloc(strlen(args) + 1); + if (!mod->args) { + err = -ENOMEM; + goto free1; + } + strcpy(mod->args, args); + } + + layout_sections(mod, info); + layout_symtab(mod, info); + + if ((err = move_module(mod, info))) { + goto free; + } + + if ((err = simplify_symbols(mod, info))) { + goto free; + } + + if ((err = apply_relocations(mod, info))) { + goto free; + } + + flush_icache_all(); + + err = (*mod->init)(mod->args); + + if (!err) { + logki("module: [%s] init succeed\n", mod->info.name); + list_add_tail(&mod->list, &modules.list); + goto out; + } else { + logki("module: [%s] init failed: %d, try exit ...\n", mod->info.name, err); + (*mod->exit)(); + } + +free: + if (mod->args) kp_free(mod->args); + kp_free_exec(mod->start); +free1: + kp_free(mod); +out: + return err; +} + +int unload_module(const char *name) +{ + int err = 0; + struct module *mod = find_module(name); + if (!mod) { + err = -ENOENT; + goto out; + } + list_del(&mod->list); + (*mod->exit)(); + + if (mod->args) kp_free(mod->args); + kp_free_exec(mod->start); + kp_free(mod); +out: + return err; +} + +int load_module_path(const char *path, const char *args) +{ + long err = 0; + logkd("loading module with path: %s, args: %s\n", path, args); + + struct file *filp = filp_open(path, O_RDONLY, 0); + if (unlikely(IS_ERR(filp))) { + logke("open module error\n"); + err = PTR_ERR(filp); + goto out; + } + loff_t len = vfs_llseek(filp, 0, SEEK_END); + logkd("module size: %llx\n", len); + vfs_llseek(filp, 0, SEEK_SET); + + void *data = kp_malloc(len); + if (!data) { + err = -ENOMEM; + goto out; + } + memset(data, 0, len); + + loff_t pos = 0; + kernel_read(filp, data, len, &pos); + filp_close(filp, 0); + + if (pos != len) { + logke("read module error\n"); + err = -EIO; + goto free; + } + + err = load_module(data, len, args); + +free: + kp_free(data); +out: + return err; +} + +struct module *find_module(const char *name) +{ + struct module *pos; + list_for_each_entry(pos, &modules.list, list) + { + if (!strcmp(name, pos->info.name)) { + return pos; + } + } + return 0; +} + +int get_module_nums() +{ + struct module *pos; + int n = 0; + list_for_each_entry(pos, &modules.list, list) + { + n++; + } + return n; +} + +int get_module_info(int index, char *info, int size) +{ + if (size <= 0) return 0; + + struct module *pos = 0, *mod = 0; + int n = 0; + list_for_each_entry(pos, &modules.list, list) + { + if (n == index) { + mod = pos; + break; + } + n++; + } + if (!mod) return -ENOENT; + + int sz = snprintf(info, size - 1, + "name=%s\n" + "version=%s\n" + "license=%s\n" + "author=%s\n" + "description=%s\n", + mod->info.name, mod->info.version, mod->info.license, mod->info.author, mod->info.description); + return sz; +} + +int module_init() +{ + INIT_LIST_HEAD(&modules.list); + return 0; +} \ No newline at end of file diff --git a/kernel/patch/module/relo.c b/kernel/patch/module/relo.c new file mode 100644 index 00000000..c9366604 --- /dev/null +++ b/kernel/patch/module/relo.c @@ -0,0 +1,329 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "insn.h" + +#define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX +#define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16 + +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) + +enum aarch64_reloc_op +{ + RELOC_OP_NONE, + RELOC_OP_ABS, + RELOC_OP_PREL, + RELOC_OP_PAGE, +}; + +static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val) +{ + switch (reloc_op) { + case RELOC_OP_ABS: + return val; + case RELOC_OP_PREL: + return val - (u64)place; + case RELOC_OP_PAGE: + return (val & ~0xfff) - ((u64)place & ~0xfff); + case RELOC_OP_NONE: + return 0; + } + + pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); + return 0; +} + +static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) +{ + u64 imm_mask = (1 << len) - 1; + s64 sval = do_reloc(op, place, val); + + switch (len) { + case 16: + *(s16 *)place = sval; + break; + case 32: + *(s32 *)place = sval; + break; + case 64: + *(s64 *)place = sval; + break; + default: + pr_err("Invalid length (%d) for data relocation\n", len); + return 0; + } + /* + * Extract the upper value bits (including the sign bit) and + * shift them to bit 0. + */ + sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); + + /* + * Overflow has occurred if the value is not representable in + * len bits (i.e the bottom len bits are not sign-extended and + * the top bits are not all zero). + */ + if ((u64)(sval + 1) > 2) return -ERANGE; + + return 0; +} + +static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, int lsb, enum aarch64_insn_imm_type imm_type) +{ + u64 imm, limit = 0; + s64 sval; + u32 insn = le32_to_cpu(*(u32 *)place); + + sval = do_reloc(op, place, val); + sval >>= lsb; + imm = sval & 0xffff; + + if (imm_type == AARCH64_INSN_IMM_MOVNZ) { + /* + * For signed MOVW relocations, we have to manipulate the + * instruction encoding depending on whether or not the + * immediate is less than zero. + */ + insn &= ~(3 << 29); + if ((s64)imm >= 0) { + /* >=0: Set the instruction to MOVZ (opcode 10b). */ + insn |= 2 << 29; + } else { + /* + * <0: Set the instruction to MOVN (opcode 00b). + * Since we've masked the opcode already, we + * don't need to do anything other than + * inverting the new immediate field. + */ + imm = ~imm; + } + imm_type = AARCH64_INSN_IMM_MOVK; + } + + /* Update the instruction with the new encoding. */ + insn = aarch64_insn_encode_immediate(imm_type, insn, imm); + *(u32 *)place = cpu_to_le32(insn); + + /* Shift out the immediate field. */ + sval >>= 16; + + /* + * For unsigned immediates, the overflow check is straightforward. + * For signed immediates, the sign bit is actually the bit past the + * most significant bit of the field. + * The AARCH64_INSN_IMM_16 immediate type is unsigned. + */ + if (imm_type != AARCH64_INSN_IMM_16) { + sval++; + limit++; + } + + /* Check the upper bits depending on the sign of the immediate. */ + if ((u64)sval > limit) return -ERANGE; + + return 0; +} + +static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, int lsb, int len, + enum aarch64_insn_imm_type imm_type) +{ + u64 imm, imm_mask; + s64 sval; + u32 insn = le32_to_cpu(*(u32 *)place); + + /* Calculate the relocation value. */ + sval = do_reloc(op, place, val); + sval >>= lsb; + /* Extract the value bits and shift them to bit 0. */ + imm_mask = (BIT(lsb + len) - 1) >> lsb; + imm = sval & imm_mask; + /* Update the instruction's immediate field. */ + insn = aarch64_insn_encode_immediate(imm_type, insn, imm); + *(u32 *)place = cpu_to_le32(insn); + /* + * Extract the upper value bits (including the sign bit) and + * shift them to bit 0. + */ + sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); + /* + * Overflow has occurred if the upper bits are not all equal to + * the sign bit of the value. + */ + if ((u64)(sval + 1) >= 2) return -ERANGE; + + return 0; +} + +int apply_relocate(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, + struct module *me) +{ + return 0; +}; + +int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, + struct module *me) +{ + unsigned int i; + int ovf; + bool overflow_check; + Elf64_Sym *sym; + void *loc; + u64 val; + Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* loc corresponds to P in the AArch64 ELF document. */ + loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; + /* sym is the ELF symbol we're referring to. */ + sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + ELF64_R_SYM(rel[i].r_info); + /* val corresponds to (S + A) in the AArch64 ELF document. */ + val = sym->st_value + rel[i].r_addend; + + overflow_check = true; + + /* Perform the static relocation. */ + switch (ELF64_R_TYPE(rel[i].r_info)) { + /* Null relocations. */ + case R_ARM_NONE: + case R_AARCH64_NONE: + ovf = 0; + break; + /* Data relocations. */ + case R_AARCH64_ABS64: + overflow_check = false; + ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); + break; + case R_AARCH64_ABS32: + ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); + break; + case R_AARCH64_ABS16: + ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); + break; + case R_AARCH64_PREL64: + overflow_check = false; + ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); + break; + case R_AARCH64_PREL32: + ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); + break; + case R_AARCH64_PREL16: + ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); + break; + + /* MOVW instruction relocations. */ + case R_AARCH64_MOVW_UABS_G0_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G0: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G1_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G1: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G2_NC: + overflow_check = false; + case R_AARCH64_MOVW_UABS_G2: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_UABS_G3: + /* We're using the top bits so we can't overflow. */ + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, AARCH64_INSN_IMM_16); + break; + case R_AARCH64_MOVW_SABS_G0: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_SABS_G1: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_SABS_G2: + ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G0_NC: + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, AARCH64_INSN_IMM_MOVK); + break; + case R_AARCH64_MOVW_PREL_G0: + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G1_NC: + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, AARCH64_INSN_IMM_MOVK); + break; + case R_AARCH64_MOVW_PREL_G1: + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G2_NC: + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, AARCH64_INSN_IMM_MOVK); + break; + case R_AARCH64_MOVW_PREL_G2: + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, AARCH64_INSN_IMM_MOVNZ); + break; + case R_AARCH64_MOVW_PREL_G3: + /* We're using the top bits so we can't overflow. */ + overflow_check = false; + ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, AARCH64_INSN_IMM_MOVNZ); + break; + /* Immediate instruction relocations. */ + case R_AARCH64_LD_PREL_LO19: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, AARCH64_INSN_IMM_19); + break; + case R_AARCH64_ADR_PREL_LO21: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, AARCH64_INSN_IMM_ADR); + break; + case R_AARCH64_ADR_PREL_PG_HI21_NC: + overflow_check = false; + case R_AARCH64_ADR_PREL_PG_HI21: + ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, AARCH64_INSN_IMM_ADR); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST8_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST16_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST32_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, AARCH64_INSN_IMM_12); + break; + case R_AARCH64_LDST128_ABS_LO12_NC: + overflow_check = false; + ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, AARCH64_INSN_IMM_12); + break; + case R_AARCH64_TSTBR14: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, AARCH64_INSN_IMM_14); + break; + case R_AARCH64_CONDBR19: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, AARCH64_INSN_IMM_19); + break; + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, AARCH64_INSN_IMM_26); + break; + default: + pr_err("unsupported RELA relocation: %llu\n", ELF64_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + + if (overflow_check && ovf == -ERANGE) goto overflow; + } + return 0; +overflow: + pr_err("overflow in relocation type %d val %llx\n", (int)ELF64_R_TYPE(rel[i].r_info), val); + return -ENOEXEC; +} \ No newline at end of file diff --git a/kernel/patch/module/relo.h b/kernel/patch/module/relo.h new file mode 100644 index 00000000..bf41e5a1 --- /dev/null +++ b/kernel/patch/module/relo.h @@ -0,0 +1,11 @@ +#ifndef _KP_RELO_H_ +#define _KP_RELO_H_ + +#include + +int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, + struct module *me); +int apply_relocate(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, + struct module *me); + +#endif \ No newline at end of file diff --git a/kernel/patch/old/hooksysc.h b/kernel/patch/old/hooksysc.h new file mode 100644 index 00000000..4a098455 --- /dev/null +++ b/kernel/patch/old/hooksysc.h @@ -0,0 +1,111 @@ +#ifndef _KP_SYSCALL_H_ +#define _KP_SYSCALL_H_ + +#include +#include +#include +#include +#include + +#define __MAP0(m, ...) +#define __MAP1(m, t, a, ...) m(t, a) +#define __MAP2(m, t, a, ...) m(t, a), __MAP1(m, __VA_ARGS__) +#define __MAP3(m, t, a, ...) m(t, a), __MAP2(m, __VA_ARGS__) +#define __MAP4(m, t, a, ...) m(t, a), __MAP3(m, __VA_ARGS__) +#define __MAP5(m, t, a, ...) m(t, a), __MAP4(m, __VA_ARGS__) +#define __MAP6(m, t, a, ...) m(t, a), __MAP5(m, __VA_ARGS__) +#define __MAP(n, ...) __MAP##n(__VA_ARGS__) + +#define __SC_DECL(t, a) t a +#define __SC_ARGS(t, a) a +#define __SC_EMPTY(t, a) 0 + +#define ARM64_REGS_TO_ARGS(x, ...) \ + __MAP(x, __SC_ARGS, , regs->regs[0], , regs->regs[1], , regs->regs[2], , regs->regs[3], , regs->regs[4], , \ + regs->regs[5]) + +#define __REGS_ASSIGN0(n, ...) +#define __REGS_ASSIGN1(n, t, a, ...) \ + a = (t)(regs->regs[n - 1]); \ + __REGS_ASSIGN0(n, __VA_ARGS__) +#define __REGS_ASSIGN2(n, t, a, ...) \ + a = (t)(regs->regs[n - 2]); \ + __REGS_ASSIGN1(n, __VA_ARGS__) +#define __REGS_ASSIGN3(n, t, a, ...) \ + a = (t)(regs->regs[n - 3]); \ + __REGS_ASSIGN2(n, __VA_ARGS__) +#define __REGS_ASSIGN4(n, t, a, ...) \ + a = (t)(regs->regs[n - 4]); \ + __REGS_ASSIGN3(n, __VA_ARGS__) +#define __REGS_ASSIGN5(n, t, a, ...) \ + a = (t)(regs->regs[n - 5]); \ + __REGS_ASSIGN4(n, __VA_ARGS__) +#define __REGS_ASSIGN6(n, t, a, ...) \ + a = (t)(regs->regs[n - 6]); \ + __REGS_ASSIGN5(n, __VA_ARGS__) +#define __REGS_ASSIGN(n, ...) __REGS_ASSIGN##n(n, __VA_ARGS__) + +#define HOOK_SYSCALL_DEFINE(x, nr, ...) \ + static long (*__hook_sys_backup_##nr)(__MAP(x, __SC_DECL, __VA_ARGS__)) = 0; \ + static long (*__hook_sys_wrap_backup_##nr)(const struct pt_regs *regs) = 0; \ + static long __hook_sys_bridge_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)); \ + static long __hook_sys_common_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)); \ + long __attribute__((__noinline__)) __hook_sys_##nr(__MAP(x, __SC_DECL, __VA_ARGS__)) \ + { \ + return __hook_sys_bridge_##nr(0, __MAP(x, __SC_ARGS, __VA_ARGS__)); \ + } \ + long __attribute__((__noinline__)) __hook_sys_wrap_##nr(const struct pt_regs *regs) \ + { \ + return __hook_sys_bridge_##nr(regs, __MAP(x, __SC_EMPTY, __VA_ARGS__)); \ + } \ + static long inline __hook_sys_bridge_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)) \ + { \ + if (regs) { \ + __REGS_ASSIGN(x, __VA_ARGS__); \ + } \ + return __hook_sys_common_##nr(regs, __MAP(x, __SC_ARGS, __VA_ARGS__)); \ + } \ + static long inline __hook_sys_common_##nr(const struct pt_regs *regs, __MAP(x, __SC_DECL, __VA_ARGS__)) + +#define HOOK_SYSCALL_DEFINE0(nr, ...) HOOK_SYSCALL_DEFINE(0, nr, __VA_ARGS__) +#define HOOK_SYSCALL_DEFINE1(nr, ...) HOOK_SYSCALL_DEFINE(1, nr, __VA_ARGS__) +#define HOOK_SYSCALL_DEFINE2(nr, ...) HOOK_SYSCALL_DEFINE(2, nr, __VA_ARGS__) +#define HOOK_SYSCALL_DEFINE3(nr, ...) HOOK_SYSCALL_DEFINE(3, nr, __VA_ARGS__) +#define HOOK_SYSCALL_DEFINE4(nr, ...) HOOK_SYSCALL_DEFINE(4, nr, __VA_ARGS__) +#define HOOK_SYSCALL_DEFINE5(nr, ...) HOOK_SYSCALL_DEFINE(5, nr, __VA_ARGS__) +#define HOOK_SYSCALL_DEFINE6(nr, ...) HOOK_SYSCALL_DEFINE(6, nr, __VA_ARGS__) + +#define __HOOK_SYSCALL_CALL_ORIGIN(nr, ...) \ + (syscall_has_wrapper ? __hook_sys_wrap_backup_##nr(regs) : __hook_sys_backup_##nr(__VA_ARGS__)); + +#define HOOK_SYSCALL_CALL_ORIGIN(nr, ...) __HOOK_SYSCALL_CALL_ORIGIN(nr, __VA_ARGS__) + +#define __REPLACE_SYSCALL_INSTALL(nr) \ + if (syscall_has_wrapper) { \ + replace_syscall_with(nr, (uintptr_t *)&__hook_sys_wrap_backup_##nr, (uintptr_t)__hook_sys_wrap_##nr); \ + } else { \ + replace_syscall_with(nr, (uintptr_t *)&__hook_sys_backup_##nr, (uintptr_t)__hook_sys_##nr); \ + } +#define REPLACE_SYSCALL_INSTALL(nr) __REPLACE_SYSCALL_INSTALL(nr) + +#define __INLINE_SYSCALL_INSTALL(nr) \ + if (syscall_has_wrapper) { \ + inline_syscall_with(nr, (uintptr_t *)&__hook_sys_wrap_backup_##nr, (uintptr_t)__hook_sys_wrap_##nr); \ + } else { \ + inline_syscall_with(nr, (uintptr_t *)&__hook_sys_backup_##nr, (uintptr_t)__hook_sys_##nr); \ + } +#define INLINE_SYSCALL_INSTALL(nr) __INLINE_SYSCALL_INSTALL(nr) + +#define _ARGS_TO_REGS(regs, idx, val, ...) \ + do { \ + regs.regs[idx] = val; \ + ARGS_TO_REGS(regs, idx + 1, __VA_ARGS__); \ + } while (0) + +#define ARGS_TO_REGS(regs, ...) _ARGS_TO_REGS(regs, 0, __VA_ARGS__) + +extern bool syscall_has_wrapper; +extern uintptr_t syscall_table_addr; +extern uintptr_t compat_syscall_table_addr; + +#endif \ No newline at end of file diff --git a/kernel/patch/accctl/lsmhook.c b/kernel/patch/old/lsmhook.c similarity index 99% rename from kernel/patch/accctl/lsmhook.c rename to kernel/patch/old/lsmhook.c index 4aae7e01..666916a7 100644 --- a/kernel/patch/accctl/lsmhook.c +++ b/kernel/patch/old/lsmhook.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/kernel/patch/ksyms/security.c b/kernel/patch/old/security.c similarity index 56% rename from kernel/patch/ksyms/security.c rename to kernel/patch/old/security.c index e69ce702..59327f82 100644 --- a/kernel/patch/ksyms/security.c +++ b/kernel/patch/old/security.c @@ -309,358 +309,281 @@ int kfunc_def(security_uring_cmd)(struct io_uring_cmd *ioucmd) = 0; void _linux_security_security_sym_match(const char *name, unsigned long addr) { - /* Security operations */ - kfunc_match(security_binder_set_context_mgr, name, addr); - kfunc_match(security_binder_transaction, name, addr); - kfunc_match(security_binder_transfer_binder, name, addr); - kfunc_match(security_binder_transfer_file, name, addr); - kfunc_match(security_ptrace_access_check, name, addr); - kfunc_match(security_ptrace_traceme, name, addr); - kfunc_match(security_capget, name, addr); - kfunc_match(security_capset, name, addr); - kfunc_match(security_capable, name, addr); - kfunc_match(security_quotactl, name, addr); - kfunc_match(security_quota_on, name, addr); - kfunc_match(security_syslog, name, addr); - kfunc_match(security_settime64, name, addr); - kfunc_match(security_vm_enough_memory_mm, name, addr); - kfunc_match(security_bprm_creds_for_exec, name, addr); - kfunc_match(security_bprm_creds_from_file, name, addr); - kfunc_match(security_bprm_check, name, addr); - kfunc_match(security_bprm_committing_creds, name, addr); - kfunc_match(security_bprm_committed_creds, name, addr); - kfunc_match(security_fs_context_dup, name, addr); - kfunc_match(security_fs_context_parse_param, name, addr); - kfunc_match(security_sb_alloc, name, addr); - kfunc_match(security_sb_delete, name, addr); - kfunc_match(security_sb_free, name, addr); - kfunc_match(security_free_mnt_opts, name, addr); - kfunc_match(security_sb_eat_lsm_opts, name, addr); - kfunc_match(security_sb_remount, name, addr); - kfunc_match(security_sb_kern_mount, name, addr); - kfunc_match(security_sb_show_options, name, addr); - kfunc_match(security_sb_statfs, name, addr); - kfunc_match(security_sb_mount, name, addr); - kfunc_match(security_sb_umount, name, addr); - kfunc_match(security_sb_pivotroot, name, addr); - kfunc_match(security_sb_set_mnt_opts, name, addr); - kfunc_match(security_sb_clone_mnt_opts, name, addr); - kfunc_match(security_add_mnt_opt, name, addr); - kfunc_match(security_move_mount, name, addr); - kfunc_match(security_dentry_init_security, name, addr); - kfunc_match(security_dentry_create_files_as, name, addr); - - //CONFIG_SECURITY_PATH - kfunc_match(security_path_unlink, name, addr); - kfunc_match(security_path_mkdir, name, addr); - kfunc_match(security_path_rmdir, name, addr); - kfunc_match(security_path_mknod, name, addr); - kfunc_match(security_path_truncate, name, addr); - kfunc_match(security_path_symlink, name, addr); - kfunc_match(security_path_link, name, addr); - kfunc_match(security_path_rename, name, addr); - kfunc_match(security_path_chmod, name, addr); - kfunc_match(security_path_chown, name, addr); - kfunc_match(security_path_chroot, name, addr); - /* CONFIG_SECURITY_PATH */ - - /* Needed for inode based security check */ - kfunc_match(security_path_notify, name, addr); - kfunc_match(security_inode_alloc, name, addr); - kfunc_match(security_inode_free, name, addr); - kfunc_match(security_inode_init_security, name, addr); - kfunc_match(security_old_inode_init_security, name, addr); - kfunc_match(security_inode_create, name, addr); - kfunc_match(security_inode_link, name, addr); - kfunc_match(security_inode_unlink, name, addr); - kfunc_match(security_inode_symlink, name, addr); - kfunc_match(security_inode_mkdir, name, addr); - kfunc_match(security_inode_rmdir, name, addr); - kfunc_match(security_inode_mknod, name, addr); - kfunc_match(security_inode_rename, name, addr); - kfunc_match(security_inode_readlink, name, addr); - kfunc_match(security_inode_follow_link, name, addr); - kfunc_match(security_inode_permission, name, addr); - kfunc_match(security_inode_setattr, name, addr); - kfunc_match(security_inode_getattr, name, addr); - kfunc_match(security_inode_setxattr, name, addr); - kfunc_match(security_inode_post_setxattr, name, addr); - kfunc_match(security_inode_getxattr, name, addr); - kfunc_match(security_inode_listxattr, name, addr); - kfunc_match(security_inode_removexattr, name, addr); - kfunc_match(security_inode_set_acl, name, addr); - kfunc_match(security_inode_get_acl, name, addr); - kfunc_match(security_inode_remove_acl, name, addr); - kfunc_match(security_inode_need_killpriv, name, addr); - kfunc_match(security_inode_killpriv, name, addr); - kfunc_match(security_inode_getsecurity, name, addr); - kfunc_match(security_inode_setsecurity, name, addr); - kfunc_match(security_inode_listsecurity, name, addr); - kfunc_match(security_inode_getsecid, name, addr); - kfunc_match(security_inode_copy_up, name, addr); - kfunc_match(security_inode_copy_up_xattr, name, addr); - kfunc_match(security_kernfs_init_security, name, addr); - kfunc_match(security_file_permission, name, addr); - kfunc_match(security_file_alloc, name, addr); - kfunc_match(security_file_free, name, addr); - kfunc_match(security_file_ioctl, name, addr); - kfunc_match(security_mmap_addr, name, addr); - kfunc_match(security_mmap_file, name, addr); - kfunc_match(security_file_mprotect, name, addr); - kfunc_match(security_file_lock, name, addr); - kfunc_match(security_file_fcntl, name, addr); - kfunc_match(security_file_set_fowner, name, addr); - kfunc_match(security_file_send_sigiotask, name, addr); - kfunc_match(security_file_receive, name, addr); - kfunc_match(security_file_open, name, addr); - kfunc_match(security_file_truncate, name, addr); - kfunc_match(security_task_alloc, name, addr); - kfunc_match(security_task_free, name, addr); - kfunc_match(security_cred_alloc_blank, name, addr); - kfunc_match(security_cred_free, name, addr); - kfunc_match(security_prepare_creds, name, addr); - kfunc_match(security_transfer_creds, name, addr); + // kfunc_match(security_binder_set_context_mgr, name, addr); + // kfunc_match(security_binder_transaction, name, addr); + // kfunc_match(security_binder_transfer_binder, name, addr); + // kfunc_match(security_binder_transfer_file, name, addr); + // kfunc_match(security_ptrace_access_check, name, addr); + // kfunc_match(security_ptrace_traceme, name, addr); + // kfunc_match(security_capget, name, addr); + // kfunc_match(security_capset, name, addr); + // kfunc_match(security_capable, name, addr); + // kfunc_match(security_quotactl, name, addr); + // kfunc_match(security_quota_on, name, addr); + // kfunc_match(security_syslog, name, addr); + // kfunc_match(security_settime64, name, addr); + // kfunc_match(security_vm_enough_memory_mm, name, addr); + // kfunc_match(security_bprm_creds_for_exec, name, addr); + // kfunc_match(security_bprm_creds_from_file, name, addr); + // kfunc_match(security_bprm_check, name, addr); + // kfunc_match(security_bprm_committing_creds, name, addr); + // kfunc_match(security_bprm_committed_creds, name, addr); + // kfunc_match(security_fs_context_dup, name, addr); + // kfunc_match(security_fs_context_parse_param, name, addr); + // kfunc_match(security_sb_alloc, name, addr); + // kfunc_match(security_sb_delete, name, addr); + // kfunc_match(security_sb_free, name, addr); + // kfunc_match(security_free_mnt_opts, name, addr); + // kfunc_match(security_sb_eat_lsm_opts, name, addr); + // kfunc_match(security_sb_remount, name, addr); + // kfunc_match(security_sb_kern_mount, name, addr); + // kfunc_match(security_sb_show_options, name, addr); + // kfunc_match(security_sb_statfs, name, addr); + // kfunc_match(security_sb_mount, name, addr); + // kfunc_match(security_sb_umount, name, addr); + // kfunc_match(security_sb_pivotroot, name, addr); + // kfunc_match(security_sb_set_mnt_opts, name, addr); + // kfunc_match(security_sb_clone_mnt_opts, name, addr); + // kfunc_match(security_add_mnt_opt, name, addr); + // kfunc_match(security_move_mount, name, addr); + // kfunc_match(security_dentry_init_security, name, addr); + // kfunc_match(security_dentry_create_files_as, name, addr); + + // //CONFIG_SECURITY_PATH + // kfunc_match(security_path_unlink, name, addr); + // kfunc_match(security_path_mkdir, name, addr); + // kfunc_match(security_path_rmdir, name, addr); + // kfunc_match(security_path_mknod, name, addr); + // kfunc_match(security_path_truncate, name, addr); + // kfunc_match(security_path_symlink, name, addr); + // kfunc_match(security_path_link, name, addr); + // kfunc_match(security_path_rename, name, addr); + // kfunc_match(security_path_chmod, name, addr); + // kfunc_match(security_path_chown, name, addr); + // kfunc_match(security_path_chroot, name, addr); + // /* CONFIG_SECURITY_PATH */ + + // /* Needed for inode based security check */ + // kfunc_match(security_path_notify, name, addr); + // kfunc_match(security_inode_alloc, name, addr); + // kfunc_match(security_inode_free, name, addr); + // kfunc_match(security_inode_init_security, name, addr); + // kfunc_match(security_old_inode_init_security, name, addr); + // kfunc_match(security_inode_create, name, addr); + // kfunc_match(security_inode_link, name, addr); + // kfunc_match(security_inode_unlink, name, addr); + // kfunc_match(security_inode_symlink, name, addr); + // kfunc_match(security_inode_mkdir, name, addr); + // kfunc_match(security_inode_rmdir, name, addr); + // kfunc_match(security_inode_mknod, name, addr); + // kfunc_match(security_inode_rename, name, addr); + // kfunc_match(security_inode_readlink, name, addr); + // kfunc_match(security_inode_follow_link, name, addr); + // kfunc_match(security_inode_permission, name, addr); + // kfunc_match(security_inode_setattr, name, addr); + // kfunc_match(security_inode_getattr, name, addr); + // kfunc_match(security_inode_setxattr, name, addr); + // kfunc_match(security_inode_post_setxattr, name, addr); + // kfunc_match(security_inode_getxattr, name, addr); + // kfunc_match(security_inode_listxattr, name, addr); + // kfunc_match(security_inode_removexattr, name, addr); + // kfunc_match(security_inode_set_acl, name, addr); + // kfunc_match(security_inode_get_acl, name, addr); + // kfunc_match(security_inode_remove_acl, name, addr); + // kfunc_match(security_inode_need_killpriv, name, addr); + // kfunc_match(security_inode_killpriv, name, addr); + // kfunc_match(security_inode_getsecurity, name, addr); + // kfunc_match(security_inode_setsecurity, name, addr); + // kfunc_match(security_inode_listsecurity, name, addr); + // kfunc_match(security_inode_getsecid, name, addr); + // kfunc_match(security_inode_copy_up, name, addr); + // kfunc_match(security_inode_copy_up_xattr, name, addr); + // kfunc_match(security_kernfs_init_security, name, addr); + // kfunc_match(security_file_permission, name, addr); + // kfunc_match(security_file_alloc, name, addr); + // kfunc_match(security_file_free, name, addr); + // kfunc_match(security_file_ioctl, name, addr); + // kfunc_match(security_mmap_addr, name, addr); + // kfunc_match(security_mmap_file, name, addr); + // kfunc_match(security_file_mprotect, name, addr); + // kfunc_match(security_file_lock, name, addr); + // kfunc_match(security_file_fcntl, name, addr); + // kfunc_match(security_file_set_fowner, name, addr); + // kfunc_match(security_file_send_sigiotask, name, addr); + // kfunc_match(security_file_receive, name, addr); + // kfunc_match(security_file_open, name, addr); + // kfunc_match(security_file_truncate, name, addr); + // kfunc_match(security_task_alloc, name, addr); + // kfunc_match(security_task_free, name, addr); + // kfunc_match(security_cred_alloc_blank, name, addr); + // kfunc_match(security_cred_free, name, addr); + // kfunc_match(security_prepare_creds, name, addr); + // kfunc_match(security_transfer_creds, name, addr); kfunc_match(security_cred_getsecid, name, addr); - kfunc_match(security_kernel_act_as, name, addr); - kfunc_match(security_kernel_create_files_as, name, addr); - kfunc_match(security_kernel_module_request, name, addr); - kfunc_match(security_kernel_load_data, name, addr); - kfunc_match(security_kernel_post_load_data, name, addr); - kfunc_match(security_kernel_read_file, name, addr); - kfunc_match(security_kernel_post_read_file, name, addr); - kfunc_match(security_task_fix_setuid, name, addr); - kfunc_match(security_task_fix_setgid, name, addr); - kfunc_match(security_task_fix_setgroups, name, addr); - kfunc_match(security_task_setpgid, name, addr); - kfunc_match(security_task_getpgid, name, addr); - kfunc_match(security_task_getsid, name, addr); - kfunc_match(security_current_getsecid_subj, name, addr); - kfunc_match(security_task_getsecid_obj, name, addr); - kfunc_match(security_task_getsecid, name, addr); - kfunc_match(security_task_setnice, name, addr); - kfunc_match(security_task_setioprio, name, addr); - kfunc_match(security_task_getioprio, name, addr); - kfunc_match(security_task_prlimit, name, addr); - kfunc_match(security_task_setrlimit, name, addr); - kfunc_match(security_task_setscheduler, name, addr); - kfunc_match(security_task_getscheduler, name, addr); - kfunc_match(security_task_movememory, name, addr); - kfunc_match(security_task_kill, name, addr); - kfunc_match(security_task_prctl, name, addr); - kfunc_match(security_task_to_inode, name, addr); - kfunc_match(security_create_user_ns, name, addr); - kfunc_match(security_ipc_permission, name, addr); - kfunc_match(security_ipc_getsecid, name, addr); - kfunc_match(security_msg_msg_alloc, name, addr); - kfunc_match(security_msg_msg_free, name, addr); - kfunc_match(security_msg_queue_alloc, name, addr); - kfunc_match(security_msg_queue_free, name, addr); - kfunc_match(security_msg_queue_associate, name, addr); - kfunc_match(security_msg_queue_msgctl, name, addr); - kfunc_match(security_msg_queue_msgsnd, name, addr); - kfunc_match(security_msg_queue_msgrcv, name, addr); - kfunc_match(security_shm_alloc, name, addr); - kfunc_match(security_shm_free, name, addr); - kfunc_match(security_shm_associate, name, addr); - kfunc_match(security_shm_shmctl, name, addr); - kfunc_match(security_shm_shmat, name, addr); - kfunc_match(security_sem_alloc, name, addr); - kfunc_match(security_sem_free, name, addr); - kfunc_match(security_sem_associate, name, addr); - kfunc_match(security_sem_semctl, name, addr); - kfunc_match(security_sem_semop, name, addr); - kfunc_match(security_d_instantiate, name, addr); - kfunc_match(security_getprocattr, name, addr); - kfunc_match(security_setprocattr, name, addr); - kfunc_match(security_netlink_send, name, addr); - kfunc_match(security_ismaclabel, name, addr); - kfunc_match(security_secid_to_secctx, name, addr); - kfunc_match(security_secctx_to_secid, name, addr); - kfunc_match(security_release_secctx, name, addr); - kfunc_match(security_inode_invalidate_secctx, name, addr); - kfunc_match(security_inode_notifysecctx, name, addr); - kfunc_match(security_inode_setsecctx, name, addr); - kfunc_match(security_inode_getsecctx, name, addr); - - // CONFIG_WATCH_QUEUE - kfunc_match(security_post_notification, name, addr); - - // CONFIG_KEY_NOTIFICATIONS - kfunc_match(security_watch_key, name, addr); - - // CONFIG_SECURITY_NETWORK - kfunc_match(security_unix_stream_connect, name, addr); - kfunc_match(security_unix_may_send, name, addr); - kfunc_match(security_socket_create, name, addr); - kfunc_match(security_socket_post_create, name, addr); - kfunc_match(security_socket_socketpair, name, addr); - kfunc_match(security_socket_bind, name, addr); - kfunc_match(security_socket_connect, name, addr); - kfunc_match(security_socket_listen, name, addr); - kfunc_match(security_socket_accept, name, addr); - kfunc_match(security_socket_sendmsg, name, addr); - kfunc_match(security_socket_recvmsg, name, addr); - kfunc_match(security_socket_getsockname, name, addr); - kfunc_match(security_socket_getpeername, name, addr); - kfunc_match(security_socket_getsockopt, name, addr); - kfunc_match(security_socket_setsockopt, name, addr); - kfunc_match(security_socket_shutdown, name, addr); - kfunc_match(security_sock_rcv_skb, name, addr); - kfunc_match(security_socket_getpeersec_stream, name, addr); - kfunc_match(security_socket_getpeersec_dgram, name, addr); - kfunc_match(security_sk_alloc, name, addr); - kfunc_match(security_sk_free, name, addr); - kfunc_match(security_sk_clone, name, addr); - kfunc_match(security_sk_classify_flow, name, addr); - kfunc_match(security_req_classify_flow, name, addr); - kfunc_match(security_sock_graft, name, addr); - kfunc_match(security_inet_conn_request, name, addr); - kfunc_match(security_inet_csk_clone, name, addr); - kfunc_match(security_inet_conn_established, name, addr); - kfunc_match(security_secmark_relabel_packet, name, addr); - kfunc_match(security_secmark_refcount_inc, name, addr); - kfunc_match(security_secmark_refcount_dec, name, addr); - kfunc_match(security_tun_dev_alloc_security, name, addr); - kfunc_match(security_tun_dev_free_security, name, addr); - kfunc_match(security_tun_dev_create, name, addr); - kfunc_match(security_tun_dev_attach_queue, name, addr); - kfunc_match(security_tun_dev_attach, name, addr); - kfunc_match(security_tun_dev_open, name, addr); - kfunc_match(security_sctp_assoc_request, name, addr); - kfunc_match(security_sctp_bind_connect, name, addr); - kfunc_match(security_sctp_sk_clone, name, addr); - kfunc_match(security_sctp_assoc_established, name, addr); - - // CONFIG_SECURITY_INFINIBAND - kfunc_match(security_ib_pkey_access, name, addr); - kfunc_match(security_ib_endport_manage_subnet, name, addr); - kfunc_match(security_ib_alloc_security, name, addr); - kfunc_match(security_ib_free_security, name, addr); - - // CONFIG_SECURITY_NETWORK_XFRM - kfunc_match(security_xfrm_policy_alloc, name, addr); - kfunc_match(security_xfrm_policy_clone, name, addr); - kfunc_match(security_xfrm_policy_free, name, addr); - kfunc_match(security_xfrm_policy_delete, name, addr); - kfunc_match(security_xfrm_state_alloc, name, addr); - kfunc_match(security_xfrm_state_alloc_acquire, name, addr); - kfunc_match(security_xfrm_state_delete, name, addr); - kfunc_match(security_xfrm_state_free, name, addr); - kfunc_match(security_xfrm_policy_lookup, name, addr); - kfunc_match(security_xfrm_state_pol_flow_match, name, addr); - kfunc_match(security_xfrm_decode_session, name, addr); - kfunc_match(security_skb_classify_flow, name, addr); - - /* key management security hooks */ - // CONFIG_KEYS - kfunc_match(security_key_alloc, name, addr); - kfunc_match(security_key_free, name, addr); - kfunc_match(security_key_permission, name, addr); - kfunc_match(security_key_getsecurity, name, addr); - - // CONFIG_AUDIT - kfunc_match(security_audit_rule_init, name, addr); - kfunc_match(security_audit_rule_known, name, addr); - kfunc_match(security_audit_rule_free, name, addr); - kfunc_match(security_audit_rule_match, name, addr); - - // CONFIG_BPF_SYSCALL - kfunc_match(security_bpf, name, addr); - kfunc_match(security_bpf_map, name, addr); - kfunc_match(security_bpf_prog, name, addr); - kfunc_match(security_bpf_map_alloc, name, addr); - kfunc_match(security_bpf_prog_alloc, name, addr); - kfunc_match(security_bpf_map_free, name, addr); - kfunc_match(security_bpf_prog_free, name, addr); - // CONFIG_BPF_SYSCALL - - kfunc_match(security_locked_down, name, addr); - - // CONFIG_PERF_EVENTS - kfunc_match(security_perf_event_open, name, addr); - kfunc_match(security_perf_event_alloc, name, addr); - kfunc_match(security_perf_event_free, name, addr); - kfunc_match(security_perf_event_read, name, addr); - kfunc_match(security_perf_event_write, name, addr); - - // CONFIG_IO_URING - kfunc_match(security_uring_override_creds, name, addr); - kfunc_match(security_uring_sqpoll, name, addr); - kfunc_match(security_uring_cmd, name, addr); -} - -// security/selinux/avc.c -#include - -int kfunc_def(avc_denied)(u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 xperm, unsigned int flags, - struct av_decision *avd) = 0; -int kfunc_def(avc_has_perm_noaudit)(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, - struct av_decision *avd) = 0; -int kfunc_def(avc_has_perm)(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata) = 0; -int kfunc_def(avc_has_perm_flags)(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata, - int flags) = 0; -int kfunc_def(avc_has_extended_perms)(u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 perm, - struct common_audit_data *ad) = 0; - -void _linux_security_selinux_avc_sym_match(const char *name, unsigned long addr) -{ - kfunc_match(avc_denied, name, addr); - kfunc_match(avc_has_perm_noaudit, name, addr); - kfunc_match(avc_has_perm, name, addr); - kfunc_match(avc_has_perm_flags, name, addr); - kfunc_match(avc_has_extended_perms, name, addr); -} - -// security/commmoncap.c -#include - -int kfunc_def(cap_capable)(const struct cred *cred, struct user_namespace *ns, int cap, unsigned int opts) = 0; -int kfunc_def(cap_settime)(const struct timespec64 *ts, const struct timezone *tz) = 0; -int kfunc_def(cap_ptrace_access_check)(struct task_struct *child, unsigned int mode) = 0; -int kfunc_def(cap_ptrace_traceme)(struct task_struct *parent) = 0; -int kfunc_def(cap_capget)(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, - kernel_cap_t *permitted) = 0; -int kfunc_def(cap_capset)(struct cred *new, const struct cred *old, const kernel_cap_t *effective, - const kernel_cap_t *inheritable, const kernel_cap_t *permitted) = 0; -int kfunc_def(cap_bprm_creds_from_file)(struct linux_binprm *bprm, struct file *file) = 0; -int kfunc_def(cap_inode_setxattr)(struct dentry *dentry, const char *name, const void *value, size_t size, - int flags) = 0; -int kfunc_def(cap_inode_removexattr)(struct dentry *dentry, const char *name) = 0; -int kfunc_def(cap_inode_need_killpriv)(struct dentry *dentry) = 0; -int kfunc_def(cap_inode_killpriv)(struct dentry *dentry) = 0; -int kfunc_def(cap_inode_getsecurity)(struct inode *inode, const char *name, void **buffer, bool alloc) = 0; -int kfunc_def(cap_mmap_addr)(unsigned long addr) = 0; -int kfunc_def(cap_mmap_file)(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) = 0; -int kfunc_def(cap_task_fix_setuid)(struct cred *new, const struct cred *old, int flags) = 0; -int kfunc_def(cap_task_prctl)(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, - unsigned long arg5) = 0; -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; - -kernel_cap_t full_cap = { 0 }; - -void _linux_security_commoncap_sym_match(const char *name, unsigned long addr) -{ - kfunc_match(cap_capable, name, addr); - kfunc_match(cap_settime, name, addr); - kfunc_match(cap_ptrace_access_check, name, addr); - kfunc_match(cap_ptrace_traceme, name, addr); - kfunc_match(cap_capget, name, addr); - kfunc_match(cap_capset, name, addr); - kfunc_match(cap_bprm_creds_from_file, name, addr); - kfunc_match(cap_inode_setxattr, name, addr); - kfunc_match(cap_inode_removexattr, name, addr); - kfunc_match(cap_inode_need_killpriv, name, addr); - kfunc_match(cap_inode_killpriv, name, addr); - kfunc_match(cap_inode_getsecurity, name, addr); - kfunc_match(cap_mmap_addr, name, addr); - kfunc_match(cap_mmap_file, name, addr); - kfunc_match(cap_task_fix_setuid, name, addr); - kfunc_match(cap_task_prctl, name, addr); - 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_kernel_act_as, name, addr); + // kfunc_match(security_kernel_create_files_as, name, addr); + // kfunc_match(security_kernel_module_request, name, addr); + // kfunc_match(security_kernel_load_data, name, addr); + // kfunc_match(security_kernel_post_load_data, name, addr); + // kfunc_match(security_kernel_read_file, name, addr); + // kfunc_match(security_kernel_post_read_file, name, addr); + // kfunc_match(security_task_fix_setuid, name, addr); + // kfunc_match(security_task_fix_setgid, name, addr); + // kfunc_match(security_task_fix_setgroups, name, addr); + // kfunc_match(security_task_setpgid, name, addr); + // kfunc_match(security_task_getpgid, name, addr); + // kfunc_match(security_task_getsid, name, addr); + // kfunc_match(security_current_getsecid_subj, name, addr); + // kfunc_match(security_task_getsecid_obj, name, addr); + // kfunc_match(security_task_getsecid, name, addr); + // kfunc_match(security_task_setnice, name, addr); + // kfunc_match(security_task_setioprio, name, addr); + // kfunc_match(security_task_getioprio, name, addr); + // kfunc_match(security_task_prlimit, name, addr); + // kfunc_match(security_task_setrlimit, name, addr); + // kfunc_match(security_task_setscheduler, name, addr); + // kfunc_match(security_task_getscheduler, name, addr); + // kfunc_match(security_task_movememory, name, addr); + // kfunc_match(security_task_kill, name, addr); + // kfunc_match(security_task_prctl, name, addr); + // kfunc_match(security_task_to_inode, name, addr); + // kfunc_match(security_create_user_ns, name, addr); + // kfunc_match(security_ipc_permission, name, addr); + // kfunc_match(security_ipc_getsecid, name, addr); + // kfunc_match(security_msg_msg_alloc, name, addr); + // kfunc_match(security_msg_msg_free, name, addr); + // kfunc_match(security_msg_queue_alloc, name, addr); + // kfunc_match(security_msg_queue_free, name, addr); + // kfunc_match(security_msg_queue_associate, name, addr); + // kfunc_match(security_msg_queue_msgctl, name, addr); + // kfunc_match(security_msg_queue_msgsnd, name, addr); + // kfunc_match(security_msg_queue_msgrcv, name, addr); + // kfunc_match(security_shm_alloc, name, addr); + // kfunc_match(security_shm_free, name, addr); + // kfunc_match(security_shm_associate, name, addr); + // kfunc_match(security_shm_shmctl, name, addr); + // kfunc_match(security_shm_shmat, name, addr); + // kfunc_match(security_sem_alloc, name, addr); + // kfunc_match(security_sem_free, name, addr); + // kfunc_match(security_sem_associate, name, addr); + // kfunc_match(security_sem_semctl, name, addr); + // kfunc_match(security_sem_semop, name, addr); + // kfunc_match(security_d_instantiate, name, addr); + // kfunc_match(security_getprocattr, name, addr); + // kfunc_match(security_setprocattr, name, addr); + // kfunc_match(security_netlink_send, name, addr); + // kfunc_match(security_ismaclabel, name, addr); + // kfunc_match(security_secid_to_secctx, name, addr); + // kfunc_match(security_secctx_to_secid, name, addr); + // kfunc_match(security_release_secctx, name, addr); + // kfunc_match(security_inode_invalidate_secctx, name, addr); + // kfunc_match(security_inode_notifysecctx, name, addr); + // kfunc_match(security_inode_setsecctx, name, addr); + // kfunc_match(security_inode_getsecctx, name, addr); + + // // CONFIG_WATCH_QUEUE + // kfunc_match(security_post_notification, name, addr); + + // // CONFIG_KEY_NOTIFICATIONS + // kfunc_match(security_watch_key, name, addr); + + // // CONFIG_SECURITY_NETWORK + // kfunc_match(security_unix_stream_connect, name, addr); + // kfunc_match(security_unix_may_send, name, addr); + // kfunc_match(security_socket_create, name, addr); + // kfunc_match(security_socket_post_create, name, addr); + // kfunc_match(security_socket_socketpair, name, addr); + // kfunc_match(security_socket_bind, name, addr); + // kfunc_match(security_socket_connect, name, addr); + // kfunc_match(security_socket_listen, name, addr); + // kfunc_match(security_socket_accept, name, addr); + // kfunc_match(security_socket_sendmsg, name, addr); + // kfunc_match(security_socket_recvmsg, name, addr); + // kfunc_match(security_socket_getsockname, name, addr); + // kfunc_match(security_socket_getpeername, name, addr); + // kfunc_match(security_socket_getsockopt, name, addr); + // kfunc_match(security_socket_setsockopt, name, addr); + // kfunc_match(security_socket_shutdown, name, addr); + // kfunc_match(security_sock_rcv_skb, name, addr); + // kfunc_match(security_socket_getpeersec_stream, name, addr); + // kfunc_match(security_socket_getpeersec_dgram, name, addr); + // kfunc_match(security_sk_alloc, name, addr); + // kfunc_match(security_sk_free, name, addr); + // kfunc_match(security_sk_clone, name, addr); + // kfunc_match(security_sk_classify_flow, name, addr); + // kfunc_match(security_req_classify_flow, name, addr); + // kfunc_match(security_sock_graft, name, addr); + // kfunc_match(security_inet_conn_request, name, addr); + // kfunc_match(security_inet_csk_clone, name, addr); + // kfunc_match(security_inet_conn_established, name, addr); + // kfunc_match(security_secmark_relabel_packet, name, addr); + // kfunc_match(security_secmark_refcount_inc, name, addr); + // kfunc_match(security_secmark_refcount_dec, name, addr); + // kfunc_match(security_tun_dev_alloc_security, name, addr); + // kfunc_match(security_tun_dev_free_security, name, addr); + // kfunc_match(security_tun_dev_create, name, addr); + // kfunc_match(security_tun_dev_attach_queue, name, addr); + // kfunc_match(security_tun_dev_attach, name, addr); + // kfunc_match(security_tun_dev_open, name, addr); + // kfunc_match(security_sctp_assoc_request, name, addr); + // kfunc_match(security_sctp_bind_connect, name, addr); + // kfunc_match(security_sctp_sk_clone, name, addr); + // kfunc_match(security_sctp_assoc_established, name, addr); + + // // CONFIG_SECURITY_INFINIBAND + // kfunc_match(security_ib_pkey_access, name, addr); + // kfunc_match(security_ib_endport_manage_subnet, name, addr); + // kfunc_match(security_ib_alloc_security, name, addr); + // kfunc_match(security_ib_free_security, name, addr); + + // // CONFIG_SECURITY_NETWORK_XFRM + // kfunc_match(security_xfrm_policy_alloc, name, addr); + // kfunc_match(security_xfrm_policy_clone, name, addr); + // kfunc_match(security_xfrm_policy_free, name, addr); + // kfunc_match(security_xfrm_policy_delete, name, addr); + // kfunc_match(security_xfrm_state_alloc, name, addr); + // kfunc_match(security_xfrm_state_alloc_acquire, name, addr); + // kfunc_match(security_xfrm_state_delete, name, addr); + // kfunc_match(security_xfrm_state_free, name, addr); + // kfunc_match(security_xfrm_policy_lookup, name, addr); + // kfunc_match(security_xfrm_state_pol_flow_match, name, addr); + // kfunc_match(security_xfrm_decode_session, name, addr); + // kfunc_match(security_skb_classify_flow, name, addr); + + // /* key management security hooks */ + // // CONFIG_KEYS + // kfunc_match(security_key_alloc, name, addr); + // kfunc_match(security_key_free, name, addr); + // kfunc_match(security_key_permission, name, addr); + // kfunc_match(security_key_getsecurity, name, addr); + + // // CONFIG_AUDIT + // kfunc_match(security_audit_rule_init, name, addr); + // kfunc_match(security_audit_rule_known, name, addr); + // kfunc_match(security_audit_rule_free, name, addr); + // kfunc_match(security_audit_rule_match, name, addr); + + // // CONFIG_BPF_SYSCALL + // kfunc_match(security_bpf, name, addr); + // kfunc_match(security_bpf_map, name, addr); + // kfunc_match(security_bpf_prog, name, addr); + // kfunc_match(security_bpf_map_alloc, name, addr); + // kfunc_match(security_bpf_prog_alloc, name, addr); + // kfunc_match(security_bpf_map_free, name, addr); + // kfunc_match(security_bpf_prog_free, name, addr); + // // CONFIG_BPF_SYSCALL + + // kfunc_match(security_locked_down, name, addr); + + // // CONFIG_PERF_EVENTS + // kfunc_match(security_perf_event_open, name, addr); + // kfunc_match(security_perf_event_alloc, name, addr); + // kfunc_match(security_perf_event_free, name, addr); + // kfunc_match(security_perf_event_read, name, addr); + // kfunc_match(security_perf_event_write, name, addr); + + // // CONFIG_IO_URING + // kfunc_match(security_uring_override_creds, name, addr); + // kfunc_match(security_uring_sqpoll, name, addr); + // kfunc_match(security_uring_cmd, name, addr); } diff --git a/kernel/patch/ksyms/selinux.c b/kernel/patch/old/selinux.c similarity index 94% rename from kernel/patch/ksyms/selinux.c rename to kernel/patch/old/selinux.c index 7a7447b9..3002b4c2 100644 --- a/kernel/patch/ksyms/selinux.c +++ b/kernel/patch/old/selinux.c @@ -72,21 +72,21 @@ int kfunc_def(security_sidtab_hash_stats)(char *page) = 0; void _linux_security_selinux_sym_match(const char *name, unsigned long addr) { - kvar_match(selinux_enabled_boot, name, addr); - kvar_match(selinux_enabled, name, addr); - kvar_match(selinux_state, name, addr); - kvar_match(secclass_map, name, addr); + // kvar_match(selinux_enabled_boot, name, addr); + // kvar_match(selinux_enabled, name, addr); + // kvar_match(selinux_state, name, addr); + // kvar_match(secclass_map, name, addr); - kfunc_match(security_mls_enabled, name, addr); + // kfunc_match(security_mls_enabled, name, addr); // kfunc_match(security_load_policy, name, addr); // kfunc_match(selinux_policy_commit, name, addr); // kfunc_match(selinux_policy_cancel, name, addr); // kfunc_match(security_read_policy, name, addr); // kfunc_match(security_read_state_kernel, name, addr); // kfunc_match(security_policycap_supported, name, addr); - kfunc_match(security_compute_av, name, addr); - kfunc_match(security_compute_xperms_decision, name, addr); - kfunc_match(security_compute_av_user, name, addr); + // kfunc_match(security_compute_av, name, addr); + // kfunc_match(security_compute_xperms_decision, name, addr); + // kfunc_match(security_compute_av_user, name, addr); // kfunc_match(security_transition_sid, name, addr); // kfunc_match(security_transition_sid_user, name, addr); // kfunc_match(security_member_sid, name, addr); diff --git a/kernel/patch/patch.c b/kernel/patch/patch.c index 2750547e..e40193cf 100644 --- a/kernel/patch/patch.c +++ b/kernel/patch/patch.c @@ -10,99 +10,106 @@ #include #include #include -#include -#include -#include - -void _linux_kernel_cred_sym_match(); -void _linux_kernel_pid_sym_match(); -void _linux_kernel_fork_sym_match(); -void _linux_lib_strncpy_from_user_sym_match(); -void _linxu_lib_strnlen_user_sym_match(); -void _linux_lib_string_sym_match(); -void _linux_mm_utils_sym_match(); -void _linux_lib_argv_split_sym_match(); -void _linxu_lib_kstrtox_sym_match(); -void _linux_kernel_stop_machine_sym_match(); -void _linux_init_task_sym_match(); -void _linux_lib_dump_stack_sym_match(); -void _linux_mm_vmalloc_sym_match(); -void _linux_security_security_sym_match(); -void _linux_security_selinux_avc_sym_match(); -void _linux_security_commoncap_sym_match(); -void _linux_locking_spinlock_sym_match(); -void _linux_security_selinux_sym_match(); -void _linux_lib_seq_buf_sym_match(); -void _linux_fs_sym_match(); - -void linux_sybmol_len_init(); - -int build_struct(); +#include + +int linux_sybmol_len_init(); +int linux_misc_symbol_init(); +int linux_libs_symbol_init(); + +int resolve_struct(); int task_observer(); +int bypass_kcfi(); -int linux_symbol_init() +void before_panic(hook_fargs12_t *args, void *udata) { - _linux_kernel_cred_sym_match(); - _linux_kernel_pid_sym_match(); - _linux_kernel_fork_sym_match(); - _linux_lib_strncpy_from_user_sym_match(); - _linxu_lib_strnlen_user_sym_match(); - _linux_mm_utils_sym_match(); - _linux_kernel_stop_machine_sym_match(); - _linux_init_task_sym_match(); - _linux_lib_dump_stack_sym_match(); - _linux_mm_vmalloc_sym_match(); - _linux_security_selinux_avc_sym_match(); - _linux_security_commoncap_sym_match(); - _linux_locking_spinlock_sym_match(); - _linux_security_selinux_sym_match(); - _linux_lib_string_sym_match(); - _linux_lib_seq_buf_sym_match(); - _linux_fs_sym_match(); - - // _linux_lib_argv_split_sym_match(); - // _linxu_lib_kstrtox_sym_match(); - // _linux_security_security_sym_match(); - - return 0; + printk("==== Start KernelPatch for Kernel panic ====\n"); + + const char *log = get_boot_log(); + char buf[1024]; + int off = 0; + char c; + for (int i = 0; (c = log[i]); i++) { + if (c == '\n') { + buf[off++] = c; + buf[off] = '\0'; + + printk("KP %s", buf); + off = 0; + } else { + buf[off++] = log[i]; + } + } + + printk("==== End KernelPatch for Kernel panic ====\n"); } -static inline void do_init() +static void before_kernel_init(hook_fargs4_t *args, void *udata) { - logki("==== KernelPatch Do Init ====\n"); - linux_symbol_init(); - linux_sybmol_len_init(); - syscall_init(); - build_struct(); - task_observer(); - selinux_hook_install(); - supercall_install(); + int err = 0; + log_boot("entering kernel init ...\n"); + + if ((err = linux_sybmol_len_init())) goto out; + if ((err = linux_libs_symbol_init())) goto out; + if ((err = linux_misc_symbol_init())) goto out; + + if ((err = syscall_init())) goto out; + if ((err = resolve_struct())) goto out; + if ((err = bypass_kcfi())) goto out; + if ((err = task_observer())) goto out; + if ((err = selinux_hook_install())) goto out; + if ((err = module_init())) goto out; + if ((err = supercall_install())) goto out; + #ifdef ANDROID - su_compat_init(); + if ((err = kpuserd_init())) goto out; + if ((err = su_compat_init())) goto out; #endif - logki("==== KernelPatch Everything Done ====\n"); -} -static void (*backup_cgroup_init)() = 0; +out: + return; +} -void replace_cgroup_init() +static void after_kernel_init(hook_fargs4_t *args, void *udata) { - backup_cgroup_init(); - do_init(); + log_boot("exiting kernel init ...\n"); } int patch() { - int err = 0; + int rc = 0; + + unsigned long panic_addr = kallsyms_lookup_name("panic"); + if (!panic_addr) { + log_boot("no symbol panic\n"); + rc = -ENOENT; + goto out; + } else { + hook_err_t err = hook_wrap12((void *)panic_addr, before_panic, 0, 0); + if (err) { + log_boot("hook panic: %llx, error: %d\n", panic_addr, rc); + rc = err; + goto out; + } + } - unsigned long cgroup_init_addr = kallsyms_lookup_name("cgroup_init"); - if (!cgroup_init_addr) { - logke("Can't find symbol cgroup_init\n"); - return ERR_NO_SUCH_SYMBOL; + // kernel_init or rest_init + unsigned long init_addr = kallsyms_lookup_name("rest_init"); + if (!init_addr) { + init_addr = kallsyms_lookup_name("kernel_init"); } - hook_err_t rc = hook((void *)cgroup_init_addr, (void *)replace_cgroup_init, (void **)&backup_cgroup_init); - if (rc) { - logke("Hook cgroup_init error: %d\n", rc); + if (!init_addr) { + log_boot("no symbol rest_init or kernel_init\n"); + rc = -ENOENT; + goto out; + } else { + hook_err_t err = hook_wrap4((void *)init_addr, before_kernel_init, after_kernel_init, 0); + if (err) { + log_boot("hook kernel init: %llx, error: %d\n", init_addr, err); + rc = err; + goto out; + } } - return err; + +out: + return rc; } diff --git a/kernel/version b/kernel/version index 6e7bdda8..b28fb1d6 100644 --- a/kernel/version +++ b/kernel/version @@ -1,3 +1,3 @@ #define MAJOR 0 -#define MINOR 4 +#define MINOR 5 #define PATCH 0 \ No newline at end of file diff --git a/kernel/module/.gitignore b/kpm-demo/hello/.gitignore similarity index 70% rename from kernel/module/.gitignore rename to kpm-demo/hello/.gitignore index ddb2fa15..2085cbfc 100644 --- a/kernel/module/.gitignore +++ b/kpm-demo/hello/.gitignore @@ -16,10 +16,4 @@ *.bin *.elf -# kernel patch module *.kpm - -# debug -*.dSYM - -testmain \ No newline at end of file diff --git a/kpm-demo/hello/Makefile b/kpm-demo/hello/Makefile new file mode 100644 index 00000000..9592b661 --- /dev/null +++ b/kpm-demo/hello/Makefile @@ -0,0 +1,30 @@ +ifndef TARGET_COMPILE + $(error TARGET_COMPILE not set) +endif + +ifndef KP_DIR + KP_DIR = ../.. +endif + + +CC = $(TARGET_COMPILE)gcc +LD = $(TARGET_COMPILE)ld + +INCLUDE_DIRS := . include patch/include linux/include linux/arch/arm64/include linux/tools/arch/arm64/include + +INCLUDE_FLAGS := $(foreach dir,$(INCLUDE_DIRS),-I$(KP_DIR)/kernel/$(dir)) + +objs := hello.o + +all: hello.kpm + +hello.kpm: ${objs} + ${CC} -r -o $@ $^ + +%.o: %.c + ${CC} $(CFLAGS) $(INCLUDE_FLAGS) -Thello.lds -c -O2 -o $@ $< + +.PHONY: clean +clean: + rm -rf *.kpm + find . -name "*.o" | xargs rm -f \ No newline at end of file diff --git a/kpm-demo/hello/hello.c b/kpm-demo/hello/hello.c new file mode 100644 index 00000000..54c0aefe --- /dev/null +++ b/kpm-demo/hello/hello.c @@ -0,0 +1,23 @@ +#include +#include +#include + +KPM_NAME("kpm-hello-demo"); +KPM_VERSION("1.0.0"); +KPM_LICENSE("GPL v2"); +KPM_AUTHOR("bmax121"); +KPM_DESCRIPTION("KernelPatch Module Example"); + +int hello_init(const char *args) +{ + pr_info("kpm hello init, args: %s\n", args); + return 0; +} + +void hello_exit() +{ + pr_info("kpm hello exit\n"); +} + +KPM_INIT(hello_init); +KPM_EXIT(hello_exit); diff --git a/kpm-demo/hello/hello.lds b/kpm-demo/hello/hello.lds new file mode 100644 index 00000000..d599a67a --- /dev/null +++ b/kpm-demo/hello/hello.lds @@ -0,0 +1,5 @@ +SECTIONS { + .plt (NOLOAD) : { BYTE(0) } + .init.plt (NOLOAD) : { BYTE(0) } + .text.ftrace_trampoline (NOLOAD) : { BYTE(0) } +} \ No newline at end of file diff --git a/kpm-demo/inlinehook/.gitignore b/kpm-demo/inlinehook/.gitignore new file mode 100644 index 00000000..2085cbfc --- /dev/null +++ b/kpm-demo/inlinehook/.gitignore @@ -0,0 +1,19 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Libraries +*.lib +*.a +*.la +*.lo + +*.bin +*.elf + +*.kpm diff --git a/kpm-demo/inlinehook/Makefile b/kpm-demo/inlinehook/Makefile new file mode 100644 index 00000000..30715e0a --- /dev/null +++ b/kpm-demo/inlinehook/Makefile @@ -0,0 +1,30 @@ +ifndef TARGET_COMPILE + $(error TARGET_COMPILE not set) +endif + +ifndef KP_DIR + KP_DIR = ../.. +endif + + +CC = $(TARGET_COMPILE)gcc +LD = $(TARGET_COMPILE)ld + +INCLUDE_DIRS := . include patch/include linux/include linux/arch/arm64/include linux/tools/arch/arm64/include + +INCLUDE_FLAGS := $(foreach dir,$(INCLUDE_DIRS),-I$(KP_DIR)/kernel/$(dir)) + +objs := inlinehook.o + +all: inlinehook.kpm + +inlinehook.kpm: ${objs} + ${CC} -r -o $@ $^ + +%.o: %.c + ${CC} $(CFLAGS) $(INCLUDE_FLAGS) -c -O2 -o $@ $< + +.PHONY: clean +clean: + rm -rf *.kpm + find . -name "*.o" | xargs rm -f \ No newline at end of file diff --git a/kpm-demo/inlinehook/inlinehook.c b/kpm-demo/inlinehook/inlinehook.c new file mode 100644 index 00000000..209e65bb --- /dev/null +++ b/kpm-demo/inlinehook/inlinehook.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include + +KPM_NAME("kpm-inline-hook-demo"); +KPM_VERSION("1.0.0"); +KPM_LICENSE("GPL v2"); +KPM_AUTHOR("bmax121"); +KPM_DESCRIPTION("KernelPatch Module Inline Hook Example"); + +int __noinline add(int a, int b) +{ + logkd("origin add called\n"); + int ret = a + b; + return ret; +} + +void before_add(hook_fargs2_t *args, void *udata) +{ + logkd("before add arg0: %d, arg1: %d\n", (int)args->arg0, (int)args->arg1); +} + +void after_add(hook_fargs2_t *args, void *udata) +{ + logkd("after add arg0: %d, arg1: %d, ret: %d\n", (int)args->arg0, (int)args->arg1, (int)args->ret); + args->ret = 100; +} + +int inline_hook_demo_init() +{ + logkd("kpm inline-hook-demo init\n"); + + int a = 20; + int b = 10; + + int ret = add(a, b); + logkd("%d + %d = %d\n", a, b, ret); + + hook_err_t err = hook_wrap2((void *)add, before_add, after_add, 0); + logkd("hook err: %d\n", err); + + ret = add(a, b); + logkd("%d + %d = %d\n", a, b, ret); + + return 0; +} + +void inline_hook_demo_exit() +{ + unhook((void *)add); + + int a = 20; + int b = 10; + + int ret = add(a, b); + logkd("%d + %d = %d\n", a, b, ret); + + logkd("kpm inline-hook-demo exit\n"); +} + +KPM_INIT(inline_hook_demo_init); +KPM_EXIT(inline_hook_demo_exit); \ No newline at end of file diff --git a/kpm-demo/syscallhook/.gitignore b/kpm-demo/syscallhook/.gitignore new file mode 100644 index 00000000..2085cbfc --- /dev/null +++ b/kpm-demo/syscallhook/.gitignore @@ -0,0 +1,19 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Libraries +*.lib +*.a +*.la +*.lo + +*.bin +*.elf + +*.kpm diff --git a/kpm-demo/syscallhook/Makefile b/kpm-demo/syscallhook/Makefile new file mode 100644 index 00000000..d003f0eb --- /dev/null +++ b/kpm-demo/syscallhook/Makefile @@ -0,0 +1,30 @@ +ifndef TARGET_COMPILE + $(error TARGET_COMPILE not set) +endif + +ifndef KP_DIR + KP_DIR = ../.. +endif + + +CC = $(TARGET_COMPILE)gcc +LD = $(TARGET_COMPILE)ld + +INCLUDE_DIRS := . include patch/include linux/include linux/arch/arm64/include linux/tools/arch/arm64/include + +INCLUDE_FLAGS := $(foreach dir,$(INCLUDE_DIRS),-I$(KP_DIR)/kernel/$(dir)) + +objs := syscallhook.o + +all: syscallhook.kpm + +syscallhook.kpm: ${objs} + ${CC} -r -o $@ $^ + +%.o: %.c + ${CC} $(CFLAGS) $(INCLUDE_FLAGS) -c -O2 -o $@ $< + +.PHONY: clean +clean: + rm -rf *.kpm + find . -name "*.o" | xargs rm -f \ No newline at end of file diff --git a/kpm-demo/syscallhook/syscallhook.c b/kpm-demo/syscallhook/syscallhook.c new file mode 100644 index 00000000..68a63a57 --- /dev/null +++ b/kpm-demo/syscallhook/syscallhook.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +KPM_NAME("kpm-syscall-hook-demo"); +KPM_VERSION("1.0.0"); +KPM_LICENSE("GPL v2"); +KPM_AUTHOR("bmax121"); +KPM_DESCRIPTION("KernelPatch Module System Call Hook Example"); + +const char *margs = 0; +enum hook_type hook_type = NONE; + +enum pid_type +{ + PIDTYPE_PID, + PIDTYPE_TGID, + PIDTYPE_PGID, + PIDTYPE_SID, + PIDTYPE_MAX, +}; +struct pid_namespace; +pid_t (*__task_pid_nr_ns)(struct task_struct *task, enum pid_type type, struct pid_namespace *ns) = 0; + +void before_openat_0(hook_fargs4_t *args, void *udata) +{ + int dfd = (int)syscall_argn(args, 0); + const char __user *filename = (typeof(filename))syscall_argn(args, 1); + int flag = (int)syscall_argn(args, 2); + umode_t mode = (int)syscall_argn(args, 3); + + char buf[1024]; + strncpy_from_user_nofault(buf, filename, 1024); + + struct task_struct *task = current; + pid_t pid = -1, tgid = -1; + if (__task_pid_nr_ns) { + pid = __task_pid_nr_ns(task, PIDTYPE_PID, 0); + tgid = __task_pid_nr_ns(task, PIDTYPE_TGID, 0); + } + + args->local.data0 = (uint64_t)task; + + pr_info("hook_chain_0 task: %llx, pid: %d, tgid: %d, openat dfd: %d, filename: %s, flag: %x, mode: %d\n", task, pid, + tgid, dfd, buf, flag, mode); +} + +uint64_t open_counts = 0; + +void before_openat_1(hook_fargs4_t *args, void *udata) +{ + uint64_t *pcount = (uint64_t *)udata; + (*pcount)++; + pr_info("hook_chain_1 before openat task: %llx, count: %llx\n", args->local.data0, *pcount); +} + +void after_openat_1(hook_fargs4_t *args, void *udata) +{ + pr_info("hook_chain_1 after openat task: %llx\n", args->local.data0); +} + +int syscall_hook_demo_init(const char *args) +{ + margs = args; + pr_info("kpm-syscall-hook-demo init ..., args: %s\n", margs); + + __task_pid_nr_ns = (typeof(__task_pid_nr_ns))kallsyms_lookup_name("__task_pid_nr_ns"); + pr_info("kernel function __task_pid_nr_ns addr: %llx\n", __task_pid_nr_ns); + + if (!margs) { + pr_warn("no args specified, skip hook\n"); + return 0; + } + + hook_err_t err = HOOK_NO_ERR; + + if (!strcmp("function_pointer_hook", margs)) { + pr_info("function pointer hook ..."); + hook_type = FUNCTION_POINTER_CHAIN; + err = fp_hook_syscalln(__NR_openat, 4, before_openat_0, 0, 0); + if (err) goto out; + err = fp_hook_syscalln(__NR_openat, 4, before_openat_1, after_openat_1, &open_counts); + } else if (!strcmp("inline_hook", margs)) { + pr_info("inline hook ..."); + hook_type = INLINE_CHAIN; + err = inline_hook_syscalln(__NR_openat, 4, before_openat_0, 0, 0); + } else { + pr_warn("unknown args: %s\n", margs); + return 0; + } + +out: + if (err) { + pr_err("hook openat error: %d\n", err); + } else { + pr_info("hook openat success\n"); + } + return 0; +} + +void syscall_hook_demo_exit() +{ + pr_info("kpm-syscall-hook-demo exit ...\n"); + + if (hook_type == INLINE_CHAIN) { + inline_unhook_syscall(__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); + } else { + } +} + +KPM_INIT(syscall_hook_demo_init); +KPM_EXIT(syscall_hook_demo_exit); \ No newline at end of file diff --git a/tools/Makefile b/tools/Makefile index 03f3213a..e9454706 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -2,10 +2,16 @@ CFLAGS = -std=c11 -Wall -Wextra -Wno-unused -Wno-unused-parameter # CFLAGS += -g +ifdef ANDROID + CFLAGS += -DANDROID +endif + objs := image.o kallsym.o kptools.o order.o +.PHONY: all all: kptools +.PHONY: kptools kptools: ${objs} ${CC} -o $@ $^ diff --git a/tools/image.c b/tools/image.c index ace760fe..a823bb35 100644 --- a/tools/image.c +++ b/tools/image.c @@ -121,8 +121,7 @@ int32_t kernel_resize(kernel_info_t *kinfo, char *img, int32_t size) { arm64_hdr_t *khdr = (arm64_hdr_t *)(img + kinfo->img_offset); uint64_t ksize = size; - if (is_be() ^ kinfo->is_be) - ksize = u64swp(size); + if (is_be() ^ kinfo->is_be) ksize = u64swp(size); khdr->kernel_size_le = ksize; return 0; } \ No newline at end of file diff --git a/tools/kallsym.c b/tools/kallsym.c index 8fc55f00..7ab6d4b3 100644 --- a/tools/kallsym.c +++ b/tools/kallsym.c @@ -129,24 +129,20 @@ static int find_token_table(kallsym_t *info, char *img, int32_t imglen) return -1; } char *num_end = num_start + sizeof(nums_syms); - if (!*num_end || !*(num_end + 1)) - continue; + if (!*num_end || !*(num_end + 1)) continue; char *letter = num_end; for (int32_t i = 0; letter < imgend && i < 'a' - '9' - 1; letter++) { - if (!*letter) - i++; + if (!*letter) i++; } - if (letter != (char *)memmem(letter, sizeof(letters_syms), letters_syms, sizeof(letters_syms))) - continue; + if (letter != (char *)memmem(letter, sizeof(letters_syms), letters_syms, sizeof(letters_syms))) continue; break; } // backward to start pos = num_start; for (int32_t i = 0; pos > img && i < '0' + 1; pos--) { - if (!*pos) - i++; + if (!*pos) i++; } int32_t offset = pos + 2 - img; @@ -238,8 +234,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; + if (!info->try_relo) return 0; uint64_t min_va = 0xffffff8008080000; uint64_t max_va = 0xffffffffffffffff; uint64_t kernel_va = max_va; @@ -250,16 +245,14 @@ static int try_find_arm64_relo_table(kallsym_t *info, char *img, int32_t imglen) uint64_t r_info = uint_unpack(img + cand + 8, 8, info->is_be); uint64_t r_addend = uint_unpack(img + cand + 16, 8, info->is_be); if ((r_offset & 0xffff000000000000) == 0xffff000000000000 && r_info == 0x403) { - if (!(r_addend & 0xfff) && r_addend >= min_va && r_addend < kernel_va) - kernel_va = r_addend; + if (!(r_addend & 0xfff) && r_addend >= min_va && r_addend < kernel_va) kernel_va = r_addend; cand += 24; rela_num++; } else if (rela_num && !r_offset && !r_info && !r_addend) { cand += 24; rela_num++; } else { - if (rela_num >= ARM64_RELO_MIN_NUM) - break; + if (rela_num >= ARM64_RELO_MIN_NUM) break; cand += 8; rela_num = 0; kernel_va = max_va; @@ -289,8 +282,7 @@ static int try_find_arm64_relo_table(kallsym_t *info, char *img, int32_t imglen) uint64_t r_offset = uint_unpack(img + cand, 8, info->is_be); uint64_t r_info = uint_unpack(img + cand + 8, 8, info->is_be); uint64_t r_addend = uint_unpack(img + cand + 16, 8, info->is_be); - if (!r_offset && !r_info && !r_addend) - continue; + if (!r_offset && !r_info && !r_addend) continue; if (r_offset <= kernel_va || r_offset >= max_va - imglen) { // fprintf(stdout, "[-] kallsyms warn ignore arm64 relocation r_offset: 0x%08lx at 0x%08x\n", r_offset, cand); continue; @@ -301,17 +293,14 @@ static int try_find_arm64_relo_table(kallsym_t *info, char *img, int32_t imglen) return -1; } uint64_t value = uint_unpack(img + offset, 8, info->is_be); - if (value == r_addend) - continue; + if (value == r_addend) continue; *(uint64_t *)(img + offset) = value + r_addend; apply_num++; } - if (apply_num) - apply_num--; + if (apply_num) apply_num--; fprintf(stdout, "[+] kallsyms apply 0x%08x relocation entries\n", apply_num); - if (apply_num) - info->relo_applied = 1; + if (apply_num) info->relo_applied = 1; // #define KALLSYM_SAVE_RELO #ifdef KALLSYM_SAVE_RELO @@ -334,20 +323,16 @@ static int find_approx_addresses(kallsym_t *info, char *img, int32_t imglen) for (; cand < imglen - KSYM_MIN_NEQ_SYMS * elem_size; cand += elem_size) { uint64_t address = uint_unpack(img + cand, elem_size, info->is_be); if (!sym_num) { // first address - if (address & 0xff) - continue; - if (elem_size == 4 && (address & 0xff800000) != 0xff800000) - continue; - if (elem_size == 8 && (address & 0xffff000000000000) != 0xffff000000000000) - continue; + if (address & 0xff) continue; + if (elem_size == 4 && (address & 0xff800000) != 0xff800000) continue; + if (elem_size == 8 && (address & 0xffff000000000000) != 0xffff000000000000) continue; prev_offset = address; sym_num++; continue; } if (address >= prev_offset) { prev_offset = address; - if (sym_num++ >= KSYM_MIN_NEQ_SYMS) - break; + if (sym_num++ >= KSYM_MIN_NEQ_SYMS) break; } else { prev_offset = 0; sym_num = 0; @@ -366,8 +351,7 @@ static int find_approx_addresses(kallsym_t *info, char *img, int32_t imglen) prev_offset = 0; for (; cand < imglen; cand += elem_size) { uint64_t offset = uint_unpack(img + cand, elem_size, info->is_be); - if (offset < prev_offset) - break; + if (offset < prev_offset) break; prev_offset = offset; } // end is not include @@ -383,7 +367,7 @@ static int find_approx_addresses(kallsym_t *info, char *img, int32_t imglen) // // todo: tmp fix relo error, some bugs if (info->relo_applied) { - fprintf(stderr, "[-] kallsyms Here are some known bug, subsequent operations is undefined\n"); + fprintf(stdout, "[-] kallsyms Here are some known bug, subsequent operations is undefined\n"); } return 0; @@ -403,8 +387,7 @@ static int find_approx_offsets(kallsym_t *info, char *img, int32_t imglen) continue; } else if (offset > prev_offset) { prev_offset = offset; - if (sym_num++ >= KSYM_MIN_NEQ_SYMS) - break; + if (sym_num++ >= KSYM_MIN_NEQ_SYMS) break; } else { prev_offset = 0; sym_num = 0; @@ -416,13 +399,10 @@ static int find_approx_offsets(kallsym_t *info, char *img, int32_t imglen) } cand -= KSYM_MIN_NEQ_SYMS * elem_size; for (;; cand -= elem_size) - if (!int_unpack(img + cand, elem_size, info->is_be)) - break; + if (!int_unpack(img + cand, elem_size, info->is_be)) break; for (;; cand -= elem_size) { - if (int_unpack(img + cand, elem_size, info->is_be)) - break; - if (zero_offset_num++ >= MAX_ZERO_OFFSET_NUM) - break; + if (int_unpack(img + cand, elem_size, info->is_be)) break; + if (zero_offset_num++ >= MAX_ZERO_OFFSET_NUM) break; } cand += elem_size; int32_t approx_offset = cand; @@ -432,8 +412,7 @@ static int find_approx_offsets(kallsym_t *info, char *img, int32_t imglen) prev_offset = 0; for (; cand < imglen; cand += elem_size) { int64_t offset = int_unpack(img + cand, elem_size, info->is_be); - if (offset < prev_offset) - break; + if (offset < prev_offset) break; prev_offset = offset; } // the last symbol may not 4k alinged @@ -457,8 +436,7 @@ static int32_t find_approx_addresses_or_offset(kallsym_t *info, char *img, int32 if (info->version.major > 4 || (info->version.major == 4 && info->version.minor >= 6)) { // may have kallsyms_relative_base ret = find_approx_offsets(info, img, imglen); - if (!ret) - return 0; + if (!ret) return 0; } ret = find_approx_addresses(info, img, imglen); return ret; @@ -479,8 +457,7 @@ static int find_num_syms(kallsym_t *info, char *img, int32_t imglen) 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 (approx_num_syms >= nsyms && approx_num_syms - nsyms < NSYMS_MAX_GAP) break; } if (cand >= nsyms_max_offset) { @@ -501,15 +478,13 @@ static int find_markers(kallsym_t *info, char *img, int32_t imglen) int64_t marker; for (;; cand -= elem_size) { marker = int_unpack(img + cand, elem_size, info->is_be); - if (marker) - break; + 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; + if (!marker || last_marker <= marker) break; last_marker = marker; } int32_t marker_num = (marker_end - cand) / elem_size; @@ -528,22 +503,18 @@ static int decompress_symbol_name(kallsym_t *info, char *img, int32_t *pos_to_ne { int32_t pos = *pos_to_next; int32_t len = *(uint8_t *)(img + pos++); - if (len > 0x7F) - len = (len & 0x7F) + (*(uint8_t *)(img + pos++) << 7); - if (!len || len >= KSYM_SYMBOL_LEN) - return -1; + if (len > 0x7F) len = (len & 0x7F) + (*(uint8_t *)(img + pos++) << 7); + if (!len || len >= KSYM_SYMBOL_LEN) return -1; *pos_to_next = pos + len; for (int32_t i = 0; i < len; i++) { int32_t tokidx = *(uint8_t *)(img + pos + i); char *token = info->kallsyms_token_table[tokidx]; if (!i) { // first character, symbol type - if (out_type) - *out_type = *token; + if (out_type) *out_type = *token; token++; } - if (out_symbol) - strcat(out_symbol, token); + if (out_symbol) strcat(out_symbol, token); } return 0; } @@ -551,19 +522,15 @@ static int decompress_symbol_name(kallsym_t *info, char *img, int32_t *pos_to_ne static int is_symbol_name_pos(kallsym_t *info, char *img, int32_t pos, char *symbol) { int32_t len = *(uint8_t *)(img + pos++); - if (len > 0x7F) - len = (len & 0x7F) + (*(uint8_t *)(img + pos++) << 7); - if (!len || len >= KSYM_SYMBOL_LEN) - return 0; + if (len > 0x7F) len = (len & 0x7F) + (*(uint8_t *)(img + pos++) << 7); + if (!len || len >= KSYM_SYMBOL_LEN) return 0; int32_t symidx = 0; for (int32_t i = 0; i < len; i++) { int32_t tokidx = *(uint8_t *)(img + pos + i); char *token = info->kallsyms_token_table[tokidx]; - if (!i) - token++; // ignore symbol type + if (!i) token++; // ignore symbol type int32_t toklen = strlen(token); - if (strncmp(symbol + symidx, token, toklen)) - break; + if (strncmp(symbol + symidx, token, toklen)) break; symidx += toklen; } return (int32_t)strlen(symbol) == symidx; @@ -579,25 +546,19 @@ static int find_names(kallsym_t *info, char *img, int32_t imglen) test_marker_num = KSYM_FIND_NAMES_USED_MARKER; // check n * 256 symbols for (int32_t i = 0;; i++) { int32_t len = *(uint8_t *)(img + pos++); - if (len > 0x7F) - len = (len & 0x7F) + (*(uint8_t *)(img + pos++) << 7); - if (!len || len >= KSYM_SYMBOL_LEN) - break; + if (len > 0x7F) len = (len & 0x7F) + (*(uint8_t *)(img + pos++) << 7); + if (!len || len >= KSYM_SYMBOL_LEN) break; pos += len; - if (pos >= info->kallsyms_markers_offset) - break; + if (pos >= info->kallsyms_markers_offset) break; if (i && (i & 0xFF) == 0xFF) { // every 256 symbols int32_t mark_len = int_unpack(img + info->kallsyms_markers_offset + ((i >> 8) + 1) * marker_elem_size, marker_elem_size, info->is_be); - if (pos - cand != mark_len) - break; - if (!--test_marker_num) - break; + if (pos - cand != mark_len) break; + if (!--test_marker_num) break; } } - if (!test_marker_num) - break; + if (!test_marker_num) break; } if (test_marker_num) { fprintf(stderr, "[-] kallsyms find kallsyms_names error\n"); @@ -625,8 +586,7 @@ static int correct_addresses_or_offsets(kallsym_t *info, char *img, int32_t imgl while (pos < info->kallsyms_markers_offset) { memset(symbol, 0, sizeof(symbol)); int32_t ret = decompress_symbol_name(info, img, &pos, NULL, symbol); - if (ret) - break; + if (ret) break; if (!ret && !strcmp(symbol, "linux_banner")) { fprintf(stdout, "[+] kallsyms linux_banner index: 0x%08x\n", index); break; @@ -644,8 +604,7 @@ static int correct_addresses_or_offsets(kallsym_t *info, char *img, int32_t imgl 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; - if (offset == target_offset) - break; + if (offset == target_offset) break; } if (pos < end) { info->symbol_banner_idx = i; @@ -683,8 +642,7 @@ void init_not_tested_arch_kallsym_t(kallsym_t *info, int32_t is_64) info->asm_long_size = 4; info->asm_PTR_size = 4; info->try_relo = 0; - if (is_64) - info->asm_PTR_size = 8; + if (is_64) info->asm_PTR_size = 8; } /* @@ -702,10 +660,8 @@ int analyze_kallsym_info(kallsym_t *info, char *img, int32_t imglen, enum arch_t info->is_64 = is_64; info->asm_long_size = 4; info->asm_PTR_size = 4; - if (arch == ARM64) - info->try_relo = 1; - if (is_64) - info->asm_PTR_size = 8; + if (arch == ARM64) info->try_relo = 1; + if (is_64) info->asm_PTR_size = 8; info->img_offset = 0; if (!strncmp("UNCOMPRESSED_IMG", img, strlen("UNCOMPRESSED_IMG"))) { @@ -724,8 +680,7 @@ int analyze_kallsym_info(kallsym_t *info, char *img, int32_t imglen, enum arch_t find_num_syms, correct_addresses_or_offsets }; for (int i = 0; i < (int)(sizeof(funcs) / sizeof(funcs[0])); i++) { - if (funcs[i](info, img, imglen)) - return -1; + if (funcs[i](info, img, imglen)) return -1; } return 0; } @@ -799,8 +754,7 @@ int on_each_symbol(kallsym_t *info, char *img, void *userdata, memset(symbol, 0, sizeof(symbol)); decompress_symbol_name(info, img, &pos, &type, symbol); int32_t offset = get_symbol_index_offset(info, img, i); - if (fn(i, &type, symbol, offset, userdata)) - return -1; + if (fn(i, &type, symbol, offset, userdata)) return -1; } return 0; } diff --git a/tools/kptools.c b/tools/kptools.c index 5bc787fb..bf09ed39 100644 --- a/tools/kptools.c +++ b/tools/kptools.c @@ -1,4 +1,3 @@ - #include #include #include @@ -20,7 +19,7 @@ #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 INSN_IS_B(inst) (((inst)&0xFC000000) == 0x14000000) +#define INSN_IS_B(inst) (((inst) & 0xFC000000) == 0x14000000) #define bits32(n, high, low) ((uint32_t)((n) << (31u - (high))) >> (31u - (high) + (low))) @@ -121,8 +120,7 @@ static void print_kpimg_info(const char *img) static void target_endian_preset(setup_preset_t *preset, int32_t target_is_be) { - if (!(is_be() ^ target_is_be)) - return; + if (!(is_be() ^ target_is_be)) return; preset->kernel_size = i64swp(preset->kernel_size); preset->page_shift = i64swp(preset->page_shift); preset->kp_offset = i64swp(preset->kp_offset); @@ -206,8 +204,10 @@ int patch_image() setup_header_t *sdata = (setup_header_t *)(out_buf + align_image_len); setup_preset_t *preset = (setup_preset_t *)(out_buf + align_image_len + KP_HEADER_SIZE); patch_config_t *config = &preset->patch_config; + memset(config, 0, sizeof(patch_config_t)); // todo - strncpy(config->default_dir, "/todo/dir/", PATCH_CONFIG_DIR_LEN); + strlcpy(config->su_config_file, "/data/adb/kernelpatch/su.conf", 128); + strlcpy(config->test_kpm_file, "/data/local/tmp/hello.kpm", 128); preset->kernel_size = kinfo.kernel_size; preset->start_offset = align_kernel_size; @@ -228,8 +228,7 @@ int patch_image() preset->kallsyms_lookup_name_offset = get_symbol_offset(&kallsym, image_buf, "kallsyms_lookup_name"); preset->printk_offset = get_symbol_offset(&kallsym, image_buf, "printk"); - if (preset->printk_offset < 0) - preset->printk_offset = get_symbol_offset(&kallsym, image_buf, "_printk"); + if (preset->printk_offset < 0) preset->printk_offset = get_symbol_offset(&kallsym, image_buf, "_printk"); int32_t paging_init_offset = get_symbol_offset(&kallsym, image_buf, "paging_init"); preset->paging_init_offset = relo_branch_func(image_buf, paging_init_offset); @@ -246,17 +245,13 @@ int patch_image() } preset->memstart_addr_offset = get_symbol_offset(&kallsym, image_buf, "memstart_addr"); - if (preset->memstart_addr_offset < 0) - preset->memstart_addr_offset = 0; + if (preset->memstart_addr_offset < 0) preset->memstart_addr_offset = 0; - if (kallsym.version.major >= 6) - preset->vabits_flag = 1; - if (get_symbol_offset(&kallsym, image_buf, "vabits_actual") > 0) - preset->vabits_flag = 1; + if (kallsym.version.major >= 6) preset->vabits_flag = 1; + if (get_symbol_offset(&kallsym, image_buf, "vabits_actual") > 0) preset->vabits_flag = 1; preset->kimage_voffset_offset = get_symbol_offset(&kallsym, image_buf, "kimage_voffset"); - if (preset->kimage_voffset_offset < 0) - preset->kimage_voffset_offset = 0; + if (preset->kimage_voffset_offset < 0) preset->kimage_voffset_offset = 0; if (strlen(superkey) > 0) { strncpy((char *)preset->superkey, superkey, SUPER_KEY_LEN); diff --git a/tools/version b/tools/version index 144691c4..c7db7f14 100644 --- a/tools/version +++ b/tools/version @@ -1,3 +1,3 @@ #define MAJOR 0 -#define MINOR 3 -#define PATCH 0 \ No newline at end of file +#define MINOR 4 +#define PATCH 1 \ No newline at end of file diff --git a/user/kpatch.c b/user/kpatch.c index 3c219df7..88fe7dba 100644 --- a/user/kpatch.c +++ b/user/kpatch.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "version" @@ -19,35 +20,7 @@ uint32_t get_version() long su_fork(const char *key, const char *sctx) { long ret = 0; -#if 0 - uid_t ruid, euid, suid; - gid_t rgid, egid, sgid; - getresuid(&ruid, &euid, &suid); - getresgid(&rgid, &egid, &sgid); - fprintf(stdout, "before resuid: %ud, %ud, %ud, resgid: %ud, %ud, %ud\n", ruid, euid, suid, rgid, egid, sgid); - - struct __user_cap_header_struct cap_header; - struct __user_cap_data_struct cap_data; - cap_header.pid = getpid(); - cap_header.version = _LINUX_CAPABILITY_VERSION_3; - ret = syscall(SYS_capget, &cap_header, &cap_data); - fprintf(stdout, "before capabilities: ret: %ld 0x%x, 0x%x, 0x%x\n", ret, cap_data.effective, cap_data.permitted, - cap_data.inheritable); -#endif ret = sc_su(key, sctx); -#if 0 - getresuid(&ruid, &euid, &suid); - getresgid(&rgid, &egid, &sgid); - fprintf(stdout, "after resuid: %ud, %ud, %ud, resgid: %ud, %ud, %ud\n", ruid, euid, suid, rgid, egid, sgid); - - cap_header.pid = getpid(); - cap_header.version = _LINUX_CAPABILITY_VERSION_3; - ret = syscall(SYS_capget, &cap_header, &cap_data); - fprintf(stdout, "after capabilities: ret: %ld, 0x%x, %x, %x\n", ret, cap_data.effective, cap_data.permitted, - cap_data.inheritable); -#endif - // todo: shell path - if (!ret) - execlp("/system/bin/sh", "sh", NULL); + if (!ret || ret == -EINVAL) execlp("sh", "", NULL); return ret; } diff --git a/user/main.c b/user/main.c index c9009b33..2f40ad1c 100644 --- a/user/main.c +++ b/user/main.c @@ -11,65 +11,75 @@ void print_usage(char **argv) { - char *c = - "\nkpatch: KernelPatch Userspace Executable.\n" - "\n" - "Common Usage:\n" - "./kpatch -h, --help\n" - " Print this message.\n" - "./kpatch -v, --version\n" - " Print kpatch version.\n" - "\n" - "SuperCall Usage:\n" - "./kpatch [args...]\n" - "command:\n" - " --hello\n" - " Print SuperCall hello message in the kernel. Return 0 if succeed, others if failed!\n" - " --kv\n" - " Get Kernel version.\n" - " --kpv\n" - " Get KernelPatch version.\n" - " --su [--arg1 scontext]\n" - " Fork a root shell and change security context to scontext.\n" - " If scontext is not specified, \n" - " bypass all selinux permission checks for all calls initiated by this thread using hooks, \n" - " but the permission determined by other threads remain unchanged.\n" - " --load_kpm --arg1 path\n" - " Load KernelPatch Module\n" - " (Unimplemented ...).\n" - " --unload_kpm --arg1 path\n" - " Unload KernelPatch Module\n" - " (Unimplemented ...).\n" - " --thread_su --arg1 tid\n" - " Grant root privileges to the thread corresponding to the given tid.\n" - " --thread_unsu --arg1 tid\n" - " Revoke root privileges to the thread corresponding to the given tid.\n" - " (Unimplemented ...).\n" + char *c = "\n" + " _ __ _ ____ _ _ \n" + "| |/ /___ _ __ _ __ ___| | _ \\ __ _| |_ ___| |__ \n" + "| ' // _ \\ '__| '_ \\ / _ \\ | |_) / _` | __/ __| '_ \\ \n" + "| . \\ __/ | | | | | __/ | __/ (_| | || (__| | | |\n" + "|_|\\_\\___|_| |_| |_|\\___|_|_| \\__,_|\\__\\___|_| |_|\n" + "\n" + "KernelPatch Userspace Executable.\n" + "Common Usage:\n" + "./kpatch -h, --help\n" + " Print this message.\n" + "./kpatch -v, --version\n" + " Print kpatch version.\n" + "\n" + "SuperCall Usage:\n" + "./kpatch [args...]\n" + "\n" + "Command:\n" + " --hello\n" + " Print SuperCall hello message in the kernel. 'hello' will echoed\n" + " if KernelPatch installed successfully.\n" + " --kv\n" + " Get Kernel version.\n" + " --kpv\n" + " Get KernelPatch version.\n" + " --su [scontext]\n" + " Fork a root shell and change security context to 'scontext'.\n" + " If scontext is not specified or fails to be set, \n" + " bypass all selinux permission checks for all calls initiated by this thread using hooks,\n" + " but the permission determined by other threads remain unchanged.\n" + " --load_kpm path [args]\n" + " Load KernelPatch Module\n" + " --unload_kpm name\n" + " Unload KernelPatch Module\n" + " --kpm_num\n" + " Get the number of KernelPatch Modules\n" + " --kpm_info index\n" + " Get information of the module at 'index'.\n" + " --thread_su tid\n" + " Grant root privileges to the thread corresponding to the given 'tid'.\n" + " --thread_unsu tid\n" + " Revoke root privileges to the thread corresponding to the given 'tid'.\n" + " (Unimplemented ...).\n" #ifdef ANDROID - "\n" - "Android Specific Usage:\n" - "The default command to get a root shell is 'kp', whose full path is '/system/bin/kp'.\n" - "This can avoid conflicts with the existing 'su' command.\n" - "If you want to change this path, you can use the 'reset_su' command, " - "but keep in mind that the command's length should not exceed two characters.\n" - " --grant_su --arg1 uid\n" - " Grant root privileges to the user corresponding to the given uid.\n" - " --revoke_su --arg1 uid\n" - " Revoke root privileges to the user corresponding to the given uid.\n" - " --list_su\n" - " List su allowed uids.\n" - " --reset_su --arg1 cmd\n" - " Reset root shell command full path to '/system/bin/cmd'. The length of cmd must not exceed two characters.\n" + "\n" + "Android Specific Command:\n" + " The default command to get a root shell is 'kp', whose full path is '/system/bin/kp'.\n" + " This can avoid conflicts with the existing 'su' command.\n" + " If you want to change this path, you can use the 'reset_su' command.\n" + " --grant_su uid\n" + " Grant root privileges to the user corresponding to the given 'uid'.\n" + " --revoke_su uid\n" + " Revoke root privileges to the user corresponding to the given 'uid'.\n" + " --num_su\n" + " Get the number of su allowed uids\n" + " --list_su\n" + " List su allowed uids.\n" + " --reset_su path\n" + " Reset root shell command full path to 'path'. The length of 'path' must not exceed 14 characters.\n" + " --get_su\n" + " Get full path of current root shell command.\n" #endif - "\n"; + "\n"; fprintf(stdout, "%s", c); } int main(int argc, char **argv) { int cmd = -1; - char *arg1 = 0, *arg2 = 0, *arg3 = 0; - if (argc == 2) { if (!strcmp(argv[1], "-v") || !(strcmp(argv[1], "--version"))) { fprintf(stdout, "%x\n", get_version()); @@ -82,116 +92,151 @@ int main(int argc, char **argv) return 0; } - char key[SUPER_KEY_LEN] = { '\0' }; - strncpy(key, argv[1], SUPER_KEY_LEN); - - if (!strnlen(key, SUPER_KEY_LEN)) { + if (!strnlen(argv[1], SUPER_KEY_LEN)) { fprintf(stderr, "Super key must be specified\n"); return -1; } + const char *key = argv[1]; - struct option longopts[] = { { "arg1", required_argument, NULL, '1' }, - { "arg2", required_argument, NULL, '2' }, - { "arg3", required_argument, NULL, '3' }, - { "hello", no_argument, &cmd, SUPERCALL_HELLO }, + struct option longopts[] = { { "hello", no_argument, &cmd, SUPERCALL_HELLO }, { "kv", no_argument, &cmd, SUPERCALL_GET_KERNEL_VERSION }, { "kpv", no_argument, &cmd, SUPERCALL_GET_KP_VERSION }, - { "load_kpm", no_argument, NULL, SUPERCALL_LOAD_KPM }, - { "unload_kpm", no_argument, NULL, SUPERCALL_UNLOAD_KPM }, + { "load_kpm", no_argument, &cmd, SUPERCALL_LOAD_KPM }, + { "unload_kpm", no_argument, &cmd, SUPERCALL_UNLOAD_KPM }, + { "kpm_num", no_argument, &cmd, SUPERCALL_KPM_NUMS }, + { "kpm_info", no_argument, &cmd, SUPERCALL_KPM_INFO }, { "su", no_argument, &cmd, SUPERCALL_SU }, { "thread_su", no_argument, &cmd, SUPERCALL_THREAD_SU }, { "thread_unsu", no_argument, &cmd, SUPERCALL_THREAD_UNSU }, #ifdef ANDROID { "grant_su", no_argument, &cmd, SUPERCALL_GRANT_SU }, { "revoke_su", no_argument, &cmd, SUPERCALL_REVOKE_SU }, + { "num_su", no_argument, &cmd, SUPERCALL_SU_ALLOW_NUM }, { "list_su", no_argument, &cmd, SUPERCALL_LIST_SU_ALLOW }, - { "reset_su", no_argument, &cmd, SUPERCALL_RESET_SU_CMD }, + { "reset_su", no_argument, &cmd, SUPERCALL_SU_RESET_PATH }, + { "get_su", no_argument, &cmd, SUPERCALL_SU_GET_PATH }, #endif { 0, 0, 0, 0 } }; - char *optstr = "1:2:3:"; + char *optstr = ""; int opt = -1; int opt_index = -1; int verbose = 0; while ((opt = getopt_long(argc, argv, optstr, longopts, &opt_index)) != -1) { switch (opt) { - case '1': - arg1 = optarg; - break; - case '2': - arg2 = optarg; - break; - case '3': - arg3 = optarg; - break; - default: - continue; } } + long ret = 0; if (cmd == SUPERCALL_HELLO) { ret = sc_hello(key); - if (ret == SUPERCALL_HELLO_MAGIC) + if (ret == SUPERCALL_HELLO_MAGIC) { + fprintf(stdout, "hello\n"); ret = 0; + } } else if (cmd == SUPERCALL_GET_KERNEL_VERSION) { long kv = sc_get_kernel_version(key); fprintf(stdout, "%lx\n", kv); } else if (cmd == SUPERCALL_GET_KP_VERSION) { long kpv = sc_get_kp_version(key); fprintf(stdout, "%lx\n", kpv); + } else if (cmd == SUPERCALL_LOAD_KPM) { + if (argc < 4) { + fprintf(stderr, "Empty path!\n"); + return -1; + } + const char *path = argv[3]; + const char *args = argc < 5 ? NULL : argv[4]; + ret = sc_load_kpm(key, path, args); + } else if (cmd == SUPERCALL_UNLOAD_KPM) { + if (argc < 4) { + fprintf(stderr, "Empty name!\n"); + return -1; + } + const char *name = argv[3]; + ret = sc_unload_kpm(key, name); + } else if (cmd == SUPERCALL_KPM_NUMS) { + int num = sc_kpm_nums(key); + fprintf(stdout, "%d\n", num); + ret = 0; + } else if (cmd == SUPERCALL_KPM_INFO) { + if (argc < 4) { + fprintf(stderr, "Empty index!\n"); + return -1; + } + const char *si = argv[3]; + int index = atoi(si); + char buf[1024]; + long ret = sc_kpm_info(key, index, buf, sizeof(buf)); + if (ret > 0) { + fprintf(stdout, "index: %d\n", index); + fprintf(stdout, "%s", buf); + ret = 0; + } } else if (cmd == SUPERCALL_SU) { - ret = su_fork(key, arg1); + const char *scontext = argc < 4 ? NULL : argv[3]; + ret = su_fork(key, scontext); } else if (cmd == SUPERCALL_THREAD_SU) { - if (!arg1) { + if (argc < 4) { fprintf(stderr, "Empty tid!\n"); return -1; } - int pid = atoi(arg1); + const char *stid = argv[3]; + int pid = atoi(stid); ret = sc_thread_su(key, pid, 0); } else if (cmd == SUPERCALL_THREAD_UNSU) { - if (!arg1) { + if (argc < 4) { fprintf(stderr, "Empty tid!\n"); return -1; } - int pid = atoi(arg1); + const char *stid = argv[3]; + int pid = atoi(stid); ret = sc_thread_unsu(key, pid); } #ifdef ANDROID else if (cmd == SUPERCALL_GRANT_SU) { - if (!arg1) { + if (argc < 4) { fprintf(stderr, "Empty uid!\n"); return -1; } - uid_t uid = atoi(arg1); + const char *suid = argv[3]; + uid_t uid = atoi(suid); ret = sc_grant_su(key, uid); } else if (cmd == SUPERCALL_REVOKE_SU) { - if (!arg1) { + if (argc < 4) { fprintf(stderr, "Empty uid!\n"); return -1; } - uid_t uid = atoi(arg1); + const char *suid = argv[3]; + uid_t uid = atoi(suid); ret = sc_revoke_su(key, uid); + } else if (cmd == SUPERCALL_SU_ALLOW_NUM) { + int num = sc_num_su(key); + fprintf(stdout, "%d\n", num); + ret = 0; } else if (cmd == SUPERCALL_LIST_SU_ALLOW) { uid_t uids[SUPERCALL_SU_ALLOW_UID_MAX]; - size_t size = SUPERCALL_SU_ALLOW_UID_MAX; - ret = sc_list_su_allow(key, uids, &size); - if (ret) - return ret; - fprintf(stdout, "su allow nums: %d\n", (int)size); - for (int i = 0; i < size; i++) { + ret = sc_list_su_allow(key, uids, SUPERCALL_SU_ALLOW_UID_MAX); + for (int i = 0; i < ret; i++) { fprintf(stdout, "%d\t", uids[i]); } fprintf(stdout, "\n"); - } else if (cmd == SUPERCALL_RESET_SU_CMD) { - const char *cmd = (const char *)arg1; - if (!cmd) { - fprintf(stderr, "Empty su cmd!\n"); + ret = 0; + } else if (cmd == SUPERCALL_SU_RESET_PATH) { + if (argc < 4) { + fprintf(stderr, "Empty path!\n"); return -1; } - if (strnlen(cmd, 3) > 2) { - fprintf(stderr, "The string length of arg1 should not exceed two characters.\n"); + const char *path = argv[3]; + if (strnlen(path, SUPERCALL_SU_PATH_LEN) >= SUPERCALL_SU_PATH_LEN) { + fprintf(stderr, "The length of the 'path' should not exceed the length of /system/bin/sh.\n"); return -1; } - ret = sc_reset_su_cmd(key, cmd); + ret = sc_su_reset_path(key, path); + } else if (cmd == SUPERCALL_SU_GET_PATH) { + char path[32] = { '\0' }; + ret = sc_su_get_path(key, path, 32); + fprintf(stdout, "%s\n", path); + if (ret > 0) ret = 0; } #endif else { @@ -199,8 +244,5 @@ int main(int argc, char **argv) return 0; } - if (ret == SUPERCALL_RES_NOT_IMPL) { - fprintf(stdout, "Unimplemented SuperCall\n"); - } return ret; } diff --git a/user/supercall.h b/user/supercall.h index a40764ce..9c227c53 100644 --- a/user/supercall.h +++ b/user/supercall.h @@ -7,6 +7,7 @@ #include #include #include +#include static inline long sc_hello(const char *key) { @@ -31,24 +32,36 @@ static inline long sc_get_kp_version(const char *key) return ret; } -static inline long sc_load_kpm(const char *key, const char *path) +static inline long sc_load_kpm(const char *key, const char *path, const char *args) { - long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_LOAD_KPM, path); + if (!path || strlen(path) <= 0) return EINVAL; + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_LOAD_KPM, path, args); return ret; } -static inline long sc_unload_kpm(const char *key, const char *path) +static inline long sc_unload_kpm(const char *key, const char *name) { - long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_UNLOAD_KPM, path); + if (!name || strlen(name) <= 0) return EINVAL; + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_UNLOAD_KPM, name); + return ret; +} + +static inline long sc_kpm_nums(const char *key) +{ + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_KPM_NUMS); + return ret; +} + +static inline long sc_kpm_info(const char *key, int index, char *buf, int buf_len) +{ + if (!buf || buf_len <= 0) return EINVAL; + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_KPM_INFO, index, buf, buf_len); return ret; } static inline long sc_su(const char *key, const char *sctx) { - // todo: error code - if (sctx && strlen(sctx) > SUPERCALL_SCONTEXT_LEN) { - return -1; - } + if (sctx && strlen(sctx) >= SUPERCALL_SCONTEXT_LEN) return EINVAL; long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_SU, sctx); return ret; } @@ -78,20 +91,31 @@ static inline long sc_revoke_su(const char *key, uid_t uid) return ret; } -static inline long sc_list_su_allow(const char *key, uid_t *uids, size_t *size) +static inline long sc_num_su(const char *key) +{ + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_SU_ALLOW_NUM); + return ret; +} + +static inline long sc_list_su_allow(const char *key, uid_t *uids, int uid_cap) +{ + if (!uids || uid_cap <= 0) return EINVAL; + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_LIST_SU_ALLOW, uids, uid_cap); + return ret; +} + +static inline long sc_su_reset_path(const char *key, const char cmd[SUPERCALL_SU_PATH_LEN]) { - // todo: size enough - long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_LIST_SU_ALLOW, uids, size); + if (!cmd) return EINVAL; + if (strlen(cmd) >= SUPERCALL_SU_PATH_LEN) return -EINVAL; + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_SU_RESET_PATH, cmd); return ret; } -static inline long sc_reset_su_cmd(const char *key, const char *path) +static inline long sc_su_get_path(const char *key, char out_path[SUPERCALL_SU_PATH_LEN], int size) { - // todo: error code - if (strlen(path) > SUPERCALL_SU_CMD_LEN) { - return -1; - } - long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_RESET_SU_CMD, path); + if (!out_path || size <= 0) return EINVAL; + long ret = syscall(__NR_supercall, key, hash_key(key), SUPERCALL_SU_GET_PATH, out_path, size); return ret; }