Compare commits
1 Commits
ksud-susfs
...
WX-new
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ed6e1e8c |
137
.github/workflows/avd-kernel.yml
vendored
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
name: GKI Kernel Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
version_name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
With SUBLEVEL of kernel,
|
||||||
|
for example: android12-5.10.66
|
||||||
|
arch:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Build arch: aarch64/x86_64
|
||||||
|
debug:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
manifest_name:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Local repo manifest xml path,
|
||||||
|
typically for AVD kernel build.
|
||||||
|
secrets:
|
||||||
|
BOOT_SIGN_KEY:
|
||||||
|
required: false
|
||||||
|
CHAT_ID:
|
||||||
|
required: false
|
||||||
|
BOT_TOKEN:
|
||||||
|
required: false
|
||||||
|
MESSAGE_THREAD_ID:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build ${{ inputs.version_name }}
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Maximize build space
|
||||||
|
uses: easimon/maximize-build-space@master
|
||||||
|
with:
|
||||||
|
root-reserve-mb: 8192
|
||||||
|
temp-reserve-mb: 2048
|
||||||
|
remove-dotnet: 'true'
|
||||||
|
remove-android: 'true'
|
||||||
|
remove-haskell: 'true'
|
||||||
|
remove-codeql: 'true'
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup need_upload
|
||||||
|
id: need_upload
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup kernel source
|
||||||
|
run: |
|
||||||
|
echo "Free space:"
|
||||||
|
df -h
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
sudo apt-get install repo -y
|
||||||
|
mkdir android-kernel && cd android-kernel
|
||||||
|
repo init --depth=1 -u https://android.googlesource.com/kernel/manifest -m "$GITHUB_WORKSPACE/KernelSU/.github/manifests/${{ inputs.manifest_name }}" --repo-rev=v2.16
|
||||||
|
repo --version
|
||||||
|
repo --trace sync -c -j$(nproc --all) --no-tags
|
||||||
|
df -h
|
||||||
|
|
||||||
|
- name: Setup KernelSU
|
||||||
|
env:
|
||||||
|
PATCH_PATH: ${{ inputs.patch_path }}
|
||||||
|
IS_DEBUG_KERNEL: ${{ inputs.debug }}
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/android-kernel
|
||||||
|
echo "[+] KernelSU setup"
|
||||||
|
GKI_ROOT=$(pwd)
|
||||||
|
echo "[+] GKI_ROOT: $GKI_ROOT"
|
||||||
|
echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers"
|
||||||
|
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
|
||||||
|
echo "[+] Add KernelSU driver to Makefile"
|
||||||
|
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
|
||||||
|
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
|
||||||
|
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
|
||||||
|
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
|
||||||
|
echo "[+] Apply KernelSU patches"
|
||||||
|
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found"
|
||||||
|
|
||||||
|
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
|
||||||
|
echo "[+] Enable debug features for kernel"
|
||||||
|
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
|
||||||
|
fi
|
||||||
|
repo status
|
||||||
|
echo "[+] KernelSU setup done."
|
||||||
|
cd $GITHUB_WORKSPACE/KernelSU
|
||||||
|
VERSION=$(($(git rev-list --count HEAD) + 10200))
|
||||||
|
echo "VERSION: $VERSION"
|
||||||
|
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Make working directory clean to avoid dirty
|
||||||
|
working-directory: android-kernel
|
||||||
|
run: |
|
||||||
|
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
|
||||||
|
git config --global user.email "bot@kernelsu.org"
|
||||||
|
git config --global user.name "KernelSUBot"
|
||||||
|
cd common/ && git add -A && git commit -a -m "Add KernelSU"
|
||||||
|
repo status
|
||||||
|
|
||||||
|
- name: Build kernel
|
||||||
|
working-directory: android-kernel
|
||||||
|
run: |
|
||||||
|
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
|
||||||
|
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
|
||||||
|
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||||
|
fi
|
||||||
|
tools/bazel run --config=fast --config=stamp --lto=thin //common-modules/virtual-device:virtual_device_${{ inputs.arch }}_dist -- --dist_dir=dist
|
||||||
|
NAME=kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
|
||||||
|
TARGET_IMAGE=dist/bzImage
|
||||||
|
if [ ! -e $TARGET_IMAGE ]; then
|
||||||
|
TARGET_IMAGE=dist/Image
|
||||||
|
fi
|
||||||
|
mv $TARGET_IMAGE $NAME
|
||||||
|
echo "file_path=android-kernel/$NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Upload Kernel
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
|
||||||
|
path: "${{ env.file_path }}"
|
||||||
20
.github/workflows/build-gki-image.yml
vendored
@@ -1,20 +0,0 @@
|
|||||||
name: Build Android GKI Image
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-a12-kernel:
|
|
||||||
uses: ./.github/workflows/build-kernel-a12.yml
|
|
||||||
secrets: inherit
|
|
||||||
build-a13-kernel:
|
|
||||||
uses: ./.github/workflows/build-kernel-a13.yml
|
|
||||||
secrets: inherit
|
|
||||||
build-a14-kernel:
|
|
||||||
uses: ./.github/workflows/build-kernel-a14.yml
|
|
||||||
secrets: inherit
|
|
||||||
build-a15-kernel:
|
|
||||||
uses: ./.github/workflows/build-kernel-a15.yml
|
|
||||||
secrets: inherit
|
|
||||||
build-a16-kernel:
|
|
||||||
uses: ./.github/workflows/build-kernel-a16.yml
|
|
||||||
secrets: inherit
|
|
||||||
111
.github/workflows/build-kernel-a12.yml
vendored
@@ -1,111 +0,0 @@
|
|||||||
name: Build Kernel - Android 12
|
|
||||||
on:
|
|
||||||
# push:
|
|
||||||
# branches: ["main", "ci", "checkci"]
|
|
||||||
# paths:
|
|
||||||
# - ".github/workflows/deps/gki/build-kernel-a12.yml"
|
|
||||||
# - ".github/workflows/deps/gki/gki-kernel.yml"
|
|
||||||
# - ".github/scripts/build_a12.sh"
|
|
||||||
# - "kernel/**"
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
jobs:
|
|
||||||
build-kernel:
|
|
||||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- sub_level: 209
|
|
||||||
os_patch_level: 2024-05
|
|
||||||
- sub_level: 218
|
|
||||||
os_patch_level: 2024-08
|
|
||||||
- sub_level: 226
|
|
||||||
os_patch_level: 2024-11
|
|
||||||
- sub_level: 233
|
|
||||||
os_patch_level: 2025-02
|
|
||||||
- sub_level: 236
|
|
||||||
os_patch_level: 2025-05
|
|
||||||
uses: ./.github/workflows/gki-kernel.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
version: android12-5.10
|
|
||||||
version_name: android12-5.10.${{ matrix.sub_level }}
|
|
||||||
tag: android12-5.10-${{ matrix.os_patch_level }}
|
|
||||||
os_patch_level: ${{ matrix.os_patch_level }}
|
|
||||||
patch_path: "5.10"
|
|
||||||
debug: ${{ inputs.debug || false }}
|
|
||||||
|
|
||||||
upload-artifacts:
|
|
||||||
needs: build-kernel
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
|
||||||
env:
|
|
||||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
|
||||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
|
||||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
|
||||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
|
||||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
|
||||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
steps:
|
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
path: KernelSU
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: List artifacts
|
|
||||||
run: |
|
|
||||||
tree
|
|
||||||
|
|
||||||
- name: Download prebuilt toolchain
|
|
||||||
run: |
|
|
||||||
AOSP_MIRROR=https://android.googlesource.com
|
|
||||||
BRANCH=main-kernel-build-2024
|
|
||||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
|
||||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
|
||||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
|
||||||
pip3 install telethon
|
|
||||||
|
|
||||||
- name: Set boot sign key
|
|
||||||
env:
|
|
||||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
|
||||||
run: |
|
|
||||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
|
||||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build boot images
|
|
||||||
run: |
|
|
||||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
|
||||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
|
||||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
|
||||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
|
||||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
|
||||||
cd $GITHUB_WORKSPACE/KernelSU
|
|
||||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
|
||||||
echo "VERSION: $VERSION"
|
|
||||||
cd -
|
|
||||||
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a12.sh
|
|
||||||
|
|
||||||
- name: Display structure of boot files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Upload images artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: boot-images-android12
|
|
||||||
path: Image-android12*/*.img.gz
|
|
||||||
146
.github/workflows/build-kernel-a13.yml
vendored
@@ -1,146 +0,0 @@
|
|||||||
name: Build Kernel - Android 13
|
|
||||||
on:
|
|
||||||
# push:
|
|
||||||
# branches: ["main", "ci", "checkci"]
|
|
||||||
# paths:
|
|
||||||
# - ".github/workflows/deps/gki/build-kernel-a13.yml"
|
|
||||||
# - ".github/workflows/deps/gki/gki-kernel.yml"
|
|
||||||
# - ".github/scripts/build_a13.sh"
|
|
||||||
# - "kernel/**"
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
jobs:
|
|
||||||
build-kernel:
|
|
||||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- version: "5.10"
|
|
||||||
sub_level: 209
|
|
||||||
os_patch_level: 2024-05
|
|
||||||
- version: "5.10"
|
|
||||||
sub_level: 210
|
|
||||||
os_patch_level: 2024-06
|
|
||||||
- version: "5.10"
|
|
||||||
sub_level: 214
|
|
||||||
os_patch_level: 2024-07
|
|
||||||
- version: "5.10"
|
|
||||||
sub_level: 218
|
|
||||||
os_patch_level: 2024-08
|
|
||||||
- version: "5.10"
|
|
||||||
sub_level: 223
|
|
||||||
os_patch_level: 2024-11
|
|
||||||
- version: "5.10"
|
|
||||||
sub_level: 228
|
|
||||||
os_patch_level: 2025-01
|
|
||||||
- version: "5.10"
|
|
||||||
sub_level: 234
|
|
||||||
os_patch_level: 2025-03
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 148
|
|
||||||
os_patch_level: 2024-05
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 149
|
|
||||||
os_patch_level: 2024-07
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 151
|
|
||||||
os_patch_level: 2024-08
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 153
|
|
||||||
os_patch_level: 2024-09
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 167
|
|
||||||
os_patch_level: 2024-11
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 178
|
|
||||||
os_patch_level: 2024-11
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 170
|
|
||||||
os_patch_level: 2025-01
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 178
|
|
||||||
os_patch_level: 2025-03
|
|
||||||
uses: ./.github/workflows/gki-kernel.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
version: android13-${{ matrix.version }}
|
|
||||||
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
|
|
||||||
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
|
||||||
os_patch_level: ${{ matrix.os_patch_level }}
|
|
||||||
patch_path: ${{ matrix.version }}
|
|
||||||
debug: ${{ inputs.debug || false }}
|
|
||||||
|
|
||||||
upload-artifacts:
|
|
||||||
needs: build-kernel
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
|
||||||
env:
|
|
||||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
|
||||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
|
||||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
|
||||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
|
||||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
|
||||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
steps:
|
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
path: KernelSU
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: List artifacts
|
|
||||||
run: |
|
|
||||||
tree
|
|
||||||
|
|
||||||
- name: Download prebuilt toolchain
|
|
||||||
run: |
|
|
||||||
AOSP_MIRROR=https://android.googlesource.com
|
|
||||||
BRANCH=main-kernel-build-2024
|
|
||||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
|
||||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
|
||||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
|
||||||
pip3 install telethon
|
|
||||||
|
|
||||||
- name: Set boot sign key
|
|
||||||
env:
|
|
||||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
|
||||||
run: |
|
|
||||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
|
||||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build boot images
|
|
||||||
run: |
|
|
||||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
|
||||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
|
||||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
|
||||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
|
||||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
|
||||||
cd $GITHUB_WORKSPACE/KernelSU
|
|
||||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
|
||||||
echo "VERSION: $VERSION"
|
|
||||||
cd -
|
|
||||||
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
|
|
||||||
|
|
||||||
- name: Display structure of boot files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Upload images artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: boot-images-android13
|
|
||||||
path: Image-android13*/*.img.gz
|
|
||||||
158
.github/workflows/build-kernel-a14.yml
vendored
@@ -1,158 +0,0 @@
|
|||||||
name: Build Kernel - Android 14
|
|
||||||
on:
|
|
||||||
# push:
|
|
||||||
# branches: ["main", "ci", "checkci"]
|
|
||||||
# paths:
|
|
||||||
# - ".github/workflows/deps/gki/build-kernel-a14.yml"
|
|
||||||
# - ".github/workflows/deps/gki/gki-kernel.yml"
|
|
||||||
# - ".github/scripts/build_a13.sh"
|
|
||||||
# - "kernel/**"
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
jobs:
|
|
||||||
build-kernel:
|
|
||||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 148
|
|
||||||
os_patch_level: 2024-05
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 149
|
|
||||||
os_patch_level: 2024-06
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 153
|
|
||||||
os_patch_level: 2024-07
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 158
|
|
||||||
os_patch_level: 2024-08
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 164
|
|
||||||
os_patch_level: 2024-09
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 167
|
|
||||||
os_patch_level: 2024-11
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 170
|
|
||||||
os_patch_level: 2025-01
|
|
||||||
- version: "5.15"
|
|
||||||
sub_level: 178
|
|
||||||
os_patch_level: 2025-03
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 75
|
|
||||||
os_patch_level: 2024-05
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 78
|
|
||||||
os_patch_level: 2024-06
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 84
|
|
||||||
os_patch_level: 2024-07
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 90
|
|
||||||
os_patch_level: 2024-08
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 93
|
|
||||||
os_patch_level: 2024-09
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 99
|
|
||||||
os_patch_level: 2024-10
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 112
|
|
||||||
os_patch_level: 2024-11
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 115
|
|
||||||
os_patch_level: 2024-12
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 118
|
|
||||||
os_patch_level: 2025-01
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 128
|
|
||||||
os_patch_level: 2025-03
|
|
||||||
- version: "6.1"
|
|
||||||
sub_level: 134
|
|
||||||
os_patch_level: 2025-05
|
|
||||||
uses: ./.github/workflows/gki-kernel.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
version: android14-${{ matrix.version }}
|
|
||||||
version_name: android14-${{ matrix.version }}.${{ matrix.sub_level }}
|
|
||||||
tag: android14-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
|
||||||
os_patch_level: ${{ matrix.os_patch_level }}
|
|
||||||
patch_path: ${{ matrix.version }}
|
|
||||||
debug: ${{ inputs.debug || false }}
|
|
||||||
|
|
||||||
upload-artifacts:
|
|
||||||
needs: build-kernel
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
|
||||||
env:
|
|
||||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
|
||||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
|
||||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
|
||||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
|
||||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
|
||||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
steps:
|
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
path: KernelSU
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: List artifacts
|
|
||||||
run: |
|
|
||||||
tree
|
|
||||||
|
|
||||||
- name: Download prebuilt toolchain
|
|
||||||
run: |
|
|
||||||
AOSP_MIRROR=https://android.googlesource.com
|
|
||||||
BRANCH=main-kernel-build-2024
|
|
||||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
|
||||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
|
||||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
|
||||||
pip3 install telethon
|
|
||||||
|
|
||||||
- name: Set boot sign key
|
|
||||||
env:
|
|
||||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
|
||||||
run: |
|
|
||||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
|
||||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build boot images
|
|
||||||
run: |
|
|
||||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
|
||||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
|
||||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
|
||||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
|
||||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
|
||||||
cd $GITHUB_WORKSPACE/KernelSU
|
|
||||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
|
||||||
echo "VERSION: $VERSION"
|
|
||||||
cd -
|
|
||||||
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
|
|
||||||
|
|
||||||
- name: Display structure of boot files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Upload images artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: boot-images-android14
|
|
||||||
path: Image-android14*/*.img.gz
|
|
||||||
131
.github/workflows/build-kernel-a15.yml
vendored
@@ -1,131 +0,0 @@
|
|||||||
name: Build Kernel - Android 15
|
|
||||||
on:
|
|
||||||
# push:
|
|
||||||
# branches: ["main", "ci", "checkci"]
|
|
||||||
# paths:
|
|
||||||
# - ".github/workflows/deps/gki/build-kernel-a15.yml"
|
|
||||||
# - ".github/workflows/deps/gki/gki-kernel.yml"
|
|
||||||
# - ".github/scripts/build_a13.sh"
|
|
||||||
# - "kernel/**"
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
jobs:
|
|
||||||
build-kernel:
|
|
||||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 30
|
|
||||||
os_patch_level: 2024-08
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 46
|
|
||||||
os_patch_level: 2024-09
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 50
|
|
||||||
os_patch_level: 2024-10
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 56
|
|
||||||
os_patch_level: 2024-11
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 57
|
|
||||||
os_patch_level: 2024-12
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 58
|
|
||||||
os_patch_level: 2025-01
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 66
|
|
||||||
os_patch_level: 2025-02
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 77
|
|
||||||
os_patch_level: 2025-03
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 82
|
|
||||||
os_patch_level: 2025-04
|
|
||||||
- version: "6.6"
|
|
||||||
sub_level: 87
|
|
||||||
os_patch_level: 2025-05
|
|
||||||
uses: ./.github/workflows/gki-kernel.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
version: android15-${{ matrix.version }}
|
|
||||||
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
|
|
||||||
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
|
||||||
os_patch_level: ${{ matrix.os_patch_level }}
|
|
||||||
patch_path: ${{ matrix.version }}
|
|
||||||
debug: ${{ inputs.debug || false }}
|
|
||||||
|
|
||||||
upload-artifacts:
|
|
||||||
needs: build-kernel
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
|
||||||
env:
|
|
||||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
|
||||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
|
||||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
|
||||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
|
||||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
|
||||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
steps:
|
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
path: KernelSU
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: List artifacts
|
|
||||||
run: |
|
|
||||||
tree
|
|
||||||
|
|
||||||
- name: Download prebuilt toolchain
|
|
||||||
run: |
|
|
||||||
AOSP_MIRROR=https://android.googlesource.com
|
|
||||||
BRANCH=main-kernel-build-2024
|
|
||||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
|
||||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
|
||||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
|
||||||
pip3 install telethon
|
|
||||||
|
|
||||||
- name: Set boot sign key
|
|
||||||
env:
|
|
||||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
|
||||||
run: |
|
|
||||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
|
||||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build boot images
|
|
||||||
run: |
|
|
||||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
|
||||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
|
||||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
|
||||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
|
||||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
|
||||||
cd $GITHUB_WORKSPACE/KernelSU
|
|
||||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
|
||||||
echo "VERSION: $VERSION"
|
|
||||||
cd -
|
|
||||||
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
|
|
||||||
|
|
||||||
- name: Display structure of boot files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Upload images artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: boot-images-android15
|
|
||||||
path: Image-android15*/*.img.gz
|
|
||||||
104
.github/workflows/build-kernel-a16.yml
vendored
@@ -1,104 +0,0 @@
|
|||||||
name: Build Kernel - Android 16
|
|
||||||
on:
|
|
||||||
# push:
|
|
||||||
# branches: ["main", "ci", "checkci"]
|
|
||||||
# paths:
|
|
||||||
# - ".github/workflows/deps/gki/build-kernel-a16.yml"
|
|
||||||
# - ".github/workflows/deps/gki/gki-kernel.yml"
|
|
||||||
# - ".github/scripts/build_a13.sh"
|
|
||||||
# - "kernel/**"
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
debug:
|
|
||||||
description: 'Build debug kernel'
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
jobs:
|
|
||||||
build-kernel:
|
|
||||||
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- version: "6.12"
|
|
||||||
sub_level: 38
|
|
||||||
os_patch_level: 2025-08
|
|
||||||
uses: ./.github/workflows/gki-kernel.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
version: android16-${{ matrix.version }}
|
|
||||||
version_name: android16-${{ matrix.version }}.${{ matrix.sub_level }}
|
|
||||||
tag: android16-${{ matrix.version }}-${{ matrix.os_patch_level }}
|
|
||||||
os_patch_level: ${{ matrix.os_patch_level }}
|
|
||||||
patch_path: ${{ matrix.version }}
|
|
||||||
debug: ${{ inputs.debug || false }}
|
|
||||||
|
|
||||||
upload-artifacts:
|
|
||||||
needs: build-kernel
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
|
|
||||||
env:
|
|
||||||
CHAT_ID: ${{ secrets.CHAT_ID }}
|
|
||||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
|
||||||
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
|
|
||||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
|
||||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
|
||||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
steps:
|
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@v6
|
|
||||||
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
path: KernelSU
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: List artifacts
|
|
||||||
run: |
|
|
||||||
tree
|
|
||||||
|
|
||||||
- name: Download prebuilt toolchain
|
|
||||||
run: |
|
|
||||||
AOSP_MIRROR=https://android.googlesource.com
|
|
||||||
BRANCH=main-kernel-build-2024
|
|
||||||
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
|
|
||||||
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
|
|
||||||
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
|
|
||||||
pip3 install telethon
|
|
||||||
|
|
||||||
- name: Set boot sign key
|
|
||||||
env:
|
|
||||||
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
|
|
||||||
run: |
|
|
||||||
if [ ! -z "$BOOT_SIGN_KEY" ]; then
|
|
||||||
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build boot images
|
|
||||||
run: |
|
|
||||||
export AVBTOOL=$GITHUB_WORKSPACE/kernel-build-tools/linux-x86/bin/avbtool
|
|
||||||
export GZIP=$GITHUB_WORKSPACE/build-tools/path/linux-x86/gzip
|
|
||||||
export LZ4=$GITHUB_WORKSPACE/build-tools/path/linux-x86/lz4
|
|
||||||
export MKBOOTIMG=$GITHUB_WORKSPACE/mkbootimg/mkbootimg.py
|
|
||||||
export UNPACK_BOOTIMG=$GITHUB_WORKSPACE/mkbootimg/unpack_bootimg.py
|
|
||||||
cd $GITHUB_WORKSPACE/KernelSU
|
|
||||||
export VERSION=$(($(git rev-list --count HEAD) + 10200))
|
|
||||||
echo "VERSION: $VERSION"
|
|
||||||
cd -
|
|
||||||
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
|
|
||||||
|
|
||||||
- name: Display structure of boot files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Upload images artifact
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
with:
|
|
||||||
name: boot-images-android16
|
|
||||||
path: Image-android16*/*.img.gz
|
|
||||||
74
.github/workflows/build-lkm-local.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
name: Build LKM for KernelSU Local
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
upload:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
description: "Whether to upload to branch"
|
||||||
|
secrets:
|
||||||
|
# username:github_pat
|
||||||
|
TOKEN:
|
||||||
|
required: true
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
upload:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
description: "Whether to upload to branch"
|
||||||
|
jobs:
|
||||||
|
build-lkm:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- version: "android12-5.10"
|
||||||
|
sub_level: 236
|
||||||
|
os_patch_level: 2025-05
|
||||||
|
- version: "android13-5.10"
|
||||||
|
sub_level: 234
|
||||||
|
os_patch_level: 2025-03
|
||||||
|
- version: "android13-5.15"
|
||||||
|
sub_level: 178
|
||||||
|
os_patch_level: 2025-03
|
||||||
|
- version: "android14-5.15"
|
||||||
|
sub_level: 178
|
||||||
|
os_patch_level: 2025-03
|
||||||
|
- version: "android14-6.1"
|
||||||
|
sub_level: 134
|
||||||
|
os_patch_level: 2025-05
|
||||||
|
- version: "android15-6.6"
|
||||||
|
sub_level: 87
|
||||||
|
os_patch_level: 2025-05
|
||||||
|
# uses: ./.github/workflows/gki-kernel-mock.yml when debugging
|
||||||
|
uses: ./.github/workflows/gki-kernel-local.yml
|
||||||
|
with:
|
||||||
|
version: ${{ matrix.version }}
|
||||||
|
version_name: ${{ matrix.version }}.${{ matrix.sub_level }}
|
||||||
|
tag: ${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||||
|
os_patch_level: ${{ matrix.os_patch_level }}
|
||||||
|
build_lkm: true
|
||||||
|
|
||||||
|
push-to-branch:
|
||||||
|
needs: [build-lkm]
|
||||||
|
runs-on: self-hosted
|
||||||
|
if: ${{ inputs.upload }}
|
||||||
|
steps:
|
||||||
|
- name: Download all workflow run artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: bin/
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Push to branch LKM
|
||||||
|
run: |
|
||||||
|
cd bin
|
||||||
|
git config --global init.defaultBranch lkm
|
||||||
|
git init
|
||||||
|
git remote add origin https://${{ secrets.TOKEN }}@github.com/${{ github.repository }}
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
find . -type f
|
||||||
|
git add .
|
||||||
|
git commit -m "Upload LKM from ${{ github.sha }}" -m "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
|
git push --force --set-upstream origin lkm
|
||||||
77
.github/workflows/build-lkm.yml
vendored
@@ -1,21 +1,74 @@
|
|||||||
name: Build LKM for KernelSU
|
name: Build LKM for KernelSU
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
upload:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
description: "Whether to upload to branch"
|
||||||
|
secrets:
|
||||||
|
# username:github_pat
|
||||||
|
TOKEN:
|
||||||
|
required: true
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
upload:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
description: "Whether to upload to branch"
|
||||||
jobs:
|
jobs:
|
||||||
build-lkm:
|
build-lkm:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
matrix:
|
||||||
kmi:
|
include:
|
||||||
- android12-5.10
|
- version: "android12-5.10"
|
||||||
- android13-5.10
|
sub_level: 237
|
||||||
- android13-5.15
|
os_patch_level: 2025-06
|
||||||
- android14-5.15
|
- version: "android13-5.10"
|
||||||
- android14-6.1
|
sub_level: 236
|
||||||
- android15-6.6
|
os_patch_level: 2025-05
|
||||||
- android16-6.12
|
- version: "android13-5.15"
|
||||||
uses: ./.github/workflows/ddk-lkm.yml
|
sub_level: 180
|
||||||
|
os_patch_level: 2025-05
|
||||||
|
- version: "android14-5.15"
|
||||||
|
sub_level: 180
|
||||||
|
os_patch_level: 2025-05
|
||||||
|
- version: "android14-6.1"
|
||||||
|
sub_level: 138
|
||||||
|
os_patch_level: 2025-06
|
||||||
|
- version: "android15-6.6"
|
||||||
|
sub_level: 89
|
||||||
|
os_patch_level: 2025-06
|
||||||
|
# uses: ./.github/workflows/gki-kernel-mock.yml when debugging
|
||||||
|
uses: ./.github/workflows/gki-kernel.yml
|
||||||
with:
|
with:
|
||||||
kmi: ${{ matrix.kmi }}
|
version: ${{ matrix.version }}
|
||||||
ddk_release: '20251104'
|
version_name: ${{ matrix.version }}.${{ matrix.sub_level }}
|
||||||
|
tag: ${{ matrix.version }}-${{ matrix.os_patch_level }}
|
||||||
|
os_patch_level: ${{ matrix.os_patch_level }}
|
||||||
|
build_lkm: true
|
||||||
|
|
||||||
|
push-to-branch:
|
||||||
|
needs: [build-lkm]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ inputs.upload }}
|
||||||
|
steps:
|
||||||
|
- name: Download all workflow run artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: bin/
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Push to branch LKM
|
||||||
|
run: |
|
||||||
|
cd bin
|
||||||
|
git config --global init.defaultBranch lkm
|
||||||
|
git init
|
||||||
|
git remote add origin https://${{ secrets.TOKEN }}@github.com/${{ github.repository }}
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
find . -type f
|
||||||
|
git add .
|
||||||
|
git commit -m "Upload LKM from ${{ github.sha }}" -m "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
|
git push --force --set-upstream origin lkm
|
||||||
|
|||||||
252
.github/workflows/build-manager-manual.yml
vendored
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
name: Build Manager Manual
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
build_lkm:
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
default: "auto"
|
||||||
|
options:
|
||||||
|
- "true"
|
||||||
|
- "false"
|
||||||
|
- "auto"
|
||||||
|
description: "Whether to build lkm"
|
||||||
|
upload_lkm:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
description: "Whether to upload lkm"
|
||||||
|
jobs:
|
||||||
|
check-build-lkm:
|
||||||
|
runs-on: self-hosted
|
||||||
|
outputs:
|
||||||
|
build_lkm: ${{ steps.check-build.outputs.build_lkm }}
|
||||||
|
upload_lkm: ${{ steps.check-build.outputs.upload_lkm }}
|
||||||
|
steps:
|
||||||
|
- name: check build
|
||||||
|
id: check-build
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ "${{ inputs.build_lkm }}" != "auto" ]; then
|
||||||
|
kernel_changed="${{ inputs.build_lkm }}"
|
||||||
|
else
|
||||||
|
kernel_changed=true
|
||||||
|
mkdir tmp
|
||||||
|
cd tmp
|
||||||
|
git config --global init.defaultBranch bot
|
||||||
|
git config --global user.name 'Bot'
|
||||||
|
git config --global user.email 'bot@github.shirkneko.io'
|
||||||
|
git init .
|
||||||
|
git remote add origin https://github.com/${{ github.repository }}
|
||||||
|
CURRENT_COMMIT="${{ github.event.head_commit.id }}"
|
||||||
|
git fetch origin $CURRENT_COMMIT --depth=1
|
||||||
|
git fetch origin lkm --depth=1
|
||||||
|
LKM_COMMIT="$(git log --format=%B -n 1 origin/lkm | head -n 1)"
|
||||||
|
LKM_COMMIT="${LKM_COMMIT#Upload LKM from }"
|
||||||
|
LKM_COMMIT=$(echo "$LKM_COMMIT" | tr -d '[:space:]')
|
||||||
|
echo "LKM_COMMIT=$LKM_COMMIT"
|
||||||
|
git fetch origin "$LKM_COMMIT" --depth=1
|
||||||
|
git diff --quiet "$LKM_COMMIT" "$CURRENT_COMMIT" -- kernel :!kernel/setup.sh .github/workflows/build-lkm-local.yml .github/workflows/build-kernel-*.yml && kernel_changed=false
|
||||||
|
cd ..
|
||||||
|
rm -rf tmp
|
||||||
|
fi
|
||||||
|
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == 'refs/heads/main' ]; then
|
||||||
|
need_upload=true
|
||||||
|
elif [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||||||
|
need_upload="${{ inputs.upload_lkm }}"
|
||||||
|
else
|
||||||
|
need_upload=false
|
||||||
|
fi
|
||||||
|
echo "kernel changed: $kernel_changed"
|
||||||
|
echo "need upload: $need_upload"
|
||||||
|
echo "build_lkm=$kernel_changed" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "upload_lkm=$need_upload" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
build-lkm:
|
||||||
|
needs: check-build-lkm
|
||||||
|
uses: ./.github/workflows/build-lkm-local.yml
|
||||||
|
if: ${{ needs.check-build-lkm.outputs.build_lkm == 'true' }}
|
||||||
|
with:
|
||||||
|
upload: ${{ needs.check-build-lkm.outputs.upload_lkm == 'true' }}
|
||||||
|
secrets: inherit
|
||||||
|
build-susfs:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: [ check-build-lkm, build-lkm ]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- target: aarch64-linux-android
|
||||||
|
os: ubuntu-latest
|
||||||
|
uses: ./.github/workflows/susfs.yml
|
||||||
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
os: ${{ matrix.os }}
|
||||||
|
|
||||||
|
build-kpmmgr:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: [ check-build-lkm, build-lkm ]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- target: aarch64-linux-android
|
||||||
|
os: ubuntu-latest
|
||||||
|
uses: ./.github/workflows/kpmmgr.yml
|
||||||
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
os: ${{ matrix.os }}
|
||||||
|
|
||||||
|
build-ksud:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: [ check-build-lkm, build-lkm ]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- target: aarch64-linux-android
|
||||||
|
os: ubuntu-latest
|
||||||
|
- target: x86_64-linux-android
|
||||||
|
os: ubuntu-latest
|
||||||
|
- target: armv7-linux-androideabi
|
||||||
|
os: ubuntu-latest
|
||||||
|
uses: ./.github/workflows/ksud.yml
|
||||||
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
os: ${{ matrix.os }}
|
||||||
|
pack_lkm: true
|
||||||
|
pull_lkm: ${{ needs.check-build-lkm.outputs.build_lkm != 'true' }}
|
||||||
|
|
||||||
|
build-manager:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: build-ksud
|
||||||
|
runs-on: self-hosted
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./manager
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup need_upload
|
||||||
|
id: need_upload
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Write key
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref == 'refs/heads/susfs' || github.ref_type == 'tag' }}
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
|
||||||
|
{
|
||||||
|
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}'
|
||||||
|
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
|
||||||
|
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
|
||||||
|
echo KEYSTORE_FILE='key.jks'
|
||||||
|
} >> gradle.properties
|
||||||
|
echo "${{ secrets.KEYSTORE }}" | base64 -d > key.jks
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download arm64 susfs
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: susfs-aarch64-linux-android
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Download arm64 kpmmgr
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: kpmmgr-aarch64-linux-android
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Download arm64 ksud
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ksud-aarch64-linux-android
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Download x86_64 ksud
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ksud-x86_64-linux-android
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Download arm ksud
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ksud-armv7-linux-androideabi
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Copy ksud to app jniLibs
|
||||||
|
run: |
|
||||||
|
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||||
|
mkdir -p app/src/main/jniLibs/x86_64
|
||||||
|
mkdir -p app/src/main/jniLibs/armeabi-v7a
|
||||||
|
cp -f ../aarch64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozako.so
|
||||||
|
cp -f ../x86_64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/x86_64/libzakozako.so
|
||||||
|
cp -f ../armv7-linux-androideabi/release/zakozako ../manager/app/src/main/jniLibs/armeabi-v7a/libzakozako.so
|
||||||
|
|
||||||
|
- name: Copy kpmmgr to app jniLibs
|
||||||
|
run: |
|
||||||
|
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||||
|
cp -f ../arm64-v8a/kpmmgr ../manager/app/src/main/jniLibs/arm64-v8a/libkpmmgr.so
|
||||||
|
|
||||||
|
- name: Copy susfs to app jniLibs
|
||||||
|
run: |
|
||||||
|
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||||
|
cp -f ../arm64-v8a/zakozakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozakozako.so
|
||||||
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: |
|
||||||
|
export ANDROID_HOME=/root/.android/sdk
|
||||||
|
export PATH=$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin:$PATH
|
||||||
|
{
|
||||||
|
echo 'org.gradle.parallel=true'
|
||||||
|
echo 'org.gradle.vfs.watch=true'
|
||||||
|
echo 'org.gradle.jvmargs=-Xmx2048m'
|
||||||
|
echo 'android.native.buildOutput=verbose'
|
||||||
|
} >> gradle.properties
|
||||||
|
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
|
||||||
|
./gradlew clean assembleRelease
|
||||||
|
|
||||||
|
- name: Upload build artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
|
with:
|
||||||
|
name: manager
|
||||||
|
path: manager/app/build/outputs/apk/release/*.apk
|
||||||
|
|
||||||
|
- name: Upload mappings
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
|
with:
|
||||||
|
name: "mappings"
|
||||||
|
path: "manager/app/build/outputs/mapping/release/"
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
|
- name: Upload to telegram
|
||||||
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
|
env:
|
||||||
|
CHAT_ID: ${{ vars.CHAT_ID }}
|
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
MESSAGE_THREAD_ID: ${{ vars.MESSAGE_THREAD_ID }}
|
||||||
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
|
TITLE: Manager
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
export VERSION=$(git rev-list --count HEAD)
|
||||||
|
APK=$(find ./app/build/outputs/apk/release -name "*.apk")
|
||||||
|
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
|
||||||
|
fi
|
||||||
201
.github/workflows/build-manager.yml
vendored
@@ -2,43 +2,116 @@ name: Build Manager
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main", "dev", "ci", "miuix" ]
|
branches: [ "main", "ci" ]
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-manager.yml'
|
- '.github/workflows/build-manager.yml'
|
||||||
- '.github/workflows/build-lkm.yml'
|
|
||||||
- 'manager/**'
|
- 'manager/**'
|
||||||
- 'kernel/**'
|
- 'kernel/**'
|
||||||
- 'userspace/ksud/**'
|
- 'userspace/ksud/**'
|
||||||
- 'userspace/user_scanner/**'
|
- 'userspace/susfs/**'
|
||||||
|
- 'userspace/kpmmgr/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main", "dev", "miuix" ]
|
branches: [ "main" ]
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/build-manager.yml'
|
|
||||||
- '.github/workflows/build-lkm.yml'
|
|
||||||
- 'manager/**'
|
- 'manager/**'
|
||||||
- 'kernel/**'
|
|
||||||
- 'userspace/ksud/**'
|
|
||||||
- 'userspace/user_scanner/**'
|
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
build_lkm:
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
default: "auto"
|
||||||
|
options:
|
||||||
|
- "true"
|
||||||
|
- "false"
|
||||||
|
- "auto"
|
||||||
|
description: "Whether to build lkm"
|
||||||
|
upload_lkm:
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
description: "Whether to upload lkm"
|
||||||
jobs:
|
jobs:
|
||||||
|
check-build-lkm:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
build_lkm: ${{ steps.check-build.outputs.build_lkm }}
|
||||||
|
upload_lkm: ${{ steps.check-build.outputs.upload_lkm }}
|
||||||
|
steps:
|
||||||
|
- name: check build
|
||||||
|
id: check-build
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ "${{ inputs.build_lkm }}" != "auto" ]; then
|
||||||
|
kernel_changed="${{ inputs.build_lkm }}"
|
||||||
|
else
|
||||||
|
kernel_changed=true
|
||||||
|
mkdir tmp
|
||||||
|
cd tmp
|
||||||
|
git config --global init.defaultBranch bot
|
||||||
|
git config --global user.name 'Bot'
|
||||||
|
git config --global user.email 'bot@github.shirkneko.io'
|
||||||
|
git init .
|
||||||
|
git remote add origin https://github.com/${{ github.repository }}
|
||||||
|
CURRENT_COMMIT="${{ github.event.head_commit.id }}"
|
||||||
|
git fetch origin $CURRENT_COMMIT --depth=1
|
||||||
|
git fetch origin lkm --depth=1
|
||||||
|
LKM_COMMIT="$(git log --format=%B -n 1 origin/lkm | head -n 1)"
|
||||||
|
LKM_COMMIT="${LKM_COMMIT#Upload LKM from }"
|
||||||
|
LKM_COMMIT=$(echo "$LKM_COMMIT" | tr -d '[:space:]')
|
||||||
|
echo "LKM_COMMIT=$LKM_COMMIT"
|
||||||
|
git fetch origin "$LKM_COMMIT" --depth=1
|
||||||
|
git diff --quiet "$LKM_COMMIT" "$CURRENT_COMMIT" -- kernel :!kernel/setup.sh .github/workflows/build-lkm.yml .github/workflows/build-kernel-*.yml && kernel_changed=false
|
||||||
|
cd ..
|
||||||
|
rm -rf tmp
|
||||||
|
fi
|
||||||
|
if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == 'refs/heads/main' ]; then
|
||||||
|
need_upload=true
|
||||||
|
elif [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||||||
|
need_upload="${{ inputs.upload_lkm }}"
|
||||||
|
else
|
||||||
|
need_upload=false
|
||||||
|
fi
|
||||||
|
echo "kernel changed: $kernel_changed"
|
||||||
|
echo "need upload: $need_upload"
|
||||||
|
echo "build_lkm=$kernel_changed" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "upload_lkm=$need_upload" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
build-lkm:
|
build-lkm:
|
||||||
|
needs: check-build-lkm
|
||||||
uses: ./.github/workflows/build-lkm.yml
|
uses: ./.github/workflows/build-lkm.yml
|
||||||
|
if: ${{ needs.check-build-lkm.outputs.build_lkm == 'true' }}
|
||||||
|
with:
|
||||||
|
upload: ${{ needs.check-build-lkm.outputs.upload_lkm == 'true' }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
build-user_scanner:
|
build-susfs:
|
||||||
needs: build-lkm
|
if: ${{ always() }}
|
||||||
|
needs: [ check-build-lkm, build-lkm ]
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- target: All-linux-android
|
- target: aarch64-linux-android
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
uses: ./.github/workflows/user_scanner.yml
|
uses: ./.github/workflows/susfs.yml
|
||||||
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
os: ${{ matrix.os }}
|
||||||
|
|
||||||
|
build-kpmmgr:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: [ check-build-lkm, build-lkm ]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- target: aarch64-linux-android
|
||||||
|
os: ubuntu-latest
|
||||||
|
uses: ./.github/workflows/kpmmgr.yml
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
os: ${{ matrix.os }}
|
os: ${{ matrix.os }}
|
||||||
|
|
||||||
build-ksud:
|
build-ksud:
|
||||||
needs: build-lkm
|
if: ${{ always() }}
|
||||||
|
needs: [ check-build-lkm, build-lkm ]
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
@@ -52,13 +125,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
os: ${{ matrix.os }}
|
os: ${{ matrix.os }}
|
||||||
|
pack_lkm: true
|
||||||
|
pull_lkm: ${{ needs.check-build-lkm.outputs.build_lkm != 'true' }}
|
||||||
|
|
||||||
build-manager:
|
build-manager:
|
||||||
|
if: ${{ always() }}
|
||||||
needs: build-ksud
|
needs: build-ksud
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
spoofed: ["true","false"]
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: ./manager
|
working-directory: ./manager
|
||||||
@@ -78,34 +151,8 @@ jobs:
|
|||||||
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
- name: Determine manager variant for telegram bot
|
|
||||||
id: determine
|
|
||||||
run: |
|
|
||||||
if [ "${{ github.ref_name }}" == "miuix" ] && [ "${{ matrix.spoofed }}" == "true" ]; then
|
|
||||||
echo "SKIP=true" >> $GITHUB_OUTPUT
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
if [ "${{ github.ref_name }}" == "miuix" ]; then
|
|
||||||
echo "title=Manager" >> $GITHUB_OUTPUT
|
|
||||||
echo "topicid=${{ vars.MESSAGE_MIUIX_THREAD_ID }}" >> $GITHUB_OUTPUT
|
|
||||||
elif [ "${{ matrix.spoofed }}" == "true" ]; then
|
|
||||||
echo "title=Spoofed-Manager" >> $GITHUB_OUTPUT
|
|
||||||
# maybe need a new var
|
|
||||||
echo "topicid=${{ vars.MESSAGE_SPOOFED_THREAD_ID }}" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "title=Manager" >> $GITHUB_OUTPUT
|
|
||||||
echo "topicid=${{ vars.MESSAGE_THREAD_ID }}" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Run randomizer
|
|
||||||
if: ${{ matrix.spoofed == 'true' && steps.determine.outputs.SKIP != 'true' }}
|
|
||||||
run: |
|
|
||||||
chmod +x randomizer
|
|
||||||
./randomizer
|
|
||||||
|
|
||||||
- name: Write key
|
- name: Write key
|
||||||
if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }}
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref == 'refs/heads/susfs' || github.ref_type == 'tag' }}
|
||||||
run: |
|
run: |
|
||||||
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
|
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
|
||||||
{
|
{
|
||||||
@@ -129,10 +176,16 @@ jobs:
|
|||||||
- name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
uses: android-actions/setup-android@v3
|
uses: android-actions/setup-android@v3
|
||||||
|
|
||||||
- name: Download all userscanner artifacts
|
- name: Download arm64 susfs
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: userscanner-all-linux-android
|
name: susfs-aarch64-linux-android
|
||||||
|
path: .
|
||||||
|
|
||||||
|
- name: Download arm64 kpmmgr
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: kpmmgr-aarch64-linux-android
|
||||||
path: .
|
path: .
|
||||||
|
|
||||||
- name: Download arm64 ksud
|
- name: Download arm64 ksud
|
||||||
@@ -158,48 +211,62 @@ jobs:
|
|||||||
mkdir -p app/src/main/jniLibs/arm64-v8a
|
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||||
mkdir -p app/src/main/jniLibs/x86_64
|
mkdir -p app/src/main/jniLibs/x86_64
|
||||||
mkdir -p app/src/main/jniLibs/armeabi-v7a
|
mkdir -p app/src/main/jniLibs/armeabi-v7a
|
||||||
cp -f ../aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud.so
|
cp -f ../aarch64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozako.so
|
||||||
cp -f ../x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud.so
|
cp -f ../x86_64-linux-android/release/zakozako ../manager/app/src/main/jniLibs/x86_64/libzakozako.so
|
||||||
cp -f ../armv7-linux-androideabi/release/ksud ../manager/app/src/main/jniLibs/armeabi-v7a/libksud.so
|
cp -f ../armv7-linux-androideabi/release/zakozako ../manager/app/src/main/jniLibs/armeabi-v7a/libzakozako.so
|
||||||
|
|
||||||
- name: Copy user_scanner to app jniLibs
|
- name: Copy kpmmgr to app jniLibs
|
||||||
run: |
|
run: |
|
||||||
mkdir -p app/src/main/jniLibs/arm64-v8a
|
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||||
mkdir -p app/src/main/jniLibs/x86_64
|
cp -f ../arm64-v8a/kpmmgr ../manager/app/src/main/jniLibs/arm64-v8a/libkpmmgr.so
|
||||||
mkdir -p app/src/main/jniLibs/armeabi-v7a
|
|
||||||
cp -f ../arm64-v8a/uid_scanner ../manager/app/src/main/jniLibs/arm64-v8a/libuid_scanner.so
|
- name: Copy susfs to app jniLibs
|
||||||
cp -f ../x86_64/uid_scanner ../manager/app/src/main/jniLibs/x86_64/libuid_scanner.so
|
run: |
|
||||||
cp -f ../armeabi-v7a/uid_scanner ../manager/app/src/main/jniLibs/armeabi-v7a/libuid_scanner.so
|
mkdir -p app/src/main/jniLibs/arm64-v8a
|
||||||
|
cp -f ../arm64-v8a/zakozakozako ../manager/app/src/main/jniLibs/arm64-v8a/libzakozakozako.so
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
if: ${{ steps.determine.outputs.SKIP != 'true' }}
|
run: |
|
||||||
run: ./gradlew clean assembleRelease
|
{
|
||||||
|
echo 'org.gradle.parallel=true'
|
||||||
|
echo 'org.gradle.vfs.watch=true'
|
||||||
|
echo 'org.gradle.jvmargs=-Xmx2048m'
|
||||||
|
echo 'android.native.buildOutput=verbose'
|
||||||
|
} >> gradle.properties
|
||||||
|
sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties
|
||||||
|
./gradlew clean assembleRelease
|
||||||
- name: Upload build artifact
|
- name: Upload build artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }}
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.determine.outputs.title }}
|
name: manager
|
||||||
path: manager/app/build/outputs/apk/release/*.apk
|
path: manager/app/build/outputs/apk/release/*.apk
|
||||||
|
|
||||||
- name: Upload mappings
|
- name: Upload mappings
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }}
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
with:
|
with:
|
||||||
name: "${{ steps.determine.outputs.title }}-mappings"
|
name: "mappings"
|
||||||
path: "manager/app/build/outputs/mapping/release/"
|
path: "manager/app/build/outputs/mapping/release/"
|
||||||
|
|
||||||
|
- name: Bot session cache
|
||||||
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
|
id: bot_session_cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: scripts/ksubot.session
|
||||||
|
key: ${{ runner.os }}-bot-session
|
||||||
|
|
||||||
- name: Upload to telegram
|
- name: Upload to telegram
|
||||||
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true' && steps.determine.outputs.SKIP != 'true'
|
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
|
||||||
env:
|
env:
|
||||||
CHAT_ID: ${{ vars.CHAT_ID }}
|
CHAT_ID: ${{ vars.CHAT_ID }}
|
||||||
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
MESSAGE_THREAD_ID: ${{ steps.determine.outputs.topicid }}
|
MESSAGE_THREAD_ID: ${{ vars.MESSAGE_THREAD_ID }}
|
||||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||||
COMMIT_URL: ${{ github.event.head_commit.url }}
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
||||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
TITLE: ${{ steps.determine.outputs.title }}
|
TITLE: Manager
|
||||||
BRANCH: ${{ github.ref_name }}
|
|
||||||
run: |
|
run: |
|
||||||
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
export VERSION=$(git rev-list --count HEAD)
|
export VERSION=$(git rev-list --count HEAD)
|
||||||
|
|||||||
2
.github/workflows/clippy.yml
vendored
@@ -34,4 +34,4 @@ jobs:
|
|||||||
- name: Run clippy
|
- name: Run clippy
|
||||||
run: |
|
run: |
|
||||||
cross clippy --manifest-path userspace/ksud/Cargo.toml --target aarch64-linux-android --release
|
cross clippy --manifest-path userspace/ksud/Cargo.toml --target aarch64-linux-android --release
|
||||||
cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release
|
cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release
|
||||||
|
|||||||
53
.github/workflows/ddk-lkm.yml
vendored
@@ -1,53 +0,0 @@
|
|||||||
name: Build KernelSU Kernel Module
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
kmi:
|
|
||||||
description: 'KMI version'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
ddk_release:
|
|
||||||
description: 'DDK release version'
|
|
||||||
required: false
|
|
||||||
default: '20251104'
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-kernelsu-ko:
|
|
||||||
name: Build kernelsu.ko for ${{ inputs.kmi }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ghcr.io/ylarod/ddk:${{ inputs.kmi }}-${{ inputs.ddk_release }}
|
|
||||||
options: --privileged
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout source code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Build kernelsu.ko
|
|
||||||
run: |
|
|
||||||
git config --global --add safe.directory /__w/SukiSU-Ultra/SukiSU-Ultra
|
|
||||||
cd kernel
|
|
||||||
|
|
||||||
echo "=== Building kernelsu.ko for KMI: ${{ inputs.kmi }} ==="
|
|
||||||
CONFIG_KSU=m CONFIG_KSU_MANUAL_SU=y make
|
|
||||||
|
|
||||||
echo "=== Build completed ==="
|
|
||||||
# Create output directory in GitHub workspace
|
|
||||||
mkdir -p /github/workspace/out
|
|
||||||
# Copy with KMI-specific naming
|
|
||||||
OUTPUT_NAME="${{ inputs.kmi }}_kernelsu.ko"
|
|
||||||
cp kernelsu.ko "/github/workspace/out/$OUTPUT_NAME"
|
|
||||||
|
|
||||||
echo "Copied to: /github/workspace/out/$OUTPUT_NAME"
|
|
||||||
ls -la "/github/workspace/out/$OUTPUT_NAME"
|
|
||||||
echo "Size: $(du -h "/github/workspace/out/$OUTPUT_NAME" | cut -f1)"
|
|
||||||
llvm-strip -d "/github/workspace/out/$OUTPUT_NAME"
|
|
||||||
echo "Size after stripping: $(du -h "/github/workspace/out/$OUTPUT_NAME" | cut -f1)"
|
|
||||||
|
|
||||||
- name: Upload kernelsu.ko artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.kmi }}-lkm
|
|
||||||
path: /github/workspace/out/${{ inputs.kmi }}_kernelsu.ko
|
|
||||||
2
.github/workflows/deploy-website.yml
vendored
@@ -64,4 +64,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v4
|
uses: actions/deploy-pages@v4
|
||||||
|
|||||||
252
.github/workflows/gki-kernel-local.yml
vendored
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
name: GKI Kernel Build Local
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Output directory of gki,
|
||||||
|
for example: android12-5.10
|
||||||
|
version_name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
With SUBLEVEL of kernel,
|
||||||
|
for example: android12-5.10.66
|
||||||
|
tag:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Part of branch name of common kernel manifest,
|
||||||
|
for example: android12-5.10-2021-11
|
||||||
|
os_patch_level:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Patch level of common kernel manifest,
|
||||||
|
for example: 2021-11
|
||||||
|
default: 2022-05
|
||||||
|
patch_path:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Directory name of .github/patches/<patch_path>
|
||||||
|
for example: 5.10
|
||||||
|
use_cache:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
embed_ksud:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ksud-aarch64-linux-android
|
||||||
|
description: >
|
||||||
|
Artifact name of prebuilt ksud to be embedded
|
||||||
|
for example: ksud-aarch64-linux-android
|
||||||
|
debug:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
build_lkm:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
secrets:
|
||||||
|
BOOT_SIGN_KEY:
|
||||||
|
required: false
|
||||||
|
CHAT_ID:
|
||||||
|
required: false
|
||||||
|
BOT_TOKEN:
|
||||||
|
required: false
|
||||||
|
MESSAGE_THREAD_ID:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build ${{ inputs.version_name }}
|
||||||
|
runs-on: self-hosted
|
||||||
|
env:
|
||||||
|
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||||
|
CCACHE_NOHASHDIR: "true"
|
||||||
|
CCACHE_HARDLINK: "true"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: KernelSU
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup need_upload
|
||||||
|
id: need_upload
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
|
||||||
|
echo "UPLOAD=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "UPLOAD=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Setup kernel source
|
||||||
|
run: |
|
||||||
|
echo "Free space:"
|
||||||
|
df -h
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
sudo apt-get install repo -y
|
||||||
|
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
|
||||||
|
mkdir android-kernel && cd android-kernel
|
||||||
|
repo init --depth=1 --u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.35
|
||||||
|
REMOTE_BRANCH=$(git ls-remote https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/kernel/common ${{ inputs.tag }})
|
||||||
|
DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
|
||||||
|
if grep -q deprecated <<< $REMOTE_BRANCH; then
|
||||||
|
echo "Found deprecated branch: ${{ inputs.tag }}"
|
||||||
|
sed -i 's/"${{ inputs.tag }}"/"deprecated\/${{ inputs.tag }}"/g' $DEFAULT_MANIFEST_PATH
|
||||||
|
cat $DEFAULT_MANIFEST_PATH
|
||||||
|
fi
|
||||||
|
repo --version
|
||||||
|
repo --trace sync -c -j$(nproc --all) --no-tags
|
||||||
|
df -h
|
||||||
|
|
||||||
|
- name: Setup KernelSU
|
||||||
|
env:
|
||||||
|
PATCH_PATH: ${{ inputs.patch_path }}
|
||||||
|
IS_DEBUG_KERNEL: ${{ inputs.debug }}
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/android-kernel
|
||||||
|
echo "[+] KernelSU setup"
|
||||||
|
GKI_ROOT=$(pwd)
|
||||||
|
echo "[+] GKI_ROOT: $GKI_ROOT"
|
||||||
|
echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers"
|
||||||
|
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
|
||||||
|
echo "[+] Add KernelSU driver to Makefile"
|
||||||
|
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
|
||||||
|
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
|
||||||
|
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
|
||||||
|
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
|
||||||
|
echo "[+] Apply Compilation Patches"
|
||||||
|
if [ ! -e build/build.sh ]; then
|
||||||
|
GLIBC_VERSION=$(ldd --version 2>/dev/null | head -n 1 | awk '{print $NF}')
|
||||||
|
echo "GLIBC_VERSION: $GLIBC_VERSION"
|
||||||
|
if [ "$(printf '%s\n' "2.38" "$GLIBC_VERSION" | sort -V | head -n1)" = "2.38" ]; then
|
||||||
|
echo "Patching resolve_btfids/Makefile"
|
||||||
|
cd $GKI_ROOT/common/ && sed -i '/\$(Q)\$(MAKE) -C \$(SUBCMD_SRC) OUTPUT=\$(abspath \$(dir \$@))\/ \$(abspath \$@)/s//$(Q)$(MAKE) -C $(SUBCMD_SRC) EXTRA_CFLAGS="$(CFLAGS)" OUTPUT=$(abspath $(dir $@))\/ $(abspath $@)/' tools/bpf/resolve_btfids/Makefile || echo "No patch needed."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
|
||||||
|
echo "[+] Enable debug features for kernel"
|
||||||
|
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
|
||||||
|
fi
|
||||||
|
repo status
|
||||||
|
echo "[+] KernelSU setup done."
|
||||||
|
|
||||||
|
- name: Symbol magic
|
||||||
|
run: |
|
||||||
|
echo "[+] Export all symbol from abi_gki_aarch64.xml"
|
||||||
|
COMMON_ROOT=$GITHUB_WORKSPACE/android-kernel/common
|
||||||
|
KSU_ROOT=$GITHUB_WORKSPACE/KernelSU
|
||||||
|
ABI_XML=$COMMON_ROOT/android/abi_gki_aarch64.xml
|
||||||
|
SYMBOL_LIST=$COMMON_ROOT/android/abi_gki_aarch64
|
||||||
|
# python3 $KSU_ROOT/scripts/abi_gki_all.py $ABI_XML > $SYMBOL_LIST
|
||||||
|
echo "[+] Add KernelSU symbols"
|
||||||
|
cat $KSU_ROOT/kernel/export_symbol.txt | awk '{sub("[ \t]+","");print " "$0}' >> $SYMBOL_LIST
|
||||||
|
|
||||||
|
- name: Setup ccache
|
||||||
|
if: inputs.use_cache == true
|
||||||
|
uses: hendrikmuhs/ccache-action@v1
|
||||||
|
with:
|
||||||
|
key: gki-kernel-aarch64-${{ inputs.version_name }}
|
||||||
|
max-size: 2G
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
|
- name: Setup for LKM
|
||||||
|
if: ${{ inputs.build_lkm == true }}
|
||||||
|
working-directory: android-kernel
|
||||||
|
run: |
|
||||||
|
pip install ast-grep-cli
|
||||||
|
sudo apt-get install llvm-15 -y
|
||||||
|
ast-grep -U -p '$$$ check_exports($$$) {$$$}' -r '' common/scripts/mod/modpost.c
|
||||||
|
ast-grep -U -p 'check_exports($$$);' -r '' common/scripts/mod/modpost.c
|
||||||
|
sed -i '/config KSU/,/help/{s/default y/default m/}' common/drivers/kernelsu/Kconfig
|
||||||
|
echo "drivers/kernelsu/kernelsu.ko" >> common/android/gki_aarch64_modules
|
||||||
|
|
||||||
|
# bazel build, android14-5.15, android14-6.1 use bazel
|
||||||
|
if [ ! -e build/build.sh ]; then
|
||||||
|
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
|
||||||
|
if [ -e common/modules.bzl ]; then
|
||||||
|
sed -i 's/_COMMON_GKI_MODULES_LIST = \[/_COMMON_GKI_MODULES_LIST = \[ "drivers\/kernelsu\/kernelsu.ko",/g' common/modules.bzl
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
TARGET_FILE="build/kernel/build.sh"
|
||||||
|
if [ ! -e "$TARGET_FILE" ]; then
|
||||||
|
TARGET_FILE="build/build.sh"
|
||||||
|
fi
|
||||||
|
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' $TARGET_FILE || echo "No unknown symbol in $TARGET_FILE"
|
||||||
|
sed -i 's/if ! diff -u "\${KERNEL_DIR}\/\${MODULES_ORDER}" "\${OUT_DIR}\/modules\.order"; then/if false; then/g' $TARGET_FILE
|
||||||
|
sed -i 's@${ROOT_DIR}/build/abi/compare_to_symbol_list@echo@g' $TARGET_FILE
|
||||||
|
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Make working directory clean to avoid dirty
|
||||||
|
working-directory: android-kernel
|
||||||
|
run: |
|
||||||
|
if [ -e common/BUILD.bazel ]; then
|
||||||
|
sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
|
||||||
|
fi
|
||||||
|
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
|
||||||
|
git config --global user.email "bot@kernelsu.org"
|
||||||
|
git config --global user.name "KernelSUBot"
|
||||||
|
cd common/ && git add -A && git commit -a -m "Add KernelSU"
|
||||||
|
repo status
|
||||||
|
|
||||||
|
- name: Build Kernel/LKM
|
||||||
|
working-directory: android-kernel
|
||||||
|
run: |
|
||||||
|
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
|
||||||
|
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
|
||||||
|
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
|
||||||
|
fi
|
||||||
|
if [ -e build/build.sh ]; then
|
||||||
|
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
|
||||||
|
else
|
||||||
|
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Prepare artifacts
|
||||||
|
id: prepareArtifacts
|
||||||
|
run: |
|
||||||
|
OUTDIR=android-kernel/out/${{ inputs.version }}/dist
|
||||||
|
if [ ! -e $OUTDIR ]; then
|
||||||
|
OUTDIR=android-kernel/dist
|
||||||
|
fi
|
||||||
|
mkdir output
|
||||||
|
if [ "${{ inputs.build_lkm}}" = "true" ]; then
|
||||||
|
llvm-strip-15 -d $OUTDIR/kernelsu.ko
|
||||||
|
mv $OUTDIR/kernelsu.ko ./output/${{ inputs.version }}_kernelsu.ko
|
||||||
|
else
|
||||||
|
cp $OUTDIR/Image ./output/
|
||||||
|
cp $OUTDIR/Image.lz4 ./output/
|
||||||
|
git clone https://github.com/Kernel-SU/AnyKernel3
|
||||||
|
rm -rf ./AnyKernel3/.git
|
||||||
|
cp $OUTDIR/Image ./AnyKernel3/
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload Image and Image.gz
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: ${{ inputs.build_lkm == false }}
|
||||||
|
with:
|
||||||
|
name: Image-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
|
||||||
|
path: ./output/*
|
||||||
|
|
||||||
|
- name: Upload AnyKernel3
|
||||||
|
if: ${{ inputs.build_lkm == false }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
|
||||||
|
path: ./AnyKernel3/*
|
||||||
|
|
||||||
|
- name: Upload LKM
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: ${{ inputs.build_lkm == true }}
|
||||||
|
with:
|
||||||
|
name: ${{ inputs.version }}-lkm
|
||||||
|
path: ./output/*_kernelsu.ko
|
||||||
79
.github/workflows/gki-kernel-mock.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
name: GKI Kernel Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Output directory of gki,
|
||||||
|
for example: android12-5.10
|
||||||
|
version_name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
With SUBLEVEL of kernel,
|
||||||
|
for example: android12-5.10.66
|
||||||
|
tag:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Part of branch name of common kernel manifest,
|
||||||
|
for example: android12-5.10-2021-11
|
||||||
|
os_patch_level:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Patch level of common kernel manifest,
|
||||||
|
for example: 2021-11
|
||||||
|
default: 2022-05
|
||||||
|
patch_path:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
description: >
|
||||||
|
Directory name of .github/patches/<patch_path>
|
||||||
|
for example: 5.10
|
||||||
|
use_cache:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
embed_ksud:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ksud-aarch64-linux-android
|
||||||
|
description: >
|
||||||
|
Artifact name of prebuilt ksud to be embedded
|
||||||
|
for example: ksud-aarch64-linux-android
|
||||||
|
debug:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
build_lkm:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
secrets:
|
||||||
|
BOOT_SIGN_KEY:
|
||||||
|
required: false
|
||||||
|
CHAT_ID:
|
||||||
|
required: false
|
||||||
|
BOT_TOKEN:
|
||||||
|
required: false
|
||||||
|
MESSAGE_THREAD_ID:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
mock_build:
|
||||||
|
name: Mock build ${{ inputs.version_name }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Create mocking ko
|
||||||
|
run: |
|
||||||
|
echo "${{ inputs.version }}_kernelsu.ko" > ${{ inputs.version }}_kernelsu.ko
|
||||||
|
- name: Upload LKM
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: ${{ inputs.build_lkm == true }}
|
||||||
|
with:
|
||||||
|
name: ${{ inputs.version }}-lkm
|
||||||
|
path: ./*_kernelsu.ko
|
||||||
45
.github/workflows/gki-kernel.yml
vendored
@@ -77,10 +77,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
root-reserve-mb: 8192
|
root-reserve-mb: 8192
|
||||||
temp-reserve-mb: 2048
|
temp-reserve-mb: 2048
|
||||||
remove-dotnet: "true"
|
remove-dotnet: 'true'
|
||||||
remove-android: "true"
|
remove-android: 'true'
|
||||||
remove-haskell: "true"
|
remove-haskell: 'true'
|
||||||
remove-codeql: "true"
|
remove-codeql: 'true'
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -103,7 +103,7 @@ jobs:
|
|||||||
cd $GITHUB_WORKSPACE
|
cd $GITHUB_WORKSPACE
|
||||||
sudo apt-get install repo -y
|
sudo apt-get install repo -y
|
||||||
mkdir android-kernel && cd android-kernel
|
mkdir android-kernel && cd android-kernel
|
||||||
repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.16
|
repo init --depth=1 --u https://android.googlesource.com/kernel/manifest -b common-${{ inputs.tag }} --repo-rev=v2.35
|
||||||
REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${{ inputs.tag }})
|
REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/kernel/common ${{ inputs.tag }})
|
||||||
DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
|
DEFAULT_MANIFEST_PATH=.repo/manifests/default.xml
|
||||||
if grep -q deprecated <<< $REMOTE_BRANCH; then
|
if grep -q deprecated <<< $REMOTE_BRANCH; then
|
||||||
@@ -195,35 +195,12 @@ jobs:
|
|||||||
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
|
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Append ashmem exports if missing
|
|
||||||
if: startsWith(inputs.version, 'android16-6.12')
|
|
||||||
working-directory: android-kernel
|
|
||||||
run: |
|
|
||||||
FILE=common/drivers/staging/android/ashmem.c
|
|
||||||
if [[ -f "$FILE" ]] && ! grep -q 'is_ashmem_file' "$FILE"; then
|
|
||||||
cat >>"$FILE" <<'EOF'
|
|
||||||
|
|
||||||
bool is_ashmem_file(struct file *file) { return false; }
|
|
||||||
int ashmem_area_name(struct file *file, char *name) { return 0; }
|
|
||||||
long ashmem_area_size(struct file *file) { return 0; }
|
|
||||||
struct file *ashmem_area_vmfile(struct file *file) { return NULL; }
|
|
||||||
EXPORT_SYMBOL_GPL(is_ashmem_file);
|
|
||||||
EXPORT_SYMBOL_GPL(ashmem_area_name);
|
|
||||||
EXPORT_SYMBOL_GPL(ashmem_area_size);
|
|
||||||
EXPORT_SYMBOL_GPL(ashmem_area_vmfile);
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -i -E 's/\$\(CONFIG_ANDROID_BINDER_IPC_RUST\)/m/g' common/drivers/android/Makefile
|
|
||||||
|
|
||||||
- name: Make working directory clean to avoid dirty
|
- name: Make working directory clean to avoid dirty
|
||||||
working-directory: android-kernel
|
working-directory: android-kernel
|
||||||
run: |
|
run: |
|
||||||
# Fix bazel build error
|
if [ -e common/BUILD.bazel ]; then
|
||||||
if [ -f common/BUILD.bazel ]; then
|
sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
|
||||||
[ -f android/abi_gki_protected_exports_aarch64 ] || sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
|
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
|
||||||
git config --global user.email "bot@kernelsu.org"
|
git config --global user.email "bot@kernelsu.org"
|
||||||
git config --global user.name "KernelSUBot"
|
git config --global user.name "KernelSUBot"
|
||||||
@@ -240,11 +217,7 @@ jobs:
|
|||||||
if [ -e build/build.sh ]; then
|
if [ -e build/build.sh ]; then
|
||||||
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
|
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
|
||||||
else
|
else
|
||||||
if [ "${{ inputs.version }}" == "android16-6.12" ]; then
|
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
|
||||||
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --destdir=dist
|
|
||||||
else
|
|
||||||
tools/bazel run --disk_cache=/home/runner/.cache/bazel --config=fast --config=stamp --lto=thin //common:kernel_aarch64_dist -- --dist_dir=dist
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Prepare artifacts
|
- name: Prepare artifacts
|
||||||
@@ -255,7 +228,7 @@ jobs:
|
|||||||
OUTDIR=android-kernel/dist
|
OUTDIR=android-kernel/dist
|
||||||
fi
|
fi
|
||||||
mkdir output
|
mkdir output
|
||||||
if [ "${{ inputs.build_lkm}}" = "true" ]; then
|
if [ "${{ inputs.build_lkm}}" = "true" ]; then
|
||||||
llvm-strip-15 -d $OUTDIR/kernelsu.ko
|
llvm-strip-15 -d $OUTDIR/kernelsu.ko
|
||||||
mv $OUTDIR/kernelsu.ko ./output/${{ inputs.version }}_kernelsu.ko
|
mv $OUTDIR/kernelsu.ko ./output/${{ inputs.version }}_kernelsu.ko
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: Build user_scanner
|
name: Build kpmmgr
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "mian" ]
|
branches: [ "mian" ]
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/user_scanner.yml'
|
- '.github/workflows/kpmmgr.yml'
|
||||||
- 'userspace/user_scanner/**'
|
- 'userspace/kpmmgr/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
@@ -18,8 +18,8 @@ on:
|
|||||||
default: self-hosted
|
default: self-hosted
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-user_scanner:
|
build-susfs:
|
||||||
name: Build userspace user_scanner
|
name: Build userspace kpmmgr
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -28,13 +28,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Build user_scanner
|
- name: Build kpmmgr
|
||||||
working-directory: ./userspace/user_scanner
|
working-directory: ./userspace/kpmmgr
|
||||||
run: |
|
run: |
|
||||||
$ANDROID_NDK_HOME/ndk-build
|
$ANDROID_NDK_HOME/ndk-build
|
||||||
|
|
||||||
- name: Upload a Build Artifact
|
- name: Upload a Build Artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: userscanner-all-linux-android
|
name: kpmmgr-aarch64-linux-android
|
||||||
path: ./userspace/user_scanner/libs
|
path: ./userspace/kpmmgr/libs
|
||||||
35
.github/workflows/ksud.yml
vendored
@@ -9,6 +9,10 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
default: ubuntu-latest
|
default: ubuntu-latest
|
||||||
|
pull_lkm:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
pack_lkm:
|
pack_lkm:
|
||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
@@ -17,8 +21,6 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ inputs.os }}
|
runs-on: ${{ inputs.os }}
|
||||||
@@ -27,19 +29,36 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download artifacts
|
- name: Pull lkms from branch
|
||||||
|
if: ${{ inputs.pack_lkm && inputs.pull_lkm }}
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: lkm
|
||||||
|
path: lkm
|
||||||
|
|
||||||
|
- name: Download lkms from artifacts
|
||||||
|
if: ${{ inputs.pack_lkm && !inputs.pull_lkm }}
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Prepare LKM fies
|
- name: Prepare LKM files
|
||||||
if: ${{ inputs.pack_lkm }}
|
if: ${{ inputs.pack_lkm && inputs.pull_lkm }}
|
||||||
|
run: |
|
||||||
|
cp lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/
|
||||||
|
|
||||||
|
- name: Prepare LKM files
|
||||||
|
if: ${{ inputs.pack_lkm && !inputs.pull_lkm }}
|
||||||
run: |
|
run: |
|
||||||
cp android*-lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/
|
cp android*-lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/
|
||||||
|
|
||||||
- name: Setup rustup
|
- name: Setup rustup
|
||||||
run: |
|
run: |
|
||||||
rustup update stable
|
rustup update stable
|
||||||
rustup target add x86_64-apple-darwin
|
rustup target add x86_64-apple-darwin
|
||||||
rustup target add aarch64-apple-darwin
|
rustup target add aarch64-apple-darwin
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: userspace/ksud
|
||||||
|
cache-targets: false
|
||||||
|
|
||||||
- name: Install cross
|
- name: Install cross
|
||||||
run: |
|
run: |
|
||||||
@@ -52,4 +71,4 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ksud-${{ inputs.target }}
|
name: ksud-${{ inputs.target }}
|
||||||
path: userspace/ksud/target/**/release/ksud*
|
path: userspace/ksud/target/**/release/zakozako*
|
||||||
|
|||||||
2
.github/workflows/shellcheck.yml
vendored
@@ -16,7 +16,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
shellcheck:
|
shellcheck:
|
||||||
runs-on: ubuntu-latest
|
runs-on: self-hosted
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|||||||
40
.github/workflows/susfs.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: Build susfs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "mian" ]
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/susfs.yml'
|
||||||
|
- 'userspace/susfs/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
target:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
os:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: self-hosted
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-susfs:
|
||||||
|
name: Build userspace susfs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Build susfs
|
||||||
|
working-directory: ./userspace/susfs
|
||||||
|
run: |
|
||||||
|
$ANDROID_NDK_HOME/ndk-build
|
||||||
|
|
||||||
|
- name: Upload a Build Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: susfs-aarch64-linux-android
|
||||||
|
path: ./userspace/susfs/libs
|
||||||
2
.gitignore
vendored
@@ -1,3 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
CLAUDE.md
|
.vscode
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# SukiSU Ultra
|
<img align='right' src='zakomonochrome-128.svg' width='100px' alt="logo">
|
||||||
<img align='right' src='SukiSU-mini.svg' width='220px' alt="sukisu logo">
|
|
||||||
|
|
||||||
|
# SukiSU Ultra
|
||||||
|
|
||||||
**English** | [简体中文](./zh/README.md) | [日本語](./ja/README.md) | [Türkçe](./tr/README.md)
|
**English** | [简体中文](./zh/README.md) | [日本語](./ja/README.md) | [Türkçe](./tr/README.md)
|
||||||
|
|
||||||
@@ -15,7 +15,6 @@ A kernel-based root solution for Android devices, forked from [`tiann/KernelSU`]
|
|||||||
|
|
||||||
1. Kernel-based `su` and root access management
|
1. Kernel-based `su` and root access management
|
||||||
2. Module system based on [Magic Mount](https://github.com/5ec1cff/KernelSU)
|
2. Module system based on [Magic Mount](https://github.com/5ec1cff/KernelSU)
|
||||||
> **Note:** SukiSU now delegates all module mounting to the installed *metamodule*; the core no longer handles mount operations.
|
|
||||||
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Lock up the root power in a cage
|
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Lock up the root power in a cage
|
||||||
4. Support non-GKI and GKI 1.0
|
4. Support non-GKI and GKI 1.0
|
||||||
5. KPM Support
|
5. KPM Support
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 185 KiB |
188
docs/SukiSU.svg
|
Before Width: | Height: | Size: 200 KiB |
@@ -24,12 +24,6 @@ Prerequisites: open source bootable kernel.
|
|||||||
- Requires [`guide/how-to-integrate.md`](guide/how-to-integrate.md)
|
- Requires [`guide/how-to-integrate.md`](guide/how-to-integrate.md)
|
||||||
- Requires [https://github.com/~](https://github.com/tiann/KernelSU/blob/main/website/docs/guide/how-to-integrate-for-non-gki.md#manually-modify-the-kernel-source)
|
- Requires [https://github.com/~](https://github.com/tiann/KernelSU/blob/main/website/docs/guide/how-to-integrate-for-non-gki.md#manually-modify-the-kernel-source)
|
||||||
|
|
||||||
3. **Tracepoint Hook:**
|
|
||||||
|
|
||||||
- Hook method introduced since SukiSU commit [49b01aad](https://github.com/SukiSU-Ultra/SukiSU-Ultra/commit/49b01aad74bcca6dba5a8a2e053bb54b648eb124)
|
|
||||||
- Requires `CONFIG_KSU_TRACEPOINT_HOOK=y`
|
|
||||||
- Requires [`guide/tracepoint-hook.md`](tracepoint-hook.md)
|
|
||||||
|
|
||||||
<!-- This part refer to [rsuntk/KernelSU](https://github.com/rsuntk/KernelSU). -->
|
<!-- This part refer to [rsuntk/KernelSU](https://github.com/rsuntk/KernelSU). -->
|
||||||
|
|
||||||
If you're able to build a bootable kernel, there are two ways to integrate KernelSU into the kernel source code:
|
If you're able to build a bootable kernel, there are two ways to integrate KernelSU into the kernel source code:
|
||||||
|
|||||||
@@ -1,239 +0,0 @@
|
|||||||
# Tracepoint Hook Integration
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Since commit [49b01aad](https://github.com/SukiSU-Ultra/SukiSU-Ultra/commit/49b01aad74bcca6dba5a8a2e053bb54b648eb124), SukiSU has introduced Tracepoint Hook
|
|
||||||
|
|
||||||
This Hook theoretically has lower performance overhead compared to Kprobes Hook, but is inferior to Manual Hook / Syscall Hook
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> This tutorial references the syscall hook v1.4 version from [backslashxx/KernelSU#5](https://github.com/backslashxx/KernelSU/issues/5), as well as the original KernelSU's [Manual Hook](https://kernelsu.org/guide/how-to-integrate-for-non-gki.html#manually-modify-the-kernel-source)
|
|
||||||
|
|
||||||
## Guide
|
|
||||||
|
|
||||||
### execve Hook (`exec.c`)
|
|
||||||
|
|
||||||
Generally need to modify the `do_execve` and `compat_do_execve` methods in `fs/exec.c`
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/exec.c
|
|
||||||
+++ b/fs/exec.c
|
|
||||||
@@ -78,6 +78,10 @@
|
|
||||||
#include <trace/hooks/sched.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(task_rename);
|
|
||||||
|
|
||||||
static int bprm_creds_from_file(struct linux_binprm *bprm);
|
|
||||||
@@ -2037,6 +2041,9 @@ static int do_execve(struct filename *filename,
|
|
||||||
{
|
|
||||||
struct user_arg_ptr argv = { .ptr.native = __argv };
|
|
||||||
struct user_arg_ptr envp = { .ptr.native = __envp };
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_execveat_hook((int *)AT_FDCWD, &filename, &argv, &envp, 0);
|
|
||||||
+#endif
|
|
||||||
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2064,6 +2071,9 @@ static int compat_do_execve(struct filename *filename,
|
|
||||||
.is_compat = true,
|
|
||||||
.ptr.compat = __envp,
|
|
||||||
};
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_execveat_hook((int *)AT_FDCWD, &filename, &argv, &envp, 0); // 32-bit su and 32-on-64 support
|
|
||||||
+#endif
|
|
||||||
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### faccessat Hook (`open.c`)
|
|
||||||
|
|
||||||
Generally need to modify the `do_faccessat` method in `/fs/open.c`
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/open.c
|
|
||||||
+++ b/fs/open.c
|
|
||||||
@@ -37,6 +37,10 @@
|
|
||||||
#include "internal.h"
|
|
||||||
#include <trace/hooks/syscall_check.h>
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry,
|
|
||||||
loff_t length, unsigned int time_attrs, struct file *filp)
|
|
||||||
{
|
|
||||||
@@ -468,6 +472,9 @@ static long do_faccessat(int dfd, const char __user *filename, int mode, int fla
|
|
||||||
|
|
||||||
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
|
||||||
{
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_faccessat_hook(&dfd, &filename, &mode, NULL);
|
|
||||||
+#endif
|
|
||||||
return do_faccessat(dfd, filename, mode, 0);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If there's no `do_faccessat` method, you can find the `faccessat` SYSCALL definition (for kernels earlier than 4.17)
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/open.c
|
|
||||||
+++ b/fs/open.c
|
|
||||||
@@ -31,6 +31,9 @@
|
|
||||||
#include <linux/ima.h>
|
|
||||||
#include <linux/dnotify.h>
|
|
||||||
#include <linux/compat.h>
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
#include "internal.h"
|
|
||||||
|
|
||||||
@@ -369,6 +372,9 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
|
||||||
int res;
|
|
||||||
unsigned int lookup_flags = LOOKUP_FOLLOW;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_faccessat_hook(&dfd, &filename, &mode, NULL);
|
|
||||||
+#endif
|
|
||||||
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
|
||||||
return -EINVAL;
|
|
||||||
```
|
|
||||||
|
|
||||||
### sys_read Hook (`read_write.c`)
|
|
||||||
|
|
||||||
Need to modify the `sys_read` method in `fs/read_write.c` (4.19 and above)
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/read_write.c
|
|
||||||
+++ b/fs/read_write.c
|
|
||||||
@@ -25,6 +25,10 @@
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
const struct file_operations generic_ro_fops = {
|
|
||||||
.llseek = generic_file_llseek,
|
|
||||||
.read_iter = generic_file_read_iter,
|
|
||||||
@@ -630,6 +634,9 @@ ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
|
|
||||||
|
|
||||||
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
|
|
||||||
{
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_sys_read_hook(fd, &buf, &count);
|
|
||||||
+#endif
|
|
||||||
return ksys_read(fd, buf, count);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or the `read` SYSCALL definition (4.14 and below)
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/read_write.c
|
|
||||||
+++ b/fs/read_write.c
|
|
||||||
@@ -25,6 +25,11 @@
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+
|
|
||||||
const struct file_operations generic_ro_fops = {
|
|
||||||
.llseek = generic_file_llseek,
|
|
||||||
.read_iter = generic_file_read_iter,
|
|
||||||
@@ -575,6 +580,9 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
|
|
||||||
|
|
||||||
if (f.file) {
|
|
||||||
loff_t pos = file_pos_read(f.file);
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_sys_read_hook(fd, &buf, &count);
|
|
||||||
+#endif
|
|
||||||
ret = vfs_read(f.file, buf, count, &pos);
|
|
||||||
if (ret >= 0)
|
|
||||||
file_pos_write(f.file, pos);
|
|
||||||
```
|
|
||||||
|
|
||||||
### fstatat Hook (`stat.c`)
|
|
||||||
|
|
||||||
Need to modify the `newfstatat` SYSCALL definition in `stat.c`
|
|
||||||
|
|
||||||
If 32-bit support is needed, also need to modify the `statat64` SYSCALL definition
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/stat.c
|
|
||||||
+++ b/fs/stat.c
|
|
||||||
@@ -24,6 +24,10 @@
|
|
||||||
#include "internal.h"
|
|
||||||
#include "mount.h"
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
/**
|
|
||||||
* generic_fillattr - Fill in the basic attributes from the inode struct
|
|
||||||
* @mnt_userns: user namespace of the mount the inode was found from
|
|
||||||
@@ -408,6 +412,10 @@ SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename,
|
|
||||||
struct kstat stat;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_stat_hook(&dfd, &filename, &flag);
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
@@ -559,6 +567,10 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
|
|
||||||
struct kstat stat;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_stat_hook(&dfd, &filename, &flag); /* 32-bit su support */
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
```
|
|
||||||
|
|
||||||
### input Hook (`input.c`, for entering KSU built-in security mode)
|
|
||||||
|
|
||||||
Need to modify the `input_event` method in `drivers/input/input.c`, not `input_handle_event`
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/drivers/input/input.c
|
|
||||||
+++ b/drivers/input/input.c
|
|
||||||
@@ -26,6 +26,10 @@
|
|
||||||
#include "input-compat.h"
|
|
||||||
#include "input-poller.h"
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
|
|
||||||
MODULE_DESCRIPTION("Input core");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
@@ -451,6 +455,10 @@ void input_event(struct input_dev *dev,
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_input_hook(&type, &code, &value);
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
if (is_event_supported(type, dev->evbit, EV_MAX)) {
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->event_lock, flags);
|
|
||||||
```
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
# SukiSU Ultra
|
# SukiSU Ultra
|
||||||
<img align='right' src='SukiSU-mini.svg' width='220px' alt="sukisu logo">
|
|
||||||
|
|
||||||
|
|
||||||
[English](../README.md) | [简体中文](../zh/README.md) | **日本語** | [Türkçe](../tr/README.md)
|
[English](../README.md) | [简体中文](../zh/README.md) | **日本語** | [Türkçe](../tr/README.md)
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 185 KiB |
@@ -1,6 +1,4 @@
|
|||||||
# SukiSU Ultra
|
# SukiSU Ultra
|
||||||
<img align='right' src='SukiSU-mini.svg' width='250px' alt="sukisu logo">
|
|
||||||
|
|
||||||
|
|
||||||
[English](../README.md) | [简体中文](../zh/README.md) | [日本語](../ja/README.md) | **Türkçe**
|
[English](../README.md) | [简体中文](../zh/README.md) | [日本語](../ja/README.md) | **Türkçe**
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 185 KiB |
@@ -1,6 +1,6 @@
|
|||||||
# SukiSU Ultra
|
<img align='right' src='zakomonochrome-128.svg' width='100px' alt="logo">
|
||||||
<img align='right' src='SukiSU-mini.svg' width='220px' alt="sukisu logo">
|
|
||||||
|
|
||||||
|
# SukiSU Ultra
|
||||||
|
|
||||||
[English](../README.md) | **简体中文** | [日本語](../ja/README.md) | [Türkçe](../tr/README.md)
|
[English](../README.md) | **简体中文** | [日本語](../ja/README.md) | [Türkçe](../tr/README.md)
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 200 KiB |
@@ -21,15 +21,9 @@ SukiSU 可以集成到 GKI 和 non-GKI 内核中,并且已反向移植到 4.14
|
|||||||
<!-- - backslashxx's syscall manual hook: https://github.com/backslashxx/KernelSU/issues/5 (v1.5 version is not available at the moment, if you want to use it, please use v1.4 version, or standard KernelSU hooks)-->
|
<!-- - backslashxx's syscall manual hook: https://github.com/backslashxx/KernelSU/issues/5 (v1.5 version is not available at the moment, if you want to use it, please use v1.4 version, or standard KernelSU hooks)-->
|
||||||
|
|
||||||
- 需要 `CONFIG_KSU_MANUAL_HOOK=y`
|
- 需要 `CONFIG_KSU_MANUAL_HOOK=y`
|
||||||
- 需要 [`guide/how-to-integrate.md`](how-to-integrate.md)
|
- 需要 [`guide/how-to-integrate.md`](guide/how-to-integrate.md)
|
||||||
- 需要 [https://github.com/~](https://github.com/tiann/KernelSU/blob/main/website/docs/guide/how-to-integrate-for-non-gki.md#manually-modify-the-kernel-source)
|
- 需要 [https://github.com/~](https://github.com/tiann/KernelSU/blob/main/website/docs/guide/how-to-integrate-for-non-gki.md#manually-modify-the-kernel-source)
|
||||||
|
|
||||||
3. **Tracepoint Hook:**
|
|
||||||
|
|
||||||
- 自 SukiSU commit [49b01aad](https://github.com/SukiSU-Ultra/SukiSU-Ultra/commit/49b01aad74bcca6dba5a8a2e053bb54b648eb124) 引入的 hook 方法
|
|
||||||
- 需要 `CONFIG_KSU_TRACEPOINT_HOOK=y`
|
|
||||||
- 需要 [`guide/tracepoint-hook.md`](tracepoint-hook.md)
|
|
||||||
|
|
||||||
<!-- This part refer to [rsuntk/KernelSU](https://github.com/rsuntk/KernelSU). -->
|
<!-- This part refer to [rsuntk/KernelSU](https://github.com/rsuntk/KernelSU). -->
|
||||||
|
|
||||||
如果您能够构建可启动内核,有两种方法可以将 KernelSU 集成到内核源代码中:
|
如果您能够构建可启动内核,有两种方法可以将 KernelSU 集成到内核源代码中:
|
||||||
|
|||||||
@@ -1,239 +0,0 @@
|
|||||||
# Tracepoint Hook 集成
|
|
||||||
|
|
||||||
## 介绍
|
|
||||||
|
|
||||||
自 commit [49b01aad](https://github.com/SukiSU-Ultra/SukiSU-Ultra/commit/49b01aad74bcca6dba5a8a2e053bb54b648eb124) 起,SukiSU 引入了 Tracepoint Hook
|
|
||||||
|
|
||||||
该 Hook 理论上相比于 Kprobes Hook,性能开销更小,但次于 Manual Hook / Syscall Hook
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> 本教程参考了 [backslashxx/KernelSU#5](https://github.com/backslashxx/KernelSU/issues/5) 的 syscall hook v1.4 版本钩子,以及原版 KernelSU 的 [Manual Hook](https://kernelsu.org/guide/how-to-integrate-for-non-gki.html#manually-modify-the-kernel-source)
|
|
||||||
|
|
||||||
## Guide
|
|
||||||
|
|
||||||
### execve 钩子(`exec.c`)
|
|
||||||
|
|
||||||
一般需要修改 `fs/exec.c` 的 `do_execve` 和 `compat_do_execve` 方法
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/exec.c
|
|
||||||
+++ b/fs/exec.c
|
|
||||||
@@ -78,6 +78,10 @@
|
|
||||||
#include <trace/hooks/sched.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(task_rename);
|
|
||||||
|
|
||||||
static int bprm_creds_from_file(struct linux_binprm *bprm);
|
|
||||||
@@ -2037,6 +2041,9 @@ static int do_execve(struct filename *filename,
|
|
||||||
{
|
|
||||||
struct user_arg_ptr argv = { .ptr.native = __argv };
|
|
||||||
struct user_arg_ptr envp = { .ptr.native = __envp };
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_execveat_hook((int *)AT_FDCWD, &filename, &argv, &envp, 0);
|
|
||||||
+#endif
|
|
||||||
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2064,6 +2071,9 @@ static int compat_do_execve(struct filename *filename,
|
|
||||||
.is_compat = true,
|
|
||||||
.ptr.compat = __envp,
|
|
||||||
};
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_execveat_hook((int *)AT_FDCWD, &filename, &argv, &envp, 0)); // 32-bit su and 32-on-64 support
|
|
||||||
+#endif
|
|
||||||
return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### faccessat 钩子 (`open.c`)
|
|
||||||
|
|
||||||
一般需要修改 `/fs/open.c` 的 `do_faccessat` 方法
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/open.c
|
|
||||||
+++ b/fs/open.c
|
|
||||||
@@ -37,6 +37,10 @@
|
|
||||||
#include "internal.h"
|
|
||||||
#include <trace/hooks/syscall_check.h>
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry,
|
|
||||||
loff_t length, unsigned int time_attrs, struct file *filp)
|
|
||||||
{
|
|
||||||
@@ -468,6 +472,9 @@ static long do_faccessat(int dfd, const char __user *filename, int mode, int fla
|
|
||||||
|
|
||||||
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
|
||||||
{
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_faccessat_hook(&dfd, &filename, &mode, NULL);
|
|
||||||
+#endif
|
|
||||||
return do_faccessat(dfd, filename, mode, 0);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
如果没有 `do_faccessat` 方法,可以找 `faccessat` 的 SYSCALL 定义(对于早于 4.17 的内核)
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/open.c
|
|
||||||
+++ b/fs/open.c
|
|
||||||
@@ -31,6 +31,9 @@
|
|
||||||
#include <linux/ima.h>
|
|
||||||
#include <linux/dnotify.h>
|
|
||||||
#include <linux/compat.h>
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
#include "internal.h"
|
|
||||||
|
|
||||||
@@ -369,6 +372,9 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
|
|
||||||
int res;
|
|
||||||
unsigned int lookup_flags = LOOKUP_FOLLOW;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_faccessat_hook(&dfd, &filename, &mode, NULL);
|
|
||||||
+#endif
|
|
||||||
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
|
|
||||||
return -EINVAL;
|
|
||||||
```
|
|
||||||
|
|
||||||
### sys_read 钩子 ( `read_write.c` )
|
|
||||||
|
|
||||||
需要修改 `fs/read_write.c` 的 `sys_read` 方法(4.19 及以上)
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/read_write.c
|
|
||||||
+++ b/fs/read_write.c
|
|
||||||
@@ -25,6 +25,10 @@
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
const struct file_operations generic_ro_fops = {
|
|
||||||
.llseek = generic_file_llseek,
|
|
||||||
.read_iter = generic_file_read_iter,
|
|
||||||
@@ -630,6 +634,9 @@ ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
|
|
||||||
|
|
||||||
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
|
|
||||||
{
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_sys_read_hook(fd, &buf, &count);
|
|
||||||
+#endif
|
|
||||||
return ksys_read(fd, buf, count);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
或者是 `read` 的 SYSCALL 定义(4.14 及以下)
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/read_write.c
|
|
||||||
+++ b/fs/read_write.c
|
|
||||||
@@ -25,6 +25,11 @@
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <asm/unistd.h>
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+
|
|
||||||
const struct file_operations generic_ro_fops = {
|
|
||||||
.llseek = generic_file_llseek,
|
|
||||||
.read_iter = generic_file_read_iter,
|
|
||||||
@@ -575,6 +580,9 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
|
|
||||||
|
|
||||||
if (f.file) {
|
|
||||||
loff_t pos = file_pos_read(f.file);
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_sys_read_hook(fd, &buf, &count);
|
|
||||||
+#endif
|
|
||||||
ret = vfs_read(f.file, buf, count, &pos);
|
|
||||||
if (ret >= 0)
|
|
||||||
file_pos_write(f.file, pos);
|
|
||||||
```
|
|
||||||
|
|
||||||
### fstatat 钩子 ( `stat.c` )
|
|
||||||
|
|
||||||
需要修改 `stat.c` 的 `newfstatat` SYSCALL 定义
|
|
||||||
|
|
||||||
如果需要 32 位支持,还需要修改 `statat64` SYSCALL 定义
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/fs/stat.c
|
|
||||||
+++ b/fs/stat.c
|
|
||||||
@@ -24,6 +24,10 @@
|
|
||||||
#include "internal.h"
|
|
||||||
#include "mount.h"
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
/**
|
|
||||||
* generic_fillattr - Fill in the basic attributes from the inode struct
|
|
||||||
* @mnt_userns: user namespace of the mount the inode was found from
|
|
||||||
@@ -408,6 +412,10 @@ SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename,
|
|
||||||
struct kstat stat;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_stat_hook(&dfd, &filename, &flag);
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
@@ -559,6 +567,10 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
|
|
||||||
struct kstat stat;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_stat_hook(&dfd, &filename, &flag); /* 32-bit su support */
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
```
|
|
||||||
|
|
||||||
### input 钩子 (`input.c` ,用于进入KSU系的内置安全模式)
|
|
||||||
|
|
||||||
需要修改 `drivers/input/input.c` 的 `input_event` 方法,而不是 `input_handle_event`
|
|
||||||
|
|
||||||
```patch
|
|
||||||
--- a/drivers/input/input.c
|
|
||||||
+++ b/drivers/input/input.c
|
|
||||||
@@ -26,6 +26,10 @@
|
|
||||||
#include "input-compat.h"
|
|
||||||
#include "input-poller.h"
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+#include <../../drivers/kernelsu/ksu_trace.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
|
|
||||||
MODULE_DESCRIPTION("Input core");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
@@ -451,6 +455,10 @@ void input_event(struct input_dev *dev,
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
+#if defined(CONFIG_KSU) && defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
|
||||||
+ trace_ksu_trace_input_hook(&type, &code, &value);
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
if (is_event_supported(type, dev->evbit, EV_MAX)) {
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->event_lock, flags);
|
|
||||||
```
|
|
||||||
65
docs/zh/zakomonochrome-128.svg
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="128"
|
||||||
|
height="128"
|
||||||
|
viewBox="0 0 128 128"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||||
|
sodipodi:docname="zakomonochrome-128.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#999999"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:zoom="2.6185048"
|
||||||
|
inkscape:cx="59.957881"
|
||||||
|
inkscape:cy="71.032903"
|
||||||
|
inkscape:window-width="1280"
|
||||||
|
inkscape:window-height="696"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="图层 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#ffffff;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;paint-order:fill markers stroke;fill-opacity:1"
|
||||||
|
id="rect1"
|
||||||
|
width="128"
|
||||||
|
height="128"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
rx="7.772471"
|
||||||
|
ry="7.772471" />
|
||||||
|
<path
|
||||||
|
id="path101"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:4.27504;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="m 42.510282,81.796052 c 0,0 -7.224141,-5.638356 -10.043315,-9.338525 M 14.847106,81.97224 25.41902,71.576535 m 0.17619,-6.695549 2.819179,19.910444 M 11.675534,73.338532 38.281518,71.047931 M 43.567475,62.7666 34.40515,62.942814 M 34.22896,62.590425 33.524162,48.494537 m -18.500855,1.58577 17.972249,-1.409582 m -11.8053,-5.462154 0.352397,18.853251"
|
||||||
|
inkscape:label="杂" />
|
||||||
|
<path
|
||||||
|
id="path111"
|
||||||
|
style="fill:#ffffff;fill-opacity:0.734285;stroke:#000000;stroke-width:3.94824;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.3;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
|
||||||
|
d="M 55.912937,82.876745 79.671596,81.412163 M 59.330273,75.391135 74.952411,74.089291 m -9.43837,-14.157553 1.139102,14.645756 m -8.299247,-7.160159 16.273048,-1.464569 m 0.650926,8.136525 0.325472,-14.808482 m -0.162747,0.162739 -17.900363,0.976379 m 0,-0.162738 1.952774,14.645756 m 12.042061,-21.154974 1.464576,-6.346492 m 0,-0.650928 -12.042063,0.650928 m -0.650918,6.509218 0.325459,-8.787441"
|
||||||
|
inkscape:label="鱼" />
|
||||||
|
<path
|
||||||
|
d="m 95.08569,51.121163 c -1.90515,0.116064 -3.64694,0.97349 -4.86738,2.391307 -1.34538,1.56738 -1.91476,3.733159 -1.59523,6.070852 0.40842,2.982962 2.1502,6.17135 5.13887,9.411078 0.63424,0.68546 1.08109,1.129773 1.98202,1.967071 1.58321,1.469144 3.01507,2.634638 4.9875,4.052454 0.70392,0.50905 2.09253,1.453525 2.61627,1.781734 l 0.15133,0.09594 0.22103,-0.140663 c 0.80481,-0.515755 2.23909,-1.504852 3.08956,-2.130057 3.21689,-2.364488 5.79232,-4.737902 7.70228,-7.100167 3.09676,-3.831409 4.4133,-7.562359 3.80549,-10.773058 -0.42043,-2.210414 -1.82588,-4.039057 -3.81992,-4.967887 -0.85767,-0.399664 -1.69132,-0.607312 -2.6355,-0.656431 -1.22285,-0.0647 -2.42648,0.178619 -3.57485,0.721182 -1.95561,0.922124 -3.58927,2.719503 -4.61752,5.081755 -0.072,0.165235 -0.1394,0.310355 -0.14895,0.319295 -0.0312,0.02902 -0.0648,-0.02679 -0.19458,-0.330457 -0.30752,-0.714476 -0.91055,-1.752718 -1.38382,-2.377871 -0.4853,-0.645282 -1.2661,-1.431214 -1.84749,-1.862143 -1.50155,-1.114153 -3.26013,-1.658924 -5.00914,-1.553996 z"
|
||||||
|
id="path1-4"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.00231605" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -56,8 +56,8 @@ ColumnLimit: 80
|
|||||||
CommentPragmas: '^ IWYU pragma:'
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
#CompactNamespaces: false # Unknown to clang-format-4.0
|
#CompactNamespaces: false # Unknown to clang-format-4.0
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
ConstructorInitializerIndentWidth: 4
|
ConstructorInitializerIndentWidth: 8
|
||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 8
|
||||||
Cpp11BracedListStyle: false
|
Cpp11BracedListStyle: false
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
@@ -501,7 +501,7 @@ IncludeCategories:
|
|||||||
IncludeIsMainRegex: '(Test)?$'
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
IndentCaseLabels: false
|
IndentCaseLabels: false
|
||||||
#IndentPPDirectives: None # Unknown to clang-format-5.0
|
#IndentPPDirectives: None # Unknown to clang-format-5.0
|
||||||
IndentWidth: 4
|
IndentWidth: 8
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
JavaScriptQuotes: Leave
|
JavaScriptQuotes: Leave
|
||||||
JavaScriptWrapImports: true
|
JavaScriptWrapImports: true
|
||||||
@@ -511,7 +511,7 @@ MacroBlockEnd: ''
|
|||||||
MaxEmptyLinesToKeep: 1
|
MaxEmptyLinesToKeep: 1
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
|
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
|
||||||
ObjCBlockIndentWidth: 4
|
ObjCBlockIndentWidth: 8
|
||||||
ObjCSpaceAfterProperty: true
|
ObjCSpaceAfterProperty: true
|
||||||
ObjCSpaceBeforeProtocolList: true
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
|
||||||
@@ -543,6 +543,6 @@ SpacesInCStyleCastParentheses: false
|
|||||||
SpacesInParentheses: false
|
SpacesInParentheses: false
|
||||||
SpacesInSquareBrackets: false
|
SpacesInSquareBrackets: false
|
||||||
Standard: Cpp03
|
Standard: Cpp03
|
||||||
TabWidth: 4
|
TabWidth: 8
|
||||||
UseTab: Never
|
UseTab: Always
|
||||||
...
|
...
|
||||||
|
|||||||
22
kernel/.gitignore
vendored
@@ -1,22 +0,0 @@
|
|||||||
.cache/
|
|
||||||
.thinlto-cache/
|
|
||||||
compile_commands.json
|
|
||||||
*.ko
|
|
||||||
*.o
|
|
||||||
*.mod
|
|
||||||
*.lds
|
|
||||||
*.mod.o
|
|
||||||
.*.o*
|
|
||||||
.*.mod*
|
|
||||||
*.ko*
|
|
||||||
*.mod.c
|
|
||||||
*.symvers*
|
|
||||||
*.order
|
|
||||||
.*.ko.cmd
|
|
||||||
.tmp_versions/
|
|
||||||
libs/
|
|
||||||
obj/
|
|
||||||
|
|
||||||
CLAUDE.md
|
|
||||||
.ddk-version
|
|
||||||
.vscode/settings.json
|
|
||||||
11
kernel/.vscode/c_cpp_properties.json
vendored
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Linux",
|
|
||||||
"cStandard": "c11",
|
|
||||||
"intelliSenseMode": "gcc-arm64",
|
|
||||||
"compileCommands": "${workspaceFolder}/compile_commands.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": 4
|
|
||||||
}
|
|
||||||
92
kernel/.vscode/generate_compdb.py
vendored
@@ -1,92 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
from __future__ import print_function, division
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import fnmatch
|
|
||||||
import functools
|
|
||||||
import json
|
|
||||||
import math
|
|
||||||
import multiprocessing
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
CMD_VAR_RE = re.compile(r'^\s*(?:saved)?cmd_(\S+)\s*:=\s*(.+)\s*$', re.MULTILINE)
|
|
||||||
SOURCE_VAR_RE = re.compile(r'^\s*source_(\S+)\s*:=\s*(.+)\s*$', re.MULTILINE)
|
|
||||||
|
|
||||||
|
|
||||||
def print_progress_bar(progress):
|
|
||||||
progress_bar = '[' + '|' * int(50 * progress) + '-' * int(50 * (1.0 - progress)) + ']'
|
|
||||||
print('\r', progress_bar, "{0:.1%}".format(progress), end='\r', file=sys.stderr)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_cmd_file(out_dir, cmdfile_path):
|
|
||||||
with open(cmdfile_path, 'r') as cmdfile:
|
|
||||||
cmdfile_content = cmdfile.read()
|
|
||||||
|
|
||||||
commands = { match.group(1): match.group(2) for match in CMD_VAR_RE.finditer(cmdfile_content) }
|
|
||||||
sources = { match.group(1): match.group(2) for match in SOURCE_VAR_RE.finditer(cmdfile_content) }
|
|
||||||
|
|
||||||
return [{
|
|
||||||
'directory': out_dir,
|
|
||||||
'command': commands[o_file_name],
|
|
||||||
'file': source,
|
|
||||||
'output': o_file_name
|
|
||||||
} for o_file_name, source in sources.items()]
|
|
||||||
|
|
||||||
|
|
||||||
def gen_compile_commands(cmd_file_search_path, out_dir):
|
|
||||||
print("Building *.o.cmd file list...", file=sys.stderr)
|
|
||||||
|
|
||||||
out_dir = os.path.abspath(out_dir)
|
|
||||||
|
|
||||||
if not cmd_file_search_path:
|
|
||||||
cmd_file_search_path = [out_dir]
|
|
||||||
|
|
||||||
cmd_files = []
|
|
||||||
for search_path in cmd_file_search_path:
|
|
||||||
if (os.path.isdir(search_path)):
|
|
||||||
for cur_dir, subdir, files in os.walk(search_path):
|
|
||||||
cmd_files.extend(os.path.join(cur_dir, cmdfile_name) for cmdfile_name in fnmatch.filter(files, '*.o.cmd'))
|
|
||||||
else:
|
|
||||||
cmd_files.extend(search_path)
|
|
||||||
|
|
||||||
if not cmd_files:
|
|
||||||
print("No *.o.cmd files found in", ", ".join(cmd_file_search_path), file=sys.stderr)
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Parsing *.o.cmd files...", file=sys.stderr)
|
|
||||||
|
|
||||||
n_processed = 0
|
|
||||||
print_progress_bar(0)
|
|
||||||
|
|
||||||
compdb = []
|
|
||||||
pool = multiprocessing.Pool()
|
|
||||||
try:
|
|
||||||
for compdb_chunk in pool.imap_unordered(functools.partial(parse_cmd_file, out_dir), cmd_files, chunksize=int(math.sqrt(len(cmd_files)))):
|
|
||||||
compdb.extend(compdb_chunk)
|
|
||||||
n_processed += 1
|
|
||||||
print_progress_bar(n_processed / len(cmd_files))
|
|
||||||
|
|
||||||
finally:
|
|
||||||
pool.terminate()
|
|
||||||
pool.join()
|
|
||||||
|
|
||||||
print(file=sys.stderr)
|
|
||||||
print("Writing compile_commands.json...", file=sys.stderr)
|
|
||||||
|
|
||||||
with open('compile_commands.json', 'w') as compdb_file:
|
|
||||||
json.dump(compdb, compdb_file, indent=1)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
cmd_parser = argparse.ArgumentParser()
|
|
||||||
cmd_parser.add_argument('-O', '--out-dir', type=str, default=os.getcwd(), help="Build output directory")
|
|
||||||
cmd_parser.add_argument('cmd_file_search_path', nargs='*', help="*.cmd file search path")
|
|
||||||
gen_compile_commands(**vars(cmd_parser.parse_args()))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
16
kernel/.vscode/tasks.json
vendored
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
||||||
// for the documentation about the tasks.json format
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"label": "Generate compile_commands.json",
|
|
||||||
"type": "process",
|
|
||||||
"command": "python",
|
|
||||||
"args": [
|
|
||||||
"${workspaceRoot}/.vscode/generate_compdb.py"
|
|
||||||
],
|
|
||||||
"problemMatcher": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,42 +1,57 @@
|
|||||||
menu "KernelSU"
|
menu "KernelSU"
|
||||||
|
|
||||||
config KSU
|
config KSU
|
||||||
tristate "KernelSU function support"
|
tristate "KernelSU function support"
|
||||||
default y
|
depends on OVERLAY_FS
|
||||||
help
|
default y
|
||||||
Enable kernel-level root privileges on Android System.
|
help
|
||||||
To compile as a module, choose M here: the
|
Enable kernel-level root privileges on Android System.
|
||||||
module will be called kernelsu.
|
To compile as a module, choose M here: the
|
||||||
|
module will be called kernelsu.
|
||||||
|
|
||||||
config KSU_DEBUG
|
config KSU_DEBUG
|
||||||
bool "KernelSU debug mode"
|
bool "KernelSU debug mode"
|
||||||
depends on KSU
|
depends on KSU
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Enable KernelSU debug mode.
|
Enable KernelSU debug mode.
|
||||||
|
|
||||||
config KSU_MANUAL_SU
|
|
||||||
bool "Use manual su"
|
|
||||||
depends on KSU
|
|
||||||
default y
|
|
||||||
help
|
|
||||||
Use manual su and authorize the corresponding command line and application via prctl
|
|
||||||
|
|
||||||
config KPM
|
config KPM
|
||||||
bool "Enable SukiSU KPM"
|
bool "Enable SukiSU KPM"
|
||||||
depends on KSU && 64BIT
|
depends on KSU && 64BIT
|
||||||
default n
|
default n
|
||||||
|
help
|
||||||
|
Enabling this option will activate the KPM feature of SukiSU.
|
||||||
|
This option is suitable for scenarios where you need to force KPM to be enabled.
|
||||||
|
but it may affect system stability.
|
||||||
|
select KALLSYMS
|
||||||
|
select KALLSYMS_ALL
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "KernelSU hook type"
|
||||||
|
depends on KSU
|
||||||
|
default KSU_KPROBES_HOOK
|
||||||
help
|
help
|
||||||
Enabling this option will activate the KPM feature of SukiSU.
|
Hook type for KernelSU
|
||||||
This option is suitable for scenarios where you need to force KPM to be enabled.
|
|
||||||
but it may affect system stability.
|
config KSU_KPROBES_HOOK
|
||||||
select KALLSYMS
|
bool "Hook KernelSU with Kprobes"
|
||||||
select KALLSYMS_ALL
|
depends on KPROBES
|
||||||
|
help
|
||||||
|
If enabled, Hook required KernelSU syscalls with Kernel-probe.
|
||||||
|
|
||||||
|
config KSU_TRACEPOINT_HOOK
|
||||||
|
bool "Hook KernelSU with Tracepoint"
|
||||||
|
depends on TRACEPOINTS
|
||||||
|
help
|
||||||
|
If enabled, Hook required KernelSU syscalls with Tracepoint.
|
||||||
|
|
||||||
config KSU_MANUAL_HOOK
|
config KSU_MANUAL_HOOK
|
||||||
bool "Hook KernelSU manually"
|
bool "Hook KernelSU manually"
|
||||||
depends on KSU != m
|
depends on KSU != m
|
||||||
help
|
help
|
||||||
If enabled, Hook required KernelSU syscalls with manually-patched function.
|
If enabled, Hook required KernelSU syscalls with manually-patched function.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -1,28 +1,16 @@
|
|||||||
kernelsu-objs := ksu.o
|
kernelsu-objs := ksu.o
|
||||||
kernelsu-objs += allowlist.o
|
kernelsu-objs += allowlist.o
|
||||||
kernelsu-objs += app_profile.o
|
kernelsu-objs += dynamic_sign.o
|
||||||
kernelsu-objs += dynamic_manager.o
|
|
||||||
kernelsu-objs += apk_sign.o
|
kernelsu-objs += apk_sign.o
|
||||||
kernelsu-objs += sucompat.o
|
kernelsu-objs += sucompat.o
|
||||||
kernelsu-objs += syscall_hook_manager.o
|
|
||||||
kernelsu-objs += throne_tracker.o
|
kernelsu-objs += throne_tracker.o
|
||||||
kernelsu-objs += pkg_observer.o
|
kernelsu-objs += core_hook.o
|
||||||
kernelsu-objs += throne_tracker.o
|
|
||||||
kernelsu-objs += umount_manager.o
|
|
||||||
kernelsu-objs += setuid_hook.o
|
|
||||||
kernelsu-objs += kernel_umount.o
|
|
||||||
kernelsu-objs += supercalls.o
|
|
||||||
kernelsu-objs += feature.o
|
|
||||||
kernelsu-objs += ksud.o
|
kernelsu-objs += ksud.o
|
||||||
kernelsu-objs += embed_ksud.o
|
kernelsu-objs += embed_ksud.o
|
||||||
kernelsu-objs += seccomp_cache.o
|
kernelsu-objs += kernel_compat.o
|
||||||
kernelsu-objs += file_wrapper.o
|
|
||||||
kernelsu-objs += throne_comm.o
|
|
||||||
kernelsu-objs += sulog.o
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_KSU_MANUAL_SU), y)
|
ifeq ($(strip $(CONFIG_KSU_TRACEPOINT_HOOK)),y)
|
||||||
ccflags-y += -DCONFIG_KSU_MANUAL_SU
|
kernelsu-objs += ksu_trace.o
|
||||||
kernelsu-objs += manual_su.o
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
kernelsu-objs += selinux/selinux.o
|
kernelsu-objs += selinux/selinux.o
|
||||||
@@ -32,62 +20,46 @@ ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
|||||||
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
|
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
|
||||||
|
|
||||||
obj-$(CONFIG_KSU) += kernelsu.o
|
obj-$(CONFIG_KSU) += kernelsu.o
|
||||||
|
obj-$(CONFIG_KSU_TRACEPOINT_HOOK) += ksu_trace_export.o
|
||||||
|
|
||||||
obj-$(CONFIG_KPM) += kpm/
|
obj-$(CONFIG_KPM) += kpm/
|
||||||
|
|
||||||
|
|
||||||
REPO_OWNER := SukiSU-Ultra
|
REPO_OWNER := SukiSU-Ultra
|
||||||
REPO_NAME := SukiSU-Ultra
|
REPO_NAME := SukiSU-Ultra
|
||||||
REPO_BRANCH := main
|
REPO_BRANCH := main
|
||||||
KSU_VERSION_API := 4.0.0
|
KSU_VERSION_API := 3.1.8
|
||||||
|
|
||||||
GIT_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git
|
GIT_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git
|
||||||
CURL_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin curl
|
CURL_BIN := /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin curl
|
||||||
|
|
||||||
KDIR := $(KDIR)
|
|
||||||
MDIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
|
|
||||||
|
|
||||||
ifneq ($(KDIR),)
|
|
||||||
$(info -- KDIR: $(KDIR))
|
|
||||||
$(info -- MDIR: $(MDIR))
|
|
||||||
endif
|
|
||||||
|
|
||||||
KSU_GITHUB_VERSION := $(shell $(CURL_BIN) -s "https://api.github.com/repos/$(REPO_OWNER)/$(REPO_NAME)/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
|
KSU_GITHUB_VERSION := $(shell $(CURL_BIN) -s "https://api.github.com/repos/$(REPO_OWNER)/$(REPO_NAME)/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
|
||||||
KSU_GITHUB_VERSION_COMMIT := $(shell $(CURL_BIN) -sI "https://api.github.com/repos/$(REPO_OWNER)/$(REPO_NAME)/commits?sha=$(REPO_BRANCH)&per_page=1" | grep -i "link:" | sed -n 's/.*page=\([0-9]*\)>; rel="last".*/\1/p')
|
KSU_GITHUB_VERSION_COMMIT := $(shell $(CURL_BIN) -sI "https://api.github.com/repos/$(REPO_OWNER)/$(REPO_NAME)/commits?sha=$(REPO_BRANCH)&per_page=1" | grep -i "link:" | sed -n 's/.*page=\([0-9]*\)>; rel="last".*/\1/p')
|
||||||
|
|
||||||
ifeq ($(findstring $(srctree),$(src)),$(srctree))
|
LOCAL_GIT_EXISTS := $(shell test -e $(srctree)/$(src)/../.git && echo 1 || echo 0)
|
||||||
KSU_SRC := $(src)
|
|
||||||
else
|
|
||||||
KSU_SRC := $(srctree)/$(src)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(shell test -e $(KSU_SRC)/../.git && echo "in-tree"),in-tree)
|
|
||||||
KSU_SRC := $(MDIR)
|
|
||||||
endif
|
|
||||||
|
|
||||||
LOCAL_GIT_EXISTS := $(shell test -e $(KSU_SRC)/../.git && echo 1 || echo 0)
|
|
||||||
|
|
||||||
define get_ksu_version_full
|
define get_ksu_version_full
|
||||||
v$1-$(shell cd $(KSU_SRC); $(GIT_BIN) rev-parse --short=8 HEAD)@$(shell cd $(KSU_SRC); $(GIT_BIN) rev-parse --abbrev-ref HEAD)
|
v$1-$(shell cd $(srctree)/$(src); $(GIT_BIN) rev-parse --short=8 HEAD)@$(shell cd $(srctree)/$(src); $(GIT_BIN) rev-parse --abbrev-ref HEAD)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
ifeq ($(KSU_GITHUB_VERSION_COMMIT),)
|
ifeq ($(KSU_GITHUB_VERSION_COMMIT),)
|
||||||
ifeq ($(LOCAL_GIT_EXISTS),1)
|
ifeq ($(LOCAL_GIT_EXISTS),1)
|
||||||
$(shell cd $(KSU_SRC); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
|
$(shell cd $(srctree)/$(src); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
|
||||||
KSU_LOCAL_VERSION := $(shell cd $(KSU_SRC); $(GIT_BIN) rev-list --count $(REPO_BRANCH))
|
KSU_LOCAL_VERSION := $(shell cd $(srctree)/$(src); $(GIT_BIN) rev-list --count $(REPO_BRANCH))
|
||||||
KSU_VERSION := $(shell expr 40000 + $(KSU_LOCAL_VERSION) - 2815)
|
KSU_VERSION := $(shell expr 10000 + $(KSU_LOCAL_VERSION) + 700)
|
||||||
$(info -- $(REPO_NAME) version (local .git): $(KSU_VERSION))
|
$(info -- $(REPO_NAME) version (local .git): $(KSU_VERSION))
|
||||||
else
|
else
|
||||||
KSU_VERSION := 13000
|
KSU_VERSION := 13000
|
||||||
$(warning -- Could not fetch version online or via local .git! Using fallback version: $(KSU_VERSION))
|
$(warning -- Could not fetch version online or via local .git! Using fallback version: $(KSU_VERSION))
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
KSU_VERSION := $(shell expr 40000 + $(KSU_GITHUB_VERSION_COMMIT) - 2815)
|
KSU_VERSION := $(shell expr 10000 + $(KSU_GITHUB_VERSION_COMMIT) + 700)
|
||||||
$(info -- $(REPO_NAME) version (GitHub): $(KSU_VERSION))
|
$(info -- $(REPO_NAME) version (GitHub): $(KSU_VERSION))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(KSU_GITHUB_VERSION),)
|
ifeq ($(KSU_GITHUB_VERSION),)
|
||||||
ifeq ($(LOCAL_GIT_EXISTS),1)
|
ifeq ($(LOCAL_GIT_EXISTS),1)
|
||||||
$(shell cd $(KSU_SRC); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
|
$(shell cd $(srctree)/$(src); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
|
||||||
KSU_VERSION_FULL := $(call get_ksu_version_full,$(KSU_VERSION_API))
|
KSU_VERSION_FULL := $(call get_ksu_version_full,$(KSU_VERSION_API))
|
||||||
$(info -- $(REPO_NAME) version (local .git): $(KSU_VERSION_FULL))
|
$(info -- $(REPO_NAME) version (local .git): $(KSU_VERSION_FULL))
|
||||||
$(info -- $(REPO_NAME) Formatted version (local .git): $(KSU_VERSION))
|
$(info -- $(REPO_NAME) Formatted version (local .git): $(KSU_VERSION))
|
||||||
@@ -96,7 +68,7 @@ ifeq ($(KSU_GITHUB_VERSION),)
|
|||||||
$(warning -- $(REPO_NAME) version: $(KSU_VERSION_FULL))
|
$(warning -- $(REPO_NAME) version: $(KSU_VERSION_FULL))
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
$(shell cd $(KSU_SRC); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
|
$(shell cd $(srctree)/$(src); [ -f ../.git/shallow ] && $(GIT_BIN) fetch --unshallow)
|
||||||
KSU_VERSION_FULL := $(call get_ksu_version_full,$(KSU_GITHUB_VERSION))
|
KSU_VERSION_FULL := $(call get_ksu_version_full,$(KSU_GITHUB_VERSION))
|
||||||
$(info -- $(REPO_NAME) version (Github): $(KSU_VERSION_FULL))
|
$(info -- $(REPO_NAME) version (Github): $(KSU_VERSION_FULL))
|
||||||
endif
|
endif
|
||||||
@@ -120,13 +92,14 @@ ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\"
|
|||||||
$(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE))
|
$(info -- SukiSU Manager package name: $(KSU_MANAGER_PACKAGE))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_KSU_MANUAL_HOOK), y)
|
$(info -- Supported Unofficial Manager: 5ec1cff (GKI) ShirkNeko udochina (GKI and KPM))
|
||||||
ccflags-y += -DKSU_MANUAL_HOOK
|
|
||||||
$(info -- SukiSU: KSU_MANUAL_HOOK Temporarily discontinued))
|
ifeq ($(strip $(CONFIG_KSU_KPROBES_HOOK)),y)
|
||||||
else
|
$(info -- SukiSU: CONFIG_KSU_KPROBES_HOOK)
|
||||||
ccflags-y += -DKSU_KPROBES_HOOK
|
else ifeq ($(strip $(CONFIG_KSU_TRACEPOINT_HOOK)),y)
|
||||||
ccflags-y += -DKSU_TP_HOOK
|
$(info -- SukiSU: CONFIG_KSU_TRACEPOINT_HOOK)
|
||||||
$(info -- SukiSU: KSU_TRACEPOINT_HOOK)
|
else ifeq ($(strip $(CONFIG_KSU_MANUAL_HOOK)),y)
|
||||||
|
$(info -- SukiSU: CONFIG_KSU_MANUAL_HOOK)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
KERNEL_VERSION := $(VERSION).$(PATCHLEVEL)
|
KERNEL_VERSION := $(VERSION).$(PATCHLEVEL)
|
||||||
@@ -143,30 +116,14 @@ endif
|
|||||||
$(info -- KERNEL_VERSION: $(KERNEL_VERSION))
|
$(info -- KERNEL_VERSION: $(KERNEL_VERSION))
|
||||||
$(info -- KERNEL_TYPE: $(KERNEL_TYPE))
|
$(info -- KERNEL_TYPE: $(KERNEL_TYPE))
|
||||||
|
|
||||||
ifeq ($(CONFIG_KPM), y)
|
$(info -- KERNEL_VERSION: $(KERNEL_VERSION))
|
||||||
|
ifeq ($(CONFIG_KPM),y)
|
||||||
$(info -- KPM is enabled)
|
$(info -- KPM is enabled)
|
||||||
else
|
else
|
||||||
$(info -- KPM is disabled)
|
$(info -- KPM is disabled)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check new vfs_getattr()
|
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
||||||
ifeq ($(shell grep -A1 "^int vfs_getattr" $(srctree)/fs/stat.c | grep -q "query_flags" ; echo $$?),0)
|
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
||||||
ccflags-y += -DKSU_HAS_NEW_VFS_GETATTR
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Function proc_ops check
|
|
||||||
ifeq ($(shell grep -q "struct proc_ops " $(srctree)/include/linux/proc_fs.h; echo $$?),0)
|
|
||||||
ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS
|
|
||||||
endif
|
|
||||||
|
|
||||||
ccflags-y += -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat -Wno-missing-prototypes
|
|
||||||
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable
|
|
||||||
|
|
||||||
all:
|
|
||||||
make -C $(KDIR) M=$(MDIR) modules
|
|
||||||
compdb:
|
|
||||||
python3 $(MDIR)/.vscode/generate_compdb.py -O $(KDIR) $(MDIR)
|
|
||||||
clean:
|
|
||||||
make -C $(KDIR) M=$(MDIR) clean
|
|
||||||
|
|
||||||
# Keep a new line here!! Because someone may append config
|
# Keep a new line here!! Because someone may append config
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/task_work.h>
|
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
@@ -10,16 +8,14 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
|
|
||||||
#include <linux/compiler_types.h>
|
#include <linux/compiler_types.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#include "ksu.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "ksud.h"
|
|
||||||
#include "selinux/selinux.h"
|
#include "selinux/selinux.h"
|
||||||
|
#include "kernel_compat.h"
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
#include "syscall_hook_manager.h"
|
|
||||||
|
|
||||||
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
|
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
|
||||||
#define FILE_FORMAT_VERSION 3 // u32
|
#define FILE_FORMAT_VERSION 3 // u32
|
||||||
@@ -33,61 +29,58 @@ static DEFINE_MUTEX(allowlist_mutex);
|
|||||||
static struct root_profile default_root_profile;
|
static struct root_profile default_root_profile;
|
||||||
static struct non_root_profile default_non_root_profile;
|
static struct non_root_profile default_non_root_profile;
|
||||||
|
|
||||||
void persistent_allow_list(void);
|
static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly __aligned(PAGE_SIZE);
|
||||||
|
|
||||||
static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly
|
|
||||||
__aligned(PAGE_SIZE);
|
|
||||||
static int allow_list_pointer __read_mostly = 0;
|
static int allow_list_pointer __read_mostly = 0;
|
||||||
|
|
||||||
static void remove_uid_from_arr(uid_t uid)
|
static void remove_uid_from_arr(uid_t uid)
|
||||||
{
|
{
|
||||||
int *temp_arr;
|
int *temp_arr;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if (allow_list_pointer == 0)
|
if (allow_list_pointer == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
temp_arr = kzalloc(sizeof(allow_list_arr), GFP_KERNEL);
|
temp_arr = kmalloc(sizeof(allow_list_arr), GFP_KERNEL);
|
||||||
if (temp_arr == NULL) {
|
if (temp_arr == NULL) {
|
||||||
pr_err("%s: unable to allocate memory\n", __func__);
|
pr_err("%s: unable to allocate memory\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = j = 0; i < allow_list_pointer; i++) {
|
for (i = j = 0; i < allow_list_pointer; i++) {
|
||||||
if (allow_list_arr[i] == uid)
|
if (allow_list_arr[i] == uid)
|
||||||
continue;
|
continue;
|
||||||
temp_arr[j++] = allow_list_arr[i];
|
temp_arr[j++] = allow_list_arr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
allow_list_pointer = j;
|
allow_list_pointer = j;
|
||||||
|
|
||||||
for (; j < ARRAY_SIZE(allow_list_arr); j++)
|
for (; j < ARRAY_SIZE(allow_list_arr); j++)
|
||||||
temp_arr[j] = -1;
|
temp_arr[j] = -1;
|
||||||
|
|
||||||
memcpy(&allow_list_arr, temp_arr, PAGE_SIZE);
|
memcpy(&allow_list_arr, temp_arr, PAGE_SIZE);
|
||||||
kfree(temp_arr);
|
kfree(temp_arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_default_profiles(void)
|
static void init_default_profiles()
|
||||||
{
|
{
|
||||||
kernel_cap_t full_cap = CAP_FULL_SET;
|
kernel_cap_t full_cap = CAP_FULL_SET;
|
||||||
|
|
||||||
default_root_profile.uid = 0;
|
default_root_profile.uid = 0;
|
||||||
default_root_profile.gid = 0;
|
default_root_profile.gid = 0;
|
||||||
default_root_profile.groups_count = 1;
|
default_root_profile.groups_count = 1;
|
||||||
default_root_profile.groups[0] = 0;
|
default_root_profile.groups[0] = 0;
|
||||||
memcpy(&default_root_profile.capabilities.effective, &full_cap,
|
memcpy(&default_root_profile.capabilities.effective, &full_cap,
|
||||||
sizeof(default_root_profile.capabilities.effective));
|
sizeof(default_root_profile.capabilities.effective));
|
||||||
default_root_profile.namespaces = 0;
|
default_root_profile.namespaces = 0;
|
||||||
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
||||||
|
|
||||||
// This means that we will umount modules by default!
|
// This means that we will umount modules by default!
|
||||||
default_non_root_profile.umount_modules = true;
|
default_non_root_profile.umount_modules = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct perm_data {
|
struct perm_data {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct app_profile profile;
|
struct app_profile profile;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct list_head allow_list;
|
static struct list_head allow_list;
|
||||||
@@ -97,535 +90,437 @@ static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
|
|||||||
|
|
||||||
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
|
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
|
||||||
|
|
||||||
|
static struct work_struct ksu_save_work;
|
||||||
|
static struct work_struct ksu_load_work;
|
||||||
|
|
||||||
|
bool persistent_allow_list(void);
|
||||||
|
|
||||||
void ksu_show_allow_list(void)
|
void ksu_show_allow_list(void)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
pr_info("ksu_show_allow_list\n");
|
pr_info("ksu_show_allow_list\n");
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
|
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
|
||||||
p->profile.allow_su);
|
p->profile.allow_su);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
static void ksu_grant_root_to_shell(void)
|
static void ksu_grant_root_to_shell()
|
||||||
{
|
{
|
||||||
struct app_profile profile = {
|
struct app_profile profile = {
|
||||||
.version = KSU_APP_PROFILE_VER,
|
.version = KSU_APP_PROFILE_VER,
|
||||||
.allow_su = true,
|
.allow_su = true,
|
||||||
.current_uid = 2000,
|
.current_uid = 2000,
|
||||||
};
|
};
|
||||||
strcpy(profile.key, "com.android.shell");
|
strcpy(profile.key, "com.android.shell");
|
||||||
strcpy(profile.rp_config.profile.selinux_domain,
|
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
||||||
KSU_DEFAULT_SELINUX_DOMAIN);
|
ksu_set_app_profile(&profile, false);
|
||||||
ksu_set_app_profile(&profile, false);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ksu_get_app_profile(struct app_profile *profile)
|
bool ksu_get_app_profile(struct app_profile *profile)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
bool uid_match = profile->current_uid == p->profile.current_uid;
|
bool uid_match = profile->current_uid == p->profile.current_uid;
|
||||||
if (uid_match) {
|
if (uid_match) {
|
||||||
// found it, override it with ours
|
// found it, override it with ours
|
||||||
memcpy(profile, &p->profile, sizeof(*profile));
|
memcpy(profile, &p->profile, sizeof(*profile));
|
||||||
found = true;
|
found = true;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool forbid_system_uid(uid_t uid)
|
static inline bool forbid_system_uid(uid_t uid) {
|
||||||
{
|
#define SHELL_UID 2000
|
||||||
#define SHELL_UID 2000
|
#define SYSTEM_UID 1000
|
||||||
#define SYSTEM_UID 1000
|
return uid < SHELL_UID && uid != SYSTEM_UID;
|
||||||
return uid < SHELL_UID && uid != SYSTEM_UID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool profile_valid(struct app_profile *profile)
|
static bool profile_valid(struct app_profile *profile)
|
||||||
{
|
{
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile->version < KSU_APP_PROFILE_VER) {
|
if (profile->version < KSU_APP_PROFILE_VER) {
|
||||||
pr_info("Unsupported profile version: %d\n", profile->version);
|
pr_info("Unsupported profile version: %d\n", profile->version);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile->allow_su) {
|
if (profile->allow_su) {
|
||||||
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
|
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
|
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
|
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if (!profile_valid(profile)) {
|
if (!profile_valid(profile)) {
|
||||||
pr_err("Failed to set app profile: invalid profile!\n");
|
pr_err("Failed to set app profile: invalid profile!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
// both uid and package must match, otherwise it will break multiple package with different user id
|
// both uid and package must match, otherwise it will break multiple package with different user id
|
||||||
if (profile->current_uid == p->profile.current_uid &&
|
if (profile->current_uid == p->profile.current_uid &&
|
||||||
!strcmp(profile->key, p->profile.key)) {
|
!strcmp(profile->key, p->profile.key)) {
|
||||||
// found it, just override it all!
|
// found it, just override it all!
|
||||||
memcpy(&p->profile, profile, sizeof(*profile));
|
memcpy(&p->profile, profile, sizeof(*profile));
|
||||||
result = true;
|
result = true;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// not found, alloc a new node!
|
// not found, alloc a new node!
|
||||||
p = (struct perm_data *)kzalloc(sizeof(struct perm_data), GFP_KERNEL);
|
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
pr_err("ksu_set_app_profile alloc failed\n");
|
pr_err("ksu_set_app_profile alloc failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&p->profile, profile, sizeof(*profile));
|
memcpy(&p->profile, profile, sizeof(*profile));
|
||||||
if (profile->allow_su) {
|
if (profile->allow_su) {
|
||||||
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
|
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
|
||||||
profile->key, profile->current_uid,
|
profile->key, profile->current_uid,
|
||||||
profile->rp_config.profile.gid,
|
profile->rp_config.profile.gid,
|
||||||
profile->rp_config.profile.selinux_domain);
|
profile->rp_config.profile.selinux_domain);
|
||||||
} else {
|
} else {
|
||||||
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
|
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
|
||||||
profile->key, profile->current_uid,
|
profile->key, profile->current_uid,
|
||||||
profile->nrp_config.profile.umount_modules);
|
profile->nrp_config.profile.umount_modules);
|
||||||
}
|
}
|
||||||
list_add_tail(&p->list, &allow_list);
|
list_add_tail(&p->list, &allow_list);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (profile->current_uid <= BITMAP_UID_MAX) {
|
if (profile->current_uid <= BITMAP_UID_MAX) {
|
||||||
if (profile->allow_su)
|
if (profile->allow_su)
|
||||||
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |=
|
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= 1 << (profile->current_uid % BITS_PER_BYTE);
|
||||||
1 << (profile->current_uid % BITS_PER_BYTE);
|
else
|
||||||
else
|
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= ~(1 << (profile->current_uid % BITS_PER_BYTE));
|
||||||
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &=
|
} else {
|
||||||
~(1 << (profile->current_uid % BITS_PER_BYTE));
|
if (profile->allow_su) {
|
||||||
} else {
|
/*
|
||||||
if (profile->allow_su) {
|
* 1024 apps with uid higher than BITMAP_UID_MAX
|
||||||
/*
|
* registered to request superuser?
|
||||||
* 1024 apps with uid higher than BITMAP_UID_MAX
|
*/
|
||||||
* registered to request superuser?
|
if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) {
|
||||||
*/
|
pr_err("too many apps registered\n");
|
||||||
if (allow_list_pointer >= ARRAY_SIZE(allow_list_arr)) {
|
WARN_ON(1);
|
||||||
pr_err("too many apps registered\n");
|
return false;
|
||||||
WARN_ON(1);
|
}
|
||||||
return false;
|
allow_list_arr[allow_list_pointer++] = profile->current_uid;
|
||||||
}
|
} else {
|
||||||
allow_list_arr[allow_list_pointer++] = profile->current_uid;
|
remove_uid_from_arr(profile->current_uid);
|
||||||
} else {
|
}
|
||||||
remove_uid_from_arr(profile->current_uid);
|
}
|
||||||
}
|
result = true;
|
||||||
}
|
|
||||||
result = true;
|
|
||||||
|
|
||||||
// check if the default profiles is changed, cache it to a single struct to accelerate access.
|
// check if the default profiles is changed, cache it to a single struct to accelerate access.
|
||||||
if (unlikely(!strcmp(profile->key, "$"))) {
|
if (unlikely(!strcmp(profile->key, "$"))) {
|
||||||
// set default non root profile
|
// set default non root profile
|
||||||
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
|
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
|
||||||
sizeof(default_non_root_profile));
|
sizeof(default_non_root_profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!strcmp(profile->key, "#"))) {
|
if (unlikely(!strcmp(profile->key, "#"))) {
|
||||||
// set default root profile
|
// set default root profile
|
||||||
memcpy(&default_root_profile, &profile->rp_config.profile,
|
memcpy(&default_root_profile, &profile->rp_config.profile,
|
||||||
sizeof(default_root_profile));
|
sizeof(default_root_profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (persist) {
|
if (persist)
|
||||||
persistent_allow_list();
|
persistent_allow_list();
|
||||||
// FIXME: use a new flag
|
|
||||||
ksu_mark_running_process();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __ksu_is_allow_uid(uid_t uid)
|
bool __ksu_is_allow_uid(uid_t uid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (forbid_system_uid(uid)) {
|
if (unlikely(uid == 0)) {
|
||||||
// do not bother going through the list if it's system
|
// already root, but only allow our domain.
|
||||||
return false;
|
return is_ksu_domain();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(ksu_is_manager_uid_valid()) &&
|
if (forbid_system_uid(uid)) {
|
||||||
unlikely(ksu_get_manager_uid() == uid)) {
|
// do not bother going through the list if it's system
|
||||||
// manager is always allowed!
|
return false;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (likely(uid <= BITMAP_UID_MAX)) {
|
if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) {
|
||||||
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] &
|
// manager is always allowed!
|
||||||
(1 << (uid % BITS_PER_BYTE)));
|
return true;
|
||||||
} else {
|
}
|
||||||
for (i = 0; i < allow_list_pointer; i++) {
|
|
||||||
if (allow_list_arr[i] == uid)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
if (likely(uid <= BITMAP_UID_MAX)) {
|
||||||
}
|
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE)));
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < allow_list_pointer; i++) {
|
||||||
|
if (allow_list_arr[i] == uid)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool __ksu_is_allow_uid_for_current(uid_t uid)
|
return false;
|
||||||
{
|
|
||||||
if (unlikely(uid == 0)) {
|
|
||||||
// already root, but only allow our domain.
|
|
||||||
return is_ksu_domain();
|
|
||||||
}
|
|
||||||
return __ksu_is_allow_uid(uid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_uid_should_umount(uid_t uid)
|
bool ksu_uid_should_umount(uid_t uid)
|
||||||
{
|
{
|
||||||
struct app_profile profile = { .current_uid = uid };
|
struct app_profile profile = { .current_uid = uid };
|
||||||
if (likely(ksu_is_manager_uid_valid()) &&
|
if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) {
|
||||||
unlikely(ksu_get_manager_uid() == uid)) {
|
// we should not umount on manager!
|
||||||
// we should not umount on manager!
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
bool found = ksu_get_app_profile(&profile);
|
||||||
bool found = ksu_get_app_profile(&profile);
|
if (!found) {
|
||||||
if (!found) {
|
// no app profile found, it must be non root app
|
||||||
// no app profile found, it must be non root app
|
return default_non_root_profile.umount_modules;
|
||||||
return default_non_root_profile.umount_modules;
|
}
|
||||||
}
|
if (profile.allow_su) {
|
||||||
if (profile.allow_su) {
|
// if found and it is granted to su, we shouldn't umount for it
|
||||||
// if found and it is granted to su, we shouldn't umount for it
|
return false;
|
||||||
return false;
|
} else {
|
||||||
} else {
|
// found an app profile
|
||||||
// found an app profile
|
if (profile.nrp_config.use_default) {
|
||||||
if (profile.nrp_config.use_default) {
|
return default_non_root_profile.umount_modules;
|
||||||
return default_non_root_profile.umount_modules;
|
} else {
|
||||||
} else {
|
return profile.nrp_config.profile.umount_modules;
|
||||||
return profile.nrp_config.profile.umount_modules;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct root_profile *ksu_get_root_profile(uid_t uid)
|
struct root_profile *ksu_get_root_profile(uid_t uid)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
if (uid == p->profile.current_uid && p->profile.allow_su) {
|
if (uid == p->profile.current_uid && p->profile.allow_su) {
|
||||||
if (!p->profile.rp_config.use_default) {
|
if (!p->profile.rp_config.use_default) {
|
||||||
return &p->profile.rp_config.profile;
|
return &p->profile.rp_config.profile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// use default profile
|
// use default profile
|
||||||
return &default_root_profile;
|
return &default_root_profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_get_allow_list(int *array, int *length, bool allow)
|
bool ksu_get_allow_list(int *array, int *length, bool allow)
|
||||||
{
|
{
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
|
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
|
||||||
if (p->profile.allow_su == allow) {
|
if (p->profile.allow_su == allow) {
|
||||||
array[i++] = p->profile.current_uid;
|
array[i++] = p->profile.current_uid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*length = i;
|
*length = i;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_persistent_allow_list(struct callback_head *_cb)
|
void do_save_allow_list(struct work_struct *work)
|
||||||
{
|
{
|
||||||
u32 magic = FILE_MAGIC;
|
u32 magic = FILE_MAGIC;
|
||||||
u32 version = FILE_FORMAT_VERSION;
|
u32 version = FILE_FORMAT_VERSION;
|
||||||
struct perm_data *p = NULL;
|
struct perm_data *p = NULL;
|
||||||
struct list_head *pos = NULL;
|
struct list_head *pos = NULL;
|
||||||
loff_t off = 0;
|
loff_t off = 0;
|
||||||
|
|
||||||
mutex_lock(&allowlist_mutex);
|
struct file *fp =
|
||||||
struct file *fp =
|
ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
if (IS_ERR(fp)) {
|
||||||
if (IS_ERR(fp)) {
|
pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp));
|
||||||
pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp));
|
return;
|
||||||
goto unlock;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// store magic and version
|
// store magic and version
|
||||||
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
|
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
|
||||||
pr_err("save_allow_list write magic failed.\n");
|
sizeof(magic)) {
|
||||||
goto close_file;
|
pr_err("save_allow_list write magic failed.\n");
|
||||||
}
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
|
||||||
pr_err("save_allow_list write version failed.\n");
|
sizeof(version)) {
|
||||||
goto close_file;
|
pr_err("save_allow_list write version failed.\n");
|
||||||
}
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
list_for_each (pos, &allow_list) {
|
||||||
p = list_entry(pos, struct perm_data, list);
|
p = list_entry(pos, struct perm_data, list);
|
||||||
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
|
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
|
||||||
p->profile.key, p->profile.current_uid, p->profile.allow_su);
|
p->profile.key, p->profile.current_uid,
|
||||||
|
p->profile.allow_su);
|
||||||
|
|
||||||
kernel_write(fp, &p->profile, sizeof(p->profile), &off);
|
ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile),
|
||||||
}
|
&off);
|
||||||
|
}
|
||||||
close_file:
|
|
||||||
filp_close(fp, 0);
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(&allowlist_mutex);
|
|
||||||
kfree(_cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void persistent_allow_list()
|
|
||||||
{
|
|
||||||
struct task_struct *tsk;
|
|
||||||
|
|
||||||
tsk = get_pid_task(find_vpid(1), PIDTYPE_PID);
|
|
||||||
if (!tsk) {
|
|
||||||
pr_err("save_allow_list find init task err\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct callback_head *cb =
|
|
||||||
kzalloc(sizeof(struct callback_head), GFP_KERNEL);
|
|
||||||
if (!cb) {
|
|
||||||
pr_err("save_allow_list alloc cb err\b");
|
|
||||||
goto put_task;
|
|
||||||
}
|
|
||||||
cb->func = do_persistent_allow_list;
|
|
||||||
task_work_add(tsk, cb, TWA_RESUME);
|
|
||||||
|
|
||||||
put_task:
|
|
||||||
put_task_struct(tsk);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_load_allow_list()
|
|
||||||
{
|
|
||||||
loff_t off = 0;
|
|
||||||
ssize_t ret = 0;
|
|
||||||
struct file *fp = NULL;
|
|
||||||
u32 magic;
|
|
||||||
u32 version;
|
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
|
||||||
// always allow adb shell by default
|
|
||||||
ksu_grant_root_to_shell();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// load allowlist now!
|
|
||||||
fp = filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
|
|
||||||
if (IS_ERR(fp)) {
|
|
||||||
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify magic
|
|
||||||
if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
|
|
||||||
magic != FILE_MAGIC) {
|
|
||||||
pr_err("allowlist file invalid: %d!\n", magic);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kernel_read(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
|
||||||
pr_err("allowlist read version: %d failed\n", version);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("allowlist version: %d\n", version);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
struct app_profile profile;
|
|
||||||
|
|
||||||
ret = kernel_read(fp, &profile, sizeof(profile), &off);
|
|
||||||
|
|
||||||
if (ret <= 0) {
|
|
||||||
pr_info("load_allow_list read err: %zd\n", ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n", profile.key,
|
|
||||||
profile.current_uid, profile.allow_su);
|
|
||||||
ksu_set_app_profile(&profile, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
ksu_show_allow_list();
|
filp_close(fp, 0);
|
||||||
filp_close(fp, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *),
|
void do_load_allow_list(struct work_struct *work)
|
||||||
void *data)
|
|
||||||
{
|
{
|
||||||
struct perm_data *np = NULL;
|
loff_t off = 0;
|
||||||
struct perm_data *n = NULL;
|
ssize_t ret = 0;
|
||||||
|
struct file *fp = NULL;
|
||||||
|
u32 magic;
|
||||||
|
u32 version;
|
||||||
|
|
||||||
if (!ksu_boot_completed) {
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
pr_info("boot not completed, skip prune\n");
|
// always allow adb shell by default
|
||||||
return;
|
ksu_grant_root_to_shell();
|
||||||
}
|
#endif
|
||||||
|
|
||||||
bool modified = false;
|
// load allowlist now!
|
||||||
// TODO: use RCU!
|
fp = ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
|
||||||
mutex_lock(&allowlist_mutex);
|
if (IS_ERR(fp)) {
|
||||||
list_for_each_entry_safe (np, n, &allow_list, list) {
|
pr_err("load_allow_list open file failed: %ld\n", PTR_ERR(fp));
|
||||||
uid_t uid = np->profile.current_uid;
|
return;
|
||||||
char *package = np->profile.key;
|
}
|
||||||
// we use this uid for special cases, don't prune it!
|
|
||||||
bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID;
|
|
||||||
if (!is_preserved_uid && !is_uid_valid(uid, package, data)) {
|
|
||||||
modified = true;
|
|
||||||
pr_info("prune uid: %d, package: %s\n", uid, package);
|
|
||||||
list_del(&np->list);
|
|
||||||
if (likely(uid <= BITMAP_UID_MAX)) {
|
|
||||||
allow_list_bitmap[uid / BITS_PER_BYTE] &=
|
|
||||||
~(1 << (uid % BITS_PER_BYTE));
|
|
||||||
}
|
|
||||||
remove_uid_from_arr(uid);
|
|
||||||
smp_mb();
|
|
||||||
kfree(np);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&allowlist_mutex);
|
|
||||||
|
|
||||||
if (modified) {
|
// verify magic
|
||||||
persistent_allow_list();
|
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) !=
|
||||||
}
|
sizeof(magic) ||
|
||||||
|
magic != FILE_MAGIC) {
|
||||||
|
pr_err("allowlist file invalid: %d!\n", magic);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) !=
|
||||||
|
sizeof(version)) {
|
||||||
|
pr_err("allowlist read version: %d failed\n", version);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("allowlist version: %d\n", version);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
struct app_profile profile;
|
||||||
|
|
||||||
|
ret = ksu_kernel_read_compat(fp, &profile, sizeof(profile),
|
||||||
|
&off);
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
pr_info("load_allow_list read err: %zd\n", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("load_allow_uid, name: %s, uid: %d, allow: %d\n",
|
||||||
|
profile.key, profile.current_uid, profile.allow_su);
|
||||||
|
ksu_set_app_profile(&profile, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
ksu_show_allow_list();
|
||||||
|
filp_close(fp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data)
|
||||||
|
{
|
||||||
|
struct perm_data *np = NULL;
|
||||||
|
struct perm_data *n = NULL;
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
// TODO: use RCU!
|
||||||
|
mutex_lock(&allowlist_mutex);
|
||||||
|
list_for_each_entry_safe (np, n, &allow_list, list) {
|
||||||
|
uid_t uid = np->profile.current_uid;
|
||||||
|
char *package = np->profile.key;
|
||||||
|
// we use this uid for special cases, don't prune it!
|
||||||
|
bool is_preserved_uid = uid == KSU_APP_PROFILE_PRESERVE_UID;
|
||||||
|
if (!is_preserved_uid && !is_uid_valid(uid, package, data)) {
|
||||||
|
modified = true;
|
||||||
|
pr_info("prune uid: %d, package: %s\n", uid, package);
|
||||||
|
list_del(&np->list);
|
||||||
|
if (likely(uid <= BITMAP_UID_MAX)) {
|
||||||
|
allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE));
|
||||||
|
}
|
||||||
|
remove_uid_from_arr(uid);
|
||||||
|
smp_mb();
|
||||||
|
kfree(np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&allowlist_mutex);
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
persistent_allow_list();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure allow list works cross boot
|
||||||
|
bool persistent_allow_list(void)
|
||||||
|
{
|
||||||
|
return ksu_queue_work(&ksu_save_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ksu_load_allow_list(void)
|
||||||
|
{
|
||||||
|
return ksu_queue_work(&ksu_load_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_allowlist_init(void)
|
void ksu_allowlist_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE);
|
BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE);
|
||||||
BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE);
|
BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++)
|
for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++)
|
||||||
allow_list_arr[i] = -1;
|
allow_list_arr[i] = -1;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&allow_list);
|
INIT_LIST_HEAD(&allow_list);
|
||||||
|
|
||||||
init_default_profiles();
|
INIT_WORK(&ksu_save_work, do_save_allow_list);
|
||||||
|
INIT_WORK(&ksu_load_work, do_load_allow_list);
|
||||||
|
|
||||||
|
init_default_profiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_allowlist_exit(void)
|
void ksu_allowlist_exit(void)
|
||||||
{
|
{
|
||||||
struct perm_data *np = NULL;
|
struct perm_data *np = NULL;
|
||||||
struct perm_data *n = NULL;
|
struct perm_data *n = NULL;
|
||||||
|
|
||||||
// free allowlist
|
do_save_allow_list(NULL);
|
||||||
mutex_lock(&allowlist_mutex);
|
|
||||||
list_for_each_entry_safe (np, n, &allow_list, list) {
|
// free allowlist
|
||||||
list_del(&np->list);
|
mutex_lock(&allowlist_mutex);
|
||||||
kfree(np);
|
list_for_each_entry_safe (np, n, &allow_list, list) {
|
||||||
}
|
list_del(&np->list);
|
||||||
mutex_unlock(&allowlist_mutex);
|
kfree(np);
|
||||||
|
}
|
||||||
|
mutex_unlock(&allowlist_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
|
||||||
bool ksu_temp_grant_root_once(uid_t uid)
|
|
||||||
{
|
|
||||||
struct app_profile profile = {
|
|
||||||
.version = KSU_APP_PROFILE_VER,
|
|
||||||
.allow_su = true,
|
|
||||||
.current_uid = uid,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *default_key = "com.temp.once";
|
|
||||||
|
|
||||||
struct perm_data *p = NULL;
|
|
||||||
struct list_head *pos = NULL;
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
|
||||||
p = list_entry(pos, struct perm_data, list);
|
|
||||||
if (p->profile.current_uid == uid) {
|
|
||||||
strcpy(profile.key, p->profile.key);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
strcpy(profile.key, default_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.rp_config.profile.uid = default_root_profile.uid;
|
|
||||||
profile.rp_config.profile.gid = default_root_profile.gid;
|
|
||||||
profile.rp_config.profile.groups_count = default_root_profile.groups_count;
|
|
||||||
memcpy(profile.rp_config.profile.groups, default_root_profile.groups, sizeof(default_root_profile.groups));
|
|
||||||
memcpy(&profile.rp_config.profile.capabilities, &default_root_profile.capabilities, sizeof(default_root_profile.capabilities));
|
|
||||||
profile.rp_config.profile.namespaces = default_root_profile.namespaces;
|
|
||||||
strcpy(profile.rp_config.profile.selinux_domain, default_root_profile.selinux_domain);
|
|
||||||
|
|
||||||
bool ok = ksu_set_app_profile(&profile, false);
|
|
||||||
if (ok)
|
|
||||||
pr_info("pending_root: UID=%d granted and persisted\n", uid);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_temp_revoke_root_once(uid_t uid)
|
|
||||||
{
|
|
||||||
struct app_profile profile = {
|
|
||||||
.version = KSU_APP_PROFILE_VER,
|
|
||||||
.allow_su = false,
|
|
||||||
.current_uid = uid,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *default_key = "com.temp.once";
|
|
||||||
|
|
||||||
struct perm_data *p = NULL;
|
|
||||||
struct list_head *pos = NULL;
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
list_for_each (pos, &allow_list) {
|
|
||||||
p = list_entry(pos, struct perm_data, list);
|
|
||||||
if (p->profile.current_uid == uid) {
|
|
||||||
strcpy(profile.key, p->profile.key);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
strcpy(profile.key, default_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.nrp_config.profile.umount_modules = default_non_root_profile.umount_modules;
|
|
||||||
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
|
|
||||||
|
|
||||||
ksu_set_app_profile(&profile, false);
|
|
||||||
persistent_allow_list();
|
|
||||||
pr_info("pending_root: UID=%d removed and persist updated\n", uid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -2,31 +2,19 @@
|
|||||||
#define __KSU_H_ALLOWLIST
|
#define __KSU_H_ALLOWLIST
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/uidgid.h>
|
#include "ksu.h"
|
||||||
#include "app_profile.h"
|
|
||||||
|
|
||||||
#define PER_USER_RANGE 100000
|
|
||||||
#define FIRST_APPLICATION_UID 10000
|
|
||||||
#define LAST_APPLICATION_UID 19999
|
|
||||||
#define FIRST_ISOLATED_UID 99000
|
|
||||||
#define LAST_ISOLATED_UID 99999
|
|
||||||
|
|
||||||
void ksu_allowlist_init(void);
|
void ksu_allowlist_init(void);
|
||||||
|
|
||||||
void ksu_allowlist_exit(void);
|
void ksu_allowlist_exit(void);
|
||||||
|
|
||||||
void ksu_load_allow_list(void);
|
bool ksu_load_allow_list(void);
|
||||||
|
|
||||||
void ksu_show_allow_list(void);
|
void ksu_show_allow_list(void);
|
||||||
|
|
||||||
// Check if the uid is in allow list
|
|
||||||
bool __ksu_is_allow_uid(uid_t uid);
|
bool __ksu_is_allow_uid(uid_t uid);
|
||||||
#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid))
|
#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid))
|
||||||
|
|
||||||
// Check if the uid is in allow list, or current is ksu domain root
|
|
||||||
bool __ksu_is_allow_uid_for_current(uid_t uid);
|
|
||||||
#define ksu_is_allow_uid_for_current(uid) unlikely(__ksu_is_allow_uid_for_current(uid))
|
|
||||||
|
|
||||||
bool ksu_get_allow_list(int *array, int *length, bool allow);
|
bool ksu_get_allow_list(int *array, int *length, bool allow);
|
||||||
|
|
||||||
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), void *data);
|
void ksu_prune_allowlist(bool (*is_uid_exist)(uid_t, char *, void *), void *data);
|
||||||
@@ -36,22 +24,4 @@ bool ksu_set_app_profile(struct app_profile *, bool persist);
|
|||||||
|
|
||||||
bool ksu_uid_should_umount(uid_t uid);
|
bool ksu_uid_should_umount(uid_t uid);
|
||||||
struct root_profile *ksu_get_root_profile(uid_t uid);
|
struct root_profile *ksu_get_root_profile(uid_t uid);
|
||||||
|
|
||||||
static inline bool is_appuid(uid_t uid)
|
|
||||||
{
|
|
||||||
uid_t appid = uid % PER_USER_RANGE;
|
|
||||||
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool is_isolated_process(uid_t uid)
|
|
||||||
{
|
|
||||||
uid_t appid = uid % PER_USER_RANGE;
|
|
||||||
return appid >= FIRST_ISOLATED_UID && appid <= LAST_ISOLATED_UID;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
|
||||||
bool ksu_temp_grant_root_once(uid_t uid);
|
|
||||||
void ksu_temp_revoke_root_once(uid_t uid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,375 +15,329 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "apk_sign.h"
|
#include "apk_sign.h"
|
||||||
#include "dynamic_manager.h"
|
#include "dynamic_sign.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "kernel_compat.h"
|
||||||
#include "manager_sign.h"
|
#include "manager_sign.h"
|
||||||
|
|
||||||
struct sdesc {
|
struct sdesc {
|
||||||
struct shash_desc shash;
|
struct shash_desc shash;
|
||||||
char ctx[];
|
char ctx[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static apk_sign_key_t apk_sign_keys[] = {
|
static struct apk_sign_key {
|
||||||
{EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // ShirkNeko/SukiSU
|
unsigned size;
|
||||||
|
const char *sha256;
|
||||||
|
} apk_sign_keys[] = {
|
||||||
|
{EXPECTED_SIZE_SHIRKNEKO, EXPECTED_HASH_SHIRKNEKO}, // ShirkNeko/SukiSU
|
||||||
|
{EXPECTED_SIZE_OTHER, EXPECTED_HASH_OTHER}, // Dynamic Sign
|
||||||
#ifdef EXPECTED_SIZE
|
#ifdef EXPECTED_SIZE
|
||||||
{EXPECTED_SIZE, EXPECTED_HASH}, // Custom
|
{EXPECTED_SIZE, EXPECTED_HASH}, // Custom
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sdesc *init_sdesc(struct crypto_shash *alg)
|
static struct sdesc *init_sdesc(struct crypto_shash *alg)
|
||||||
{
|
{
|
||||||
struct sdesc *sdesc;
|
struct sdesc *sdesc;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
|
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
|
||||||
sdesc = kzalloc(size, GFP_KERNEL);
|
sdesc = kmalloc(size, GFP_KERNEL);
|
||||||
if (!sdesc)
|
if (!sdesc)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
sdesc->shash.tfm = alg;
|
sdesc->shash.tfm = alg;
|
||||||
return sdesc;
|
return sdesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int calc_hash(struct crypto_shash *alg, const unsigned char *data,
|
static int calc_hash(struct crypto_shash *alg, const unsigned char *data,
|
||||||
unsigned int datalen, unsigned char *digest)
|
unsigned int datalen, unsigned char *digest)
|
||||||
{
|
{
|
||||||
struct sdesc *sdesc;
|
struct sdesc *sdesc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sdesc = init_sdesc(alg);
|
sdesc = init_sdesc(alg);
|
||||||
if (IS_ERR(sdesc)) {
|
if (IS_ERR(sdesc)) {
|
||||||
pr_info("can't alloc sdesc\n");
|
pr_info("can't alloc sdesc\n");
|
||||||
return PTR_ERR(sdesc);
|
return PTR_ERR(sdesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
|
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
|
||||||
kfree(sdesc);
|
kfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ksu_sha256(const unsigned char *data, unsigned int datalen,
|
static int ksu_sha256(const unsigned char *data, unsigned int datalen,
|
||||||
unsigned char *digest)
|
unsigned char *digest)
|
||||||
{
|
{
|
||||||
struct crypto_shash *alg;
|
struct crypto_shash *alg;
|
||||||
char *hash_alg_name = "sha256";
|
char *hash_alg_name = "sha256";
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
alg = crypto_alloc_shash(hash_alg_name, 0, 0);
|
alg = crypto_alloc_shash(hash_alg_name, 0, 0);
|
||||||
if (IS_ERR(alg)) {
|
if (IS_ERR(alg)) {
|
||||||
pr_info("can't alloc alg %s\n", hash_alg_name);
|
pr_info("can't alloc alg %s\n", hash_alg_name);
|
||||||
return PTR_ERR(alg);
|
return PTR_ERR(alg);
|
||||||
}
|
}
|
||||||
ret = calc_hash(alg, data, datalen, digest);
|
ret = calc_hash(alg, data, datalen, digest);
|
||||||
crypto_free_shash(alg);
|
crypto_free_shash(alg);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct dynamic_sign_key dynamic_sign = DYNAMIC_SIGN_DEFAULT_CONFIG;
|
|
||||||
|
|
||||||
static bool check_dynamic_sign(struct file *fp, u32 size4, loff_t *pos, int *matched_index)
|
|
||||||
{
|
|
||||||
struct dynamic_sign_key current_dynamic_key = dynamic_sign;
|
|
||||||
|
|
||||||
if (ksu_get_dynamic_manager_config(¤t_dynamic_key.size, ¤t_dynamic_key.hash)) {
|
|
||||||
pr_debug("Using dynamic manager config: size=0x%x, hash=%.16s...\n",
|
|
||||||
current_dynamic_key.size, current_dynamic_key.hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size4 != current_dynamic_key.size) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CERT_MAX_LENGTH 1024
|
|
||||||
char cert[CERT_MAX_LENGTH];
|
|
||||||
if (size4 > CERT_MAX_LENGTH) {
|
|
||||||
pr_info("cert length overlimit\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel_read(fp, cert, size4, pos);
|
|
||||||
|
|
||||||
unsigned char digest[SHA256_DIGEST_SIZE];
|
|
||||||
if (ksu_sha256(cert, size4, digest) < 0) {
|
|
||||||
pr_info("sha256 error\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char hash_str[SHA256_DIGEST_SIZE * 2 + 1];
|
|
||||||
hash_str[SHA256_DIGEST_SIZE * 2] = '\0';
|
|
||||||
bin2hex(hash_str, digest, SHA256_DIGEST_SIZE);
|
|
||||||
|
|
||||||
pr_info("sha256: %s, expected: %s, index: dynamic\n", hash_str, current_dynamic_key.hash);
|
|
||||||
|
|
||||||
if (strcmp(current_dynamic_key.hash, hash_str) == 0) {
|
|
||||||
if (matched_index) {
|
|
||||||
*matched_index = DYNAMIC_SIGN_INDEX;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, int *matched_index)
|
static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset, int *matched_index)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
apk_sign_key_t sign_key;
|
struct apk_sign_key sign_key;
|
||||||
bool signature_valid = false;
|
bool signature_valid = false;
|
||||||
|
|
||||||
kernel_read(fp, size4, 0x4, pos); // signer-sequence length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length
|
||||||
kernel_read(fp, size4, 0x4, pos); // signer length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length
|
||||||
kernel_read(fp, size4, 0x4, pos); // signed data length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length
|
||||||
|
|
||||||
*offset += 0x4 * 3;
|
*offset += 0x4 * 3;
|
||||||
|
|
||||||
kernel_read(fp, size4, 0x4, pos); // digests-sequence length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length
|
||||||
|
|
||||||
*pos += *size4;
|
*pos += *size4;
|
||||||
*offset += 0x4 + *size4;
|
*offset += 0x4 + *size4;
|
||||||
|
|
||||||
kernel_read(fp, size4, 0x4, pos); // certificates length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length
|
||||||
kernel_read(fp, size4, 0x4, pos); // certificate length
|
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length
|
||||||
*offset += 0x4 * 2;
|
*offset += 0x4 * 2;
|
||||||
|
|
||||||
if (ksu_is_dynamic_manager_enabled()) {
|
for (i = 0; i < ARRAY_SIZE(apk_sign_keys); i++) {
|
||||||
loff_t temp_pos = *pos;
|
sign_key = apk_sign_keys[i];
|
||||||
if (check_dynamic_sign(fp, *size4, &temp_pos, matched_index)) {
|
|
||||||
*pos = temp_pos;
|
|
||||||
*offset += *size4;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(apk_sign_keys); i++) {
|
if (i == 1) { // Dynamic Sign indexing
|
||||||
sign_key = apk_sign_keys[i];
|
unsigned int size;
|
||||||
|
const char *hash;
|
||||||
|
if (ksu_get_dynamic_sign_config(&size, &hash)) {
|
||||||
|
sign_key.size = size;
|
||||||
|
sign_key.sha256 = hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (*size4 != sign_key.size)
|
if (*size4 != sign_key.size)
|
||||||
continue;
|
continue;
|
||||||
*offset += *size4;
|
*offset += *size4;
|
||||||
|
|
||||||
#define CERT_MAX_LENGTH 1024
|
#define CERT_MAX_LENGTH 1024
|
||||||
char cert[CERT_MAX_LENGTH];
|
char cert[CERT_MAX_LENGTH];
|
||||||
if (*size4 > CERT_MAX_LENGTH) {
|
if (*size4 > CERT_MAX_LENGTH) {
|
||||||
pr_info("cert length overlimit\n");
|
pr_info("cert length overlimit\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
kernel_read(fp, cert, *size4, pos);
|
ksu_kernel_read_compat(fp, cert, *size4, pos);
|
||||||
unsigned char digest[SHA256_DIGEST_SIZE];
|
unsigned char digest[SHA256_DIGEST_SIZE];
|
||||||
if (ksu_sha256(cert, *size4, digest) < 0 ) {
|
if (IS_ERR(ksu_sha256(cert, *size4, digest))) {
|
||||||
pr_info("sha256 error\n");
|
pr_info("sha256 error\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char hash_str[SHA256_DIGEST_SIZE * 2 + 1];
|
char hash_str[SHA256_DIGEST_SIZE * 2 + 1];
|
||||||
hash_str[SHA256_DIGEST_SIZE * 2] = '\0';
|
hash_str[SHA256_DIGEST_SIZE * 2] = '\0';
|
||||||
|
|
||||||
bin2hex(hash_str, digest, SHA256_DIGEST_SIZE);
|
bin2hex(hash_str, digest, SHA256_DIGEST_SIZE);
|
||||||
pr_info("sha256: %s, expected: %s, index: %d\n", hash_str, sign_key.sha256, i);
|
pr_info("sha256: %s, expected: %s, index: %d\n", hash_str, sign_key.sha256, i);
|
||||||
|
|
||||||
if (strcmp(sign_key.sha256, hash_str) == 0) {
|
if (strcmp(sign_key.sha256, hash_str) == 0) {
|
||||||
signature_valid = true;
|
signature_valid = true;
|
||||||
if (matched_index) {
|
if (matched_index) {
|
||||||
*matched_index = i;
|
*matched_index = i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return signature_valid;
|
return signature_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct zip_entry_header {
|
struct zip_entry_header {
|
||||||
uint32_t signature;
|
uint32_t signature;
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint16_t compression;
|
uint16_t compression;
|
||||||
uint16_t mod_time;
|
uint16_t mod_time;
|
||||||
uint16_t mod_date;
|
uint16_t mod_date;
|
||||||
uint32_t crc32;
|
uint32_t crc32;
|
||||||
uint32_t compressed_size;
|
uint32_t compressed_size;
|
||||||
uint32_t uncompressed_size;
|
uint32_t uncompressed_size;
|
||||||
uint16_t file_name_length;
|
uint16_t file_name_length;
|
||||||
uint16_t extra_field_length;
|
uint16_t extra_field_length;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
// This is a necessary but not sufficient condition, but it is enough for us
|
// This is a necessary but not sufficient condition, but it is enough for us
|
||||||
static bool has_v1_signature_file(struct file *fp)
|
static bool has_v1_signature_file(struct file *fp)
|
||||||
{
|
{
|
||||||
struct zip_entry_header header;
|
struct zip_entry_header header;
|
||||||
const char MANIFEST[] = "META-INF/MANIFEST.MF";
|
const char MANIFEST[] = "META-INF/MANIFEST.MF";
|
||||||
|
|
||||||
loff_t pos = 0;
|
loff_t pos = 0;
|
||||||
|
|
||||||
while (kernel_read(fp, &header,
|
while (ksu_kernel_read_compat(fp, &header,
|
||||||
sizeof(struct zip_entry_header), &pos) ==
|
sizeof(struct zip_entry_header), &pos) ==
|
||||||
sizeof(struct zip_entry_header)) {
|
sizeof(struct zip_entry_header)) {
|
||||||
if (header.signature != 0x04034b50) {
|
if (header.signature != 0x04034b50) {
|
||||||
// ZIP magic: 'PK'
|
// ZIP magic: 'PK'
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Read the entry file name
|
// Read the entry file name
|
||||||
if (header.file_name_length == sizeof(MANIFEST) - 1) {
|
if (header.file_name_length == sizeof(MANIFEST) - 1) {
|
||||||
char fileName[sizeof(MANIFEST)];
|
char fileName[sizeof(MANIFEST)];
|
||||||
kernel_read(fp, fileName,
|
ksu_kernel_read_compat(fp, fileName,
|
||||||
header.file_name_length, &pos);
|
header.file_name_length, &pos);
|
||||||
fileName[header.file_name_length] = '\0';
|
fileName[header.file_name_length] = '\0';
|
||||||
|
|
||||||
// Check if the entry matches META-INF/MANIFEST.MF
|
// Check if the entry matches META-INF/MANIFEST.MF
|
||||||
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) ==
|
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) == 0) {
|
||||||
0) {
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
// Skip the entry file name
|
||||||
// Skip the entry file name
|
pos += header.file_name_length;
|
||||||
pos += header.file_name_length;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Skip to the next entry
|
// Skip to the next entry
|
||||||
pos += header.extra_field_length + header.compressed_size;
|
pos += header.extra_field_length + header.compressed_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline bool check_v2_signature(char *path, bool check_multi_manager, int *signature_index)
|
static __always_inline bool check_v2_signature(char *path, bool check_multi_manager, int *signature_index)
|
||||||
{
|
{
|
||||||
unsigned char buffer[0x11] = { 0 };
|
unsigned char buffer[0x11] = { 0 };
|
||||||
u32 size4;
|
u32 size4;
|
||||||
u64 size8, size_of_block;
|
u64 size8, size_of_block;
|
||||||
|
loff_t pos;
|
||||||
|
bool v2_signing_valid = false;
|
||||||
|
int v2_signing_blocks = 0;
|
||||||
|
bool v3_signing_exist = false;
|
||||||
|
bool v3_1_signing_exist = false;
|
||||||
|
int matched_index = -1;
|
||||||
|
int i;
|
||||||
|
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
|
||||||
|
if (IS_ERR(fp)) {
|
||||||
|
pr_err("open %s error.\n", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
loff_t pos;
|
// If you want to check for multi-manager APK signing, but dynamic signing is not enabled, skip
|
||||||
|
if (check_multi_manager && !ksu_is_dynamic_sign_enabled()) {
|
||||||
|
filp_close(fp, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool v2_signing_valid = false;
|
// disable inotify for this file
|
||||||
int v2_signing_blocks = 0;
|
fp->f_mode |= FMODE_NONOTIFY;
|
||||||
bool v3_signing_exist = false;
|
|
||||||
bool v3_1_signing_exist = false;
|
|
||||||
int matched_index = -1;
|
|
||||||
int i;
|
|
||||||
struct file *fp = filp_open(path, O_RDONLY, 0);
|
|
||||||
if (IS_ERR(fp)) {
|
|
||||||
pr_err("open %s error.\n", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If you want to check for multi-manager APK signing, but dynamic managering is not enabled, skip
|
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
|
||||||
if (check_multi_manager && !ksu_is_dynamic_manager_enabled()) {
|
for (i = 0;; ++i) {
|
||||||
filp_close(fp, 0);
|
unsigned short n;
|
||||||
return 0;
|
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
|
||||||
}
|
ksu_kernel_read_compat(fp, &n, 2, &pos);
|
||||||
|
if (n == i) {
|
||||||
|
pos -= 22;
|
||||||
|
ksu_kernel_read_compat(fp, &size4, 4, &pos);
|
||||||
|
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 0xffff) {
|
||||||
|
pr_info("error: cannot find eocd\n");
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// disable inotify for this file
|
pos += 12;
|
||||||
fp->f_mode |= FMODE_NONOTIFY;
|
// offset
|
||||||
|
ksu_kernel_read_compat(fp, &size4, 0x4, &pos);
|
||||||
|
pos = size4 - 0x18;
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
|
ksu_kernel_read_compat(fp, &size8, 0x8, &pos);
|
||||||
for (i = 0;; ++i) {
|
ksu_kernel_read_compat(fp, buffer, 0x10, &pos);
|
||||||
unsigned short n;
|
if (strcmp((char *)buffer, "APK Sig Block 42")) {
|
||||||
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
|
goto clean;
|
||||||
kernel_read(fp, &n, 2, &pos);
|
}
|
||||||
if (n == i) {
|
|
||||||
pos -= 22;
|
|
||||||
kernel_read(fp, &size4, 4, &pos);
|
|
||||||
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == 0xffff) {
|
|
||||||
pr_info("error: cannot find eocd\n");
|
|
||||||
goto clean;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += 12;
|
pos = size4 - (size8 + 0x8);
|
||||||
// offset
|
ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos);
|
||||||
kernel_read(fp, &size4, 0x4, &pos);
|
if (size_of_block != size8) {
|
||||||
pos = size4 - 0x18;
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
kernel_read(fp, &size8, 0x8, &pos);
|
int loop_count = 0;
|
||||||
kernel_read(fp, buffer, 0x10, &pos);
|
while (loop_count++ < 10) {
|
||||||
if (strcmp((char *)buffer, "APK Sig Block 42")) {
|
uint32_t id;
|
||||||
goto clean;
|
uint32_t offset;
|
||||||
}
|
ksu_kernel_read_compat(fp, &size8, 0x8,
|
||||||
|
&pos); // sequence length
|
||||||
pos = size4 - (size8 + 0x8);
|
if (size8 == size_of_block) {
|
||||||
kernel_read(fp, &size_of_block, 0x8, &pos);
|
break;
|
||||||
if (size_of_block != size8) {
|
}
|
||||||
goto clean;
|
ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id
|
||||||
}
|
offset = 4;
|
||||||
|
if (id == 0x7109871au) {
|
||||||
int loop_count = 0;
|
v2_signing_blocks++;
|
||||||
while (loop_count++ < 10) {
|
bool result = check_block(fp, &size4, &pos, &offset, &matched_index);
|
||||||
uint32_t id;
|
if (result) {
|
||||||
uint32_t offset;
|
v2_signing_valid = true;
|
||||||
kernel_read(fp, &size8, 0x8,
|
}
|
||||||
&pos); // sequence length
|
} else if (id == 0xf05368c0u) {
|
||||||
if (size8 == size_of_block) {
|
// http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#73
|
||||||
break;
|
v3_signing_exist = true;
|
||||||
}
|
} else if (id == 0x1b93ad61u) {
|
||||||
kernel_read(fp, &id, 0x4, &pos); // id
|
// http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#74
|
||||||
offset = 4;
|
v3_1_signing_exist = true;
|
||||||
if (id == 0x7109871au) {
|
} else {
|
||||||
v2_signing_blocks++;
|
|
||||||
bool result = check_block(fp, &size4, &pos, &offset, &matched_index);
|
|
||||||
if (result) {
|
|
||||||
v2_signing_valid = true;
|
|
||||||
}
|
|
||||||
} else if (id == 0xf05368c0u) {
|
|
||||||
// http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#73
|
|
||||||
v3_signing_exist = true;
|
|
||||||
} else if (id == 0x1b93ad61u) {
|
|
||||||
// http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#74
|
|
||||||
v3_1_signing_exist = true;
|
|
||||||
} else {
|
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
pr_info("Unknown id: 0x%08x\n", id);
|
pr_info("Unknown id: 0x%08x\n", id);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
pos += (size8 - offset);
|
pos += (size8 - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v2_signing_blocks != 1) {
|
if (v2_signing_blocks != 1) {
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
pr_err("Unexpected v2 signature count: %d\n",
|
pr_err("Unexpected v2 signature count: %d\n",
|
||||||
v2_signing_blocks);
|
v2_signing_blocks);
|
||||||
#endif
|
#endif
|
||||||
v2_signing_valid = false;
|
v2_signing_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v2_signing_valid) {
|
if (v2_signing_valid) {
|
||||||
int has_v1_signing = has_v1_signature_file(fp);
|
int has_v1_signing = has_v1_signature_file(fp);
|
||||||
if (has_v1_signing) {
|
if (has_v1_signing) {
|
||||||
pr_err("Unexpected v1 signature scheme found!\n");
|
pr_err("Unexpected v1 signature scheme found!\n");
|
||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clean:
|
clean:
|
||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
|
|
||||||
if (v3_signing_exist || v3_1_signing_exist) {
|
if (v3_signing_exist || v3_1_signing_exist) {
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
pr_err("Unexpected v3 signature scheme found!\n");
|
pr_err("Unexpected v3 signature scheme found!\n");
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v2_signing_valid) {
|
if (v2_signing_valid) {
|
||||||
if (signature_index) {
|
if (signature_index) {
|
||||||
*signature_index = matched_index;
|
*signature_index = matched_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_multi_manager) {
|
if (check_multi_manager) {
|
||||||
// 0: ShirkNeko/SukiSU, DYNAMIC_SIGN_INDEX : Dynamic Sign
|
// 0: ShirkNeko/SukiSU, 1: Dynamic Sign
|
||||||
if (matched_index == 0 || matched_index == DYNAMIC_SIGN_INDEX) {
|
if (matched_index == 0 || matched_index == 1) {
|
||||||
pr_info("Multi-manager APK detected (dynamic_manager enabled): signature_index=%d\n", matched_index);
|
pr_info("Multi-manager APK detected (dynamic_sign enabled): signature_index=%d\n", matched_index);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Common manager check: any valid signature will do
|
// Common manager check: any valid signature will do
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
@@ -394,19 +348,19 @@ int ksu_debug_manager_uid = -1;
|
|||||||
|
|
||||||
static int set_expected_size(const char *val, const struct kernel_param *kp)
|
static int set_expected_size(const char *val, const struct kernel_param *kp)
|
||||||
{
|
{
|
||||||
int rv = param_set_uint(val, kp);
|
int rv = param_set_uint(val, kp);
|
||||||
ksu_set_manager_uid(ksu_debug_manager_uid);
|
ksu_set_manager_uid(ksu_debug_manager_uid);
|
||||||
pr_info("ksu_manager_uid set to %d\n", ksu_debug_manager_uid);
|
pr_info("ksu_manager_uid set to %d\n", ksu_debug_manager_uid);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kernel_param_ops expected_size_ops = {
|
static struct kernel_param_ops expected_size_ops = {
|
||||||
.set = set_expected_size,
|
.set = set_expected_size,
|
||||||
.get = param_get_uint,
|
.get = param_get_uint,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
|
module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
|
||||||
&ksu_debug_manager_uid, S_IRUSR | S_IWUSR);
|
&ksu_debug_manager_uid, S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -415,7 +369,7 @@ bool is_manager_apk(char *path)
|
|||||||
return check_v2_signature(path, false, NULL);
|
return check_v2_signature(path, false, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_dynamic_manager_apk(char *path, int *signature_index)
|
bool ksu_is_multi_manager_apk(char *path, int *signature_index)
|
||||||
{
|
{
|
||||||
return check_v2_signature(path, true, signature_index);
|
return check_v2_signature(path, true, signature_index);
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,4 @@
|
|||||||
|
|
||||||
bool is_manager_apk(char *path);
|
bool is_manager_apk(char *path);
|
||||||
|
|
||||||
bool is_dynamic_manager_apk(char *path, int *signature_index);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,303 +0,0 @@
|
|||||||
#include <linux/capability.h>
|
|
||||||
#include <linux/cred.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/sched/signal.h>
|
|
||||||
#include <linux/seccomp.h>
|
|
||||||
#include <linux/thread_info.h>
|
|
||||||
#include <linux/uidgid.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include "objsec.h"
|
|
||||||
|
|
||||||
#include "allowlist.h"
|
|
||||||
#include "app_profile.h"
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
#include "selinux/selinux.h"
|
|
||||||
#include "syscall_hook_manager.h"
|
|
||||||
#include "sucompat.h"
|
|
||||||
|
|
||||||
#include "sulog.h"
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION (6, 7, 0)
|
|
||||||
static struct group_info root_groups = { .usage = REFCOUNT_INIT(2), };
|
|
||||||
#else
|
|
||||||
static struct group_info root_groups = { .usage = ATOMIC_INIT(2) };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void setup_groups(struct root_profile *profile, struct cred *cred)
|
|
||||||
{
|
|
||||||
if (profile->groups_count > KSU_MAX_GROUPS) {
|
|
||||||
pr_warn("Failed to setgroups, too large group: %d!\n",
|
|
||||||
profile->uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profile->groups_count == 1 && profile->groups[0] == 0) {
|
|
||||||
// setgroup to root and return early.
|
|
||||||
if (cred->group_info)
|
|
||||||
put_group_info(cred->group_info);
|
|
||||||
cred->group_info = get_group_info(&root_groups);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 ngroups = profile->groups_count;
|
|
||||||
struct group_info *group_info = groups_alloc(ngroups);
|
|
||||||
if (!group_info) {
|
|
||||||
pr_warn("Failed to setgroups, ENOMEM for: %d\n", profile->uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ngroups; i++) {
|
|
||||||
gid_t gid = profile->groups[i];
|
|
||||||
kgid_t kgid = make_kgid(current_user_ns(), gid);
|
|
||||||
if (!gid_valid(kgid)) {
|
|
||||||
pr_warn("Failed to setgroups, invalid gid: %d\n", gid);
|
|
||||||
put_group_info(group_info);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
group_info->gid[i] = kgid;
|
|
||||||
}
|
|
||||||
|
|
||||||
groups_sort(group_info);
|
|
||||||
set_groups(cred, group_info);
|
|
||||||
put_group_info(group_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable_seccomp(void)
|
|
||||||
{
|
|
||||||
assert_spin_locked(¤t->sighand->siglock);
|
|
||||||
// disable seccomp
|
|
||||||
#if defined(CONFIG_GENERIC_ENTRY) && \
|
|
||||||
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
|
|
||||||
clear_syscall_work(SECCOMP);
|
|
||||||
#else
|
|
||||||
clear_thread_flag(TIF_SECCOMP);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_SECCOMP
|
|
||||||
current->seccomp.mode = 0;
|
|
||||||
current->seccomp.filter = NULL;
|
|
||||||
atomic_set(¤t->seccomp.filter_count, 0);
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void escape_with_root_profile(void)
|
|
||||||
{
|
|
||||||
struct cred *cred;
|
|
||||||
struct task_struct *p = current;
|
|
||||||
struct task_struct *t;
|
|
||||||
|
|
||||||
cred = prepare_creds();
|
|
||||||
if (!cred) {
|
|
||||||
pr_warn("prepare_creds failed!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cred->euid.val == 0) {
|
|
||||||
pr_warn("Already root, don't escape!\n");
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root_failed");
|
|
||||||
#endif
|
|
||||||
abort_creds(cred);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
|
|
||||||
|
|
||||||
cred->uid.val = profile->uid;
|
|
||||||
cred->suid.val = profile->uid;
|
|
||||||
cred->euid.val = profile->uid;
|
|
||||||
cred->fsuid.val = profile->uid;
|
|
||||||
|
|
||||||
cred->gid.val = profile->gid;
|
|
||||||
cred->fsgid.val = profile->gid;
|
|
||||||
cred->sgid.val = profile->gid;
|
|
||||||
cred->egid.val = profile->gid;
|
|
||||||
cred->securebits = 0;
|
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
|
|
||||||
sizeof(kernel_cap_t));
|
|
||||||
|
|
||||||
// setup capabilities
|
|
||||||
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
|
|
||||||
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
|
|
||||||
u64 cap_for_ksud =
|
|
||||||
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
|
|
||||||
memcpy(&cred->cap_effective, &cap_for_ksud,
|
|
||||||
sizeof(cred->cap_effective));
|
|
||||||
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
|
|
||||||
sizeof(cred->cap_permitted));
|
|
||||||
memcpy(&cred->cap_bset, &profile->capabilities.effective,
|
|
||||||
sizeof(cred->cap_bset));
|
|
||||||
|
|
||||||
setup_groups(profile, cred);
|
|
||||||
|
|
||||||
commit_creds(cred);
|
|
||||||
|
|
||||||
// Refer to kernel/seccomp.c: seccomp_set_mode_strict
|
|
||||||
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
|
||||||
disable_seccomp();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
setup_selinux(profile->selinux_domain);
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_su_grant(current_euid().val, NULL, "escape_to_root");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for_each_thread (p, t) {
|
|
||||||
ksu_set_task_tracepoint_flag(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
|
||||||
|
|
||||||
#include "ksud.h"
|
|
||||||
|
|
||||||
#ifndef DEVPTS_SUPER_MAGIC
|
|
||||||
#define DEVPTS_SUPER_MAGIC 0x1cd1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int __manual_su_handle_devpts(struct inode *inode)
|
|
||||||
{
|
|
||||||
if (!current->mm) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uid_t uid = current_uid().val;
|
|
||||||
if (uid % 100000 < 10000) {
|
|
||||||
// not untrusted_app, ignore it
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (likely(!ksu_is_allow_uid_for_current(uid)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) || defined(KSU_OPTIONAL_SELINUX_INODE)
|
|
||||||
struct inode_security_struct *sec = selinux_inode(inode);
|
|
||||||
#else
|
|
||||||
struct inode_security_struct *sec =
|
|
||||||
(struct inode_security_struct *)inode->i_security;
|
|
||||||
#endif
|
|
||||||
if (ksu_file_sid && sec)
|
|
||||||
sec->sid = ksu_file_sid;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void disable_seccomp_for_task(struct task_struct *tsk)
|
|
||||||
{
|
|
||||||
assert_spin_locked(&tsk->sighand->siglock);
|
|
||||||
#ifdef CONFIG_SECCOMP
|
|
||||||
if (tsk->seccomp.mode == SECCOMP_MODE_DISABLED && !tsk->seccomp.filter)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
clear_tsk_thread_flag(tsk, TIF_SECCOMP);
|
|
||||||
#ifdef CONFIG_SECCOMP
|
|
||||||
tsk->seccomp.mode = SECCOMP_MODE_DISABLED;
|
|
||||||
if (tsk->seccomp.filter) {
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
|
||||||
seccomp_filter_release(tsk);
|
|
||||||
#else
|
|
||||||
put_seccomp_filter(tsk);
|
|
||||||
tsk->seccomp.filter = NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid)
|
|
||||||
{
|
|
||||||
struct cred *newcreds;
|
|
||||||
struct task_struct *target_task;
|
|
||||||
unsigned long flags;
|
|
||||||
struct task_struct *p = current;
|
|
||||||
struct task_struct *t;
|
|
||||||
|
|
||||||
pr_info("cmd_su: escape_to_root_for_cmd_su called for UID: %d, PID: %d\n", target_uid, target_pid);
|
|
||||||
|
|
||||||
// Find target task by PID
|
|
||||||
rcu_read_lock();
|
|
||||||
target_task = pid_task(find_vpid(target_pid), PIDTYPE_PID);
|
|
||||||
if (!target_task) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
pr_err("cmd_su: target task not found for PID: %d\n", target_pid);
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_su_grant(target_uid, "cmd_su", "target_not_found");
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
get_task_struct(target_task);
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (task_uid(target_task).val == 0) {
|
|
||||||
pr_warn("cmd_su: target task is already root, PID: %d\n", target_pid);
|
|
||||||
put_task_struct(target_task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newcreds = prepare_kernel_cred(target_task);
|
|
||||||
if (newcreds == NULL) {
|
|
||||||
pr_err("cmd_su: failed to allocate new cred for PID: %d\n", target_pid);
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_su_grant(target_uid, "cmd_su", "cred_alloc_failed");
|
|
||||||
#endif
|
|
||||||
put_task_struct(target_task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct root_profile *profile = ksu_get_root_profile(target_uid);
|
|
||||||
|
|
||||||
newcreds->uid.val = profile->uid;
|
|
||||||
newcreds->suid.val = profile->uid;
|
|
||||||
newcreds->euid.val = profile->uid;
|
|
||||||
newcreds->fsuid.val = profile->uid;
|
|
||||||
|
|
||||||
newcreds->gid.val = profile->gid;
|
|
||||||
newcreds->fsgid.val = profile->gid;
|
|
||||||
newcreds->sgid.val = profile->gid;
|
|
||||||
newcreds->egid.val = profile->gid;
|
|
||||||
newcreds->securebits = 0;
|
|
||||||
|
|
||||||
u64 cap_for_cmd_su = profile->capabilities.effective | CAP_DAC_READ_SEARCH | CAP_SETUID | CAP_SETGID;
|
|
||||||
memcpy(&newcreds->cap_effective, &cap_for_cmd_su, sizeof(newcreds->cap_effective));
|
|
||||||
memcpy(&newcreds->cap_permitted, &profile->capabilities.effective, sizeof(newcreds->cap_permitted));
|
|
||||||
memcpy(&newcreds->cap_bset, &profile->capabilities.effective, sizeof(newcreds->cap_bset));
|
|
||||||
|
|
||||||
setup_groups(profile, newcreds);
|
|
||||||
task_lock(target_task);
|
|
||||||
|
|
||||||
const struct cred *old_creds = get_task_cred(target_task);
|
|
||||||
|
|
||||||
rcu_assign_pointer(target_task->real_cred, newcreds);
|
|
||||||
rcu_assign_pointer(target_task->cred, get_cred(newcreds));
|
|
||||||
task_unlock(target_task);
|
|
||||||
|
|
||||||
if (target_task->sighand) {
|
|
||||||
spin_lock_irqsave(&target_task->sighand->siglock, flags);
|
|
||||||
disable_seccomp_for_task(target_task);
|
|
||||||
spin_unlock_irqrestore(&target_task->sighand->siglock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_selinux(profile->selinux_domain);
|
|
||||||
put_cred(old_creds);
|
|
||||||
wake_up_process(target_task);
|
|
||||||
|
|
||||||
if (target_task->signal->tty) {
|
|
||||||
struct inode *inode = target_task->signal->tty->driver_data;
|
|
||||||
if (inode && inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) {
|
|
||||||
__manual_su_handle_devpts(inode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
put_task_struct(target_task);
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_su_grant(target_uid, "cmd_su", "manual_escalation");
|
|
||||||
#endif
|
|
||||||
for_each_thread (p, t) {
|
|
||||||
ksu_set_task_tracepoint_flag(t);
|
|
||||||
}
|
|
||||||
pr_info("cmd_su: privilege escalation completed for UID: %d, PID: %d\n", target_uid, target_pid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#ifndef __KSU_H_APP_PROFILE
|
|
||||||
#define __KSU_H_APP_PROFILE
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
struct cred;
|
|
||||||
|
|
||||||
#define KSU_APP_PROFILE_VER 2
|
|
||||||
#define KSU_MAX_PACKAGE_NAME 256
|
|
||||||
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
|
|
||||||
#define KSU_MAX_GROUPS 32
|
|
||||||
#define KSU_SELINUX_DOMAIN 64
|
|
||||||
|
|
||||||
struct root_profile {
|
|
||||||
int32_t uid;
|
|
||||||
int32_t gid;
|
|
||||||
|
|
||||||
int32_t groups_count;
|
|
||||||
int32_t groups[KSU_MAX_GROUPS];
|
|
||||||
|
|
||||||
// kernel_cap_t is u32[2] for capabilities v3
|
|
||||||
struct {
|
|
||||||
u64 effective;
|
|
||||||
u64 permitted;
|
|
||||||
u64 inheritable;
|
|
||||||
} capabilities;
|
|
||||||
|
|
||||||
char selinux_domain[KSU_SELINUX_DOMAIN];
|
|
||||||
|
|
||||||
int32_t namespaces;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct non_root_profile {
|
|
||||||
bool umount_modules;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct app_profile {
|
|
||||||
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
|
|
||||||
u32 version;
|
|
||||||
|
|
||||||
// this is usually the package of the app, but can be other value for special apps
|
|
||||||
char key[KSU_MAX_PACKAGE_NAME];
|
|
||||||
int32_t current_uid;
|
|
||||||
bool allow_su;
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
bool use_default;
|
|
||||||
char template_name[KSU_MAX_PACKAGE_NAME];
|
|
||||||
|
|
||||||
struct root_profile profile;
|
|
||||||
} rp_config;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
bool use_default;
|
|
||||||
|
|
||||||
struct non_root_profile profile;
|
|
||||||
} nrp_config;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Escalate current process to root with the appropriate profile
|
|
||||||
void escape_with_root_profile(void);
|
|
||||||
|
|
||||||
void escape_to_root_for_cmd_su(uid_t target_uid, pid_t target_pid);
|
|
||||||
|
|
||||||
void disable_seccomp(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -18,8 +18,10 @@
|
|||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG pc
|
#define __PT_IP_REG pc
|
||||||
|
|
||||||
#define REBOOT_SYMBOL "__arm64_sys_reboot"
|
#define PRCTL_SYMBOL "__arm64_sys_prctl"
|
||||||
#define SYS_READ_SYMBOL "__arm64_sys_read"
|
#define SYS_READ_SYMBOL "__arm64_sys_read"
|
||||||
|
#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat"
|
||||||
|
#define SYS_FACCESSAT_SYMBOL "__arm64_sys_faccessat"
|
||||||
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
|
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
|
||||||
|
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
@@ -37,8 +39,10 @@
|
|||||||
#define __PT_RC_REG ax
|
#define __PT_RC_REG ax
|
||||||
#define __PT_SP_REG sp
|
#define __PT_SP_REG sp
|
||||||
#define __PT_IP_REG ip
|
#define __PT_IP_REG ip
|
||||||
#define REBOOT_SYMBOL "__x64_sys_reboot"
|
#define PRCTL_SYMBOL "__x64_sys_prctl"
|
||||||
#define SYS_READ_SYMBOL "__x64_sys_read"
|
#define SYS_READ_SYMBOL "__x64_sys_read"
|
||||||
|
#define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat"
|
||||||
|
#define SYS_FACCESSAT_SYMBOL "__x64_sys_faccessat"
|
||||||
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
|
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|||||||
1037
kernel/core_hook.c
Normal file
10
kernel/core_hook.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __KSU_H_KSU_CORE
|
||||||
|
#define __KSU_H_KSU_CORE
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include "apk_sign.h"
|
||||||
|
|
||||||
|
void __init ksu_core_init(void);
|
||||||
|
void ksu_core_exit(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#ifndef __KSU_H_DYNAMIC_MANAGER
|
|
||||||
#define __KSU_H_DYNAMIC_MANAGER
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include "ksu.h"
|
|
||||||
|
|
||||||
#define DYNAMIC_MANAGER_FILE_MAGIC 0x7f445347 // 'DSG', u32
|
|
||||||
#define DYNAMIC_MANAGER_FILE_VERSION 1 // u32
|
|
||||||
#define KERNEL_SU_DYNAMIC_MANAGER "/data/adb/ksu/.dynamic_manager"
|
|
||||||
#define DYNAMIC_SIGN_INDEX 100
|
|
||||||
|
|
||||||
struct dynamic_sign_key {
|
|
||||||
unsigned int size;
|
|
||||||
const char *hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DYNAMIC_SIGN_DEFAULT_CONFIG { \
|
|
||||||
.size = 0x300, \
|
|
||||||
.hash = "0000000000000000000000000000000000000000000000000000000000000000" \
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dynamic_manager_config {
|
|
||||||
unsigned int size;
|
|
||||||
char hash[65];
|
|
||||||
int is_set;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct manager_info {
|
|
||||||
uid_t uid;
|
|
||||||
int signature_index;
|
|
||||||
bool is_active;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dynamic sign operations
|
|
||||||
void ksu_dynamic_manager_init(void);
|
|
||||||
void ksu_dynamic_manager_exit(void);
|
|
||||||
int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config);
|
|
||||||
bool ksu_load_dynamic_manager(void);
|
|
||||||
bool ksu_is_dynamic_manager_enabled(void);
|
|
||||||
|
|
||||||
// Multi-manager operations
|
|
||||||
void ksu_add_manager(uid_t uid, int signature_index);
|
|
||||||
void ksu_remove_manager(uid_t uid);
|
|
||||||
bool ksu_is_any_manager(uid_t uid);
|
|
||||||
int ksu_get_manager_signature_index(uid_t uid);
|
|
||||||
int ksu_get_active_managers(struct manager_list_info *info);
|
|
||||||
|
|
||||||
// Configuration access for signature verification
|
|
||||||
bool ksu_get_dynamic_manager_config(unsigned int *size, const char **hash);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -15,14 +15,15 @@
|
|||||||
#include <crypto/sha.h>
|
#include <crypto/sha.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "dynamic_manager.h"
|
#include "dynamic_sign.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "kernel_compat.h"
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
|
||||||
#define MAX_MANAGERS 2
|
#define MAX_MANAGERS 2
|
||||||
|
|
||||||
// Dynamic sign configuration
|
// Dynamic sign configuration
|
||||||
static struct dynamic_manager_config dynamic_manager = {
|
static struct dynamic_sign_config dynamic_sign = {
|
||||||
.size = 0x300,
|
.size = 0x300,
|
||||||
.hash = "0000000000000000000000000000000000000000000000000000000000000000",
|
.hash = "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
.is_set = 0
|
.is_set = 0
|
||||||
@@ -31,21 +32,21 @@ static struct dynamic_manager_config dynamic_manager = {
|
|||||||
// Multi-manager state
|
// Multi-manager state
|
||||||
static struct manager_info active_managers[MAX_MANAGERS];
|
static struct manager_info active_managers[MAX_MANAGERS];
|
||||||
static DEFINE_SPINLOCK(managers_lock);
|
static DEFINE_SPINLOCK(managers_lock);
|
||||||
static DEFINE_SPINLOCK(dynamic_manager_lock);
|
static DEFINE_SPINLOCK(dynamic_sign_lock);
|
||||||
|
|
||||||
// Work queues for persistent storage
|
// Work queues for persistent storage
|
||||||
static struct work_struct save_dynamic_manager_work;
|
static struct work_struct ksu_save_dynamic_sign_work;
|
||||||
static struct work_struct load_dynamic_manager_work;
|
static struct work_struct ksu_load_dynamic_sign_work;
|
||||||
static struct work_struct clear_dynamic_manager_work;
|
static struct work_struct ksu_clear_dynamic_sign_work;
|
||||||
|
|
||||||
bool ksu_is_dynamic_manager_enabled(void)
|
bool ksu_is_dynamic_sign_enabled(void)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
|
||||||
spin_lock_irqsave(&dynamic_manager_lock, flags);
|
spin_lock_irqsave(&dynamic_sign_lock, flags);
|
||||||
enabled = dynamic_manager.is_set;
|
enabled = dynamic_sign.is_set;
|
||||||
spin_unlock_irqrestore(&dynamic_manager_lock, flags);
|
spin_unlock_irqrestore(&dynamic_sign_lock, flags);
|
||||||
|
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
@@ -55,7 +56,7 @@ void ksu_add_manager(uid_t uid, int signature_index)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!ksu_is_dynamic_manager_enabled()) {
|
if (!ksu_is_dynamic_sign_enabled()) {
|
||||||
pr_info("Dynamic sign not enabled, skipping multi-manager add\n");
|
pr_info("Dynamic sign not enabled, skipping multi-manager add\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -93,7 +94,7 @@ void ksu_remove_manager(uid_t uid)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!ksu_is_dynamic_manager_enabled()) {
|
if (!ksu_is_dynamic_sign_enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ bool ksu_is_any_manager(uid_t uid)
|
|||||||
bool is_manager = false;
|
bool is_manager = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!ksu_is_dynamic_manager_enabled()) {
|
if (!ksu_is_dynamic_sign_enabled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,10 +142,10 @@ int ksu_get_manager_signature_index(uid_t uid)
|
|||||||
|
|
||||||
// Check traditional manager first
|
// Check traditional manager first
|
||||||
if (ksu_manager_uid != KSU_INVALID_UID && uid == ksu_manager_uid) {
|
if (ksu_manager_uid != KSU_INVALID_UID && uid == ksu_manager_uid) {
|
||||||
return DYNAMIC_SIGN_INDEX;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ksu_is_dynamic_manager_enabled()) {
|
if (!ksu_is_dynamic_sign_enabled()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +197,7 @@ int ksu_get_active_managers(struct manager_list_info *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add dynamic managers
|
// Add dynamic managers
|
||||||
if (ksu_is_dynamic_manager_enabled()) {
|
if (ksu_is_dynamic_sign_enabled()) {
|
||||||
spin_lock_irqsave(&managers_lock, flags);
|
spin_lock_irqsave(&managers_lock, flags);
|
||||||
|
|
||||||
for (i = 0; i < MAX_MANAGERS && count < 2; i++) {
|
for (i = 0; i < MAX_MANAGERS && count < 2; i++) {
|
||||||
@@ -214,42 +215,42 @@ int ksu_get_active_managers(struct manager_list_info *info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_save_dynamic_manager(struct work_struct *work)
|
static void do_save_dynamic_sign(struct work_struct *work)
|
||||||
{
|
{
|
||||||
u32 magic = DYNAMIC_MANAGER_FILE_MAGIC;
|
u32 magic = DYNAMIC_SIGN_FILE_MAGIC;
|
||||||
u32 version = DYNAMIC_MANAGER_FILE_VERSION;
|
u32 version = DYNAMIC_SIGN_FILE_VERSION;
|
||||||
struct dynamic_manager_config config_to_save;
|
struct dynamic_sign_config config_to_save;
|
||||||
loff_t off = 0;
|
loff_t off = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct file *fp;
|
struct file *fp;
|
||||||
|
|
||||||
spin_lock_irqsave(&dynamic_manager_lock, flags);
|
spin_lock_irqsave(&dynamic_sign_lock, flags);
|
||||||
config_to_save = dynamic_manager;
|
config_to_save = dynamic_sign;
|
||||||
spin_unlock_irqrestore(&dynamic_manager_lock, flags);
|
spin_unlock_irqrestore(&dynamic_sign_lock, flags);
|
||||||
|
|
||||||
if (!config_to_save.is_set) {
|
if (!config_to_save.is_set) {
|
||||||
pr_info("Dynamic sign config not set, skipping save\n");
|
pr_info("Dynamic sign config not set, skipping save\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = filp_open(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_SIGN, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if (IS_ERR(fp)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("save_dynamic_manager create file failed: %ld\n", PTR_ERR(fp));
|
pr_err("save_dynamic_sign create file failed: %ld\n", PTR_ERR(fp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
|
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
|
||||||
pr_err("save_dynamic_manager write magic failed.\n");
|
pr_err("save_dynamic_sign write magic failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
||||||
pr_err("save_dynamic_manager write version failed.\n");
|
pr_err("save_dynamic_sign write version failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernel_write(fp, &config_to_save, sizeof(config_to_save), &off) != sizeof(config_to_save)) {
|
if (ksu_kernel_write_compat(fp, &config_to_save, sizeof(config_to_save), &off) != sizeof(config_to_save)) {
|
||||||
pr_err("save_dynamic_manager write config failed.\n");
|
pr_err("save_dynamic_sign write config failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,48 +260,48 @@ exit:
|
|||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_load_dynamic_manager(struct work_struct *work)
|
static void do_load_dynamic_sign(struct work_struct *work)
|
||||||
{
|
{
|
||||||
loff_t off = 0;
|
loff_t off = 0;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
struct file *fp = NULL;
|
struct file *fp = NULL;
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u32 version;
|
u32 version;
|
||||||
struct dynamic_manager_config loaded_config;
|
struct dynamic_sign_config loaded_config;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
fp = filp_open(KERNEL_SU_DYNAMIC_MANAGER, O_RDONLY, 0);
|
fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_SIGN, O_RDONLY, 0);
|
||||||
if (IS_ERR(fp)) {
|
if (IS_ERR(fp)) {
|
||||||
if (PTR_ERR(fp) == -ENOENT) {
|
if (PTR_ERR(fp) == -ENOENT) {
|
||||||
pr_info("No saved dynamic manager config found\n");
|
pr_info("No saved dynamic sign config found\n");
|
||||||
} else {
|
} else {
|
||||||
pr_err("load_dynamic_manager open file failed: %ld\n", PTR_ERR(fp));
|
pr_err("load_dynamic_sign open file failed: %ld\n", PTR_ERR(fp));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernel_read(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
|
if (ksu_kernel_read_compat(fp, &magic, sizeof(magic), &off) != sizeof(magic) ||
|
||||||
magic != DYNAMIC_MANAGER_FILE_MAGIC) {
|
magic != DYNAMIC_SIGN_FILE_MAGIC) {
|
||||||
pr_err("dynamic manager file invalid magic: %x!\n", magic);
|
pr_err("dynamic sign file invalid magic: %x!\n", magic);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kernel_read(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
if (ksu_kernel_read_compat(fp, &version, sizeof(version), &off) != sizeof(version)) {
|
||||||
pr_err("dynamic manager read version failed\n");
|
pr_err("dynamic sign read version failed\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("dynamic manager file version: %d\n", version);
|
pr_info("dynamic sign file version: %d\n", version);
|
||||||
|
|
||||||
ret = kernel_read(fp, &loaded_config, sizeof(loaded_config), &off);
|
ret = ksu_kernel_read_compat(fp, &loaded_config, sizeof(loaded_config), &off);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
pr_info("load_dynamic_manager read err: %zd\n", ret);
|
pr_info("load_dynamic_sign read err: %zd\n", ret);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != sizeof(loaded_config)) {
|
if (ret != sizeof(loaded_config)) {
|
||||||
pr_err("load_dynamic_manager read incomplete config: %zd/%zu\n", ret, sizeof(loaded_config));
|
pr_err("load_dynamic_sign read incomplete config: %zd/%zu\n", ret, sizeof(loaded_config));
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,9 +324,9 @@ static void do_load_dynamic_manager(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&dynamic_manager_lock, flags);
|
spin_lock_irqsave(&dynamic_sign_lock, flags);
|
||||||
dynamic_manager = loaded_config;
|
dynamic_sign = loaded_config;
|
||||||
spin_unlock_irqrestore(&dynamic_manager_lock, flags);
|
spin_unlock_irqrestore(&dynamic_sign_lock, flags);
|
||||||
|
|
||||||
pr_info("Dynamic sign config loaded: size=0x%x, hash=%.16s...\n",
|
pr_info("Dynamic sign config loaded: size=0x%x, hash=%.16s...\n",
|
||||||
loaded_config.size, loaded_config.hash);
|
loaded_config.size, loaded_config.hash);
|
||||||
@@ -334,12 +335,12 @@ exit:
|
|||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool persistent_dynamic_manager(void)
|
static bool persistent_dynamic_sign(void)
|
||||||
{
|
{
|
||||||
return ksu_queue_work(&save_dynamic_manager_work);
|
return ksu_queue_work(&ksu_save_dynamic_sign_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_clear_dynamic_manager(struct work_struct *work)
|
static void do_clear_dynamic_sign(struct work_struct *work)
|
||||||
{
|
{
|
||||||
loff_t off = 0;
|
loff_t off = 0;
|
||||||
struct file *fp;
|
struct file *fp;
|
||||||
@@ -347,15 +348,15 @@ static void do_clear_dynamic_manager(struct work_struct *work)
|
|||||||
|
|
||||||
memset(zero_buffer, 0, sizeof(zero_buffer));
|
memset(zero_buffer, 0, sizeof(zero_buffer));
|
||||||
|
|
||||||
fp = filp_open(KERNEL_SU_DYNAMIC_MANAGER, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
fp = ksu_filp_open_compat(KERNEL_SU_DYNAMIC_SIGN, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if (IS_ERR(fp)) {
|
if (IS_ERR(fp)) {
|
||||||
pr_err("clear_dynamic_manager create file failed: %ld\n", PTR_ERR(fp));
|
pr_err("clear_dynamic_sign create file failed: %ld\n", PTR_ERR(fp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write null bytes to overwrite the file content
|
// Write null bytes to overwrite the file content
|
||||||
if (kernel_write(fp, zero_buffer, sizeof(zero_buffer), &off) != sizeof(zero_buffer)) {
|
if (ksu_kernel_write_compat(fp, zero_buffer, sizeof(zero_buffer), &off) != sizeof(zero_buffer)) {
|
||||||
pr_err("clear_dynamic_manager write null bytes failed.\n");
|
pr_err("clear_dynamic_sign write null bytes failed.\n");
|
||||||
} else {
|
} else {
|
||||||
pr_info("Dynamic sign config file cleared successfully\n");
|
pr_info("Dynamic sign config file cleared successfully\n");
|
||||||
}
|
}
|
||||||
@@ -363,12 +364,12 @@ static void do_clear_dynamic_manager(struct work_struct *work)
|
|||||||
filp_close(fp, 0);
|
filp_close(fp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool clear_dynamic_manager_file(void)
|
static bool clear_dynamic_sign_file(void)
|
||||||
{
|
{
|
||||||
return ksu_queue_work(&clear_dynamic_manager_work);
|
return ksu_queue_work(&ksu_clear_dynamic_sign_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config)
|
int ksu_handle_dynamic_sign(struct dynamic_sign_user_config *config)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -379,7 +380,7 @@ int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (config->operation) {
|
switch (config->operation) {
|
||||||
case DYNAMIC_MANAGER_OP_SET:
|
case DYNAMIC_SIGN_OP_SET:
|
||||||
if (config->size < 0x100 || config->size > 0x1000) {
|
if (config->size < 0x100 || config->size > 0x1000) {
|
||||||
pr_err("invalid size: 0x%x\n", config->size);
|
pr_err("invalid size: 0x%x\n", config->size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -399,106 +400,106 @@ int ksu_handle_dynamic_manager(struct dynamic_manager_user_config *config)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&dynamic_manager_lock, flags);
|
spin_lock_irqsave(&dynamic_sign_lock, flags);
|
||||||
dynamic_manager.size = config->size;
|
dynamic_sign.size = config->size;
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||||
strscpy(dynamic_manager.hash, config->hash, sizeof(dynamic_manager.hash));
|
strscpy(dynamic_sign.hash, config->hash, sizeof(dynamic_sign.hash));
|
||||||
#else
|
#else
|
||||||
strlcpy(dynamic_manager.hash, config->hash, sizeof(dynamic_manager.hash));
|
strlcpy(dynamic_sign.hash, config->hash, sizeof(dynamic_sign.hash));
|
||||||
#endif
|
#endif
|
||||||
dynamic_manager.is_set = 1;
|
dynamic_sign.is_set = 1;
|
||||||
spin_unlock_irqrestore(&dynamic_manager_lock, flags);
|
spin_unlock_irqrestore(&dynamic_sign_lock, flags);
|
||||||
|
|
||||||
persistent_dynamic_manager();
|
persistent_dynamic_sign();
|
||||||
pr_info("dynamic manager updated: size=0x%x, hash=%.16s... (multi-manager enabled)\n",
|
pr_info("dynamic sign updated: size=0x%x, hash=%.16s... (multi-manager enabled)\n",
|
||||||
config->size, config->hash);
|
config->size, config->hash);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DYNAMIC_MANAGER_OP_GET:
|
case DYNAMIC_SIGN_OP_GET:
|
||||||
spin_lock_irqsave(&dynamic_manager_lock, flags);
|
spin_lock_irqsave(&dynamic_sign_lock, flags);
|
||||||
if (dynamic_manager.is_set) {
|
if (dynamic_sign.is_set) {
|
||||||
config->size = dynamic_manager.size;
|
config->size = dynamic_sign.size;
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||||
strscpy(config->hash, dynamic_manager.hash, sizeof(config->hash));
|
strscpy(config->hash, dynamic_sign.hash, sizeof(config->hash));
|
||||||
#else
|
#else
|
||||||
strlcpy(config->hash, dynamic_manager.hash, sizeof(config->hash));
|
strlcpy(config->hash, dynamic_sign.hash, sizeof(config->hash));
|
||||||
#endif
|
#endif
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
ret = -ENODATA;
|
ret = -ENODATA;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&dynamic_manager_lock, flags);
|
spin_unlock_irqrestore(&dynamic_sign_lock, flags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DYNAMIC_MANAGER_OP_CLEAR:
|
case DYNAMIC_SIGN_OP_CLEAR:
|
||||||
spin_lock_irqsave(&dynamic_manager_lock, flags);
|
spin_lock_irqsave(&dynamic_sign_lock, flags);
|
||||||
dynamic_manager.size = 0x300;
|
dynamic_sign.size = 0x300;
|
||||||
strcpy(dynamic_manager.hash, "0000000000000000000000000000000000000000000000000000000000000000");
|
strcpy(dynamic_sign.hash, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
dynamic_manager.is_set = 0;
|
dynamic_sign.is_set = 0;
|
||||||
spin_unlock_irqrestore(&dynamic_manager_lock, flags);
|
spin_unlock_irqrestore(&dynamic_sign_lock, flags);
|
||||||
|
|
||||||
// Clear only dynamic managers, preserve default manager
|
// Clear only dynamic managers, preserve default manager
|
||||||
clear_dynamic_manager();
|
clear_dynamic_manager();
|
||||||
|
|
||||||
// Clear file using the same method as save
|
// Clear file using the same method as save
|
||||||
clear_dynamic_manager_file();
|
clear_dynamic_sign_file();
|
||||||
|
|
||||||
pr_info("Dynamic sign config cleared (multi-manager disabled)\n");
|
pr_info("Dynamic sign config cleared (multi-manager disabled)\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
pr_err("Invalid dynamic manager operation: %d\n", config->operation);
|
pr_err("Invalid dynamic sign operation: %d\n", config->operation);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ksu_load_dynamic_manager(void)
|
bool ksu_load_dynamic_sign(void)
|
||||||
{
|
{
|
||||||
return ksu_queue_work(&load_dynamic_manager_work);
|
return ksu_queue_work(&ksu_load_dynamic_sign_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_dynamic_manager_init(void)
|
void ksu_dynamic_sign_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
INIT_WORK(&save_dynamic_manager_work, do_save_dynamic_manager);
|
INIT_WORK(&ksu_save_dynamic_sign_work, do_save_dynamic_sign);
|
||||||
INIT_WORK(&load_dynamic_manager_work, do_load_dynamic_manager);
|
INIT_WORK(&ksu_load_dynamic_sign_work, do_load_dynamic_sign);
|
||||||
INIT_WORK(&clear_dynamic_manager_work, do_clear_dynamic_manager);
|
INIT_WORK(&ksu_clear_dynamic_sign_work, do_clear_dynamic_sign);
|
||||||
|
|
||||||
// Initialize manager slots
|
// Initialize manager slots
|
||||||
for (i = 0; i < MAX_MANAGERS; i++) {
|
for (i = 0; i < MAX_MANAGERS; i++) {
|
||||||
active_managers[i].is_active = false;
|
active_managers[i].is_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ksu_load_dynamic_manager();
|
ksu_load_dynamic_sign();
|
||||||
|
|
||||||
pr_info("Dynamic sign initialized with conditional multi-manager support\n");
|
pr_info("Dynamic sign initialized with conditional multi-manager support\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_dynamic_manager_exit(void)
|
void ksu_dynamic_sign_exit(void)
|
||||||
{
|
{
|
||||||
clear_dynamic_manager();
|
clear_dynamic_manager();
|
||||||
|
|
||||||
// Save current config before exit
|
// Save current config before exit
|
||||||
do_save_dynamic_manager(NULL);
|
do_save_dynamic_sign(NULL);
|
||||||
pr_info("Dynamic sign exited with persistent storage\n");
|
pr_info("Dynamic sign exited with persistent storage\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get dynamic manager configuration for signature verification
|
// Get dynamic sign configuration for signature verification
|
||||||
bool ksu_get_dynamic_manager_config(unsigned int *size, const char **hash)
|
bool ksu_get_dynamic_sign_config(unsigned int *size, const char **hash)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
|
||||||
spin_lock_irqsave(&dynamic_manager_lock, flags);
|
spin_lock_irqsave(&dynamic_sign_lock, flags);
|
||||||
if (dynamic_manager.is_set) {
|
if (dynamic_sign.is_set) {
|
||||||
if (size) *size = dynamic_manager.size;
|
if (size) *size = dynamic_sign.size;
|
||||||
if (hash) *hash = dynamic_manager.hash;
|
if (hash) *hash = dynamic_sign.hash;
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&dynamic_manager_lock, flags);
|
spin_unlock_irqrestore(&dynamic_sign_lock, flags);
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
43
kernel/dynamic_sign.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef __KSU_H_DYNAMIC_SIGN
|
||||||
|
#define __KSU_H_DYNAMIC_SIGN
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include "ksu.h"
|
||||||
|
|
||||||
|
#define DYNAMIC_SIGN_FILE_MAGIC 0x7f445347 // 'DSG', u32
|
||||||
|
#define DYNAMIC_SIGN_FILE_VERSION 1 // u32
|
||||||
|
#define KERNEL_SU_DYNAMIC_SIGN "/data/adb/ksu/.dynamic_sign"
|
||||||
|
|
||||||
|
struct dynamic_sign_config {
|
||||||
|
unsigned int size;
|
||||||
|
char hash[65];
|
||||||
|
int is_set;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct manager_info {
|
||||||
|
uid_t uid;
|
||||||
|
int signature_index;
|
||||||
|
bool is_active;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dynamic sign operations
|
||||||
|
int ksu_handle_dynamic_sign(struct dynamic_sign_user_config *config);
|
||||||
|
void ksu_dynamic_sign_init(void);
|
||||||
|
void ksu_dynamic_sign_exit(void);
|
||||||
|
bool ksu_load_dynamic_sign(void);
|
||||||
|
bool ksu_is_dynamic_sign_enabled(void);
|
||||||
|
|
||||||
|
// Multi-manager operations
|
||||||
|
void ksu_add_manager(uid_t uid, int signature_index);
|
||||||
|
void ksu_remove_manager(uid_t uid);
|
||||||
|
bool ksu_is_any_manager(uid_t uid);
|
||||||
|
int ksu_get_manager_signature_index(uid_t uid);
|
||||||
|
int ksu_get_active_managers(struct manager_list_info *info);
|
||||||
|
|
||||||
|
// Multi-manager APK verification
|
||||||
|
bool ksu_is_multi_manager_apk(char *path, int *signature_index);
|
||||||
|
|
||||||
|
// Configuration access for signature verification
|
||||||
|
bool ksu_get_dynamic_sign_config(unsigned int *size, const char **hash);
|
||||||
|
|
||||||
|
#endif
|
||||||
173
kernel/feature.c
@@ -1,173 +0,0 @@
|
|||||||
#include "feature.h"
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
|
|
||||||
static const struct ksu_feature_handler *feature_handlers[KSU_FEATURE_MAX];
|
|
||||||
|
|
||||||
static DEFINE_MUTEX(feature_mutex);
|
|
||||||
|
|
||||||
int ksu_register_feature_handler(const struct ksu_feature_handler *handler)
|
|
||||||
{
|
|
||||||
if (!handler) {
|
|
||||||
pr_err("feature: register handler is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handler->feature_id >= KSU_FEATURE_MAX) {
|
|
||||||
pr_err("feature: invalid feature_id %u\n", handler->feature_id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handler->get_handler && !handler->set_handler) {
|
|
||||||
pr_err("feature: no handler provided for feature %u\n", handler->feature_id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
|
||||||
|
|
||||||
if (feature_handlers[handler->feature_id]) {
|
|
||||||
pr_warn("feature: handler for %u already registered, overwriting\n",
|
|
||||||
handler->feature_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
feature_handlers[handler->feature_id] = handler;
|
|
||||||
|
|
||||||
pr_info("feature: registered handler for %s (id=%u)\n",
|
|
||||||
handler->name ? handler->name : "unknown", handler->feature_id);
|
|
||||||
|
|
||||||
mutex_unlock(&feature_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ksu_unregister_feature_handler(u32 feature_id)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (feature_id >= KSU_FEATURE_MAX) {
|
|
||||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
|
||||||
|
|
||||||
if (!feature_handlers[feature_id]) {
|
|
||||||
pr_warn("feature: no handler registered for %u\n", feature_id);
|
|
||||||
ret = -ENOENT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
feature_handlers[feature_id] = NULL;
|
|
||||||
|
|
||||||
pr_info("feature: unregistered handler for id=%u\n", feature_id);
|
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&feature_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
const struct ksu_feature_handler *handler;
|
|
||||||
|
|
||||||
if (feature_id >= KSU_FEATURE_MAX) {
|
|
||||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value || !supported) {
|
|
||||||
pr_err("feature: invalid parameters\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
|
||||||
|
|
||||||
handler = feature_handlers[feature_id];
|
|
||||||
|
|
||||||
if (!handler) {
|
|
||||||
*supported = false;
|
|
||||||
*value = 0;
|
|
||||||
pr_debug("feature: feature %u not supported\n", feature_id);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
*supported = true;
|
|
||||||
|
|
||||||
if (!handler->get_handler) {
|
|
||||||
pr_warn("feature: no get_handler for feature %u\n", feature_id);
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = handler->get_handler(value);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("feature: get_handler for %u failed: %d\n", feature_id, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&feature_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ksu_set_feature(u32 feature_id, u64 value)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
const struct ksu_feature_handler *handler;
|
|
||||||
|
|
||||||
if (feature_id >= KSU_FEATURE_MAX) {
|
|
||||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
|
||||||
|
|
||||||
handler = feature_handlers[feature_id];
|
|
||||||
|
|
||||||
if (!handler) {
|
|
||||||
pr_err("feature: feature %u not registered\n", feature_id);
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handler->set_handler) {
|
|
||||||
pr_warn("feature: no set_handler for feature %u\n", feature_id);
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = handler->set_handler(value);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("feature: set_handler for %u failed: %d\n", feature_id, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&feature_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_feature_init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < KSU_FEATURE_MAX; i++) {
|
|
||||||
feature_handlers[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("feature: feature management initialized\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_feature_exit(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
mutex_lock(&feature_mutex);
|
|
||||||
|
|
||||||
for (i = 0; i < KSU_FEATURE_MAX; i++) {
|
|
||||||
feature_handlers[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&feature_mutex);
|
|
||||||
|
|
||||||
pr_info("feature: feature management cleaned up\n");
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#ifndef __KSU_H_FEATURE
|
|
||||||
#define __KSU_H_FEATURE
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
enum ksu_feature_id {
|
|
||||||
KSU_FEATURE_SU_COMPAT = 0,
|
|
||||||
KSU_FEATURE_KERNEL_UMOUNT = 1,
|
|
||||||
KSU_FEATURE_ENHANCED_SECURITY = 2,
|
|
||||||
KSU_FEATURE_SULOG = 3,
|
|
||||||
|
|
||||||
KSU_FEATURE_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int (*ksu_feature_get_t)(u64 *value);
|
|
||||||
typedef int (*ksu_feature_set_t)(u64 value);
|
|
||||||
|
|
||||||
struct ksu_feature_handler {
|
|
||||||
u32 feature_id;
|
|
||||||
const char *name;
|
|
||||||
ksu_feature_get_t get_handler;
|
|
||||||
ksu_feature_set_t set_handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
int ksu_register_feature_handler(const struct ksu_feature_handler *handler);
|
|
||||||
|
|
||||||
int ksu_unregister_feature_handler(u32 feature_id);
|
|
||||||
|
|
||||||
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported);
|
|
||||||
|
|
||||||
int ksu_set_feature(u32 feature_id, u64 value);
|
|
||||||
|
|
||||||
void ksu_feature_init(void);
|
|
||||||
|
|
||||||
void ksu_feature_exit(void);
|
|
||||||
|
|
||||||
#endif // __KSU_H_FEATURE
|
|
||||||
@@ -1,341 +0,0 @@
|
|||||||
#include <linux/export.h>
|
|
||||||
#include <linux/anon_inodes.h>
|
|
||||||
#include <linux/capability.h>
|
|
||||||
#include <linux/cred.h>
|
|
||||||
#include <linux/err.h>
|
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/seq_file.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
#include "selinux/selinux.h"
|
|
||||||
|
|
||||||
#include "file_wrapper.h"
|
|
||||||
|
|
||||||
static loff_t ksu_wrapper_llseek(struct file *fp, loff_t off, int flags) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->llseek(data->orig, off, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_wrapper_read(struct file *fp, char __user *ptr, size_t sz, loff_t *off) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->read(orig, ptr, sz, off);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_wrapper_write(struct file *fp, const char __user *ptr, size_t sz, loff_t *off) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->write(orig, ptr, sz, off);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_wrapper_read_iter(struct kiocb *iocb, struct iov_iter *iovi) {
|
|
||||||
struct ksu_file_wrapper* data = iocb->ki_filp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
iocb->ki_filp = orig;
|
|
||||||
return orig->f_op->read_iter(iocb, iovi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_wrapper_write_iter(struct kiocb *iocb, struct iov_iter *iovi) {
|
|
||||||
struct ksu_file_wrapper* data = iocb->ki_filp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
iocb->ki_filp = orig;
|
|
||||||
return orig->f_op->write_iter(iocb, iovi);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
|
||||||
static int ksu_wrapper_iopoll(struct kiocb *kiocb, struct io_comp_batch* icb, unsigned int v) {
|
|
||||||
struct ksu_file_wrapper* data = kiocb->ki_filp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
kiocb->ki_filp = orig;
|
|
||||||
return orig->f_op->iopoll(kiocb, icb, v);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static int ksu_wrapper_iopoll(struct kiocb *kiocb, bool spin) {
|
|
||||||
struct ksu_file_wrapper* data = kiocb->ki_filp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
kiocb->ki_filp = orig;
|
|
||||||
return orig->f_op->iopoll(kiocb, spin);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
|
||||||
static int ksu_wrapper_iterate (struct file *fp, struct dir_context *dc) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->iterate(orig, dc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int ksu_wrapper_iterate_shared(struct file *fp, struct dir_context *dc) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->iterate_shared(orig, dc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static __poll_t ksu_wrapper_poll(struct file *fp, struct poll_table_struct *pts) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->poll(orig, pts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long ksu_wrapper_unlocked_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->unlocked_ioctl(orig, cmd, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long ksu_wrapper_compat_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->compat_ioctl(orig, cmd, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_wrapper_mmap(struct file *fp, struct vm_area_struct * vma) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->mmap(orig, vma);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static unsigned long mmap_supported_flags {}
|
|
||||||
|
|
||||||
static int ksu_wrapper_open(struct inode *ino, struct file *fp) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
struct inode *orig_ino = file_inode(orig);
|
|
||||||
return orig->f_op->open(orig_ino, orig);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_wrapper_flush(struct file *fp, fl_owner_t id) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->flush(orig, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int ksu_wrapper_fsync(struct file *fp, loff_t off1, loff_t off2, int datasync) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->fsync(orig, off1, off2, datasync);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_wrapper_fasync(int arg, struct file *fp, int arg2) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->fasync(arg, orig, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_wrapper_lock(struct file *fp, int arg1, struct file_lock *fl) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
return orig->f_op->lock(orig, arg1, fl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
|
||||||
static ssize_t ksu_wrapper_sendpage(struct file *fp, struct page *pg, int arg1, size_t sz, loff_t *off, int arg2) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->sendpage) {
|
|
||||||
return orig->f_op->sendpage(orig, pg, arg1, sz, off, arg2);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static unsigned long ksu_wrapper_get_unmapped_area(struct file *fp, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->get_unmapped_area) {
|
|
||||||
return orig->f_op->get_unmapped_area(orig, arg1, arg2, arg3, arg4);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static int ksu_wrapper_check_flags(int arg) {}
|
|
||||||
|
|
||||||
static int ksu_wrapper_flock(struct file *fp, int arg1, struct file_lock *fl) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->flock) {
|
|
||||||
return orig->f_op->flock(orig, arg1, fl);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_wrapper_splice_write(struct pipe_inode_info * pii, struct file *fp, loff_t *off, size_t sz, unsigned int arg1) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->splice_write) {
|
|
||||||
return orig->f_op->splice_write(pii, orig, off, sz, arg1);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_wrapper_splice_read(struct file *fp, loff_t *off, struct pipe_inode_info *pii, size_t sz, unsigned int arg1) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->splice_read) {
|
|
||||||
return orig->f_op->splice_read(orig, off, pii, sz, arg1);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
|
||||||
void ksu_wrapper_splice_eof(struct file *fp) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->splice_eof) {
|
|
||||||
return orig->f_op->splice_eof(orig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
|
||||||
static int ksu_wrapper_setlease(struct file *fp, int arg1, struct file_lease **fl, void **p) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->setlease) {
|
|
||||||
return orig->f_op->setlease(orig, arg1, fl, p);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
|
||||||
static int ksu_wrapper_setlease(struct file *fp, int arg1, struct file_lock **fl, void **p) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->setlease) {
|
|
||||||
return orig->f_op->setlease(orig, arg1, fl, p);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static int ksu_wrapper_setlease(struct file *fp, long arg1, struct file_lock **fl, void **p) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->setlease) {
|
|
||||||
return orig->f_op->setlease(orig, arg1, fl, p);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static long ksu_wrapper_fallocate(struct file *fp, int mode, loff_t offset, loff_t len) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->fallocate) {
|
|
||||||
return orig->f_op->fallocate(orig, mode, offset, len);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ksu_wrapper_show_fdinfo(struct seq_file *m, struct file *f) {
|
|
||||||
struct ksu_file_wrapper* data = f->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->show_fdinfo) {
|
|
||||||
orig->f_op->show_fdinfo(m, orig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ksu_wrapper_copy_file_range(struct file *f1, loff_t off1, struct file *f2,
|
|
||||||
loff_t off2, size_t sz, unsigned int flags) {
|
|
||||||
// TODO: determine which file to use
|
|
||||||
struct ksu_file_wrapper* data = f1->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->copy_file_range) {
|
|
||||||
return orig->f_op->copy_file_range(orig, off1, f2, off2, sz, flags);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static loff_t ksu_wrapper_remap_file_range(struct file *file_in, loff_t pos_in,
|
|
||||||
struct file *file_out, loff_t pos_out,
|
|
||||||
loff_t len, unsigned int remap_flags) {
|
|
||||||
// TODO: determine which file to use
|
|
||||||
struct ksu_file_wrapper* data = file_in->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->remap_file_range) {
|
|
||||||
return orig->f_op->remap_file_range(orig, pos_in, file_out, pos_out, len, remap_flags);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_wrapper_fadvise(struct file *fp, loff_t off1, loff_t off2, int flags) {
|
|
||||||
struct ksu_file_wrapper* data = fp->private_data;
|
|
||||||
struct file* orig = data->orig;
|
|
||||||
if (orig->f_op->fadvise) {
|
|
||||||
return orig->f_op->fadvise(orig, off1, off2, flags);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ksu_wrapper_release(struct inode *inode, struct file *filp) {
|
|
||||||
ksu_delete_file_wrapper(filp->private_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp) {
|
|
||||||
struct ksu_file_wrapper* p = kcalloc(sizeof(struct ksu_file_wrapper), 1, GFP_KERNEL);
|
|
||||||
if (!p) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_file(fp);
|
|
||||||
|
|
||||||
p->orig = fp;
|
|
||||||
p->ops.owner = THIS_MODULE;
|
|
||||||
p->ops.llseek = fp->f_op->llseek ? ksu_wrapper_llseek : NULL;
|
|
||||||
p->ops.read = fp->f_op->read ? ksu_wrapper_read : NULL;
|
|
||||||
p->ops.write = fp->f_op->write ? ksu_wrapper_write : NULL;
|
|
||||||
p->ops.read_iter = fp->f_op->read_iter ? ksu_wrapper_read_iter : NULL;
|
|
||||||
p->ops.write_iter = fp->f_op->write_iter ? ksu_wrapper_write_iter : NULL;
|
|
||||||
p->ops.iopoll = fp->f_op->iopoll ? ksu_wrapper_iopoll : NULL;
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
|
||||||
p->ops.iterate = fp->f_op->iterate ? ksu_wrapper_iterate : NULL;
|
|
||||||
#endif
|
|
||||||
p->ops.iterate_shared = fp->f_op->iterate_shared ? ksu_wrapper_iterate_shared : NULL;
|
|
||||||
p->ops.poll = fp->f_op->poll ? ksu_wrapper_poll : NULL;
|
|
||||||
p->ops.unlocked_ioctl = fp->f_op->unlocked_ioctl ? ksu_wrapper_unlocked_ioctl : NULL;
|
|
||||||
p->ops.compat_ioctl = fp->f_op->compat_ioctl ? ksu_wrapper_compat_ioctl : NULL;
|
|
||||||
p->ops.mmap = fp->f_op->mmap ? ksu_wrapper_mmap : NULL;
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
|
||||||
p->ops.fop_flags = fp->f_op->fop_flags;
|
|
||||||
#else
|
|
||||||
p->ops.mmap_supported_flags = fp->f_op->mmap_supported_flags;
|
|
||||||
#endif
|
|
||||||
p->ops.open = fp->f_op->open ? ksu_wrapper_open : NULL;
|
|
||||||
p->ops.flush = fp->f_op->flush ? ksu_wrapper_flush : NULL;
|
|
||||||
p->ops.release = ksu_wrapper_release;
|
|
||||||
p->ops.fsync = fp->f_op->fsync ? ksu_wrapper_fsync : NULL;
|
|
||||||
p->ops.fasync = fp->f_op->fasync ? ksu_wrapper_fasync : NULL;
|
|
||||||
p->ops.lock = fp->f_op->lock ? ksu_wrapper_lock : NULL;
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
|
||||||
p->ops.sendpage = fp->f_op->sendpage ? ksu_wrapper_sendpage : NULL;
|
|
||||||
#endif
|
|
||||||
p->ops.get_unmapped_area = fp->f_op->get_unmapped_area ? ksu_wrapper_get_unmapped_area : NULL;
|
|
||||||
p->ops.check_flags = fp->f_op->check_flags;
|
|
||||||
p->ops.flock = fp->f_op->flock ? ksu_wrapper_flock : NULL;
|
|
||||||
p->ops.splice_write = fp->f_op->splice_write ? ksu_wrapper_splice_write : NULL;
|
|
||||||
p->ops.splice_read = fp->f_op->splice_read ? ksu_wrapper_splice_read : NULL;
|
|
||||||
p->ops.setlease = fp->f_op->setlease ? ksu_wrapper_setlease : NULL;
|
|
||||||
p->ops.fallocate = fp->f_op->fallocate ? ksu_wrapper_fallocate : NULL;
|
|
||||||
p->ops.show_fdinfo = fp->f_op->show_fdinfo ? ksu_wrapper_show_fdinfo : NULL;
|
|
||||||
p->ops.copy_file_range = fp->f_op->copy_file_range ? ksu_wrapper_copy_file_range : NULL;
|
|
||||||
p->ops.remap_file_range = fp->f_op->remap_file_range ? ksu_wrapper_remap_file_range : NULL;
|
|
||||||
p->ops.fadvise = fp->f_op->fadvise ? ksu_wrapper_fadvise : NULL;
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
|
|
||||||
p->ops.splice_eof = fp->f_op->splice_eof ? ksu_wrapper_splice_eof : NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_delete_file_wrapper(struct ksu_file_wrapper* data) {
|
|
||||||
fput((struct file*) data->orig);
|
|
||||||
kfree(data);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef KSU_FILE_WRAPPER_H
|
|
||||||
#define KSU_FILE_WRAPPER_H
|
|
||||||
|
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
|
|
||||||
struct ksu_file_wrapper {
|
|
||||||
struct file* orig;
|
|
||||||
struct file_operations ops;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_file_wrapper* ksu_create_file_wrapper(struct file* fp);
|
|
||||||
void ksu_delete_file_wrapper(struct ksu_file_wrapper* data);
|
|
||||||
#endif // KSU_FILE_WRAPPER_H
|
|
||||||
28
kernel/include/ksu_hook.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef __KSU_H_KSHOOK
|
||||||
|
#define __KSU_H_KSHOOK
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
// For sucompat
|
||||||
|
|
||||||
|
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||||
|
int *flags);
|
||||||
|
|
||||||
|
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
||||||
|
|
||||||
|
// For ksud
|
||||||
|
|
||||||
|
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
|
||||||
|
size_t *count_ptr, loff_t **pos);
|
||||||
|
|
||||||
|
// For ksud and sucompat
|
||||||
|
|
||||||
|
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||||
|
void *envp, int *flags);
|
||||||
|
|
||||||
|
// For volume button
|
||||||
|
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||||
|
int *value);
|
||||||
|
|
||||||
|
#endif
|
||||||
88
kernel/kernel_compat.c
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/nsproxy.h>
|
||||||
|
#include <linux/sched/task.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "kernel_compat.h"
|
||||||
|
|
||||||
|
extern struct task_struct init_task;
|
||||||
|
|
||||||
|
// mnt_ns context switch for environment that android_init->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns, such as WSA
|
||||||
|
struct ksu_ns_fs_saved {
|
||||||
|
struct nsproxy *ns;
|
||||||
|
struct fs_struct *fs;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ksu_save_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
|
||||||
|
{
|
||||||
|
ns_fs_saved->ns = current->nsproxy;
|
||||||
|
ns_fs_saved->fs = current->fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ksu_load_ns_fs(struct ksu_ns_fs_saved *ns_fs_saved)
|
||||||
|
{
|
||||||
|
current->nsproxy = ns_fs_saved->ns;
|
||||||
|
current->fs = ns_fs_saved->fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool android_context_saved_checked = false;
|
||||||
|
static bool android_context_saved_enabled = false;
|
||||||
|
static struct ksu_ns_fs_saved android_context_saved;
|
||||||
|
|
||||||
|
void ksu_android_ns_fs_check()
|
||||||
|
{
|
||||||
|
if (android_context_saved_checked)
|
||||||
|
return;
|
||||||
|
android_context_saved_checked = true;
|
||||||
|
task_lock(current);
|
||||||
|
if (current->nsproxy && current->fs &&
|
||||||
|
current->nsproxy->mnt_ns != init_task.nsproxy->mnt_ns) {
|
||||||
|
android_context_saved_enabled = true;
|
||||||
|
pr_info("android context saved enabled due to init mnt_ns(%p) != android mnt_ns(%p)\n",
|
||||||
|
current->nsproxy->mnt_ns, init_task.nsproxy->mnt_ns);
|
||||||
|
ksu_save_ns_fs(&android_context_saved);
|
||||||
|
} else {
|
||||||
|
pr_info("android context saved disabled\n");
|
||||||
|
}
|
||||||
|
task_unlock(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
|
||||||
|
{
|
||||||
|
// switch mnt_ns even if current is not wq_worker, to ensure what we open is the correct file in android mnt_ns, rather than user created mnt_ns
|
||||||
|
struct ksu_ns_fs_saved saved;
|
||||||
|
if (android_context_saved_enabled) {
|
||||||
|
pr_info("start switch current nsproxy and fs to android context\n");
|
||||||
|
task_lock(current);
|
||||||
|
ksu_save_ns_fs(&saved);
|
||||||
|
ksu_load_ns_fs(&android_context_saved);
|
||||||
|
task_unlock(current);
|
||||||
|
}
|
||||||
|
struct file *fp = filp_open(filename, flags, mode);
|
||||||
|
if (android_context_saved_enabled) {
|
||||||
|
task_lock(current);
|
||||||
|
ksu_load_ns_fs(&saved);
|
||||||
|
task_unlock(current);
|
||||||
|
pr_info("switch current nsproxy and fs back to saved successfully\n");
|
||||||
|
}
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
|
||||||
|
loff_t *pos)
|
||||||
|
{
|
||||||
|
return kernel_read(p, buf, count, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count,
|
||||||
|
loff_t *pos)
|
||||||
|
{
|
||||||
|
return kernel_write(p, buf, count, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
|
||||||
|
long count)
|
||||||
|
{
|
||||||
|
return strncpy_from_user_nofault(dst, unsafe_addr, count);
|
||||||
|
}
|
||||||
@@ -3,22 +3,33 @@
|
|||||||
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
#include "ss/policydb.h"
|
||||||
|
#include "linux/key.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ksu_copy_from_user_retry
|
* Adapt to Huawei HISI kernel without affecting other kernels ,
|
||||||
* try nofault copy first, if it fails, try with plain
|
* Huawei Hisi Kernel EBITMAP Enable or Disable Flag ,
|
||||||
* paramters are the same as copy_from_user
|
* From ss/ebitmap.h
|
||||||
* 0 = success
|
|
||||||
*/
|
*/
|
||||||
static long ksu_copy_from_user_retry(void *to,
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && \
|
||||||
const void __user *from, unsigned long count)
|
(LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) || \
|
||||||
{
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) && \
|
||||||
long ret = copy_from_user_nofault(to, from, count);
|
(LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
|
||||||
if (likely(!ret))
|
#ifdef HISI_SELINUX_EBITMAP_RO
|
||||||
return ret;
|
#define CONFIG_IS_HW_HISI
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// we faulted! fallback to slow path
|
extern long ksu_strncpy_from_user_nofault(char *dst,
|
||||||
return copy_from_user(to, from, count);
|
const void __user *unsafe_addr,
|
||||||
}
|
long count);
|
||||||
|
|
||||||
|
extern void ksu_android_ns_fs_check();
|
||||||
|
extern struct file *ksu_filp_open_compat(const char *filename, int flags,
|
||||||
|
umode_t mode);
|
||||||
|
extern ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
|
||||||
|
loff_t *pos);
|
||||||
|
extern ssize_t ksu_kernel_write_compat(struct file *p, const void *buf,
|
||||||
|
size_t count, loff_t *pos);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/task_work.h>
|
|
||||||
#include <linux/cred.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/mount.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
#include <linux/nsproxy.h>
|
|
||||||
#include <linux/path.h>
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
#include "kernel_umount.h"
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
#include "allowlist.h"
|
|
||||||
#include "selinux/selinux.h"
|
|
||||||
#include "feature.h"
|
|
||||||
#include "ksud.h"
|
|
||||||
|
|
||||||
#include "umount_manager.h"
|
|
||||||
#include "sulog.h"
|
|
||||||
|
|
||||||
static bool ksu_kernel_umount_enabled = true;
|
|
||||||
|
|
||||||
static int kernel_umount_feature_get(u64 *value)
|
|
||||||
{
|
|
||||||
*value = ksu_kernel_umount_enabled ? 1 : 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kernel_umount_feature_set(u64 value)
|
|
||||||
{
|
|
||||||
bool enable = value != 0;
|
|
||||||
ksu_kernel_umount_enabled = enable;
|
|
||||||
pr_info("kernel_umount: set to %d\n", enable);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct ksu_feature_handler kernel_umount_handler = {
|
|
||||||
.feature_id = KSU_FEATURE_KERNEL_UMOUNT,
|
|
||||||
.name = "kernel_umount",
|
|
||||||
.get_handler = kernel_umount_feature_get,
|
|
||||||
.set_handler = kernel_umount_feature_set,
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int path_umount(struct path *path, int flags);
|
|
||||||
|
|
||||||
static void ksu_umount_mnt(struct path *path, int flags)
|
|
||||||
{
|
|
||||||
int err = path_umount(path, flags);
|
|
||||||
if (err) {
|
|
||||||
pr_info("umount %s failed: %d\n", path->dentry->d_iname, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void try_umount(const char *mnt, int flags)
|
|
||||||
{
|
|
||||||
struct path path;
|
|
||||||
int err = kern_path(mnt, 0, &path);
|
|
||||||
if (err) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path.dentry != path.mnt->mnt_root) {
|
|
||||||
// it is not root mountpoint, maybe umounted by others already.
|
|
||||||
path_put(&path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ksu_umount_mnt(&path, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct umount_tw {
|
|
||||||
struct callback_head cb;
|
|
||||||
const struct cred *old_cred;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void umount_tw_func(struct callback_head *cb)
|
|
||||||
{
|
|
||||||
struct umount_tw *tw = container_of(cb, struct umount_tw, cb);
|
|
||||||
const struct cred *saved = NULL;
|
|
||||||
if (tw->old_cred) {
|
|
||||||
saved = override_creds(tw->old_cred);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mount_entry *entry;
|
|
||||||
down_read(&mount_list_lock);
|
|
||||||
list_for_each_entry(entry, &mount_list, list) {
|
|
||||||
pr_info("%s: unmounting: %s flags 0x%x\n", __func__, entry->umountable, entry->flags);
|
|
||||||
try_umount(entry->umountable, entry->flags);
|
|
||||||
}
|
|
||||||
up_read(&mount_list_lock);
|
|
||||||
|
|
||||||
ksu_umount_manager_execute_all(tw->old_cred);
|
|
||||||
|
|
||||||
if (saved)
|
|
||||||
revert_creds(saved);
|
|
||||||
|
|
||||||
if (tw->old_cred)
|
|
||||||
put_cred(tw->old_cred);
|
|
||||||
|
|
||||||
kfree(tw);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ksu_handle_umount(uid_t old_uid, uid_t new_uid)
|
|
||||||
{
|
|
||||||
struct umount_tw *tw;
|
|
||||||
|
|
||||||
// if there isn't any module mounted, just ignore it!
|
|
||||||
if (!ksu_module_mounted) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ksu_kernel_umount_enabled) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are 5 scenarios:
|
|
||||||
// 1. Normal app: zygote -> appuid
|
|
||||||
// 2. Isolated process forked from zygote: zygote -> isolated_process
|
|
||||||
// 3. App zygote forked from zygote: zygote -> appuid
|
|
||||||
// 4. Isolated process froked from app zygote: appuid -> isolated_process (already handled by 3)
|
|
||||||
// 5. Isolated process froked from webview zygote (no need to handle, app cannot run custom code)
|
|
||||||
if (!is_appuid(new_uid) && !is_isolated_process(new_uid)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ksu_uid_should_umount(new_uid) && !is_isolated_process(new_uid)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check old process's selinux context, if it is not zygote, ignore it!
|
|
||||||
// because some su apps may setuid to untrusted_app but they are in global mount namespace
|
|
||||||
// when we umount for such process, that is a disaster!
|
|
||||||
// also handle case 4 and 5
|
|
||||||
bool is_zygote_child = is_zygote(get_current_cred());
|
|
||||||
if (!is_zygote_child) {
|
|
||||||
pr_info("handle umount ignore non zygote child: %d\n", current->pid);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_syscall(new_uid, NULL, "setuid", NULL);
|
|
||||||
#endif
|
|
||||||
// umount the target mnt
|
|
||||||
pr_info("handle umount for uid: %d, pid: %d\n", new_uid, current->pid);
|
|
||||||
|
|
||||||
tw = kzalloc(sizeof(*tw), GFP_ATOMIC);
|
|
||||||
if (!tw)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
tw->old_cred = get_current_cred();
|
|
||||||
tw->cb.func = umount_tw_func;
|
|
||||||
|
|
||||||
int err = task_work_add(current, &tw->cb, TWA_RESUME);
|
|
||||||
if (err) {
|
|
||||||
if (tw->old_cred) {
|
|
||||||
put_cred(tw->old_cred);
|
|
||||||
}
|
|
||||||
kfree(tw);
|
|
||||||
pr_warn("unmount add task_work failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_kernel_umount_init(void)
|
|
||||||
{
|
|
||||||
int rc = 0;
|
|
||||||
rc = ksu_umount_manager_init();
|
|
||||||
if (rc) {
|
|
||||||
pr_err("Failed to initialize umount manager: %d\n", rc);
|
|
||||||
}
|
|
||||||
if (ksu_register_feature_handler(&kernel_umount_handler)) {
|
|
||||||
pr_err("Failed to register kernel_umount feature handler\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_kernel_umount_exit(void)
|
|
||||||
{
|
|
||||||
ksu_unregister_feature_handler(KSU_FEATURE_KERNEL_UMOUNT);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#ifndef __KSU_H_KERNEL_UMOUNT
|
|
||||||
#define __KSU_H_KERNEL_UMOUNT
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/rwsem.h>
|
|
||||||
|
|
||||||
void ksu_kernel_umount_init(void);
|
|
||||||
void ksu_kernel_umount_exit(void);
|
|
||||||
|
|
||||||
void try_umount(const char *mnt, int flags);
|
|
||||||
|
|
||||||
// Handler function to be called from setresuid hook
|
|
||||||
int ksu_handle_umount(uid_t old_uid, uid_t new_uid);
|
|
||||||
|
|
||||||
// for the umount list
|
|
||||||
struct mount_entry {
|
|
||||||
char *umountable;
|
|
||||||
unsigned int flags;
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
extern struct list_head mount_list;
|
|
||||||
extern struct rw_semaphore mount_list_lock;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -3,4 +3,4 @@ obj-y += compact.o
|
|||||||
obj-y += super_access.o
|
obj-y += super_access.o
|
||||||
|
|
||||||
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
||||||
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <asm/elf.h>
|
#include <asm/elf.h> /* 包含 ARM64 重定位类型定义 */
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
@@ -29,48 +29,55 @@
|
|||||||
#include "../allowlist.h"
|
#include "../allowlist.h"
|
||||||
#include "../manager.h"
|
#include "../manager.h"
|
||||||
|
|
||||||
static int sukisu_is_su_allow_uid(uid_t uid)
|
unsigned long sukisu_compact_find_symbol(const char* name);
|
||||||
{
|
|
||||||
return ksu_is_allow_uid_for_current(uid) ? 1 : 0;
|
// ======================================================================
|
||||||
|
// 兼容函数 for KPM
|
||||||
|
|
||||||
|
static
|
||||||
|
int sukisu_is_su_allow_uid(uid_t uid) {
|
||||||
|
return ksu_is_allow_uid(uid) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sukisu_get_ap_mod_exclude(uid_t uid)
|
static
|
||||||
{
|
int sukisu_get_ap_mod_exclude(uid_t uid) {
|
||||||
return 0; /* Not supported */
|
// Not supported
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sukisu_is_uid_should_umount(uid_t uid)
|
static
|
||||||
{
|
int sukisu_is_uid_should_umount(uid_t uid) {
|
||||||
return ksu_uid_should_umount(uid) ? 1 : 0;
|
return ksu_uid_should_umount(uid) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sukisu_is_current_uid_manager(void)
|
static
|
||||||
{
|
int sukisu_is_current_uid_manager() {
|
||||||
return is_manager();
|
return is_manager();
|
||||||
}
|
}
|
||||||
|
|
||||||
static uid_t sukisu_get_manager_uid(void)
|
static
|
||||||
{
|
uid_t sukisu_get_manager_uid() {
|
||||||
return ksu_manager_uid;
|
return ksu_manager_uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sukisu_set_manager_uid(uid_t uid, int force)
|
static
|
||||||
{
|
void sukisu_set_manager_uid(uid_t uid, int force) {
|
||||||
if (force || ksu_manager_uid == -1)
|
if(force || ksu_manager_uid == -1) {
|
||||||
ksu_manager_uid = uid;
|
ksu_manager_uid = uid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ======================================================================
|
||||||
|
|
||||||
struct CompactAddressSymbol {
|
struct CompactAddressSymbol {
|
||||||
const char *symbol_name;
|
const char* symbol_name;
|
||||||
void *addr;
|
void* addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned long sukisu_compact_find_symbol(const char *name);
|
static struct CompactAddressSymbol address_symbol [] = {
|
||||||
|
|
||||||
static struct CompactAddressSymbol address_symbol[] = {
|
|
||||||
{ "kallsyms_lookup_name", &kallsyms_lookup_name },
|
{ "kallsyms_lookup_name", &kallsyms_lookup_name },
|
||||||
{ "compact_find_symbol", &sukisu_compact_find_symbol },
|
{ "compact_find_symbol", &sukisu_compact_find_symbol },
|
||||||
{ "is_run_in_sukisu_ultra", (void *)1 },
|
{ "is_run_in_sukisu_ultra", (void*)1 },
|
||||||
{ "is_su_allow_uid", &sukisu_is_su_allow_uid },
|
{ "is_su_allow_uid", &sukisu_is_su_allow_uid },
|
||||||
{ "get_ap_mod_exclude", &sukisu_get_ap_mod_exclude },
|
{ "get_ap_mod_exclude", &sukisu_get_ap_mod_exclude },
|
||||||
{ "is_uid_should_umount", &sukisu_is_uid_should_umount },
|
{ "is_uid_should_umount", &sukisu_is_uid_should_umount },
|
||||||
@@ -79,22 +86,25 @@ static struct CompactAddressSymbol address_symbol[] = {
|
|||||||
{ "sukisu_set_manager_uid", &sukisu_set_manager_uid }
|
{ "sukisu_set_manager_uid", &sukisu_set_manager_uid }
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned long sukisu_compact_find_symbol(const char* name)
|
unsigned long sukisu_compact_find_symbol(const char* name) {
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
|
||||||
for (i = 0; i < (sizeof(address_symbol) / sizeof(struct CompactAddressSymbol)); i++) {
|
// 先自己在地址表部分查出来
|
||||||
struct CompactAddressSymbol *symbol = &address_symbol[i];
|
for(i = 0; i < (sizeof(address_symbol) / sizeof(struct CompactAddressSymbol)); i++) {
|
||||||
|
struct CompactAddressSymbol* symbol = &address_symbol[i];
|
||||||
if (strcmp(name, symbol->symbol_name) == 0)
|
if(strcmp(name, symbol->symbol_name) == 0) {
|
||||||
return (unsigned long)symbol->addr;
|
return (unsigned long) symbol->addr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通过内核来查
|
||||||
addr = kallsyms_lookup_name(name);
|
addr = kallsyms_lookup_name(name);
|
||||||
if (addr)
|
if(addr) {
|
||||||
return addr;
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(sukisu_compact_find_symbol);
|
EXPORT_SYMBOL(sukisu_compact_find_symbol);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifndef __SUKISU_KPM_COMPACT_H
|
#ifndef ___SUKISU_KPM_COMPACT_H
|
||||||
#define __SUKISU_KPM_COMPACT_H
|
#define ___SUKISU_KPM_COMPACT_H
|
||||||
|
|
||||||
extern unsigned long sukisu_compact_find_symbol(const char *name);
|
unsigned long sukisu_compact_find_symbol(const char* name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
324
kernel/kpm/kpm.c
@@ -8,11 +8,13 @@
|
|||||||
* 集成了 ELF 解析、内存布局、符号处理、重定位(支持 ARM64 重定位类型)
|
* 集成了 ELF 解析、内存布局、符号处理、重定位(支持 ARM64 重定位类型)
|
||||||
* 并参照KernelPatch的标准KPM格式实现加载和控制
|
* 并参照KernelPatch的标准KPM格式实现加载和控制
|
||||||
*/
|
*/
|
||||||
|
#include <linux/export.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/kernfs.h>
|
#include <linux/kernfs.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/elf.h>
|
#include <linux/elf.h>
|
||||||
@@ -21,26 +23,27 @@
|
|||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <asm/elf.h>
|
#include <asm/elf.h> /* 包含 ARM64 重定位类型定义 */
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/set_memory.h>
|
#include <linux/set_memory.h>
|
||||||
|
#include <linux/version.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <asm/insn.h>
|
#include <asm/insn.h>
|
||||||
#include <linux/kprobes.h>
|
#include <linux/kprobes.h>
|
||||||
#include <linux/stacktrace.h>
|
#include <linux/stacktrace.h>
|
||||||
|
#include <linux/kallsyms.h>
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) && defined(CONFIG_MODULES)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) && defined(CONFIG_MODULES)
|
||||||
#include <linux/moduleloader.h>
|
#include <linux/moduleloader.h> // 需要启用 CONFIG_MODULES
|
||||||
#endif
|
#endif
|
||||||
#include "kpm.h"
|
#include "kpm.h"
|
||||||
#include "compact.h"
|
#include "compact.h"
|
||||||
|
|
||||||
#define KPM_NAME_LEN 32
|
|
||||||
#define KPM_ARGS_LEN 1024
|
|
||||||
|
|
||||||
#ifndef NO_OPTIMIZE
|
#ifndef NO_OPTIMIZE
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
#define NO_OPTIMIZE __attribute__((optimize("O0")))
|
#define NO_OPTIMIZE __attribute__((optimize("O0")))
|
||||||
@@ -51,232 +54,131 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
noinline NO_OPTIMIZE void sukisu_kpm_load_module_path(const char *path,
|
// ============================================================================================
|
||||||
const char *args, void *ptr, int *result)
|
|
||||||
{
|
|
||||||
pr_info("kpm: Stub function called (sukisu_kpm_load_module_path). "
|
|
||||||
"path=%s args=%s ptr=%p\n", path, args, ptr);
|
|
||||||
|
|
||||||
__asm__ volatile("nop");
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_load_module_path(const char* path, const char* args, void* ptr, void __user* result) {
|
||||||
|
// This is a KPM module stub.
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_load_module_path). path=%s args=%s ptr=%p\n", path, args, ptr);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_unload_module(const char* name, void* ptr, void __user* result) {
|
||||||
|
// This is a KPM module stub.
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_unload_module). name=%s ptr=%p\n", name, ptr);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_num(void __user* result) {
|
||||||
|
// This is a KPM module stub.
|
||||||
|
int res = 0;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_num).\n");
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_info(const char* name, void __user* out, void __user* result) {
|
||||||
|
// This is a KPM module stub.
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_info). name=%s buffer=%p\n", name, out);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_list(void __user* out, unsigned int bufferSize, void __user* result) {
|
||||||
|
// This is a KPM module stub.
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_list). buffer=%p size=%d\n", out, bufferSize);
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_control(void __user* name, void __user* args, void __user* result) {
|
||||||
|
// This is a KPM module stub.
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_control). name=%p args=%p\n", name, args);
|
||||||
|
__asm__ volatile("nop"); // 精确控制循环不被优化
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
noinline
|
||||||
|
NO_OPTIMIZE
|
||||||
|
void sukisu_kpm_version(void __user* out, unsigned int bufferSize, void __user* result) {
|
||||||
|
int res = -1;
|
||||||
|
printk("KPM: Stub function called (sukisu_kpm_version). buffer=%p size=%d\n", out, bufferSize);
|
||||||
|
if(copy_to_user(result, &res, sizeof(res)) < 1) printk("KPM: Copy to user failed.");
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_load_module_path);
|
EXPORT_SYMBOL(sukisu_kpm_load_module_path);
|
||||||
|
|
||||||
noinline NO_OPTIMIZE void sukisu_kpm_unload_module(const char *name,
|
|
||||||
void *ptr, int *result)
|
|
||||||
{
|
|
||||||
pr_info("kpm: Stub function called (sukisu_kpm_unload_module). "
|
|
||||||
"name=%s ptr=%p\n", name, ptr);
|
|
||||||
|
|
||||||
__asm__ volatile("nop");
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_unload_module);
|
EXPORT_SYMBOL(sukisu_kpm_unload_module);
|
||||||
|
|
||||||
noinline NO_OPTIMIZE void sukisu_kpm_num(int *result)
|
|
||||||
{
|
|
||||||
pr_info("kpm: Stub function called (sukisu_kpm_num).\n");
|
|
||||||
|
|
||||||
__asm__ volatile("nop");
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_num);
|
EXPORT_SYMBOL(sukisu_kpm_num);
|
||||||
|
|
||||||
noinline NO_OPTIMIZE void sukisu_kpm_info(const char *name, char *buf, int bufferSize,
|
|
||||||
int *size)
|
|
||||||
{
|
|
||||||
pr_info("kpm: Stub function called (sukisu_kpm_info). "
|
|
||||||
"name=%s buffer=%p\n", name, buf);
|
|
||||||
|
|
||||||
__asm__ volatile("nop");
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_info);
|
EXPORT_SYMBOL(sukisu_kpm_info);
|
||||||
|
|
||||||
noinline NO_OPTIMIZE void sukisu_kpm_list(void *out, int bufferSize,
|
|
||||||
int *result)
|
|
||||||
{
|
|
||||||
pr_info("kpm: Stub function called (sukisu_kpm_list). "
|
|
||||||
"buffer=%p size=%d\n", out, bufferSize);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_list);
|
EXPORT_SYMBOL(sukisu_kpm_list);
|
||||||
|
EXPORT_SYMBOL(sukisu_kpm_version);
|
||||||
noinline NO_OPTIMIZE void sukisu_kpm_control(const char *name, const char *args, long arg_len,
|
|
||||||
int *result)
|
|
||||||
{
|
|
||||||
pr_info("kpm: Stub function called (sukisu_kpm_control). "
|
|
||||||
"name=%p args=%p arg_len=%ld\n", name, args, arg_len);
|
|
||||||
|
|
||||||
__asm__ volatile("nop");
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(sukisu_kpm_control);
|
EXPORT_SYMBOL(sukisu_kpm_control);
|
||||||
|
|
||||||
noinline NO_OPTIMIZE void sukisu_kpm_version(char *buf, int bufferSize)
|
noinline
|
||||||
|
int sukisu_handle_kpm(unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
|
||||||
{
|
{
|
||||||
pr_info("kpm: Stub function called (sukisu_kpm_version). "
|
if(arg2 == SUKISU_KPM_LOAD) {
|
||||||
"buffer=%p\n", buf);
|
char kernel_load_path[256] = { 0 };
|
||||||
}
|
char kernel_args_buffer[256] = { 0 };
|
||||||
EXPORT_SYMBOL(sukisu_kpm_version);
|
|
||||||
|
|
||||||
noinline int sukisu_handle_kpm(unsigned long control_code, unsigned long arg1, unsigned long arg2,
|
if(arg3 == 0) {
|
||||||
unsigned long result_code)
|
return -1;
|
||||||
{
|
|
||||||
int res = -1;
|
|
||||||
if (control_code == SUKISU_KPM_LOAD) {
|
|
||||||
char kernel_load_path[256];
|
|
||||||
char kernel_args_buffer[256];
|
|
||||||
|
|
||||||
if (arg1 == 0) {
|
|
||||||
res = -EINVAL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access_ok(arg1, 255)) {
|
|
||||||
goto invalid_arg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy_from_user((char *)&kernel_load_path, (const char *)arg1, 255);
|
strncpy_from_user((char*)&kernel_load_path, (const char __user *)arg3, 255);
|
||||||
|
if(arg4 != 0) {
|
||||||
if (arg2 != 0) {
|
strncpy_from_user((char*)&kernel_args_buffer, (const char __user *)arg4, 255);
|
||||||
if (!access_ok(arg2, 255)) {
|
|
||||||
goto invalid_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy_from_user((char *)&kernel_args_buffer, (const char *)arg2, 255);
|
|
||||||
}
|
}
|
||||||
|
sukisu_kpm_load_module_path((const char*)&kernel_load_path, (const char*) &kernel_args_buffer, NULL, (void __user*) arg5);
|
||||||
|
} else if(arg2 == SUKISU_KPM_UNLOAD) {
|
||||||
|
char kernel_name_buffer[256] = { 0 };
|
||||||
|
|
||||||
sukisu_kpm_load_module_path((const char *)&kernel_load_path,
|
if(arg3 == 0) {
|
||||||
(const char *)&kernel_args_buffer, NULL, &res);
|
return -1;
|
||||||
} else if (control_code == SUKISU_KPM_UNLOAD) {
|
|
||||||
char kernel_name_buffer[256];
|
|
||||||
|
|
||||||
if (arg1 == 0) {
|
|
||||||
res = -EINVAL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access_ok(arg1, sizeof(kernel_name_buffer))) {
|
|
||||||
goto invalid_arg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy_from_user((char *)&kernel_name_buffer, (const char *)arg1, sizeof(kernel_name_buffer));
|
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg3, 255);
|
||||||
|
sukisu_kpm_unload_module((const char*) &kernel_name_buffer, NULL, (void __user*) arg5);
|
||||||
sukisu_kpm_unload_module((const char *)&kernel_name_buffer, NULL, &res);
|
} else if(arg2 == SUKISU_KPM_NUM) {
|
||||||
} else if (control_code == SUKISU_KPM_NUM) {
|
sukisu_kpm_num((void __user*) arg5);
|
||||||
sukisu_kpm_num(&res);
|
} else if(arg2 == SUKISU_KPM_INFO) {
|
||||||
} else if (control_code == SUKISU_KPM_INFO) {
|
char kernel_name_buffer[256] = { 0 };
|
||||||
char kernel_name_buffer[256];
|
|
||||||
char buf[256];
|
|
||||||
int size;
|
|
||||||
|
|
||||||
if (arg1 == 0 || arg2 == 0) {
|
if(arg3 == 0 || arg4 == 0) {
|
||||||
res = -EINVAL;
|
return -1;
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access_ok(arg1, sizeof(kernel_name_buffer))) {
|
|
||||||
goto invalid_arg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy_from_user((char *)&kernel_name_buffer, (const char __user *)arg1, sizeof(kernel_name_buffer));
|
strncpy_from_user((char*)&kernel_name_buffer, (const char __user *)arg3, 255);
|
||||||
|
sukisu_kpm_info((const char*) &kernel_name_buffer, (char __user*) arg4, (void __user*) arg5);
|
||||||
sukisu_kpm_info((const char *)&kernel_name_buffer, (char *)&buf, sizeof(buf), &size);
|
} else if(arg2 == SUKISU_KPM_LIST) {
|
||||||
|
sukisu_kpm_list((char __user*) arg3, (unsigned int) arg4, (void __user*) arg5);
|
||||||
if (!access_ok(arg2, size)) {
|
} else if(arg2 == SUKISU_KPM_VERSION) {
|
||||||
goto invalid_arg;
|
sukisu_kpm_version((char __user*) arg3, (unsigned int) arg4, (void __user*) arg5);
|
||||||
}
|
} else if(arg2 == SUKISU_KPM_CONTROL) {
|
||||||
|
sukisu_kpm_control((char __user*) arg3, (char __user*) arg4, (void __user*) arg5);
|
||||||
res = copy_to_user(arg2, &buf, size);
|
|
||||||
|
|
||||||
} else if (control_code == SUKISU_KPM_LIST) {
|
|
||||||
char buf[1024];
|
|
||||||
int len = (int) arg2;
|
|
||||||
|
|
||||||
if (len <= 0) {
|
|
||||||
res = -EINVAL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access_ok(arg2, len)) {
|
|
||||||
goto invalid_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
sukisu_kpm_list((char *)&buf, sizeof(buf), &res);
|
|
||||||
|
|
||||||
if (res > len) {
|
|
||||||
res = -ENOBUFS;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_to_user(arg1, &buf, len) != 0)
|
|
||||||
pr_info("kpm: Copy to user failed.");
|
|
||||||
|
|
||||||
} else if (control_code == SUKISU_KPM_CONTROL) {
|
|
||||||
char kpm_name[KPM_NAME_LEN] = { 0 };
|
|
||||||
char kpm_args[KPM_ARGS_LEN] = { 0 };
|
|
||||||
|
|
||||||
if (!access_ok(arg1, sizeof(kpm_name))) {
|
|
||||||
goto invalid_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access_ok(arg2, sizeof(kpm_args))) {
|
|
||||||
goto invalid_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
long name_len = strncpy_from_user((char *)&kpm_name, (const char __user *)arg1, sizeof(kpm_name));
|
|
||||||
if (name_len <= 0) {
|
|
||||||
res = -EINVAL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
long arg_len = strncpy_from_user((char *)&kpm_args, (const char __user *)arg2, sizeof(kpm_args));
|
|
||||||
|
|
||||||
sukisu_kpm_control((const char *)&kpm_name, (const char *)&kpm_args, arg_len, &res);
|
|
||||||
|
|
||||||
} else if (control_code == SUKISU_KPM_VERSION) {
|
|
||||||
char buffer[256] = {0};
|
|
||||||
|
|
||||||
sukisu_kpm_version((char*) &buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
unsigned int outlen = (unsigned int) arg2;
|
|
||||||
int len = strlen(buffer);
|
|
||||||
if (len >= outlen) len = outlen - 1;
|
|
||||||
|
|
||||||
res = copy_to_user(arg1, &buffer, len + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
|
||||||
if (copy_to_user(result_code, &res, sizeof(res)) != 0)
|
|
||||||
pr_info("kpm: Copy to user failed.");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
invalid_arg:
|
|
||||||
pr_err("kpm: invalid pointer detected! arg1: %px arg2: %px\n", (void *)arg1, (void *)arg2);
|
|
||||||
res = -EFAULT;
|
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sukisu_is_kpm_control_code(unsigned long arg2) {
|
||||||
|
return (arg2 >= CMD_KPM_CONTROL && arg2 <= CMD_KPM_CONTROL_MAX) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(sukisu_handle_kpm);
|
EXPORT_SYMBOL(sukisu_handle_kpm);
|
||||||
|
|
||||||
int sukisu_is_kpm_control_code(unsigned long control_code) {
|
|
||||||
return (control_code >= CMD_KPM_CONTROL &&
|
|
||||||
control_code <= CMD_KPM_CONTROL_MAX) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int do_kpm(void __user *arg)
|
|
||||||
{
|
|
||||||
struct ksu_kpm_cmd cmd;
|
|
||||||
|
|
||||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
|
||||||
pr_err("kpm: copy_from_user failed\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access_ok(cmd.control_code, sizeof(int))) {
|
|
||||||
pr_err("kpm: invalid control_code pointer %px\n", (void *)cmd.control_code);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!access_ok(cmd.result_code, sizeof(int))) {
|
|
||||||
pr_err("kpm: invalid result_code pointer %px\n", (void *)cmd.result_code);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sukisu_handle_kpm(cmd.control_code, cmd.arg1, cmd.arg2, cmd.result_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +1,44 @@
|
|||||||
#ifndef __SUKISU_KPM_H
|
#ifndef ___SUKISU_KPM_H
|
||||||
#define __SUKISU_KPM_H
|
#define ___SUKISU_KPM_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
int sukisu_handle_kpm(unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
||||||
#include <linux/ioctl.h>
|
int sukisu_is_kpm_control_code(unsigned long arg2);
|
||||||
|
|
||||||
struct ksu_kpm_cmd {
|
// KPM控制代码
|
||||||
__aligned_u64 __user control_code;
|
#define CMD_KPM_CONTROL 28
|
||||||
__aligned_u64 __user arg1;
|
#define CMD_KPM_CONTROL_MAX 35
|
||||||
__aligned_u64 __user arg2;
|
|
||||||
__aligned_u64 __user result_code;
|
|
||||||
};
|
|
||||||
|
|
||||||
int sukisu_handle_kpm(unsigned long control_code, unsigned long arg3, unsigned long arg4, unsigned long result_code);
|
// 控制代码
|
||||||
int sukisu_is_kpm_control_code(unsigned long control_code);
|
|
||||||
int do_kpm(void __user *arg);
|
|
||||||
|
|
||||||
#define KSU_IOCTL_KPM _IOC(_IOC_READ|_IOC_WRITE, 'K', 200, 0)
|
// prctl(xxx, 28, "PATH", "ARGS")
|
||||||
|
// success return 0, error return -N
|
||||||
|
#define SUKISU_KPM_LOAD 28
|
||||||
|
|
||||||
/* KPM Control Code */
|
// prctl(xxx, 29, "NAME")
|
||||||
#define CMD_KPM_CONTROL 1
|
// success return 0, error return -N
|
||||||
#define CMD_KPM_CONTROL_MAX 10
|
#define SUKISU_KPM_UNLOAD 29
|
||||||
|
|
||||||
/* Control Code */
|
// num = prctl(xxx, 30)
|
||||||
/*
|
// error return -N
|
||||||
* prctl(xxx, 1, "PATH", "ARGS")
|
// success return +num or 0
|
||||||
* success return 0, error return -N
|
#define SUKISU_KPM_NUM 30
|
||||||
*/
|
|
||||||
#define SUKISU_KPM_LOAD 1
|
|
||||||
|
|
||||||
/*
|
// prctl(xxx, 31, Buffer, BufferSize)
|
||||||
* prctl(xxx, 2, "NAME")
|
// success return +out, error return -N
|
||||||
* success return 0, error return -N
|
#define SUKISU_KPM_LIST 31
|
||||||
*/
|
|
||||||
#define SUKISU_KPM_UNLOAD 2
|
|
||||||
|
|
||||||
/*
|
// prctl(xxx, 32, "NAME", Buffer[256])
|
||||||
* num = prctl(xxx, 3)
|
// success return +out, error return -N
|
||||||
* error return -N
|
#define SUKISU_KPM_INFO 32
|
||||||
* success return +num or 0
|
|
||||||
*/
|
|
||||||
#define SUKISU_KPM_NUM 3
|
|
||||||
|
|
||||||
/*
|
// prctl(xxx, 33, "NAME", "ARGS")
|
||||||
* prctl(xxx, 4, Buffer, BufferSize)
|
// success return KPM's result value
|
||||||
* success return +out, error return -N
|
// error return -N
|
||||||
*/
|
#define SUKISU_KPM_CONTROL 33
|
||||||
#define SUKISU_KPM_LIST 4
|
|
||||||
|
|
||||||
/*
|
// prctl(xxx, 34, buffer, bufferSize)
|
||||||
* prctl(xxx, 5, "NAME", Buffer[256])
|
// success return KPM's result value
|
||||||
* success return +out, error return -N
|
// error return -N
|
||||||
*/
|
#define SUKISU_KPM_VERSION 34
|
||||||
#define SUKISU_KPM_INFO 5
|
|
||||||
|
|
||||||
/*
|
#endif
|
||||||
* prctl(xxx, 6, "NAME", "ARGS")
|
|
||||||
* success return KPM's result value
|
|
||||||
* error return -N
|
|
||||||
*/
|
|
||||||
#define SUKISU_KPM_CONTROL 6
|
|
||||||
|
|
||||||
/*
|
|
||||||
* prctl(xxx, 7, buffer, bufferSize)
|
|
||||||
* success return KPM's result value
|
|
||||||
* error return -N
|
|
||||||
*/
|
|
||||||
#define SUKISU_KPM_VERSION 7
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <asm/elf.h>
|
#include <asm/elf.h> /* 包含 ARM64 重定位类型定义 */
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
@@ -24,37 +24,34 @@
|
|||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/stddef.h>
|
|
||||||
#include <linux/mount.h>
|
|
||||||
#include <linux/kprobes.h>
|
|
||||||
#include <linux/mm_types.h>
|
|
||||||
#include <linux/netlink.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <../fs/mount.h>
|
|
||||||
#include "kpm.h"
|
#include "kpm.h"
|
||||||
#include "compact.h"
|
#include "compact.h"
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/stddef.h>
|
||||||
|
|
||||||
|
// 结构体成员元数据
|
||||||
struct DynamicStructMember {
|
struct DynamicStructMember {
|
||||||
const char *name;
|
const char* name;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 结构体元数据(包含总大小)
|
||||||
struct DynamicStructInfo {
|
struct DynamicStructInfo {
|
||||||
const char *name;
|
const char* name;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
struct DynamicStructMember *members;
|
struct DynamicStructMember* members;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 定义结构体元数据的宏(直接使用 struct 名称)
|
||||||
#define DYNAMIC_STRUCT_BEGIN(struct_name) \
|
#define DYNAMIC_STRUCT_BEGIN(struct_name) \
|
||||||
static struct DynamicStructMember struct_name##_members[] = {
|
static struct DynamicStructMember struct_name##_members[] = {
|
||||||
|
|
||||||
#define DEFINE_MEMBER(struct_name, member) \
|
#define DEFINE_MEMBER(struct_name, member) \
|
||||||
{ \
|
{ \
|
||||||
.name = #member, \
|
.name = #member, \
|
||||||
.size = sizeof(((struct struct_name *)0)->member), \
|
.size = sizeof(((struct struct_name*)0)->member), \
|
||||||
.offset = offsetof(struct struct_name, member) \
|
.offset = offsetof(struct struct_name, member) \
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -67,6 +64,17 @@ struct DynamicStructInfo {
|
|||||||
.members = struct_name##_members \
|
.members = struct_name##_members \
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ==================================================================================
|
||||||
|
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
#define KERNEL_VERSION_6_1 KERNEL_VERSION(6, 1, 0)
|
||||||
|
#define KERNEL_VERSION_5_15 KERNEL_VERSION(5, 15, 0)
|
||||||
|
|
||||||
|
#include <../fs/mount.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
|
||||||
|
// 定义元数据
|
||||||
DYNAMIC_STRUCT_BEGIN(mount)
|
DYNAMIC_STRUCT_BEGIN(mount)
|
||||||
DEFINE_MEMBER(mount, mnt_parent)
|
DEFINE_MEMBER(mount, mnt_parent)
|
||||||
DEFINE_MEMBER(mount, mnt)
|
DEFINE_MEMBER(mount, mnt)
|
||||||
@@ -88,11 +96,13 @@ DYNAMIC_STRUCT_BEGIN(mnt_namespace)
|
|||||||
DEFINE_MEMBER(mnt_namespace, root)
|
DEFINE_MEMBER(mnt_namespace, root)
|
||||||
DEFINE_MEMBER(mnt_namespace, seq)
|
DEFINE_MEMBER(mnt_namespace, seq)
|
||||||
DEFINE_MEMBER(mnt_namespace, mounts)
|
DEFINE_MEMBER(mnt_namespace, mounts)
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION_5_15
|
||||||
DEFINE_MEMBER(mnt_namespace, count)
|
DEFINE_MEMBER(mnt_namespace, count)
|
||||||
#endif
|
#endif
|
||||||
DYNAMIC_STRUCT_END(mnt_namespace)
|
DYNAMIC_STRUCT_END(mnt_namespace)
|
||||||
|
|
||||||
|
#include <linux/kprobes.h>
|
||||||
|
|
||||||
#ifdef CONFIG_KPROBES
|
#ifdef CONFIG_KPROBES
|
||||||
DYNAMIC_STRUCT_BEGIN(kprobe)
|
DYNAMIC_STRUCT_BEGIN(kprobe)
|
||||||
DEFINE_MEMBER(kprobe, addr)
|
DEFINE_MEMBER(kprobe, addr)
|
||||||
@@ -100,13 +110,16 @@ DYNAMIC_STRUCT_BEGIN(kprobe)
|
|||||||
DEFINE_MEMBER(kprobe, offset)
|
DEFINE_MEMBER(kprobe, offset)
|
||||||
DEFINE_MEMBER(kprobe, pre_handler)
|
DEFINE_MEMBER(kprobe, pre_handler)
|
||||||
DEFINE_MEMBER(kprobe, post_handler)
|
DEFINE_MEMBER(kprobe, post_handler)
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION_5_15
|
||||||
DEFINE_MEMBER(kprobe, fault_handler)
|
DEFINE_MEMBER(kprobe, fault_handler)
|
||||||
#endif
|
#endif
|
||||||
DEFINE_MEMBER(kprobe, flags)
|
DEFINE_MEMBER(kprobe, flags)
|
||||||
DYNAMIC_STRUCT_END(kprobe)
|
DYNAMIC_STRUCT_END(kprobe)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/mm_types.h>
|
||||||
|
|
||||||
DYNAMIC_STRUCT_BEGIN(vm_area_struct)
|
DYNAMIC_STRUCT_BEGIN(vm_area_struct)
|
||||||
DEFINE_MEMBER(vm_area_struct,vm_start)
|
DEFINE_MEMBER(vm_area_struct,vm_start)
|
||||||
DEFINE_MEMBER(vm_area_struct,vm_end)
|
DEFINE_MEMBER(vm_area_struct,vm_end)
|
||||||
@@ -115,9 +128,9 @@ DYNAMIC_STRUCT_BEGIN(vm_area_struct)
|
|||||||
DEFINE_MEMBER(vm_area_struct,vm_pgoff)
|
DEFINE_MEMBER(vm_area_struct,vm_pgoff)
|
||||||
DEFINE_MEMBER(vm_area_struct,vm_file)
|
DEFINE_MEMBER(vm_area_struct,vm_file)
|
||||||
DEFINE_MEMBER(vm_area_struct,vm_private_data)
|
DEFINE_MEMBER(vm_area_struct,vm_private_data)
|
||||||
#ifdef CONFIG_ANON_VMA_NAME
|
#ifdef CONFIG_ANON_VMA_NAME
|
||||||
DEFINE_MEMBER(vm_area_struct, anon_name)
|
DEFINE_MEMBER(vm_area_struct, anon_name)
|
||||||
#endif
|
#endif
|
||||||
DEFINE_MEMBER(vm_area_struct, vm_ops)
|
DEFINE_MEMBER(vm_area_struct, vm_ops)
|
||||||
DYNAMIC_STRUCT_END(vm_area_struct)
|
DYNAMIC_STRUCT_END(vm_area_struct)
|
||||||
|
|
||||||
@@ -128,6 +141,8 @@ DYNAMIC_STRUCT_BEGIN(vm_operations_struct)
|
|||||||
DEFINE_MEMBER(vm_operations_struct, access)
|
DEFINE_MEMBER(vm_operations_struct, access)
|
||||||
DYNAMIC_STRUCT_END(vm_operations_struct)
|
DYNAMIC_STRUCT_END(vm_operations_struct)
|
||||||
|
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
|
||||||
DYNAMIC_STRUCT_BEGIN(netlink_kernel_cfg)
|
DYNAMIC_STRUCT_BEGIN(netlink_kernel_cfg)
|
||||||
DEFINE_MEMBER(netlink_kernel_cfg, groups)
|
DEFINE_MEMBER(netlink_kernel_cfg, groups)
|
||||||
DEFINE_MEMBER(netlink_kernel_cfg, flags)
|
DEFINE_MEMBER(netlink_kernel_cfg, flags)
|
||||||
@@ -135,11 +150,13 @@ DYNAMIC_STRUCT_BEGIN(netlink_kernel_cfg)
|
|||||||
DEFINE_MEMBER(netlink_kernel_cfg, cb_mutex)
|
DEFINE_MEMBER(netlink_kernel_cfg, cb_mutex)
|
||||||
DEFINE_MEMBER(netlink_kernel_cfg, bind)
|
DEFINE_MEMBER(netlink_kernel_cfg, bind)
|
||||||
DEFINE_MEMBER(netlink_kernel_cfg, unbind)
|
DEFINE_MEMBER(netlink_kernel_cfg, unbind)
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION_6_1
|
||||||
DEFINE_MEMBER(netlink_kernel_cfg, compare)
|
DEFINE_MEMBER(netlink_kernel_cfg, compare)
|
||||||
#endif
|
#endif
|
||||||
DYNAMIC_STRUCT_END(netlink_kernel_cfg)
|
DYNAMIC_STRUCT_END(netlink_kernel_cfg)
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/sched.h>
|
||||||
DYNAMIC_STRUCT_BEGIN(task_struct)
|
DYNAMIC_STRUCT_BEGIN(task_struct)
|
||||||
DEFINE_MEMBER(task_struct, pid)
|
DEFINE_MEMBER(task_struct, pid)
|
||||||
DEFINE_MEMBER(task_struct, tgid)
|
DEFINE_MEMBER(task_struct, tgid)
|
||||||
@@ -169,110 +186,104 @@ DYNAMIC_STRUCT_BEGIN(task_struct)
|
|||||||
DEFINE_MEMBER(task_struct, thread)
|
DEFINE_MEMBER(task_struct, thread)
|
||||||
DYNAMIC_STRUCT_END(task_struct)
|
DYNAMIC_STRUCT_END(task_struct)
|
||||||
|
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
#define STRUCT_INFO(name) &(name##_info)
|
#define STRUCT_INFO(name) &(name##_info)
|
||||||
|
|
||||||
static struct DynamicStructInfo *dynamic_struct_infos[] = {
|
static
|
||||||
|
struct DynamicStructInfo* dynamic_struct_infos[] = {
|
||||||
STRUCT_INFO(mount),
|
STRUCT_INFO(mount),
|
||||||
STRUCT_INFO(vfsmount),
|
STRUCT_INFO(vfsmount),
|
||||||
STRUCT_INFO(mnt_namespace),
|
STRUCT_INFO(mnt_namespace),
|
||||||
#ifdef CONFIG_KPROBES
|
#ifdef CONFIG_KPROBES
|
||||||
STRUCT_INFO(kprobe),
|
STRUCT_INFO(kprobe),
|
||||||
#endif
|
#endif
|
||||||
STRUCT_INFO(vm_area_struct),
|
STRUCT_INFO(vm_area_struct),
|
||||||
STRUCT_INFO(vm_operations_struct),
|
STRUCT_INFO(vm_operations_struct),
|
||||||
STRUCT_INFO(netlink_kernel_cfg),
|
STRUCT_INFO(netlink_kernel_cfg),
|
||||||
STRUCT_INFO(task_struct)
|
STRUCT_INFO(task_struct)
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
// return 0 if successful
|
||||||
* return 0 if successful
|
// return -1 if struct not defined
|
||||||
* return -1 if struct not defined
|
int sukisu_super_find_struct(
|
||||||
*/
|
const char* struct_name,
|
||||||
int sukisu_super_find_struct(const char *struct_name, size_t *out_size, int *out_members)
|
size_t* out_size,
|
||||||
{
|
int* out_members
|
||||||
for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
|
) {
|
||||||
struct DynamicStructInfo *info = dynamic_struct_infos[i];
|
for(size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
|
||||||
|
struct DynamicStructInfo* info = dynamic_struct_infos[i];
|
||||||
if (strcmp(struct_name, info->name) == 0) {
|
if(strcmp(struct_name, info->name) == 0) {
|
||||||
if (out_size)
|
if(out_size)
|
||||||
*out_size = info->total_size;
|
*out_size = info->total_size;
|
||||||
|
if(out_members)
|
||||||
if (out_members)
|
|
||||||
*out_members = info->count;
|
*out_members = info->count;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sukisu_super_find_struct);
|
EXPORT_SYMBOL(sukisu_super_find_struct);
|
||||||
|
|
||||||
/*
|
// Dynamic access struct
|
||||||
* Dynamic access struct
|
// return 0 if successful
|
||||||
* return 0 if successful
|
// return -1 if struct not defined
|
||||||
* return -1 if struct not defined
|
// return -2 if member not defined
|
||||||
* return -2 if member not defined
|
int sukisu_super_access (
|
||||||
*/
|
const char* struct_name,
|
||||||
int sukisu_super_access(const char *struct_name, const char *member_name, size_t *out_offset,
|
const char* member_name,
|
||||||
size_t *out_size)
|
size_t* out_offset,
|
||||||
{
|
size_t* out_size
|
||||||
for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
|
) {
|
||||||
struct DynamicStructInfo *info = dynamic_struct_infos[i];
|
for(size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
|
||||||
|
struct DynamicStructInfo* info = dynamic_struct_infos[i];
|
||||||
if (strcmp(struct_name, info->name) == 0) {
|
if(strcmp(struct_name, info->name) == 0) {
|
||||||
for (size_t i1 = 0; i1 < info->count; i1++) {
|
for (size_t i1 = 0; i1 < info->count; i1++) {
|
||||||
if (strcmp(info->members[i1].name, member_name) == 0) {
|
if (strcmp(info->members[i1].name, member_name) == 0) {
|
||||||
if (out_offset)
|
if(out_offset)
|
||||||
*out_offset = info->members[i].offset;
|
*out_offset = info->members[i].offset;
|
||||||
|
if(out_size)
|
||||||
if (out_size)
|
|
||||||
*out_size = info->members[i].size;
|
*out_size = info->members[i].size;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sukisu_super_access);
|
EXPORT_SYMBOL(sukisu_super_access);
|
||||||
|
|
||||||
|
// 动态 container_of 宏
|
||||||
#define DYNAMIC_CONTAINER_OF(offset, member_ptr) ({ \
|
#define DYNAMIC_CONTAINER_OF(offset, member_ptr) ({ \
|
||||||
(offset != (size_t)-1) ? (void*)((char*)(member_ptr) - offset) : NULL; \
|
(offset != (size_t)-1) ? (void*)((char*)(member_ptr) - offset) : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
// Dynamic container_of
|
||||||
* Dynamic container_of
|
// return 0 if success
|
||||||
* return 0 if success
|
// return -1 if current struct not defined
|
||||||
* return -1 if current struct not defined
|
// return -2 if target member not defined
|
||||||
* return -2 if target member not defined
|
int sukisu_super_container_of(
|
||||||
*/
|
const char* struct_name,
|
||||||
int sukisu_super_container_of(const char *struct_name, const char *member_name, void *ptr,
|
const char* member_name,
|
||||||
void **out_ptr)
|
void* ptr,
|
||||||
{
|
void** out_ptr
|
||||||
if (ptr == NULL)
|
) {
|
||||||
|
if(ptr == NULL) {
|
||||||
return -3;
|
return -3;
|
||||||
|
}
|
||||||
for (size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
|
for(size_t i = 0; i < (sizeof(dynamic_struct_infos) / sizeof(dynamic_struct_infos[0])); i++) {
|
||||||
struct DynamicStructInfo *info = dynamic_struct_infos[i];
|
struct DynamicStructInfo* info = dynamic_struct_infos[i];
|
||||||
|
if(strcmp(struct_name, info->name) == 0) {
|
||||||
if (strcmp(struct_name, info->name) == 0) {
|
|
||||||
for (size_t i1 = 0; i1 < info->count; i1++) {
|
for (size_t i1 = 0; i1 < info->count; i1++) {
|
||||||
if (strcmp(info->members[i1].name, member_name) == 0) {
|
if (strcmp(info->members[i1].name, member_name) == 0) {
|
||||||
*out_ptr = (void *)DYNAMIC_CONTAINER_OF(info->members[i1].offset, ptr);
|
*out_ptr = (void*) DYNAMIC_CONTAINER_OF(info->members[i1].offset, ptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sukisu_super_container_of);
|
EXPORT_SYMBOL(sukisu_super_container_of);
|
||||||
@@ -6,10 +6,34 @@
|
|||||||
#include "kpm.h"
|
#include "kpm.h"
|
||||||
#include "compact.h"
|
#include "compact.h"
|
||||||
|
|
||||||
extern int sukisu_super_find_struct(const char *struct_name, size_t *out_size, int *out_members);
|
// return 0 if successful
|
||||||
extern int sukisu_super_access(const char *struct_name, const char *member_name, size_t *out_offset,
|
// return -1 if struct not defined
|
||||||
size_t *out_size);
|
int sukisu_super_find_struct(
|
||||||
extern int sukisu_super_container_of(const char *struct_name, const char *member_name, void *ptr,
|
const char* struct_name,
|
||||||
void **out_ptr);
|
size_t* out_size,
|
||||||
|
int* out_members
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dynamic access struct
|
||||||
|
// return 0 if successful
|
||||||
|
// return -1 if struct not defined
|
||||||
|
// return -2 if member not defined
|
||||||
|
int sukisu_super_access (
|
||||||
|
const char* struct_name,
|
||||||
|
const char* member_name,
|
||||||
|
size_t* out_offset,
|
||||||
|
size_t* out_size
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dynamic container_of
|
||||||
|
// return 0 if success
|
||||||
|
// return -1 if current struct not defined
|
||||||
|
// return -2 if target member not defined
|
||||||
|
int sukisu_super_container_of(
|
||||||
|
const char* struct_name,
|
||||||
|
const char* member_name,
|
||||||
|
void* ptr,
|
||||||
|
void** out_ptr
|
||||||
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
114
kernel/ksu.c
@@ -3,103 +3,100 @@
|
|||||||
#include <linux/kobject.h>
|
#include <linux/kobject.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/version.h>
|
|
||||||
|
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "feature.h"
|
#include "arch.h"
|
||||||
|
#include "core_hook.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
|
#include "ksu.h"
|
||||||
#include "throne_tracker.h"
|
#include "throne_tracker.h"
|
||||||
#include "syscall_hook_manager.h"
|
|
||||||
#include "ksud.h"
|
|
||||||
#include "supercalls.h"
|
|
||||||
|
|
||||||
#include "sulog.h"
|
|
||||||
#include "throne_comm.h"
|
|
||||||
#include "dynamic_manager.h"
|
|
||||||
|
|
||||||
static struct workqueue_struct *ksu_workqueue;
|
static struct workqueue_struct *ksu_workqueue;
|
||||||
|
|
||||||
bool ksu_queue_work(struct work_struct *work)
|
bool ksu_queue_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
return queue_work(ksu_workqueue, work);
|
return queue_work(ksu_workqueue, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sukisu_custom_config_init(void)
|
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||||
|
void *argv, void *envp, int *flags);
|
||||||
|
|
||||||
|
extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
|
||||||
|
void *argv, void *envp, int *flags);
|
||||||
|
|
||||||
|
int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
|
||||||
|
void *envp, int *flags)
|
||||||
{
|
{
|
||||||
|
ksu_handle_execveat_ksud(fd, filename_ptr, argv, envp, flags);
|
||||||
|
return ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp,
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sukisu_custom_config_exit(void)
|
extern void ksu_sucompat_init();
|
||||||
{
|
extern void ksu_sucompat_exit();
|
||||||
ksu_uid_exit();
|
extern void ksu_ksud_init();
|
||||||
ksu_throne_comm_exit();
|
extern void ksu_ksud_exit();
|
||||||
ksu_dynamic_manager_exit();
|
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||||
#if __SULOG_GATE
|
extern void ksu_trace_register();
|
||||||
ksu_sulog_exit();
|
extern void ksu_trace_unregister();
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
int __init kernelsu_init(void)
|
int __init kernelsu_init(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KSU_DEBUG
|
#ifdef CONFIG_KSU_DEBUG
|
||||||
pr_alert("*************************************************************");
|
pr_alert("*************************************************************");
|
||||||
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||||
pr_alert("** **");
|
pr_alert("** **");
|
||||||
pr_alert("** You are running KernelSU in DEBUG mode **");
|
pr_alert("** You are running KernelSU in DEBUG mode **");
|
||||||
pr_alert("** **");
|
pr_alert("** **");
|
||||||
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||||
pr_alert("*************************************************************");
|
pr_alert("*************************************************************");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ksu_feature_init();
|
ksu_core_init();
|
||||||
|
|
||||||
ksu_supercalls_init();
|
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
|
||||||
|
|
||||||
sukisu_custom_config_init();
|
ksu_allowlist_init();
|
||||||
|
|
||||||
ksu_syscall_hook_manager_init();
|
ksu_throne_tracker_init();
|
||||||
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
|
ksu_sucompat_init();
|
||||||
|
ksu_ksud_init();
|
||||||
ksu_allowlist_init();
|
|
||||||
|
|
||||||
ksu_throne_tracker_init();
|
|
||||||
|
|
||||||
#ifdef KSU_KPROBES_HOOK
|
|
||||||
ksu_ksud_init();
|
|
||||||
#else
|
#else
|
||||||
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
|
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||||
|
ksu_trace_register();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODULE
|
#ifdef MODULE
|
||||||
#ifndef CONFIG_KSU_DEBUG
|
#ifndef CONFIG_KSU_DEBUG
|
||||||
kobject_del(&THIS_MODULE->mkobj.kobj);
|
kobject_del(&THIS_MODULE->mkobj.kobj);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void ksu_observer_exit(void);
|
|
||||||
void kernelsu_exit(void)
|
void kernelsu_exit(void)
|
||||||
{
|
{
|
||||||
ksu_allowlist_exit();
|
ksu_allowlist_exit();
|
||||||
|
|
||||||
ksu_observer_exit();
|
ksu_throne_tracker_exit();
|
||||||
|
|
||||||
ksu_throne_tracker_exit();
|
destroy_workqueue(ksu_workqueue);
|
||||||
|
|
||||||
destroy_workqueue(ksu_workqueue);
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
|
ksu_ksud_exit();
|
||||||
#ifdef KSU_KPROBES_HOOK
|
ksu_sucompat_exit();
|
||||||
ksu_ksud_exit();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ksu_syscall_hook_manager_exit();
|
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||||
|
ksu_trace_unregister();
|
||||||
|
#endif
|
||||||
|
|
||||||
sukisu_custom_config_exit();
|
ksu_core_exit();
|
||||||
|
|
||||||
ksu_supercalls_exit();
|
|
||||||
|
|
||||||
ksu_feature_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(kernelsu_init);
|
module_init(kernelsu_init);
|
||||||
@@ -108,9 +105,4 @@ module_exit(kernelsu_exit);
|
|||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("weishu");
|
MODULE_AUTHOR("weishu");
|
||||||
MODULE_DESCRIPTION("Android KernelSU");
|
MODULE_DESCRIPTION("Android KernelSU");
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0)
|
|
||||||
MODULE_IMPORT_NS("VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver");
|
|
||||||
#else
|
|
||||||
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
||||||
#endif
|
|
||||||
|
|||||||
104
kernel/ksu.h
@@ -7,27 +7,51 @@
|
|||||||
#define KERNEL_SU_VERSION KSU_VERSION
|
#define KERNEL_SU_VERSION KSU_VERSION
|
||||||
#define KERNEL_SU_OPTION 0xDEADBEEF
|
#define KERNEL_SU_OPTION 0xDEADBEEF
|
||||||
|
|
||||||
extern bool ksu_uid_scanner_enabled;
|
#define CMD_GRANT_ROOT 0
|
||||||
|
#define CMD_BECOME_MANAGER 1
|
||||||
|
#define CMD_GET_VERSION 2
|
||||||
|
#define CMD_ALLOW_SU 3
|
||||||
|
#define CMD_DENY_SU 4
|
||||||
|
#define CMD_GET_ALLOW_LIST 5
|
||||||
|
#define CMD_GET_DENY_LIST 6
|
||||||
|
#define CMD_REPORT_EVENT 7
|
||||||
|
#define CMD_SET_SEPOLICY 8
|
||||||
|
#define CMD_CHECK_SAFEMODE 9
|
||||||
|
#define CMD_GET_APP_PROFILE 10
|
||||||
|
#define CMD_SET_APP_PROFILE 11
|
||||||
|
#define CMD_UID_GRANTED_ROOT 12
|
||||||
|
#define CMD_UID_SHOULD_UMOUNT 13
|
||||||
|
#define CMD_IS_SU_ENABLED 14
|
||||||
|
#define CMD_ENABLE_SU 15
|
||||||
|
|
||||||
|
#define CMD_GET_FULL_VERSION 0xC0FFEE1A
|
||||||
|
|
||||||
|
#define CMD_ENABLE_KPM 100
|
||||||
|
#define CMD_HOOK_TYPE 101
|
||||||
|
#define CMD_DYNAMIC_SIGN 103
|
||||||
|
#define CMD_GET_MANAGERS 104
|
||||||
|
|
||||||
#define EVENT_POST_FS_DATA 1
|
#define EVENT_POST_FS_DATA 1
|
||||||
#define EVENT_BOOT_COMPLETED 2
|
#define EVENT_BOOT_COMPLETED 2
|
||||||
#define EVENT_MODULE_MOUNTED 3
|
#define EVENT_MODULE_MOUNTED 3
|
||||||
|
|
||||||
|
#define KSU_APP_PROFILE_VER 2
|
||||||
|
#define KSU_MAX_PACKAGE_NAME 256
|
||||||
|
// NGROUPS_MAX for Linux is 65535 generally, but we only supports 32 groups.
|
||||||
|
#define KSU_MAX_GROUPS 32
|
||||||
|
#define KSU_SELINUX_DOMAIN 64
|
||||||
|
|
||||||
// SukiSU Ultra kernel su version full strings
|
// SukiSU Ultra kernel su version full strings
|
||||||
#ifndef KSU_VERSION_FULL
|
#ifndef KSU_VERSION_FULL
|
||||||
#define KSU_VERSION_FULL "v3.x-00000000@unknown"
|
#define KSU_VERSION_FULL "v3.x-00000000@unknown"
|
||||||
#endif
|
#endif
|
||||||
#define KSU_FULL_VERSION_STRING 255
|
#define KSU_FULL_VERSION_STRING 255
|
||||||
|
|
||||||
#define DYNAMIC_MANAGER_OP_SET 0
|
#define DYNAMIC_SIGN_OP_SET 0
|
||||||
#define DYNAMIC_MANAGER_OP_GET 1
|
#define DYNAMIC_SIGN_OP_GET 1
|
||||||
#define DYNAMIC_MANAGER_OP_CLEAR 2
|
#define DYNAMIC_SIGN_OP_CLEAR 2
|
||||||
|
|
||||||
#define UID_SCANNER_OP_GET_STATUS 0
|
struct dynamic_sign_user_config {
|
||||||
#define UID_SCANNER_OP_TOGGLE 1
|
|
||||||
#define UID_SCANNER_OP_CLEAR_ENV 2
|
|
||||||
|
|
||||||
struct dynamic_manager_user_config {
|
|
||||||
unsigned int operation;
|
unsigned int operation;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
char hash[65];
|
char hash[65];
|
||||||
@@ -41,22 +65,68 @@ struct manager_list_info {
|
|||||||
} managers[2];
|
} managers[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct root_profile {
|
||||||
|
int32_t uid;
|
||||||
|
int32_t gid;
|
||||||
|
|
||||||
|
int32_t groups_count;
|
||||||
|
int32_t groups[KSU_MAX_GROUPS];
|
||||||
|
|
||||||
|
// kernel_cap_t is u32[2] for capabilities v3
|
||||||
|
struct {
|
||||||
|
u64 effective;
|
||||||
|
u64 permitted;
|
||||||
|
u64 inheritable;
|
||||||
|
} capabilities;
|
||||||
|
|
||||||
|
char selinux_domain[KSU_SELINUX_DOMAIN];
|
||||||
|
|
||||||
|
int32_t namespaces;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct non_root_profile {
|
||||||
|
bool umount_modules;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct app_profile {
|
||||||
|
// It may be utilized for backward compatibility, although we have never explicitly made any promises regarding this.
|
||||||
|
u32 version;
|
||||||
|
|
||||||
|
// this is usually the package of the app, but can be other value for special apps
|
||||||
|
char key[KSU_MAX_PACKAGE_NAME];
|
||||||
|
int32_t current_uid;
|
||||||
|
bool allow_su;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
bool use_default;
|
||||||
|
char template_name[KSU_MAX_PACKAGE_NAME];
|
||||||
|
|
||||||
|
struct root_profile profile;
|
||||||
|
} rp_config;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool use_default;
|
||||||
|
|
||||||
|
struct non_root_profile profile;
|
||||||
|
} nrp_config;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
bool ksu_queue_work(struct work_struct *work);
|
bool ksu_queue_work(struct work_struct *work);
|
||||||
|
|
||||||
#if 0
|
|
||||||
static inline int startswith(char *s, char *prefix)
|
static inline int startswith(char *s, char *prefix)
|
||||||
{
|
{
|
||||||
return strncmp(s, prefix, strlen(prefix));
|
return strncmp(s, prefix, strlen(prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int endswith(const char *s, const char *t)
|
static inline int endswith(const char *s, const char *t)
|
||||||
{
|
{
|
||||||
size_t slen = strlen(s);
|
size_t slen = strlen(s);
|
||||||
size_t tlen = strlen(t);
|
size_t tlen = strlen(t);
|
||||||
if (tlen > slen)
|
if (tlen > slen)
|
||||||
return 1;
|
return 1;
|
||||||
return strcmp(s + slen - tlen, t);
|
return strcmp(s + slen - tlen, t);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
90
kernel/ksu_trace.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#include "ksu_trace.h"
|
||||||
|
|
||||||
|
|
||||||
|
// extern kernelsu functions
|
||||||
|
extern bool ksu_execveat_hook __read_mostly;
|
||||||
|
extern bool ksu_vfs_read_hook __read_mostly;
|
||||||
|
extern bool ksu_input_hook __read_mostly;
|
||||||
|
extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags);
|
||||||
|
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags);
|
||||||
|
extern int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, int *flags);
|
||||||
|
extern int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr, size_t *count_ptr);
|
||||||
|
extern int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
||||||
|
extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value);
|
||||||
|
extern int ksu_handle_devpts(struct inode*);
|
||||||
|
// end kernelsu functions
|
||||||
|
|
||||||
|
|
||||||
|
// tracepoint callback functions
|
||||||
|
void ksu_trace_execveat_hook_callback(void *data, int *fd, struct filename **filename_ptr,
|
||||||
|
void *argv, void *envp, int *flags)
|
||||||
|
{
|
||||||
|
if (unlikely(ksu_execveat_hook))
|
||||||
|
ksu_handle_execveat(fd, filename_ptr, argv, envp, flags);
|
||||||
|
else
|
||||||
|
ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_trace_execveat_sucompat_hook_callback(void *data, int *fd, struct filename **filename_ptr,
|
||||||
|
void *argv, void *envp, int *flags)
|
||||||
|
{
|
||||||
|
if (!ksu_execveat_hook)
|
||||||
|
ksu_handle_execveat_sucompat(fd, filename_ptr, argv, envp, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_trace_faccessat_hook_callback(void *data, int *dfd, const char __user **filename_user,
|
||||||
|
int *mode, int *flags)
|
||||||
|
{
|
||||||
|
ksu_handle_faccessat(dfd, filename_user, mode, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_trace_sys_read_hook_callback(void *data, unsigned int fd, char __user **buf_ptr,
|
||||||
|
size_t *count_ptr)
|
||||||
|
{
|
||||||
|
if (unlikely(ksu_vfs_read_hook))
|
||||||
|
ksu_handle_sys_read(fd, buf_ptr, count_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_trace_stat_hook_callback(void *data, int *dfd, const char __user **filename_user,
|
||||||
|
int *flags)
|
||||||
|
{
|
||||||
|
ksu_handle_stat(dfd, filename_user, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_trace_input_hook_callback(void *data, unsigned int *type, unsigned int *code,
|
||||||
|
int *value)
|
||||||
|
{
|
||||||
|
if (unlikely(ksu_input_hook))
|
||||||
|
ksu_handle_input_handle_event(type, code, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ksu_trace_devpts_hook_callback(void *data, struct inode *inode)
|
||||||
|
{
|
||||||
|
ksu_handle_devpts(inode);
|
||||||
|
}
|
||||||
|
// end tracepoint callback functions
|
||||||
|
|
||||||
|
|
||||||
|
// register tracepoint callback functions
|
||||||
|
void ksu_trace_register(void)
|
||||||
|
{
|
||||||
|
register_trace_ksu_trace_execveat_hook(ksu_trace_execveat_hook_callback, NULL);
|
||||||
|
register_trace_ksu_trace_execveat_sucompat_hook(ksu_trace_execveat_sucompat_hook_callback, NULL);
|
||||||
|
register_trace_ksu_trace_faccessat_hook(ksu_trace_faccessat_hook_callback, NULL);
|
||||||
|
register_trace_ksu_trace_sys_read_hook(ksu_trace_sys_read_hook_callback, NULL);
|
||||||
|
register_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback, NULL);
|
||||||
|
register_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback, NULL);
|
||||||
|
register_trace_ksu_trace_devpts_hook(ksu_trace_devpts_hook_callback, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unregister tracepoint callback functions
|
||||||
|
void ksu_trace_unregister(void)
|
||||||
|
{
|
||||||
|
unregister_trace_ksu_trace_execveat_hook(ksu_trace_execveat_hook_callback, NULL);
|
||||||
|
unregister_trace_ksu_trace_execveat_sucompat_hook(ksu_trace_execveat_sucompat_hook_callback, NULL);
|
||||||
|
unregister_trace_ksu_trace_faccessat_hook(ksu_trace_faccessat_hook_callback, NULL);
|
||||||
|
unregister_trace_ksu_trace_sys_read_hook(ksu_trace_sys_read_hook_callback, NULL);
|
||||||
|
unregister_trace_ksu_trace_stat_hook(ksu_trace_stat_hook_callback, NULL);
|
||||||
|
unregister_trace_ksu_trace_input_hook(ksu_trace_input_hook_callback, NULL);
|
||||||
|
unregister_trace_ksu_trace_devpts_hook(ksu_trace_devpts_hook_callback, NULL);
|
||||||
|
}
|
||||||
45
kernel/ksu_trace.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#undef TRACE_SYSTEM
|
||||||
|
#define TRACE_SYSTEM ksu_trace
|
||||||
|
|
||||||
|
#if !defined(_KSU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||||
|
#define _KSU_TRACE_H
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/tracepoint.h>
|
||||||
|
|
||||||
|
DECLARE_TRACE(ksu_trace_execveat_hook,
|
||||||
|
TP_PROTO(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags),
|
||||||
|
TP_ARGS(fd, filename_ptr, argv, envp, flags));
|
||||||
|
|
||||||
|
DECLARE_TRACE(ksu_trace_execveat_sucompat_hook,
|
||||||
|
TP_PROTO(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags),
|
||||||
|
TP_ARGS(fd, filename_ptr, argv, envp, flags));
|
||||||
|
|
||||||
|
DECLARE_TRACE(ksu_trace_faccessat_hook,
|
||||||
|
TP_PROTO(int *dfd, const char __user **filename_user, int *mode, int *flags),
|
||||||
|
TP_ARGS(dfd, filename_user, mode, flags));
|
||||||
|
|
||||||
|
DECLARE_TRACE(ksu_trace_sys_read_hook,
|
||||||
|
TP_PROTO(unsigned int fd, char __user **buf_ptr, size_t *count_ptr),
|
||||||
|
TP_ARGS(fd, buf_ptr, count_ptr));
|
||||||
|
|
||||||
|
DECLARE_TRACE(ksu_trace_stat_hook,
|
||||||
|
TP_PROTO(int *dfd, const char __user **filename_user, int *flags),
|
||||||
|
TP_ARGS(dfd, filename_user, flags));
|
||||||
|
|
||||||
|
DECLARE_TRACE(ksu_trace_input_hook,
|
||||||
|
TP_PROTO(unsigned int *type, unsigned int *code, int *value),
|
||||||
|
TP_ARGS(type, code, value));
|
||||||
|
|
||||||
|
DECLARE_TRACE(ksu_trace_devpts_hook,
|
||||||
|
TP_PROTO(struct inode *inode),
|
||||||
|
TP_ARGS(inode));
|
||||||
|
|
||||||
|
#endif /* _KSU_TRACE_H */
|
||||||
|
|
||||||
|
#undef TRACE_INCLUDE_PATH
|
||||||
|
#define TRACE_INCLUDE_PATH .
|
||||||
|
#undef TRACE_INCLUDE_FILE
|
||||||
|
#define TRACE_INCLUDE_FILE ksu_trace
|
||||||
|
|
||||||
|
#include <trace/define_trace.h>
|
||||||
10
kernel/ksu_trace_export.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#define CREATE_TRACE_POINTS
|
||||||
|
#include "ksu_trace.h"
|
||||||
|
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_execveat_hook);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_execveat_sucompat_hook);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_faccessat_hook);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_sys_read_hook);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_stat_hook);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_input_hook);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL_GPL(ksu_trace_devpts_hook);
|
||||||
829
kernel/ksud.c
@@ -3,19 +3,9 @@
|
|||||||
|
|
||||||
#define KSUD_PATH "/data/adb/ksud"
|
#define KSUD_PATH "/data/adb/ksud"
|
||||||
|
|
||||||
void ksu_ksud_init();
|
|
||||||
void ksu_ksud_exit();
|
|
||||||
|
|
||||||
void on_post_fs_data(void);
|
void on_post_fs_data(void);
|
||||||
void on_module_mounted(void);
|
|
||||||
void on_boot_completed(void);
|
|
||||||
|
|
||||||
bool ksu_is_safe_mode(void);
|
bool ksu_is_safe_mode(void);
|
||||||
|
|
||||||
int nuke_ext4_sysfs(const char* mnt);
|
extern u32 ksu_devpts_sid;
|
||||||
|
|
||||||
extern u32 ksu_file_sid;
|
|
||||||
extern bool ksu_module_mounted;
|
|
||||||
extern bool ksu_boot_completed;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,31 +13,29 @@ extern void ksu_add_manager(uid_t uid, int signature_index);
|
|||||||
extern void ksu_remove_manager(uid_t uid);
|
extern void ksu_remove_manager(uid_t uid);
|
||||||
extern int ksu_get_manager_signature_index(uid_t uid);
|
extern int ksu_get_manager_signature_index(uid_t uid);
|
||||||
|
|
||||||
static inline bool ksu_is_manager_uid_valid(void)
|
static inline bool ksu_is_manager_uid_valid()
|
||||||
{
|
{
|
||||||
return ksu_manager_uid != KSU_INVALID_UID;
|
return ksu_manager_uid != KSU_INVALID_UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool is_manager(void)
|
static inline bool is_manager()
|
||||||
{
|
{
|
||||||
return unlikely(ksu_is_any_manager(current_uid().val) ||
|
return unlikely(ksu_is_any_manager(current_uid().val) || ksu_manager_uid == current_uid().val);
|
||||||
(ksu_manager_uid != KSU_INVALID_UID && ksu_manager_uid == current_uid().val));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uid_t ksu_get_manager_uid(void)
|
static inline uid_t ksu_get_manager_uid()
|
||||||
{
|
{
|
||||||
return ksu_manager_uid;
|
return ksu_manager_uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ksu_set_manager_uid(uid_t uid)
|
static inline void ksu_set_manager_uid(uid_t uid)
|
||||||
{
|
{
|
||||||
ksu_manager_uid = uid;
|
ksu_manager_uid = uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ksu_invalidate_manager_uid(void)
|
static inline void ksu_invalidate_manager_uid()
|
||||||
{
|
{
|
||||||
ksu_manager_uid = KSU_INVALID_UID;
|
ksu_manager_uid = KSU_INVALID_UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_observer_init(void);
|
#endif
|
||||||
#endif
|
|
||||||
@@ -9,9 +9,5 @@
|
|||||||
#define EXPECTED_SIZE_OTHER 0x300
|
#define EXPECTED_SIZE_OTHER 0x300
|
||||||
#define EXPECTED_HASH_OTHER "0000000000000000000000000000000000000000000000000000000000000000"
|
#define EXPECTED_HASH_OTHER "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned size;
|
|
||||||
const char *sha256;
|
|
||||||
} apk_sign_key_t;
|
|
||||||
|
|
||||||
#endif /* MANAGER_SIGN_H */
|
#endif /* MANAGER_SIGN_H */
|
||||||
@@ -1,357 +0,0 @@
|
|||||||
#include <linux/string.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#include <linux/cred.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/binfmts.h>
|
|
||||||
|
|
||||||
#include "manual_su.h"
|
|
||||||
#include "ksu.h"
|
|
||||||
#include "allowlist.h"
|
|
||||||
#include "manager.h"
|
|
||||||
#include "app_profile.h"
|
|
||||||
|
|
||||||
static bool current_verified = false;
|
|
||||||
static void ksu_cleanup_expired_tokens(void);
|
|
||||||
static bool is_current_verified(void);
|
|
||||||
static void add_pending_root(uid_t uid);
|
|
||||||
|
|
||||||
static struct pending_uid pending_uids[MAX_PENDING] = {0};
|
|
||||||
static int pending_cnt = 0;
|
|
||||||
static struct ksu_token_entry auth_tokens[MAX_TOKENS] = {0};
|
|
||||||
static int token_count = 0;
|
|
||||||
static DEFINE_SPINLOCK(token_lock);
|
|
||||||
|
|
||||||
static char* get_token_from_envp(void)
|
|
||||||
{
|
|
||||||
struct mm_struct *mm;
|
|
||||||
char *envp_start, *envp_end;
|
|
||||||
char *env_ptr, *token = NULL;
|
|
||||||
unsigned long env_len;
|
|
||||||
char *env_copy = NULL;
|
|
||||||
|
|
||||||
if (!current->mm)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mm = current->mm;
|
|
||||||
|
|
||||||
down_read(&mm->mmap_lock);
|
|
||||||
|
|
||||||
envp_start = (char *)mm->env_start;
|
|
||||||
envp_end = (char *)mm->env_end;
|
|
||||||
env_len = envp_end - envp_start;
|
|
||||||
|
|
||||||
if (env_len <= 0 || env_len > PAGE_SIZE * 32) {
|
|
||||||
up_read(&mm->mmap_lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
env_copy = kzalloc(env_len + 1, GFP_KERNEL);
|
|
||||||
if (!env_copy) {
|
|
||||||
up_read(&mm->mmap_lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_from_user(env_copy, envp_start, env_len)) {
|
|
||||||
kfree(env_copy);
|
|
||||||
up_read(&mm->mmap_lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
up_read(&mm->mmap_lock);
|
|
||||||
|
|
||||||
env_copy[env_len] = '\0';
|
|
||||||
env_ptr = env_copy;
|
|
||||||
|
|
||||||
while (env_ptr < env_copy + env_len) {
|
|
||||||
if (strncmp(env_ptr, KSU_TOKEN_ENV_NAME "=", strlen(KSU_TOKEN_ENV_NAME) + 1) == 0) {
|
|
||||||
char *token_start = env_ptr + strlen(KSU_TOKEN_ENV_NAME) + 1;
|
|
||||||
char *token_end = strchr(token_start, '\0');
|
|
||||||
|
|
||||||
if (token_end && (token_end - token_start) == KSU_TOKEN_LENGTH) {
|
|
||||||
token = kzalloc(KSU_TOKEN_LENGTH + 1, GFP_KERNEL);
|
|
||||||
if (token) {
|
|
||||||
memcpy(token, token_start, KSU_TOKEN_LENGTH);
|
|
||||||
token[KSU_TOKEN_LENGTH] = '\0';
|
|
||||||
pr_info("manual_su: found auth token in environment\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
env_ptr += strlen(env_ptr) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(env_copy);
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* ksu_generate_auth_token(void)
|
|
||||||
{
|
|
||||||
static char token_buffer[KSU_TOKEN_LENGTH + 1];
|
|
||||||
unsigned long flags;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ksu_cleanup_expired_tokens();
|
|
||||||
|
|
||||||
spin_lock_irqsave(&token_lock, flags);
|
|
||||||
|
|
||||||
if (token_count >= MAX_TOKENS) {
|
|
||||||
for (i = 0; i < MAX_TOKENS - 1; i++) {
|
|
||||||
auth_tokens[i] = auth_tokens[i + 1];
|
|
||||||
}
|
|
||||||
token_count = MAX_TOKENS - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < KSU_TOKEN_LENGTH; i++) {
|
|
||||||
u8 rand_byte;
|
|
||||||
get_random_bytes(&rand_byte, 1);
|
|
||||||
int char_type = rand_byte % 3;
|
|
||||||
if (char_type == 0) {
|
|
||||||
token_buffer[i] = 'A' + (rand_byte % 26);
|
|
||||||
} else if (char_type == 1) {
|
|
||||||
token_buffer[i] = 'a' + (rand_byte % 26);
|
|
||||||
} else {
|
|
||||||
token_buffer[i] = '0' + (rand_byte % 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
|
||||||
strscpy(auth_tokens[token_count].token, token_buffer, KSU_TOKEN_LENGTH + 1);
|
|
||||||
#else
|
|
||||||
strlcpy(auth_tokens[token_count].token, token_buffer, KSU_TOKEN_LENGTH + 1);
|
|
||||||
#endif
|
|
||||||
auth_tokens[token_count].expire_time = jiffies + KSU_TOKEN_EXPIRE_TIME * HZ;
|
|
||||||
auth_tokens[token_count].used = false;
|
|
||||||
token_count++;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&token_lock, flags);
|
|
||||||
|
|
||||||
pr_info("manual_su: generated new auth token (expires in %d seconds)\n", KSU_TOKEN_EXPIRE_TIME);
|
|
||||||
return token_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ksu_verify_auth_token(const char *token)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
bool valid = false;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!token || strlen(token) != KSU_TOKEN_LENGTH) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&token_lock, flags);
|
|
||||||
|
|
||||||
for (i = 0; i < token_count; i++) {
|
|
||||||
if (!auth_tokens[i].used &&
|
|
||||||
time_before(jiffies, auth_tokens[i].expire_time) &&
|
|
||||||
strcmp(auth_tokens[i].token, token) == 0) {
|
|
||||||
|
|
||||||
auth_tokens[i].used = true;
|
|
||||||
valid = true;
|
|
||||||
pr_info("manual_su: auth token verified successfully\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&token_lock, flags);
|
|
||||||
|
|
||||||
if (!valid) {
|
|
||||||
pr_warn("manual_su: invalid or expired auth token\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ksu_cleanup_expired_tokens(void)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&token_lock, flags);
|
|
||||||
|
|
||||||
for (i = 0; i < token_count; ) {
|
|
||||||
if (time_after(jiffies, auth_tokens[i].expire_time) || auth_tokens[i].used) {
|
|
||||||
for (j = i; j < token_count - 1; j++) {
|
|
||||||
auth_tokens[j] = auth_tokens[j + 1];
|
|
||||||
}
|
|
||||||
token_count--;
|
|
||||||
pr_debug("manual_su: cleaned up expired/used token\n");
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&token_lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_token_generation(struct manual_su_request *request)
|
|
||||||
{
|
|
||||||
if (current_uid().val > 2000) {
|
|
||||||
pr_warn("manual_su: token generation denied for app UID %d\n", current_uid().val);
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *new_token = ksu_generate_auth_token();
|
|
||||||
if (!new_token) {
|
|
||||||
pr_err("manual_su: failed to generate token\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
|
||||||
strscpy(request->token_buffer, new_token, KSU_TOKEN_LENGTH + 1);
|
|
||||||
#else
|
|
||||||
strlcpy(request->token_buffer, new_token, KSU_TOKEN_LENGTH + 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pr_info("manual_su: auth token generated successfully\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_escalation_request(struct manual_su_request *request)
|
|
||||||
{
|
|
||||||
uid_t target_uid = request->target_uid;
|
|
||||||
pid_t target_pid = request->target_pid;
|
|
||||||
struct task_struct *tsk;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
tsk = pid_task(find_vpid(target_pid), PIDTYPE_PID);
|
|
||||||
if (!tsk || ksu_task_is_dead(tsk)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
pr_err("cmd_su: PID %d is invalid or dead\n", target_pid);
|
|
||||||
return -ESRCH;
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (current_uid().val == 0 || is_manager() || ksu_is_allow_uid_for_current(current_uid().val))
|
|
||||||
goto allowed;
|
|
||||||
|
|
||||||
char *env_token = get_token_from_envp();
|
|
||||||
if (!env_token) {
|
|
||||||
pr_warn("manual_su: no auth token found in environment\n");
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool token_valid = ksu_verify_auth_token(env_token);
|
|
||||||
kfree(env_token);
|
|
||||||
|
|
||||||
if (!token_valid) {
|
|
||||||
pr_warn("manual_su: token verification failed\n");
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
allowed:
|
|
||||||
current_verified = true;
|
|
||||||
escape_to_root_for_cmd_su(target_uid, target_pid);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_add_pending_request(struct manual_su_request *request)
|
|
||||||
{
|
|
||||||
uid_t target_uid = request->target_uid;
|
|
||||||
|
|
||||||
if (!is_current_verified()) {
|
|
||||||
pr_warn("manual_su: add_pending denied, not verified\n");
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_pending_root(target_uid);
|
|
||||||
current_verified = false;
|
|
||||||
pr_info("manual_su: pending root added for UID %d\n", target_uid);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ksu_handle_manual_su_request(int option, struct manual_su_request *request)
|
|
||||||
{
|
|
||||||
if (!request) {
|
|
||||||
pr_err("manual_su: invalid request pointer\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (option) {
|
|
||||||
case MANUAL_SU_OP_GENERATE_TOKEN:
|
|
||||||
pr_info("manual_su: handling token generation request\n");
|
|
||||||
return handle_token_generation(request);
|
|
||||||
|
|
||||||
case MANUAL_SU_OP_ESCALATE:
|
|
||||||
pr_info("manual_su: handling escalation request for UID %d, PID %d\n",
|
|
||||||
request->target_uid, request->target_pid);
|
|
||||||
return handle_escalation_request(request);
|
|
||||||
|
|
||||||
case MANUAL_SU_OP_ADD_PENDING:
|
|
||||||
pr_info("manual_su: handling add pending request for UID %d\n", request->target_uid);
|
|
||||||
return handle_add_pending_request(request);
|
|
||||||
|
|
||||||
default:
|
|
||||||
pr_err("manual_su: unknown option %d\n", option);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_current_verified(void)
|
|
||||||
{
|
|
||||||
return current_verified;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_pending_root(uid_t uid)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < pending_cnt; i++) {
|
|
||||||
if (pending_uids[i].uid == uid) {
|
|
||||||
pending_uids[i].use_count++;
|
|
||||||
pending_uids[i].remove_calls++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_pending_root(uid_t uid)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < pending_cnt; i++) {
|
|
||||||
if (pending_uids[i].uid == uid) {
|
|
||||||
pending_uids[i].remove_calls++;
|
|
||||||
|
|
||||||
if (pending_uids[i].remove_calls >= REMOVE_DELAY_CALLS) {
|
|
||||||
pending_uids[i] = pending_uids[--pending_cnt];
|
|
||||||
pr_info("pending_root: removed UID %d after %d calls\n", uid, REMOVE_DELAY_CALLS);
|
|
||||||
ksu_temp_revoke_root_once(uid);
|
|
||||||
} else {
|
|
||||||
pr_info("pending_root: UID %d remove_call=%d (<%d)\n",
|
|
||||||
uid, pending_uids[i].remove_calls, REMOVE_DELAY_CALLS);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_pending_root(uid_t uid)
|
|
||||||
{
|
|
||||||
if (pending_cnt >= MAX_PENDING) {
|
|
||||||
pr_warn("pending_root: cache full\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < pending_cnt; i++) {
|
|
||||||
if (pending_uids[i].uid == uid) {
|
|
||||||
pending_uids[i].use_count = 0;
|
|
||||||
pending_uids[i].remove_calls = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pending_uids[pending_cnt++] = (struct pending_uid){uid, 0};
|
|
||||||
ksu_temp_grant_root_once(uid);
|
|
||||||
pr_info("pending_root: cached UID %d\n", uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_try_escalate_for_uid(uid_t uid)
|
|
||||||
{
|
|
||||||
if (!is_pending_root(uid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
pr_info("pending_root: UID=%d temporarily allowed\n", uid);
|
|
||||||
remove_pending_root(uid);
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#ifndef __KSU_MANUAL_SU_H
|
|
||||||
#define __KSU_MANUAL_SU_H
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)
|
|
||||||
#define mmap_lock mmap_sem
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ksu_task_is_dead(t) ((t)->exit_state != 0)
|
|
||||||
|
|
||||||
#define MAX_PENDING 16
|
|
||||||
#define REMOVE_DELAY_CALLS 150
|
|
||||||
#define MAX_TOKENS 10
|
|
||||||
|
|
||||||
#define KSU_SU_VERIFIED_BIT (1UL << 0)
|
|
||||||
#define KSU_TOKEN_LENGTH 32
|
|
||||||
#define KSU_TOKEN_ENV_NAME "KSU_AUTH_TOKEN"
|
|
||||||
#define KSU_TOKEN_EXPIRE_TIME 150
|
|
||||||
|
|
||||||
#define MANUAL_SU_OP_GENERATE_TOKEN 0
|
|
||||||
#define MANUAL_SU_OP_ESCALATE 1
|
|
||||||
#define MANUAL_SU_OP_ADD_PENDING 2
|
|
||||||
|
|
||||||
struct pending_uid {
|
|
||||||
uid_t uid;
|
|
||||||
int use_count;
|
|
||||||
int remove_calls;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct manual_su_request {
|
|
||||||
uid_t target_uid;
|
|
||||||
pid_t target_pid;
|
|
||||||
char token_buffer[KSU_TOKEN_LENGTH + 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_token_entry {
|
|
||||||
char token[KSU_TOKEN_LENGTH + 1];
|
|
||||||
unsigned long expire_time;
|
|
||||||
bool used;
|
|
||||||
};
|
|
||||||
|
|
||||||
int ksu_handle_manual_su_request(int option, struct manual_su_request *request);
|
|
||||||
bool is_pending_root(uid_t uid);
|
|
||||||
void remove_pending_root(uid_t uid);
|
|
||||||
void ksu_try_escalate_for_uid(uid_t uid);
|
|
||||||
#endif
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
#include <linux/fsnotify_backend.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/rculist.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
#include "ksu.h"
|
|
||||||
#include "throne_tracker.h"
|
|
||||||
#include "throne_comm.h"
|
|
||||||
|
|
||||||
#define MASK_SYSTEM (FS_CREATE | FS_MOVE | FS_EVENT_ON_CHILD)
|
|
||||||
|
|
||||||
struct watch_dir {
|
|
||||||
const char *path;
|
|
||||||
u32 mask;
|
|
||||||
struct path kpath;
|
|
||||||
struct inode *inode;
|
|
||||||
struct fsnotify_mark *mark;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct fsnotify_group *g;
|
|
||||||
|
|
||||||
static int ksu_handle_inode_event(struct fsnotify_mark *mark, u32 mask,
|
|
||||||
struct inode *inode, struct inode *dir,
|
|
||||||
const struct qstr *file_name, u32 cookie)
|
|
||||||
{
|
|
||||||
if (!file_name)
|
|
||||||
return 0;
|
|
||||||
if (mask & FS_ISDIR)
|
|
||||||
return 0;
|
|
||||||
if (file_name->len == 13 &&
|
|
||||||
!memcmp(file_name->name, "packages.list", 13)) {
|
|
||||||
pr_info("packages.list detected: %d\n", mask);
|
|
||||||
if (ksu_uid_scanner_enabled) {
|
|
||||||
ksu_request_userspace_scan();
|
|
||||||
}
|
|
||||||
track_throne(false);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct fsnotify_ops ksu_ops = {
|
|
||||||
.handle_inode_event = ksu_handle_inode_event,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int add_mark_on_inode(struct inode *inode, u32 mask,
|
|
||||||
struct fsnotify_mark **out)
|
|
||||||
{
|
|
||||||
struct fsnotify_mark *m;
|
|
||||||
|
|
||||||
m = kzalloc(sizeof(*m), GFP_KERNEL);
|
|
||||||
if (!m)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
fsnotify_init_mark(m, g);
|
|
||||||
m->mask = mask;
|
|
||||||
|
|
||||||
if (fsnotify_add_inode_mark(m, inode, 0)) {
|
|
||||||
fsnotify_put_mark(m);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
*out = m;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int watch_one_dir(struct watch_dir *wd)
|
|
||||||
{
|
|
||||||
int ret = kern_path(wd->path, LOOKUP_FOLLOW, &wd->kpath);
|
|
||||||
if (ret) {
|
|
||||||
pr_info("path not ready: %s (%d)\n", wd->path, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
wd->inode = d_inode(wd->kpath.dentry);
|
|
||||||
ihold(wd->inode);
|
|
||||||
|
|
||||||
ret = add_mark_on_inode(wd->inode, wd->mask, &wd->mark);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("Add mark failed for %s (%d)\n", wd->path, ret);
|
|
||||||
path_put(&wd->kpath);
|
|
||||||
iput(wd->inode);
|
|
||||||
wd->inode = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
pr_info("watching %s\n", wd->path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unwatch_one_dir(struct watch_dir *wd)
|
|
||||||
{
|
|
||||||
if (wd->mark) {
|
|
||||||
fsnotify_destroy_mark(wd->mark, g);
|
|
||||||
fsnotify_put_mark(wd->mark);
|
|
||||||
wd->mark = NULL;
|
|
||||||
}
|
|
||||||
if (wd->inode) {
|
|
||||||
iput(wd->inode);
|
|
||||||
wd->inode = NULL;
|
|
||||||
}
|
|
||||||
if (wd->kpath.dentry) {
|
|
||||||
path_put(&wd->kpath);
|
|
||||||
memset(&wd->kpath, 0, sizeof(wd->kpath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct watch_dir g_watch = { .path = "/data/system",
|
|
||||||
.mask = MASK_SYSTEM };
|
|
||||||
|
|
||||||
int ksu_observer_init(void)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
|
|
||||||
g = fsnotify_alloc_group(&ksu_ops, 0);
|
|
||||||
#else
|
|
||||||
g = fsnotify_alloc_group(&ksu_ops);
|
|
||||||
#endif
|
|
||||||
if (IS_ERR(g))
|
|
||||||
return PTR_ERR(g);
|
|
||||||
|
|
||||||
ret = watch_one_dir(&g_watch);
|
|
||||||
pr_info("observer init done\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_observer_exit(void)
|
|
||||||
{
|
|
||||||
unwatch_one_dir(&g_watch);
|
|
||||||
fsnotify_put_group(g);
|
|
||||||
pr_info("observer exit done\n");
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include <linux/version.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/nsproxy.h>
|
|
||||||
#include <linux/sched/task.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/filter.h>
|
|
||||||
#include <linux/seccomp.h>
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
#include "seccomp_cache.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 2) // Android backport this feature in 5.10.2
|
|
||||||
struct action_cache {
|
|
||||||
DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR);
|
|
||||||
#ifdef SECCOMP_ARCH_COMPAT
|
|
||||||
DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct seccomp_filter {
|
|
||||||
refcount_t refs;
|
|
||||||
refcount_t users;
|
|
||||||
bool log;
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
|
||||||
bool wait_killable_recv;
|
|
||||||
#endif
|
|
||||||
struct action_cache cache;
|
|
||||||
struct seccomp_filter *prev;
|
|
||||||
struct bpf_prog *prog;
|
|
||||||
struct notification *notif;
|
|
||||||
struct mutex notify_lock;
|
|
||||||
wait_queue_head_t wqh;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr)
|
|
||||||
{
|
|
||||||
if (!filter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
|
|
||||||
clear_bit(nr, filter->cache.allow_native);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SECCOMP_ARCH_COMPAT
|
|
||||||
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
|
||||||
clear_bit(nr, filter->cache.allow_compat);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr)
|
|
||||||
{
|
|
||||||
if (!filter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
|
|
||||||
set_bit(nr, filter->cache.allow_native);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SECCOMP_ARCH_COMPAT
|
|
||||||
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
|
||||||
set_bit(nr, filter->cache.allow_compat);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef __KSU_H_SECCOMP_CACHE
|
|
||||||
#define __KSU_H_SECCOMP_CACHE
|
|
||||||
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 2) // Android backport this feature in 5.10.2
|
|
||||||
extern void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr);
|
|
||||||
extern void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -2,7 +2,15 @@ obj-y += selinux.o
|
|||||||
obj-y += sepolicy.o
|
obj-y += sepolicy.o
|
||||||
obj-y += rules.o
|
obj-y += rules.o
|
||||||
|
|
||||||
ccflags-y += -Wno-strict-prototypes -Wno-int-conversion
|
ifeq ($(shell grep -q " current_sid(void)" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||||
|
ccflags-y += -DKSU_COMPAT_HAS_CURRENT_SID
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(shell grep -q "struct selinux_state " $(srctree)/security/selinux/include/security.h; echo $$?),0)
|
||||||
|
ccflags-y += -DKSU_COMPAT_HAS_SELINUX_STATE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion
|
||||||
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
||||||
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
||||||
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
|
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "selinux.h"
|
#include "selinux.h"
|
||||||
#include "sepolicy.h"
|
#include "sepolicy.h"
|
||||||
#include "ss/services.h"
|
#include "ss/services.h"
|
||||||
#include "linux/lsm_audit.h" // IWYU pragma: keep
|
#include "linux/lsm_audit.h"
|
||||||
#include "xfrm.h"
|
#include "xfrm.h"
|
||||||
|
|
||||||
#define SELINUX_POLICY_INSTEAD_SELINUX_SS
|
#define SELINUX_POLICY_INSTEAD_SELINUX_SS
|
||||||
@@ -18,119 +18,119 @@
|
|||||||
|
|
||||||
static struct policydb *get_policydb(void)
|
static struct policydb *get_policydb(void)
|
||||||
{
|
{
|
||||||
struct policydb *db;
|
struct policydb *db;
|
||||||
struct selinux_policy *policy = selinux_state.policy;
|
struct selinux_policy *policy = selinux_state.policy;
|
||||||
db = &policy->policydb;
|
db = &policy->policydb;
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFINE_MUTEX(ksu_rules);
|
static DEFINE_MUTEX(ksu_rules);
|
||||||
|
|
||||||
void apply_kernelsu_rules()
|
void apply_kernelsu_rules()
|
||||||
{
|
{
|
||||||
struct policydb *db;
|
struct policydb *db;
|
||||||
|
|
||||||
if (!getenforce()) {
|
if (!getenforce()) {
|
||||||
pr_info("SELinux permissive or disabled, apply rules!\n");
|
pr_info("SELinux permissive or disabled, apply rules!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&ksu_rules);
|
mutex_lock(&ksu_rules);
|
||||||
|
|
||||||
db = get_policydb();
|
db = get_policydb();
|
||||||
|
|
||||||
ksu_permissive(db, KERNEL_SU_DOMAIN);
|
ksu_permissive(db, KERNEL_SU_DOMAIN);
|
||||||
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
|
||||||
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain");
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "netdomain");
|
||||||
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain");
|
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "bluetoothdomain");
|
||||||
|
|
||||||
// Create unconstrained file type
|
// Create unconstrained file type
|
||||||
ksu_type(db, KERNEL_SU_FILE, "file_type");
|
ksu_type(db, KERNEL_SU_FILE, "file_type");
|
||||||
ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject");
|
ksu_typeattribute(db, KERNEL_SU_FILE, "mlstrustedobject");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL);
|
ksu_allow(db, ALL, KERNEL_SU_FILE, ALL, ALL);
|
||||||
|
|
||||||
// allow all!
|
// allow all!
|
||||||
ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL);
|
ksu_allow(db, KERNEL_SU_DOMAIN, ALL, ALL, ALL);
|
||||||
|
|
||||||
// allow us do any ioctl
|
// allow us do any ioctl
|
||||||
if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) {
|
if (db->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL) {
|
||||||
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL);
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "blk_file", ALL);
|
||||||
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL);
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "fifo_file", ALL);
|
||||||
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL);
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL);
|
||||||
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL);
|
ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "file", ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need to save allowlist in /data/adb/ksu
|
// we need to save allowlist in /data/adb/ksu
|
||||||
ksu_allow(db, "kernel", "adb_data_file", "dir", ALL);
|
ksu_allow(db, "kernel", "adb_data_file", "dir", ALL);
|
||||||
ksu_allow(db, "kernel", "adb_data_file", "file", ALL);
|
ksu_allow(db, "kernel", "adb_data_file", "file", ALL);
|
||||||
// we need to search /data/app
|
// we need to search /data/app
|
||||||
ksu_allow(db, "kernel", "apk_data_file", "file", "open");
|
ksu_allow(db, "kernel", "apk_data_file", "file", "open");
|
||||||
ksu_allow(db, "kernel", "apk_data_file", "dir", "open");
|
ksu_allow(db, "kernel", "apk_data_file", "dir", "open");
|
||||||
ksu_allow(db, "kernel", "apk_data_file", "dir", "read");
|
ksu_allow(db, "kernel", "apk_data_file", "dir", "read");
|
||||||
ksu_allow(db, "kernel", "apk_data_file", "dir", "search");
|
ksu_allow(db, "kernel", "apk_data_file", "dir", "search");
|
||||||
// we may need to do mount on shell
|
// we may need to do mount on shell
|
||||||
ksu_allow(db, "kernel", "shell_data_file", "file", ALL);
|
ksu_allow(db, "kernel", "shell_data_file", "file", ALL);
|
||||||
// we need to read /data/system/packages.list
|
// we need to read /data/system/packages.list
|
||||||
ksu_allow(db, "kernel", "kernel", "capability", "dac_override");
|
ksu_allow(db, "kernel", "kernel", "capability", "dac_override");
|
||||||
// Android 10+:
|
// Android 10+:
|
||||||
// http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512
|
// http://aospxref.com/android-12.0.0_r3/xref/system/sepolicy/private/file_contexts#512
|
||||||
ksu_allow(db, "kernel", "packages_list_file", "file", ALL);
|
ksu_allow(db, "kernel", "packages_list_file", "file", ALL);
|
||||||
// Kernel 4.4
|
// Kernel 4.4
|
||||||
ksu_allow(db, "kernel", "packages_list_file", "dir", ALL);
|
ksu_allow(db, "kernel", "packages_list_file", "dir", ALL);
|
||||||
// Android 9-:
|
// Android 9-:
|
||||||
// http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360
|
// http://aospxref.com/android-9.0.0_r61/xref/system/sepolicy/private/file_contexts#360
|
||||||
ksu_allow(db, "kernel", "system_data_file", "file", ALL);
|
ksu_allow(db, "kernel", "system_data_file", "file", ALL);
|
||||||
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
|
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
|
||||||
// our ksud triggered by init
|
// our ksud triggered by init
|
||||||
ksu_allow(db, "init", "adb_data_file", "file", ALL);
|
ksu_allow(db, "init", "adb_data_file", "file", ALL);
|
||||||
ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289
|
ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289
|
||||||
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);
|
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);
|
||||||
// we need to umount modules in zygote
|
// we need to umount modules in zygote
|
||||||
ksu_allow(db, "zygote", "adb_data_file", "dir", "search");
|
ksu_allow(db, "zygote", "adb_data_file", "dir", "search");
|
||||||
|
|
||||||
// copied from Magisk rules
|
// copied from Magisk rules
|
||||||
// suRights
|
// suRights
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read");
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "dir", "read");
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr");
|
ksu_allow(db, "servicemanager", KERNEL_SU_DOMAIN, "process", "getattr");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "process", "sigchld");
|
||||||
|
|
||||||
// allowLog
|
// allowLog
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search");
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read");
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open");
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr");
|
ksu_allow(db, "logd", KERNEL_SU_DOMAIN, "file", "getattr");
|
||||||
|
|
||||||
// dumpsys
|
// dumpsys
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fd", "use");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "write");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "read");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "open");
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr");
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "fifo_file", "getattr");
|
||||||
|
|
||||||
// bootctl
|
// bootctl
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "dir", "search");
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "read");
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "file", "open");
|
||||||
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process",
|
ksu_allow(db, "hwservicemanager", KERNEL_SU_DOMAIN, "process",
|
||||||
"getattr");
|
"getattr");
|
||||||
|
|
||||||
// For mounting loop devices, mirrors, tmpfs
|
// For mounting loop devices, mirrors, tmpfs
|
||||||
ksu_allow(db, "kernel", ALL, "file", "read");
|
ksu_allow(db, "kernel", ALL, "file", "read");
|
||||||
ksu_allow(db, "kernel", ALL, "file", "write");
|
ksu_allow(db, "kernel", ALL, "file", "write");
|
||||||
|
|
||||||
// Allow all binder transactions
|
// Allow all binder transactions
|
||||||
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
|
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
|
||||||
|
|
||||||
// Allow system server kill su process
|
// Allow system server kill su process
|
||||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
|
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
|
||||||
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
|
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
|
||||||
|
|
||||||
// https://android-review.googlesource.com/c/platform/system/logging/+/3725346
|
// https://android-review.googlesource.com/c/platform/system/logging/+/3725346
|
||||||
ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr");
|
ksu_dontaudit(db, "untrusted_app", KERNEL_SU_DOMAIN, "dir", "getattr");
|
||||||
|
|
||||||
mutex_unlock(&ksu_rules);
|
mutex_unlock(&ksu_rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_SEPOL_LEN 128
|
#define MAX_SEPOL_LEN 128
|
||||||
@@ -145,333 +145,401 @@ void apply_kernelsu_rules()
|
|||||||
#define CMD_TYPE_CHANGE 8
|
#define CMD_TYPE_CHANGE 8
|
||||||
#define CMD_GENFSCON 9
|
#define CMD_GENFSCON 9
|
||||||
|
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
struct sepol_data {
|
struct sepol_data {
|
||||||
u32 cmd;
|
u32 cmd;
|
||||||
u32 subcmd;
|
u32 subcmd;
|
||||||
char __user *sepol1;
|
u64 field_sepol1;
|
||||||
char __user *sepol2;
|
u64 field_sepol2;
|
||||||
char __user *sepol3;
|
u64 field_sepol3;
|
||||||
char __user *sepol4;
|
u64 field_sepol4;
|
||||||
char __user *sepol5;
|
u64 field_sepol5;
|
||||||
char __user *sepol6;
|
u64 field_sepol6;
|
||||||
char __user *sepol7;
|
u64 field_sepol7;
|
||||||
};
|
};
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
extern bool ksu_is_compat __read_mostly;
|
||||||
|
struct sepol_compat_data {
|
||||||
|
u32 cmd;
|
||||||
|
u32 subcmd;
|
||||||
|
u32 field_sepol1;
|
||||||
|
u32 field_sepol2;
|
||||||
|
u32 field_sepol3;
|
||||||
|
u32 field_sepol4;
|
||||||
|
u32 field_sepol5;
|
||||||
|
u32 field_sepol6;
|
||||||
|
u32 field_sepol7;
|
||||||
|
};
|
||||||
|
#endif // CONFIG_COMPAT
|
||||||
|
#else
|
||||||
|
struct sepol_data {
|
||||||
|
u32 cmd;
|
||||||
|
u32 subcmd;
|
||||||
|
u32 field_sepol1;
|
||||||
|
u32 field_sepol2;
|
||||||
|
u32 field_sepol3;
|
||||||
|
u32 field_sepol4;
|
||||||
|
u32 field_sepol5;
|
||||||
|
u32 field_sepol6;
|
||||||
|
u32 field_sepol7;
|
||||||
|
};
|
||||||
|
#endif // CONFIG_64BIT
|
||||||
|
|
||||||
static int get_object(char *buf, char __user *user_object, size_t buf_sz,
|
static int get_object(char *buf, char __user *user_object, size_t buf_sz,
|
||||||
char **object)
|
char **object)
|
||||||
{
|
{
|
||||||
if (!user_object) {
|
if (!user_object) {
|
||||||
*object = ALL;
|
*object = ALL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncpy_from_user(buf, user_object, buf_sz) < 0) {
|
if (strncpy_from_user(buf, user_object, buf_sz) < 0) {
|
||||||
return -EINVAL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*object = buf;
|
*object = buf;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0))
|
|
||||||
extern int avc_ss_reset(u32 seqno);
|
|
||||||
#else
|
|
||||||
extern int avc_ss_reset(struct selinux_avc *avc, u32 seqno);
|
|
||||||
#endif
|
|
||||||
// reset avc cache table, otherwise the new rules will not take effect if already denied
|
// reset avc cache table, otherwise the new rules will not take effect if already denied
|
||||||
static void reset_avc_cache()
|
static void reset_avc_cache()
|
||||||
{
|
{
|
||||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0))
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0))
|
||||||
avc_ss_reset(0);
|
avc_ss_reset(0);
|
||||||
selnl_notify_policyload(0);
|
selnl_notify_policyload(0);
|
||||||
selinux_status_update_policyload(0);
|
selinux_status_update_policyload(0);
|
||||||
#else
|
#else
|
||||||
struct selinux_avc *avc = selinux_state.avc;
|
struct selinux_avc *avc = selinux_state.avc;
|
||||||
avc_ss_reset(avc, 0);
|
avc_ss_reset(avc, 0);
|
||||||
selnl_notify_policyload(0);
|
selnl_notify_policyload(0);
|
||||||
selinux_status_update_policyload(&selinux_state, 0);
|
selinux_status_update_policyload(&selinux_state, 0);
|
||||||
#endif
|
#endif
|
||||||
selinux_xfrm_notify_policyload();
|
selinux_xfrm_notify_policyload();
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||||
{
|
{
|
||||||
struct policydb *db;
|
struct policydb *db;
|
||||||
|
|
||||||
if (!arg4) {
|
if (!arg4) {
|
||||||
return -EINVAL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getenforce()) {
|
if (!getenforce()) {
|
||||||
pr_info("SELinux permissive or disabled when handle policy!\n");
|
pr_info("SELinux permissive or disabled when handle policy!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 cmd, subcmd;
|
||||||
|
char __user *sepol1, *sepol2, *sepol3, *sepol4, *sepol5, *sepol6, *sepol7;
|
||||||
|
|
||||||
struct sepol_data data;
|
#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT)
|
||||||
if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
|
if (unlikely(ksu_is_compat)) {
|
||||||
pr_err("sepol: copy sepol_data failed.\n");
|
struct sepol_compat_data compat_data;
|
||||||
return -EINVAL;
|
if (copy_from_user(&compat_data, arg4, sizeof(struct sepol_compat_data))) {
|
||||||
}
|
pr_err("sepol: copy sepol_data failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sepol1 = compat_ptr(compat_data.field_sepol1);
|
||||||
|
sepol2 = compat_ptr(compat_data.field_sepol2);
|
||||||
|
sepol3 = compat_ptr(compat_data.field_sepol3);
|
||||||
|
sepol4 = compat_ptr(compat_data.field_sepol4);
|
||||||
|
sepol5 = compat_ptr(compat_data.field_sepol5);
|
||||||
|
sepol6 = compat_ptr(compat_data.field_sepol6);
|
||||||
|
sepol7 = compat_ptr(compat_data.field_sepol7);
|
||||||
|
cmd = compat_data.cmd;
|
||||||
|
subcmd = compat_data.subcmd;
|
||||||
|
} else {
|
||||||
|
struct sepol_data data;
|
||||||
|
if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
|
||||||
|
pr_err("sepol: copy sepol_data failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sepol1 = data.field_sepol1;
|
||||||
|
sepol2 = data.field_sepol2;
|
||||||
|
sepol3 = data.field_sepol3;
|
||||||
|
sepol4 = data.field_sepol4;
|
||||||
|
sepol5 = data.field_sepol5;
|
||||||
|
sepol6 = data.field_sepol6;
|
||||||
|
sepol7 = data.field_sepol7;
|
||||||
|
cmd = data.cmd;
|
||||||
|
subcmd = data.subcmd;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// basically for full native, say (64BIT=y COMPAT=n) || (64BIT=n)
|
||||||
|
struct sepol_data data;
|
||||||
|
if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
|
||||||
|
pr_err("sepol: copy sepol_data failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sepol1 = data.field_sepol1;
|
||||||
|
sepol2 = data.field_sepol2;
|
||||||
|
sepol3 = data.field_sepol3;
|
||||||
|
sepol4 = data.field_sepol4;
|
||||||
|
sepol5 = data.field_sepol5;
|
||||||
|
sepol6 = data.field_sepol6;
|
||||||
|
sepol7 = data.field_sepol7;
|
||||||
|
cmd = data.cmd;
|
||||||
|
subcmd = data.subcmd;
|
||||||
|
#endif
|
||||||
|
|
||||||
u32 cmd = data.cmd;
|
mutex_lock(&ksu_rules);
|
||||||
u32 subcmd = data.subcmd;
|
|
||||||
|
|
||||||
mutex_lock(&ksu_rules);
|
db = get_policydb();
|
||||||
|
|
||||||
db = get_policydb();
|
int ret = -1;
|
||||||
|
if (cmd == CMD_NORMAL_PERM) {
|
||||||
|
char src_buf[MAX_SEPOL_LEN];
|
||||||
|
char tgt_buf[MAX_SEPOL_LEN];
|
||||||
|
char cls_buf[MAX_SEPOL_LEN];
|
||||||
|
char perm_buf[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
int ret = -EINVAL;
|
char *s, *t, *c, *p;
|
||||||
if (cmd == CMD_NORMAL_PERM) {
|
if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) {
|
||||||
char src_buf[MAX_SEPOL_LEN];
|
pr_err("sepol: copy src failed.\n");
|
||||||
char tgt_buf[MAX_SEPOL_LEN];
|
goto exit;
|
||||||
char cls_buf[MAX_SEPOL_LEN];
|
}
|
||||||
char perm_buf[MAX_SEPOL_LEN];
|
|
||||||
|
|
||||||
char *s, *t, *c, *p;
|
if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) {
|
||||||
if (get_object(src_buf, data.sepol1, sizeof(src_buf), &s) < 0) {
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
pr_err("sepol: copy src failed.\n");
|
goto exit;
|
||||||
goto exit;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (get_object(tgt_buf, data.sepol2, sizeof(tgt_buf), &t) < 0) {
|
if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) {
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
pr_err("sepol: copy cls failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_object(cls_buf, data.sepol3, sizeof(cls_buf), &c) < 0) {
|
if (get_object(perm_buf, sepol4, sizeof(perm_buf), &p) <
|
||||||
pr_err("sepol: copy cls failed.\n");
|
0) {
|
||||||
goto exit;
|
pr_err("sepol: copy perm failed.\n");
|
||||||
}
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_object(perm_buf, data.sepol4, sizeof(perm_buf), &p) <
|
bool success = false;
|
||||||
0) {
|
if (subcmd == 1) {
|
||||||
pr_err("sepol: copy perm failed.\n");
|
success = ksu_allow(db, s, t, c, p);
|
||||||
goto exit;
|
} else if (subcmd == 2) {
|
||||||
}
|
success = ksu_deny(db, s, t, c, p);
|
||||||
|
} else if (subcmd == 3) {
|
||||||
|
success = ksu_auditallow(db, s, t, c, p);
|
||||||
|
} else if (subcmd == 4) {
|
||||||
|
success = ksu_dontaudit(db, s, t, c, p);
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
|
}
|
||||||
|
ret = success ? 0 : -1;
|
||||||
|
|
||||||
bool success = false;
|
} else if (cmd == CMD_XPERM) {
|
||||||
if (subcmd == 1) {
|
char src_buf[MAX_SEPOL_LEN];
|
||||||
success = ksu_allow(db, s, t, c, p);
|
char tgt_buf[MAX_SEPOL_LEN];
|
||||||
} else if (subcmd == 2) {
|
char cls_buf[MAX_SEPOL_LEN];
|
||||||
success = ksu_deny(db, s, t, c, p);
|
|
||||||
} else if (subcmd == 3) {
|
|
||||||
success = ksu_auditallow(db, s, t, c, p);
|
|
||||||
} else if (subcmd == 4) {
|
|
||||||
success = ksu_dontaudit(db, s, t, c, p);
|
|
||||||
} else {
|
|
||||||
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
|
||||||
}
|
|
||||||
ret = success ? 0 : -EINVAL;
|
|
||||||
|
|
||||||
} else if (cmd == CMD_XPERM) {
|
char __maybe_unused
|
||||||
char src_buf[MAX_SEPOL_LEN];
|
operation[MAX_SEPOL_LEN]; // it is always ioctl now!
|
||||||
char tgt_buf[MAX_SEPOL_LEN];
|
char perm_set[MAX_SEPOL_LEN];
|
||||||
char cls_buf[MAX_SEPOL_LEN];
|
|
||||||
|
|
||||||
char __maybe_unused
|
char *s, *t, *c;
|
||||||
operation[MAX_SEPOL_LEN]; // it is always ioctl now!
|
if (get_object(src_buf, sepol1, sizeof(src_buf), &s) < 0) {
|
||||||
char perm_set[MAX_SEPOL_LEN];
|
pr_err("sepol: copy src failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (get_object(tgt_buf, sepol2, sizeof(tgt_buf), &t) < 0) {
|
||||||
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (get_object(cls_buf, sepol3, sizeof(cls_buf), &c) < 0) {
|
||||||
|
pr_err("sepol: copy cls failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(operation, sepol4,
|
||||||
|
sizeof(operation)) < 0) {
|
||||||
|
pr_err("sepol: copy operation failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(perm_set, sepol5, sizeof(perm_set)) <
|
||||||
|
0) {
|
||||||
|
pr_err("sepol: copy perm_set failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
char *s, *t, *c;
|
bool success = false;
|
||||||
if (get_object(src_buf, data.sepol1, sizeof(src_buf), &s) < 0) {
|
if (subcmd == 1) {
|
||||||
pr_err("sepol: copy src failed.\n");
|
success = ksu_allowxperm(db, s, t, c, perm_set);
|
||||||
goto exit;
|
} else if (subcmd == 2) {
|
||||||
}
|
success = ksu_auditallowxperm(db, s, t, c, perm_set);
|
||||||
if (get_object(tgt_buf, data.sepol2, sizeof(tgt_buf), &t) < 0) {
|
} else if (subcmd == 3) {
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
success = ksu_dontauditxperm(db, s, t, c, perm_set);
|
||||||
goto exit;
|
} else {
|
||||||
}
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
if (get_object(cls_buf, data.sepol3, sizeof(cls_buf), &c) < 0) {
|
}
|
||||||
pr_err("sepol: copy cls failed.\n");
|
ret = success ? 0 : -1;
|
||||||
goto exit;
|
} else if (cmd == CMD_TYPE_STATE) {
|
||||||
}
|
char src[MAX_SEPOL_LEN];
|
||||||
if (strncpy_from_user(operation, data.sepol4,
|
|
||||||
sizeof(operation)) < 0) {
|
|
||||||
pr_err("sepol: copy operation failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (strncpy_from_user(perm_set, data.sepol5, sizeof(perm_set)) <
|
|
||||||
0) {
|
|
||||||
pr_err("sepol: copy perm_set failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = false;
|
if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) {
|
||||||
if (subcmd == 1) {
|
pr_err("sepol: copy src failed.\n");
|
||||||
success = ksu_allowxperm(db, s, t, c, perm_set);
|
goto exit;
|
||||||
} else if (subcmd == 2) {
|
}
|
||||||
success = ksu_auditallowxperm(db, s, t, c, perm_set);
|
|
||||||
} else if (subcmd == 3) {
|
|
||||||
success = ksu_dontauditxperm(db, s, t, c, perm_set);
|
|
||||||
} else {
|
|
||||||
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
|
||||||
}
|
|
||||||
ret = success ? 0 : -EINVAL;
|
|
||||||
} else if (cmd == CMD_TYPE_STATE) {
|
|
||||||
char src[MAX_SEPOL_LEN];
|
|
||||||
|
|
||||||
if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) {
|
bool success = false;
|
||||||
pr_err("sepol: copy src failed.\n");
|
if (subcmd == 1) {
|
||||||
goto exit;
|
success = ksu_permissive(db, src);
|
||||||
}
|
} else if (subcmd == 2) {
|
||||||
|
success = ksu_enforce(db, src);
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
|
}
|
||||||
|
if (success)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
bool success = false;
|
} else if (cmd == CMD_TYPE || cmd == CMD_TYPE_ATTR) {
|
||||||
if (subcmd == 1) {
|
char type[MAX_SEPOL_LEN];
|
||||||
success = ksu_permissive(db, src);
|
char attr[MAX_SEPOL_LEN];
|
||||||
} else if (subcmd == 2) {
|
|
||||||
success = ksu_enforce(db, src);
|
|
||||||
} else {
|
|
||||||
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
|
||||||
}
|
|
||||||
if (success)
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
} else if (cmd == CMD_TYPE || cmd == CMD_TYPE_ATTR) {
|
if (strncpy_from_user(type, sepol1, sizeof(type)) < 0) {
|
||||||
char type[MAX_SEPOL_LEN];
|
pr_err("sepol: copy type failed.\n");
|
||||||
char attr[MAX_SEPOL_LEN];
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(attr, sepol2, sizeof(attr)) < 0) {
|
||||||
|
pr_err("sepol: copy attr failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (strncpy_from_user(type, data.sepol1, sizeof(type)) < 0) {
|
bool success = false;
|
||||||
pr_err("sepol: copy type failed.\n");
|
if (cmd == CMD_TYPE) {
|
||||||
goto exit;
|
success = ksu_type(db, type, attr);
|
||||||
}
|
} else {
|
||||||
if (strncpy_from_user(attr, data.sepol2, sizeof(attr)) < 0) {
|
success = ksu_typeattribute(db, type, attr);
|
||||||
pr_err("sepol: copy attr failed.\n");
|
}
|
||||||
goto exit;
|
if (!success) {
|
||||||
}
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
bool success = false;
|
} else if (cmd == CMD_ATTR) {
|
||||||
if (cmd == CMD_TYPE) {
|
char attr[MAX_SEPOL_LEN];
|
||||||
success = ksu_type(db, type, attr);
|
|
||||||
} else {
|
|
||||||
success = ksu_typeattribute(db, type, attr);
|
|
||||||
}
|
|
||||||
if (!success) {
|
|
||||||
pr_err("sepol: %d failed.\n", cmd);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
} else if (cmd == CMD_ATTR) {
|
if (strncpy_from_user(attr, sepol1, sizeof(attr)) < 0) {
|
||||||
char attr[MAX_SEPOL_LEN];
|
pr_err("sepol: copy attr failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (!ksu_attribute(db, attr)) {
|
||||||
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
if (strncpy_from_user(attr, data.sepol1, sizeof(attr)) < 0) {
|
} else if (cmd == CMD_TYPE_TRANSITION) {
|
||||||
pr_err("sepol: copy attr failed.\n");
|
char src[MAX_SEPOL_LEN];
|
||||||
goto exit;
|
char tgt[MAX_SEPOL_LEN];
|
||||||
}
|
char cls[MAX_SEPOL_LEN];
|
||||||
if (!ksu_attribute(db, attr)) {
|
char default_type[MAX_SEPOL_LEN];
|
||||||
pr_err("sepol: %d failed.\n", cmd);
|
char object[MAX_SEPOL_LEN];
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
} else if (cmd == CMD_TYPE_TRANSITION) {
|
if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) {
|
||||||
char src[MAX_SEPOL_LEN];
|
pr_err("sepol: copy src failed.\n");
|
||||||
char tgt[MAX_SEPOL_LEN];
|
goto exit;
|
||||||
char cls[MAX_SEPOL_LEN];
|
}
|
||||||
char default_type[MAX_SEPOL_LEN];
|
if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) {
|
||||||
char object[MAX_SEPOL_LEN];
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) {
|
||||||
|
pr_err("sepol: copy cls failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(default_type, sepol4,
|
||||||
|
sizeof(default_type)) < 0) {
|
||||||
|
pr_err("sepol: copy default_type failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
char *real_object;
|
||||||
|
if (sepol5 == NULL) {
|
||||||
|
real_object = NULL;
|
||||||
|
} else {
|
||||||
|
if (strncpy_from_user(object, sepol5,
|
||||||
|
sizeof(object)) < 0) {
|
||||||
|
pr_err("sepol: copy object failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
real_object = object;
|
||||||
|
}
|
||||||
|
|
||||||
if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) {
|
bool success = ksu_type_transition(db, src, tgt, cls,
|
||||||
pr_err("sepol: copy src failed.\n");
|
default_type, real_object);
|
||||||
goto exit;
|
if (success)
|
||||||
}
|
ret = 0;
|
||||||
if (strncpy_from_user(tgt, data.sepol2, sizeof(tgt)) < 0) {
|
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (strncpy_from_user(cls, data.sepol3, sizeof(cls)) < 0) {
|
|
||||||
pr_err("sepol: copy cls failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (strncpy_from_user(default_type, data.sepol4,
|
|
||||||
sizeof(default_type)) < 0) {
|
|
||||||
pr_err("sepol: copy default_type failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
char *real_object;
|
|
||||||
if (data.sepol5 == NULL) {
|
|
||||||
real_object = NULL;
|
|
||||||
} else {
|
|
||||||
if (strncpy_from_user(object, data.sepol5,
|
|
||||||
sizeof(object)) < 0) {
|
|
||||||
pr_err("sepol: copy object failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
real_object = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = ksu_type_transition(db, src, tgt, cls,
|
} else if (cmd == CMD_TYPE_CHANGE) {
|
||||||
default_type, real_object);
|
char src[MAX_SEPOL_LEN];
|
||||||
if (success)
|
char tgt[MAX_SEPOL_LEN];
|
||||||
ret = 0;
|
char cls[MAX_SEPOL_LEN];
|
||||||
|
char default_type[MAX_SEPOL_LEN];
|
||||||
|
|
||||||
} else if (cmd == CMD_TYPE_CHANGE) {
|
if (strncpy_from_user(src, sepol1, sizeof(src)) < 0) {
|
||||||
char src[MAX_SEPOL_LEN];
|
pr_err("sepol: copy src failed.\n");
|
||||||
char tgt[MAX_SEPOL_LEN];
|
goto exit;
|
||||||
char cls[MAX_SEPOL_LEN];
|
}
|
||||||
char default_type[MAX_SEPOL_LEN];
|
if (strncpy_from_user(tgt, sepol2, sizeof(tgt)) < 0) {
|
||||||
|
pr_err("sepol: copy tgt failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(cls, sepol3, sizeof(cls)) < 0) {
|
||||||
|
pr_err("sepol: copy cls failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(default_type, sepol4,
|
||||||
|
sizeof(default_type)) < 0) {
|
||||||
|
pr_err("sepol: copy default_type failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
bool success = false;
|
||||||
|
if (subcmd == 1) {
|
||||||
|
success = ksu_type_change(db, src, tgt, cls,
|
||||||
|
default_type);
|
||||||
|
} else if (subcmd == 2) {
|
||||||
|
success = ksu_type_member(db, src, tgt, cls,
|
||||||
|
default_type);
|
||||||
|
} else {
|
||||||
|
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
||||||
|
}
|
||||||
|
if (success)
|
||||||
|
ret = 0;
|
||||||
|
} else if (cmd == CMD_GENFSCON) {
|
||||||
|
char name[MAX_SEPOL_LEN];
|
||||||
|
char path[MAX_SEPOL_LEN];
|
||||||
|
char context[MAX_SEPOL_LEN];
|
||||||
|
if (strncpy_from_user(name, sepol1, sizeof(name)) < 0) {
|
||||||
|
pr_err("sepol: copy name failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(path, sepol2, sizeof(path)) < 0) {
|
||||||
|
pr_err("sepol: copy path failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncpy_from_user(context, sepol3, sizeof(context)) <
|
||||||
|
0) {
|
||||||
|
pr_err("sepol: copy context failed.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (strncpy_from_user(src, data.sepol1, sizeof(src)) < 0) {
|
if (!ksu_genfscon(db, name, path, context)) {
|
||||||
pr_err("sepol: copy src failed.\n");
|
pr_err("sepol: %d failed.\n", cmd);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (strncpy_from_user(tgt, data.sepol2, sizeof(tgt)) < 0) {
|
ret = 0;
|
||||||
pr_err("sepol: copy tgt failed.\n");
|
} else {
|
||||||
goto exit;
|
pr_err("sepol: unknown cmd: %d\n", cmd);
|
||||||
}
|
}
|
||||||
if (strncpy_from_user(cls, data.sepol3, sizeof(cls)) < 0) {
|
|
||||||
pr_err("sepol: copy cls failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (strncpy_from_user(default_type, data.sepol4,
|
|
||||||
sizeof(default_type)) < 0) {
|
|
||||||
pr_err("sepol: copy default_type failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
bool success = false;
|
|
||||||
if (subcmd == 1) {
|
|
||||||
success = ksu_type_change(db, src, tgt, cls,
|
|
||||||
default_type);
|
|
||||||
} else if (subcmd == 2) {
|
|
||||||
success = ksu_type_member(db, src, tgt, cls,
|
|
||||||
default_type);
|
|
||||||
} else {
|
|
||||||
pr_err("sepol: unknown subcmd: %d\n", subcmd);
|
|
||||||
}
|
|
||||||
if (success)
|
|
||||||
ret = 0;
|
|
||||||
} else if (cmd == CMD_GENFSCON) {
|
|
||||||
char name[MAX_SEPOL_LEN];
|
|
||||||
char path[MAX_SEPOL_LEN];
|
|
||||||
char context[MAX_SEPOL_LEN];
|
|
||||||
if (strncpy_from_user(name, data.sepol1, sizeof(name)) < 0) {
|
|
||||||
pr_err("sepol: copy name failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (strncpy_from_user(path, data.sepol2, sizeof(path)) < 0) {
|
|
||||||
pr_err("sepol: copy path failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (strncpy_from_user(context, data.sepol3, sizeof(context)) <
|
|
||||||
0) {
|
|
||||||
pr_err("sepol: copy context failed.\n");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ksu_genfscon(db, name, path, context)) {
|
|
||||||
pr_err("sepol: %d failed.\n", cmd);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
pr_err("sepol: unknown cmd: %d\n", cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
mutex_unlock(&ksu_rules);
|
mutex_unlock(&ksu_rules);
|
||||||
|
|
||||||
// only allow and xallow needs to reset avc cache, but we cannot do that because
|
// only allow and xallow needs to reset avc cache, but we cannot do that because
|
||||||
// we are in atomic context. so we just reset it every time.
|
// we are in atomic context. so we just reset it every time.
|
||||||
reset_avc_cache();
|
reset_avc_cache();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#include "selinux.h"
|
#include "selinux.h"
|
||||||
#include "linux/cred.h"
|
|
||||||
#include "linux/sched.h"
|
|
||||||
#include "objsec.h"
|
#include "objsec.h"
|
||||||
#include "linux/version.h"
|
#include "linux/version.h"
|
||||||
#include "../klog.h" // IWYU pragma: keep
|
#include "../klog.h" // IWYU pragma: keep
|
||||||
@@ -9,146 +7,124 @@
|
|||||||
|
|
||||||
static int transive_to_domain(const char *domain)
|
static int transive_to_domain(const char *domain)
|
||||||
{
|
{
|
||||||
struct cred *cred;
|
struct cred *cred;
|
||||||
struct task_security_struct *tsec;
|
struct task_security_struct *tsec;
|
||||||
u32 sid;
|
u32 sid;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
cred = (struct cred *)__task_cred(current);
|
cred = (struct cred *)__task_cred(current);
|
||||||
|
|
||||||
tsec = cred->security;
|
tsec = cred->security;
|
||||||
if (!tsec) {
|
if (!tsec) {
|
||||||
pr_err("tsec == NULL!\n");
|
pr_err("tsec == NULL!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = security_secctx_to_secid(domain, strlen(domain), &sid);
|
error = security_secctx_to_secid(domain, strlen(domain), &sid);
|
||||||
if (error) {
|
if (error) {
|
||||||
pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n",
|
pr_info("security_secctx_to_secid %s -> sid: %d, error: %d\n",
|
||||||
domain, sid, error);
|
domain, sid, error);
|
||||||
}
|
}
|
||||||
if (!error) {
|
if (!error) {
|
||||||
tsec->sid = sid;
|
tsec->sid = sid;
|
||||||
tsec->create_sid = 0;
|
tsec->create_sid = 0;
|
||||||
tsec->keycreate_sid = 0;
|
tsec->keycreate_sid = 0;
|
||||||
tsec->sockcreate_sid = 0;
|
tsec->sockcreate_sid = 0;
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_selinux(const char *domain)
|
void setup_selinux(const char *domain)
|
||||||
{
|
{
|
||||||
if (transive_to_domain(domain)) {
|
if (transive_to_domain(domain)) {
|
||||||
pr_err("transive domain failed.\n");
|
pr_err("transive domain failed.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we didn't need this now, we have change selinux rules when boot!
|
||||||
|
if (!is_domain_permissive) {
|
||||||
|
if (set_domain_permissive() == 0) {
|
||||||
|
is_domain_permissive = true;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void setenforce(bool enforce)
|
void setenforce(bool enforce)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
||||||
selinux_state.enforcing = enforce;
|
selinux_state.enforcing = enforce;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getenforce()
|
bool getenforce()
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
|
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
|
||||||
if (selinux_state.disabled) {
|
if (selinux_state.disabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
||||||
return selinux_state.enforcing;
|
return selinux_state.enforcing;
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 14, 0)
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \
|
||||||
struct lsm_context {
|
!defined(KSU_COMPAT_HAS_CURRENT_SID)
|
||||||
char *context;
|
/*
|
||||||
u32 len;
|
* get the subjective security ID of the current task
|
||||||
};
|
*/
|
||||||
|
static inline u32 current_sid(void)
|
||||||
|
{
|
||||||
|
const struct task_security_struct *tsec = current_security();
|
||||||
|
|
||||||
static int __security_secid_to_secctx(u32 secid, struct lsm_context *cp)
|
return tsec->sid;
|
||||||
{
|
|
||||||
return security_secid_to_secctx(secid, &cp->context, &cp->len);
|
|
||||||
}
|
}
|
||||||
static void __security_release_secctx(struct lsm_context *cp)
|
|
||||||
{
|
|
||||||
return security_release_secctx(cp->context, cp->len);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define __security_secid_to_secctx security_secid_to_secctx
|
|
||||||
#define __security_release_secctx security_release_secctx
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool is_task_ksu_domain(const struct cred* cred)
|
|
||||||
{
|
|
||||||
struct lsm_context ctx;
|
|
||||||
bool result;
|
|
||||||
if (!cred) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const struct task_security_struct *tsec = selinux_cred(cred);
|
|
||||||
if (!tsec) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int err = __security_secid_to_secctx(tsec->sid, &ctx);
|
|
||||||
if (err) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
result = strncmp(KERNEL_SU_DOMAIN, ctx.context, ctx.len) == 0;
|
|
||||||
__security_release_secctx(&ctx);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_ksu_domain()
|
bool is_ksu_domain()
|
||||||
{
|
{
|
||||||
current_sid();
|
char *domain;
|
||||||
return is_task_ksu_domain(current_cred());
|
u32 seclen;
|
||||||
|
bool result;
|
||||||
|
int err = security_secid_to_secctx(current_sid(), &domain, &seclen);
|
||||||
|
if (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0;
|
||||||
|
security_release_secctx(domain, seclen);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_context(const struct cred* cred, const char* context)
|
bool is_zygote(void *sec)
|
||||||
{
|
{
|
||||||
if (!cred) {
|
struct task_security_struct *tsec = (struct task_security_struct *)sec;
|
||||||
return false;
|
if (!tsec) {
|
||||||
}
|
return false;
|
||||||
const struct task_security_struct * tsec = selinux_cred(cred);
|
}
|
||||||
if (!tsec) {
|
char *domain;
|
||||||
return false;
|
u32 seclen;
|
||||||
}
|
bool result;
|
||||||
struct lsm_context ctx;
|
int err = security_secid_to_secctx(tsec->sid, &domain, &seclen);
|
||||||
bool result;
|
if (err) {
|
||||||
int err = __security_secid_to_secctx(tsec->sid, &ctx);
|
return false;
|
||||||
if (err) {
|
}
|
||||||
return false;
|
result = strncmp("u:r:zygote:s0", domain, seclen) == 0;
|
||||||
}
|
security_release_secctx(domain, seclen);
|
||||||
result = strncmp(context, ctx.context, ctx.len) == 0;
|
return result;
|
||||||
__security_release_secctx(&ctx);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_zygote(const struct cred* cred)
|
#define DEVPTS_DOMAIN "u:object_r:ksu_file:s0"
|
||||||
|
|
||||||
|
u32 ksu_get_devpts_sid()
|
||||||
{
|
{
|
||||||
return is_context(cred, "u:r:zygote:s0");
|
u32 devpts_sid = 0;
|
||||||
}
|
int err = security_secctx_to_secid(DEVPTS_DOMAIN, strlen(DEVPTS_DOMAIN),
|
||||||
|
&devpts_sid);
|
||||||
bool is_init(const struct cred* cred) {
|
if (err) {
|
||||||
return is_context(cred, "u:r:init:s0");
|
pr_info("get devpts sid err %d\n", err);
|
||||||
}
|
}
|
||||||
|
return devpts_sid;
|
||||||
#define KSU_FILE_DOMAIN "u:object_r:ksu_file:s0"
|
|
||||||
|
|
||||||
u32 ksu_get_ksu_file_sid()
|
|
||||||
{
|
|
||||||
u32 ksu_file_sid = 0;
|
|
||||||
int err = security_secctx_to_secid(KSU_FILE_DOMAIN, strlen(KSU_FILE_DOMAIN),
|
|
||||||
&ksu_file_sid);
|
|
||||||
if (err) {
|
|
||||||
pr_info("get ksufile sid err %d\n", err);
|
|
||||||
}
|
|
||||||
return ksu_file_sid;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "linux/types.h"
|
#include "linux/types.h"
|
||||||
#include "linux/version.h"
|
#include "linux/version.h"
|
||||||
#include "linux/cred.h"
|
|
||||||
|
|
||||||
void setup_selinux(const char *);
|
void setup_selinux(const char *);
|
||||||
|
|
||||||
@@ -11,18 +10,12 @@ void setenforce(bool);
|
|||||||
|
|
||||||
bool getenforce();
|
bool getenforce();
|
||||||
|
|
||||||
bool is_task_ksu_domain(const struct cred* cred);
|
|
||||||
|
|
||||||
bool is_ksu_domain();
|
bool is_ksu_domain();
|
||||||
|
|
||||||
bool is_zygote(const struct cred* cred);
|
bool is_zygote(void *cred);
|
||||||
|
|
||||||
bool is_init(const struct cred* cred);
|
|
||||||
|
|
||||||
void apply_kernelsu_rules();
|
void apply_kernelsu_rules();
|
||||||
|
|
||||||
u32 ksu_get_ksu_file_sid();
|
u32 ksu_get_devpts_sid();
|
||||||
|
|
||||||
int handle_sepolicy(unsigned long arg3, void __user *arg4);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,32 +15,32 @@ bool ksu_exists(struct policydb *db, const char *type);
|
|||||||
|
|
||||||
// Access vector rules
|
// Access vector rules
|
||||||
bool ksu_allow(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_allow(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *perm);
|
const char *cls, const char *perm);
|
||||||
bool ksu_deny(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_deny(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *perm);
|
const char *cls, const char *perm);
|
||||||
bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_auditallow(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *perm);
|
const char *cls, const char *perm);
|
||||||
bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_dontaudit(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *perm);
|
const char *cls, const char *perm);
|
||||||
|
|
||||||
// Extended permissions access vector rules
|
// Extended permissions access vector rules
|
||||||
bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_allowxperm(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *range);
|
const char *cls, const char *range);
|
||||||
bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_auditallowxperm(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *range);
|
const char *cls, const char *range);
|
||||||
bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_dontauditxperm(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *range);
|
const char *cls, const char *range);
|
||||||
|
|
||||||
// Type rules
|
// Type rules
|
||||||
bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_type_transition(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *def, const char *obj);
|
const char *cls, const char *def, const char *obj);
|
||||||
bool ksu_type_change(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_type_change(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *def);
|
const char *cls, const char *def);
|
||||||
bool ksu_type_member(struct policydb *db, const char *src, const char *tgt,
|
bool ksu_type_member(struct policydb *db, const char *src, const char *tgt,
|
||||||
const char *cls, const char *def);
|
const char *cls, const char *def);
|
||||||
|
|
||||||
// File system labeling
|
// File system labeling
|
||||||
bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path,
|
bool ksu_genfscon(struct policydb *db, const char *fs_name, const char *path,
|
||||||
const char *ctx);
|
const char *ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
#include <linux/compiler.h>
|
|
||||||
#include <linux/sched/signal.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/task_work.h>
|
|
||||||
#include <linux/thread_info.h>
|
|
||||||
#include <linux/seccomp.h>
|
|
||||||
#include <linux/bpf.h>
|
|
||||||
#include <linux/capability.h>
|
|
||||||
#include <linux/cred.h>
|
|
||||||
#include <linux/dcache.h>
|
|
||||||
#include <linux/err.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/init_task.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/kprobes.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/mount.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
#include <linux/nsproxy.h>
|
|
||||||
#include <linux/path.h>
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/security.h>
|
|
||||||
#include <linux/stddef.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/uidgid.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/binfmts.h>
|
|
||||||
#include <linux/tty.h>
|
|
||||||
|
|
||||||
#include "allowlist.h"
|
|
||||||
#include "setuid_hook.h"
|
|
||||||
#include "feature.h"
|
|
||||||
#include "klog.h" // IWYU pragma: keep
|
|
||||||
#include "manager.h"
|
|
||||||
#include "selinux/selinux.h"
|
|
||||||
#include "seccomp_cache.h"
|
|
||||||
#include "supercalls.h"
|
|
||||||
#include "syscall_hook_manager.h"
|
|
||||||
#include "kernel_umount.h"
|
|
||||||
#include "app_profile.h"
|
|
||||||
|
|
||||||
static bool ksu_enhanced_security_enabled = false;
|
|
||||||
|
|
||||||
static int enhanced_security_feature_get(u64 *value)
|
|
||||||
{
|
|
||||||
*value = ksu_enhanced_security_enabled ? 1 : 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int enhanced_security_feature_set(u64 value)
|
|
||||||
{
|
|
||||||
bool enable = value != 0;
|
|
||||||
ksu_enhanced_security_enabled = enable;
|
|
||||||
pr_info("enhanced_security: set to %d\n", enable);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct ksu_feature_handler enhanced_security_handler = {
|
|
||||||
.feature_id = KSU_FEATURE_ENHANCED_SECURITY,
|
|
||||||
.name = "enhanced_security",
|
|
||||||
.get_handler = enhanced_security_feature_get,
|
|
||||||
.set_handler = enhanced_security_feature_set,
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline bool is_allow_su()
|
|
||||||
{
|
|
||||||
if (is_manager()) {
|
|
||||||
// we are manager, allow!
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return ksu_is_allow_uid_for_current(current_uid().val);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid)
|
|
||||||
{
|
|
||||||
uid_t new_uid = ruid;
|
|
||||||
uid_t old_uid = current_uid().val;
|
|
||||||
|
|
||||||
pr_info("handle_setresuid from %d to %d\n", old_uid, new_uid);
|
|
||||||
|
|
||||||
// if old process is root, ignore it.
|
|
||||||
if (old_uid != 0 && ksu_enhanced_security_enabled) {
|
|
||||||
// disallow any non-ksu domain escalation from non-root to root!
|
|
||||||
// euid is what we care about here as it controls permission
|
|
||||||
if (unlikely(euid == 0)) {
|
|
||||||
if (!is_ksu_domain()) {
|
|
||||||
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
|
|
||||||
current->pid, current->comm, old_uid, new_uid);
|
|
||||||
force_sig(SIGKILL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// disallow appuid decrease to any other uid if it is not allowed to su
|
|
||||||
if (is_appuid(old_uid)) {
|
|
||||||
if (euid < current_euid().val && !ksu_is_allow_uid_for_current(old_uid)) {
|
|
||||||
pr_warn("find suspicious EoP: %d %s, from %d to %d\n",
|
|
||||||
current->pid, current->comm, old_uid, new_uid);
|
|
||||||
force_sig(SIGKILL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if on private space, see if its possibly the manager
|
|
||||||
if (new_uid > PER_USER_RANGE && new_uid % PER_USER_RANGE == ksu_get_manager_uid()) {
|
|
||||||
ksu_set_manager_uid(new_uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
|
||||||
if (ksu_get_manager_uid() == new_uid) {
|
|
||||||
pr_info("install fd for manager: %d\n", new_uid);
|
|
||||||
ksu_install_fd();
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
|
||||||
ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot);
|
|
||||||
ksu_set_task_tracepoint_flag(current);
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ksu_is_allow_uid_for_current(new_uid)) {
|
|
||||||
if (current->seccomp.mode == SECCOMP_MODE_FILTER &&
|
|
||||||
current->seccomp.filter) {
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
|
||||||
ksu_seccomp_allow_cache(current->seccomp.filter, __NR_reboot);
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
}
|
|
||||||
ksu_set_task_tracepoint_flag(current);
|
|
||||||
} else {
|
|
||||||
ksu_clear_task_tracepoint_flag_if_needed(current);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (ksu_is_allow_uid_for_current(new_uid)) {
|
|
||||||
spin_lock_irq(¤t->sighand->siglock);
|
|
||||||
disable_seccomp();
|
|
||||||
spin_unlock_irq(¤t->sighand->siglock);
|
|
||||||
|
|
||||||
if (ksu_get_manager_uid() == new_uid) {
|
|
||||||
pr_info("install fd for ksu manager(uid=%d)\n",
|
|
||||||
new_uid);
|
|
||||||
ksu_install_fd();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Handle kernel umount
|
|
||||||
ksu_handle_umount(old_uid, new_uid);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_setuid_hook_init(void)
|
|
||||||
{
|
|
||||||
ksu_kernel_umount_init();
|
|
||||||
if (ksu_register_feature_handler(&enhanced_security_handler)) {
|
|
||||||
pr_err("Failed to register enhanced security feature handler\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_setuid_hook_exit(void)
|
|
||||||
{
|
|
||||||
pr_info("ksu_core_exit\n");
|
|
||||||
ksu_kernel_umount_exit();
|
|
||||||
ksu_unregister_feature_handler(KSU_FEATURE_ENHANCED_SECURITY);
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef __KSU_H_KSU_CORE
|
|
||||||
#define __KSU_H_KSU_CORE
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include "apk_sign.h"
|
|
||||||
#include <linux/thread_info.h>
|
|
||||||
|
|
||||||
void ksu_setuid_hook_init(void);
|
|
||||||
void ksu_setuid_hook_exit(void);
|
|
||||||
|
|
||||||
int ksu_handle_setresuid(uid_t ruid, uid_t euid, uid_t suid);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,172 +1,342 @@
|
|||||||
#include "linux/compiler.h"
|
#include <linux/dcache.h>
|
||||||
#include "linux/printk.h"
|
#include <linux/security.h>
|
||||||
#include <asm/current.h>
|
#include <asm/current.h>
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
|
#include <linux/err.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/sched/task_stack.h>
|
#include <linux/sched/task_stack.h>
|
||||||
#include <linux/ptrace.h>
|
|
||||||
|
|
||||||
|
#include "objsec.h"
|
||||||
#include "allowlist.h"
|
#include "allowlist.h"
|
||||||
#include "feature.h"
|
#include "arch.h"
|
||||||
#include "klog.h" // IWYU pragma: keep
|
#include "klog.h" // IWYU pragma: keep
|
||||||
#include "ksud.h"
|
#include "ksud.h"
|
||||||
#include "sucompat.h"
|
#include "kernel_compat.h"
|
||||||
#include "app_profile.h"
|
|
||||||
#include "syscall_hook_manager.h"
|
|
||||||
|
|
||||||
#include "sulog.h"
|
|
||||||
|
|
||||||
#define SU_PATH "/system/bin/su"
|
#define SU_PATH "/system/bin/su"
|
||||||
#define SH_PATH "/system/bin/sh"
|
#define SH_PATH "/system/bin/sh"
|
||||||
|
|
||||||
bool ksu_su_compat_enabled __read_mostly = true;
|
extern void escape_to_root();
|
||||||
|
|
||||||
static int su_compat_feature_get(u64 *value)
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
{
|
static bool ksu_sucompat_non_kp __read_mostly = true;
|
||||||
*value = ksu_su_compat_enabled ? 1 : 0;
|
#endif
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int su_compat_feature_set(u64 value)
|
|
||||||
{
|
|
||||||
bool enable = value != 0;
|
|
||||||
ksu_su_compat_enabled = enable;
|
|
||||||
pr_info("su_compat: set to %d\n", enable);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct ksu_feature_handler su_compat_handler = {
|
|
||||||
.feature_id = KSU_FEATURE_SU_COMPAT,
|
|
||||||
.name = "su_compat",
|
|
||||||
.get_handler = su_compat_feature_get,
|
|
||||||
.set_handler = su_compat_feature_set,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void __user *userspace_stack_buffer(const void *d, size_t len)
|
static void __user *userspace_stack_buffer(const void *d, size_t len)
|
||||||
{
|
{
|
||||||
// To avoid having to mmap a page in userspace, just write below the stack
|
/* To avoid having to mmap a page in userspace, just write below the stack
|
||||||
// pointer.
|
* pointer. */
|
||||||
char __user *p = (void __user *)current_user_stack_pointer() - len;
|
char __user *p = (void __user *)current_user_stack_pointer() - len;
|
||||||
|
|
||||||
return copy_to_user(p, d, len) ? NULL : p;
|
return copy_to_user(p, d, len) ? NULL : p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char __user *sh_user_path(void)
|
static char __user *sh_user_path(void)
|
||||||
{
|
{
|
||||||
static const char sh_path[] = "/system/bin/sh";
|
static const char sh_path[] = "/system/bin/sh";
|
||||||
|
|
||||||
return userspace_stack_buffer(sh_path, sizeof(sh_path));
|
return userspace_stack_buffer(sh_path, sizeof(sh_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
static char __user *ksud_user_path(void)
|
static char __user *ksud_user_path(void)
|
||||||
{
|
{
|
||||||
static const char ksud_path[] = KSUD_PATH;
|
static const char ksud_path[] = KSUD_PATH;
|
||||||
|
|
||||||
return userspace_stack_buffer(ksud_path, sizeof(ksud_path));
|
return userspace_stack_buffer(ksud_path, sizeof(ksud_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
|
||||||
int *__unused_flags)
|
int *__unused_flags)
|
||||||
{
|
{
|
||||||
const char su[] = SU_PATH;
|
const char su[] = SU_PATH;
|
||||||
|
|
||||||
if (!ksu_is_allow_uid_for_current(current_uid().val)) {
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
return 0;
|
if (!ksu_sucompat_non_kp) {
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
char path[sizeof(su) + 1];
|
|
||||||
memset(path, 0, sizeof(path));
|
|
||||||
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
|
||||||
|
|
||||||
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_syscall(current_uid().val, NULL, "faccessat", path);
|
|
||||||
#endif
|
#endif
|
||||||
pr_info("faccessat su->sh!\n");
|
|
||||||
*filename_user = sh_user_path();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char path[sizeof(su) + 1];
|
||||||
|
memset(path, 0, sizeof(path));
|
||||||
|
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||||
|
|
||||||
|
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
||||||
|
pr_info("faccessat su->sh!\n");
|
||||||
|
*filename_user = sh_user_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
|
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
|
||||||
{
|
{
|
||||||
// const char sh[] = SH_PATH;
|
// const char sh[] = SH_PATH;
|
||||||
const char su[] = SU_PATH;
|
const char su[] = SU_PATH;
|
||||||
|
|
||||||
if (!ksu_is_allow_uid_for_current(current_uid().val)) {
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
return 0;
|
if (!ksu_sucompat_non_kp) {
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
if (unlikely(!filename_user)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char path[sizeof(su) + 1];
|
|
||||||
memset(path, 0, sizeof(path));
|
|
||||||
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
|
||||||
|
|
||||||
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
|
||||||
#if __SULOG_GATE
|
|
||||||
ksu_sulog_report_syscall(current_uid().val, NULL, "newfstatat", path);
|
|
||||||
#endif
|
#endif
|
||||||
pr_info("newfstatat su->sh!\n");
|
if (!ksu_is_allow_uid(current_uid().val)) {
|
||||||
*filename_user = sh_user_path();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (unlikely(!filename_user)) {
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ksu_handle_execve_sucompat(const char __user **filename_user,
|
char path[sizeof(su) + 1];
|
||||||
void *__never_use_argv, void *__never_use_envp,
|
memset(path, 0, sizeof(path));
|
||||||
int *__never_use_flags)
|
// Remove this later!! we use syscall hook, so this will never happen!!!!!
|
||||||
{
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) && 0
|
||||||
const char su[] = SU_PATH;
|
// it becomes a `struct filename *` after 5.18
|
||||||
char path[sizeof(su) + 1];
|
// https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216
|
||||||
|
const char sh[] = SH_PATH;
|
||||||
if (unlikely(!filename_user))
|
struct filename *filename = *((struct filename **)filename_user);
|
||||||
return 0;
|
if (IS_ERR(filename)) {
|
||||||
|
return 0;
|
||||||
memset(path, 0, sizeof(path));
|
}
|
||||||
strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
if (likely(memcmp(filename->name, su, sizeof(su))))
|
||||||
|
return 0;
|
||||||
if (likely(memcmp(path, su, sizeof(su))))
|
pr_info("vfs_statx su->sh!\n");
|
||||||
return 0;
|
memcpy((void *)filename->name, sh, sizeof(sh));
|
||||||
|
|
||||||
#if __SULOG_GATE
|
|
||||||
bool is_allowed = ksu_is_allow_uid_for_current(current_uid().val);
|
|
||||||
ksu_sulog_report_syscall(current_uid().val, NULL, "execve", path);
|
|
||||||
|
|
||||||
if (!is_allowed)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ksu_sulog_report_su_attempt(current_uid().val, NULL, path, is_allowed);
|
|
||||||
#else
|
#else
|
||||||
if (!ksu_is_allow_uid_for_current(current_uid().val)) {
|
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||||
return 0;
|
|
||||||
}
|
if (unlikely(!memcmp(path, su, sizeof(su)))) {
|
||||||
|
pr_info("newfstatat su->sh!\n");
|
||||||
|
*filename_user = sh_user_path();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pr_info("sys_execve su found\n");
|
return 0;
|
||||||
*filename_user = ksud_user_path();
|
|
||||||
|
|
||||||
escape_with_root_profile();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sucompat: permitted process can execute 'su' to gain root access.
|
// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code
|
||||||
|
int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
|
||||||
|
void *__never_use_argv, void *__never_use_envp,
|
||||||
|
int *__never_use_flags)
|
||||||
|
{
|
||||||
|
struct filename *filename;
|
||||||
|
const char sh[] = KSUD_PATH;
|
||||||
|
const char su[] = SU_PATH;
|
||||||
|
|
||||||
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
|
if (!ksu_sucompat_non_kp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (unlikely(!filename_ptr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
filename = *filename_ptr;
|
||||||
|
if (IS_ERR(filename)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likely(memcmp(filename->name, su, sizeof(su))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!ksu_is_allow_uid(current_uid().val))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pr_info("do_execveat_common su found\n");
|
||||||
|
memcpy((void *)filename->name, sh, sizeof(sh));
|
||||||
|
|
||||||
|
escape_to_root();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
|
||||||
|
void *__never_use_argv, void *__never_use_envp,
|
||||||
|
int *__never_use_flags)
|
||||||
|
{
|
||||||
|
const char su[] = SU_PATH;
|
||||||
|
char path[sizeof(su) + 1];
|
||||||
|
|
||||||
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
|
if (!ksu_sucompat_non_kp){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (unlikely(!filename_user))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(path, 0, sizeof(path));
|
||||||
|
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
|
||||||
|
|
||||||
|
if (likely(memcmp(path, su, sizeof(su))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!ksu_is_allow_uid(current_uid().val))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pr_info("sys_execve su found\n");
|
||||||
|
*filename_user = ksud_user_path();
|
||||||
|
|
||||||
|
escape_to_root();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ksu_inline_handle_devpts(struct inode *inode)
|
||||||
|
{
|
||||||
|
if (!current->mm) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid_t uid = current_uid().val;
|
||||||
|
if (uid % 100000 < 10000) {
|
||||||
|
// not untrusted_app, ignore it
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ksu_is_allow_uid(uid))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ksu_devpts_sid) {
|
||||||
|
struct inode_security_struct *sec = selinux_inode(inode);
|
||||||
|
if (sec) {
|
||||||
|
sec->sid = ksu_devpts_sid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __ksu_handle_devpts(struct inode *inode)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||||
|
if (!ksu_sucompat_non_kp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ksu_inline_handle_devpts(inode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dead code, we are phasing out ksu_handle_devpts for LSM hooks.
|
||||||
|
int __maybe_unused ksu_handle_devpts(struct inode *inode)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
|
static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||||
|
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
|
||||||
|
const char __user **filename_user =
|
||||||
|
(const char **)&PT_REGS_PARM2(real_regs);
|
||||||
|
int *mode = (int *)&PT_REGS_PARM3(real_regs);
|
||||||
|
|
||||||
|
return ksu_handle_faccessat(dfd, filename_user, mode, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||||
|
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
|
||||||
|
const char __user **filename_user =
|
||||||
|
(const char **)&PT_REGS_PARM2(real_regs);
|
||||||
|
int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs);
|
||||||
|
|
||||||
|
return ksu_handle_stat(dfd, filename_user, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct pt_regs *real_regs = PT_REAL_REGS(regs);
|
||||||
|
const char __user **filename_user =
|
||||||
|
(const char **)&PT_REGS_PARM1(real_regs);
|
||||||
|
|
||||||
|
return ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MODULE
|
||||||
|
static struct kprobe *su_kps[4];
|
||||||
|
static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct inode *inode;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
|
||||||
|
struct file *file = (struct file *)PT_REGS_PARM2(regs);
|
||||||
|
inode = file->f_path.dentry->d_inode;
|
||||||
|
#else
|
||||||
|
inode = (struct inode *)PT_REGS_PARM2(regs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ksu_inline_handle_devpts(inode);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static struct kprobe *su_kps[3];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct kprobe *init_kprobe(const char *name,
|
||||||
|
kprobe_pre_handler_t handler)
|
||||||
|
{
|
||||||
|
struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
|
||||||
|
if (!kp)
|
||||||
|
return NULL;
|
||||||
|
kp->symbol_name = name;
|
||||||
|
kp->pre_handler = handler;
|
||||||
|
|
||||||
|
int ret = register_kprobe(kp);
|
||||||
|
pr_info("sucompat: register_%s kprobe: %d\n", name, ret);
|
||||||
|
if (ret) {
|
||||||
|
kfree(kp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_kprobe(struct kprobe **kp_ptr)
|
||||||
|
{
|
||||||
|
struct kprobe *kp = *kp_ptr;
|
||||||
|
if (!kp)
|
||||||
|
return;
|
||||||
|
unregister_kprobe(kp);
|
||||||
|
synchronize_rcu();
|
||||||
|
kfree(kp);
|
||||||
|
*kp_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// sucompat: permited process can execute 'su' to gain root access.
|
||||||
void ksu_sucompat_init()
|
void ksu_sucompat_init()
|
||||||
{
|
{
|
||||||
if (ksu_register_feature_handler(&su_compat_handler)) {
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
pr_err("Failed to register su_compat feature handler\n");
|
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre);
|
||||||
}
|
su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre);
|
||||||
|
su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
|
||||||
|
#ifdef MODULE
|
||||||
|
su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
ksu_sucompat_non_kp = true;
|
||||||
|
pr_info("ksu_sucompat_init: hooks enabled: execve/execveat_su, faccessat, stat\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksu_sucompat_exit()
|
void ksu_sucompat_exit()
|
||||||
{
|
{
|
||||||
ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT);
|
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||||
}
|
for (int i = 0; i < ARRAY_SIZE(su_kps); i++) {
|
||||||
|
destroy_kprobe(&su_kps[i]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ksu_sucompat_non_kp = false;
|
||||||
|
pr_info("ksu_sucompat_exit: hooks disabled: execve/execveat_su, faccessat, stat\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
#ifndef __KSU_H_SUCOMPAT
|
|
||||||
#define __KSU_H_SUCOMPAT
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
extern bool ksu_su_compat_enabled;
|
|
||||||
|
|
||||||
void ksu_sucompat_init(void);
|
|
||||||
void ksu_sucompat_exit(void);
|
|
||||||
|
|
||||||
// Handler functions exported for hook_manager
|
|
||||||
int ksu_handle_faccessat(int *dfd, const char __user **filename_user,
|
|
||||||
int *mode, int *__unused_flags);
|
|
||||||
int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags);
|
|
||||||
int ksu_handle_execve_sucompat(const char __user **filename_user,
|
|
||||||
void *__never_use_argv, void *__never_use_envp,
|
|
||||||
int *__never_use_flags);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
369
kernel/sulog.c
@@ -1,369 +0,0 @@
|
|||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/time.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <linux/cred.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
|
|
||||||
#include "klog.h"
|
|
||||||
|
|
||||||
#include "sulog.h"
|
|
||||||
#include "ksu.h"
|
|
||||||
#include "feature.h"
|
|
||||||
|
|
||||||
#if __SULOG_GATE
|
|
||||||
|
|
||||||
struct dedup_entry dedup_tbl[SULOG_COMM_LEN];
|
|
||||||
static DEFINE_SPINLOCK(dedup_lock);
|
|
||||||
static LIST_HEAD(sulog_queue);
|
|
||||||
static struct workqueue_struct *sulog_workqueue;
|
|
||||||
static struct work_struct sulog_work;
|
|
||||||
static bool sulog_enabled __read_mostly = true;
|
|
||||||
|
|
||||||
static int sulog_feature_get(u64 *value)
|
|
||||||
{
|
|
||||||
*value = sulog_enabled ? 1 : 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sulog_feature_set(u64 value)
|
|
||||||
{
|
|
||||||
bool enable = value != 0;
|
|
||||||
sulog_enabled = enable;
|
|
||||||
pr_info("sulog: set to %d\n", enable);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct ksu_feature_handler sulog_handler = {
|
|
||||||
.feature_id = KSU_FEATURE_SULOG,
|
|
||||||
.name = "sulog",
|
|
||||||
.get_handler = sulog_feature_get,
|
|
||||||
.set_handler = sulog_feature_set,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void get_timestamp(char *buf, size_t len)
|
|
||||||
{
|
|
||||||
struct timespec64 ts;
|
|
||||||
struct tm tm;
|
|
||||||
|
|
||||||
ktime_get_real_ts64(&ts);
|
|
||||||
time64_to_tm(ts.tv_sec - sys_tz.tz_minuteswest * 60, 0, &tm);
|
|
||||||
|
|
||||||
snprintf(buf, len, "%04ld-%02d-%02d %02d:%02d:%02d",
|
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ksu_get_cmdline(char *full_comm, const char *comm, size_t buf_len)
|
|
||||||
{
|
|
||||||
if (!full_comm || buf_len <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (comm && strlen(comm) > 0) {
|
|
||||||
KSU_STRSCPY(full_comm, comm, buf_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_atomic() || in_interrupt() || irqs_disabled()) {
|
|
||||||
KSU_STRSCPY(full_comm, current->comm, buf_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!current->mm) {
|
|
||||||
KSU_STRSCPY(full_comm, current->comm, buf_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = get_cmdline(current, full_comm, buf_len);
|
|
||||||
if (n <= 0) {
|
|
||||||
KSU_STRSCPY(full_comm, current->comm, buf_len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < n && i < buf_len - 1; i++) {
|
|
||||||
if (full_comm[i] == '\0')
|
|
||||||
full_comm[i] = ' ';
|
|
||||||
}
|
|
||||||
full_comm[n < buf_len ? n : buf_len - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sanitize_string(char *str, size_t len)
|
|
||||||
{
|
|
||||||
if (!str || len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size_t read_pos = 0, write_pos = 0;
|
|
||||||
|
|
||||||
while (read_pos < len && str[read_pos] != '\0') {
|
|
||||||
char c = str[read_pos];
|
|
||||||
|
|
||||||
if (c == '\n' || c == '\r') {
|
|
||||||
read_pos++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == ' ' && write_pos > 0 && str[write_pos - 1] == ' ') {
|
|
||||||
read_pos++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
str[write_pos++] = c;
|
|
||||||
read_pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
str[write_pos] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dedup_should_print(uid_t uid, u8 type, const char *content, size_t len)
|
|
||||||
{
|
|
||||||
struct dedup_key key = {
|
|
||||||
.crc = dedup_calc_hash(content, len),
|
|
||||||
.uid = uid,
|
|
||||||
.type = type,
|
|
||||||
};
|
|
||||||
u64 now = ktime_get_ns();
|
|
||||||
u64 delta_ns = DEDUP_SECS * NSEC_PER_SEC;
|
|
||||||
|
|
||||||
u32 idx = key.crc & (SULOG_COMM_LEN - 1);
|
|
||||||
spin_lock(&dedup_lock);
|
|
||||||
|
|
||||||
struct dedup_entry *e = &dedup_tbl[idx];
|
|
||||||
if (e->key.crc == key.crc &&
|
|
||||||
e->key.uid == key.uid &&
|
|
||||||
e->key.type == key.type &&
|
|
||||||
(now - e->ts_ns) < delta_ns) {
|
|
||||||
spin_unlock(&dedup_lock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
e->key = key;
|
|
||||||
e->ts_ns = now;
|
|
||||||
spin_unlock(&dedup_lock);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sulog_work_handler(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct file *fp;
|
|
||||||
struct sulog_entry *entry, *tmp;
|
|
||||||
LIST_HEAD(local_queue);
|
|
||||||
loff_t pos = 0;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dedup_lock, flags);
|
|
||||||
list_splice_init(&sulog_queue, &local_queue);
|
|
||||||
spin_unlock_irqrestore(&dedup_lock, flags);
|
|
||||||
|
|
||||||
if (list_empty(&local_queue))
|
|
||||||
return;
|
|
||||||
|
|
||||||
fp = filp_open(SULOG_PATH, O_WRONLY | O_CREAT | O_APPEND, 0640);
|
|
||||||
if (IS_ERR(fp)) {
|
|
||||||
pr_err("sulog: failed to open log file: %ld\n", PTR_ERR(fp));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp->f_inode->i_size > SULOG_MAX_SIZE) {
|
|
||||||
if (vfs_truncate(&fp->f_path, 0))
|
|
||||||
pr_err("sulog: failed to truncate log file\n");
|
|
||||||
pos = 0;
|
|
||||||
} else {
|
|
||||||
pos = fp->f_inode->i_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(entry, &local_queue, list)
|
|
||||||
kernel_write(fp, entry->content, strlen(entry->content), &pos);
|
|
||||||
|
|
||||||
vfs_fsync(fp, 0);
|
|
||||||
filp_close(fp, 0);
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
list_for_each_entry_safe(entry, tmp, &local_queue, list) {
|
|
||||||
list_del(&entry->list);
|
|
||||||
kfree(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sulog_add_entry(char *log_buf, size_t len, uid_t uid, u8 dedup_type)
|
|
||||||
{
|
|
||||||
struct sulog_entry *entry;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!sulog_enabled || !log_buf || len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!dedup_should_print(uid, dedup_type, log_buf, len))
|
|
||||||
return;
|
|
||||||
|
|
||||||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
|
||||||
if (!entry)
|
|
||||||
return;
|
|
||||||
|
|
||||||
KSU_STRSCPY(entry->content, log_buf, SULOG_ENTRY_MAX_LEN);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dedup_lock, flags);
|
|
||||||
list_add_tail(&entry->list, &sulog_queue);
|
|
||||||
spin_unlock_irqrestore(&dedup_lock, flags);
|
|
||||||
|
|
||||||
if (sulog_workqueue)
|
|
||||||
queue_work(sulog_workqueue, &sulog_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_sulog_report_su_grant(uid_t uid, const char *comm, const char *method)
|
|
||||||
{
|
|
||||||
char log_buf[SULOG_ENTRY_MAX_LEN];
|
|
||||||
char timestamp[32];
|
|
||||||
char full_comm[SULOG_COMM_LEN];
|
|
||||||
|
|
||||||
if (!sulog_enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
get_timestamp(timestamp, sizeof(timestamp));
|
|
||||||
ksu_get_cmdline(full_comm, comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
sanitize_string(full_comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
snprintf(log_buf, sizeof(log_buf),
|
|
||||||
"[%s] SU_GRANT: UID=%d COMM=%s METHOD=%s PID=%d\n",
|
|
||||||
timestamp, uid, full_comm, method ? method : "unknown", current->pid);
|
|
||||||
|
|
||||||
sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SU_GRANT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_sulog_report_su_attempt(uid_t uid, const char *comm, const char *target_path, bool success)
|
|
||||||
{
|
|
||||||
char log_buf[SULOG_ENTRY_MAX_LEN];
|
|
||||||
char timestamp[32];
|
|
||||||
char full_comm[SULOG_COMM_LEN];
|
|
||||||
|
|
||||||
if (!sulog_enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
get_timestamp(timestamp, sizeof(timestamp));
|
|
||||||
ksu_get_cmdline(full_comm, comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
sanitize_string(full_comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
snprintf(log_buf, sizeof(log_buf),
|
|
||||||
"[%s] SU_EXEC: UID=%d COMM=%s TARGET=%s RESULT=%s PID=%d\n",
|
|
||||||
timestamp, uid, full_comm, target_path ? target_path : "unknown",
|
|
||||||
success ? "SUCCESS" : "DENIED", current->pid);
|
|
||||||
|
|
||||||
sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SU_ATTEMPT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_sulog_report_permission_check(uid_t uid, const char *comm, bool allowed)
|
|
||||||
{
|
|
||||||
char log_buf[SULOG_ENTRY_MAX_LEN];
|
|
||||||
char timestamp[32];
|
|
||||||
char full_comm[SULOG_COMM_LEN];
|
|
||||||
|
|
||||||
if (!sulog_enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
get_timestamp(timestamp, sizeof(timestamp));
|
|
||||||
ksu_get_cmdline(full_comm, comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
sanitize_string(full_comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
snprintf(log_buf, sizeof(log_buf),
|
|
||||||
"[%s] PERM_CHECK: UID=%d COMM=%s RESULT=%s PID=%d\n",
|
|
||||||
timestamp, uid, full_comm, allowed ? "ALLOWED" : "DENIED", current->pid);
|
|
||||||
|
|
||||||
sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_PERM_CHECK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_sulog_report_manager_operation(const char *operation, uid_t manager_uid, uid_t target_uid)
|
|
||||||
{
|
|
||||||
char log_buf[SULOG_ENTRY_MAX_LEN];
|
|
||||||
char timestamp[32];
|
|
||||||
char full_comm[SULOG_COMM_LEN];
|
|
||||||
|
|
||||||
if (!sulog_enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
get_timestamp(timestamp, sizeof(timestamp));
|
|
||||||
ksu_get_cmdline(full_comm, NULL, sizeof(full_comm));
|
|
||||||
|
|
||||||
sanitize_string(full_comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
snprintf(log_buf, sizeof(log_buf),
|
|
||||||
"[%s] MANAGER_OP: OP=%s MANAGER_UID=%d TARGET_UID=%d COMM=%s PID=%d\n",
|
|
||||||
timestamp, operation ? operation : "unknown", manager_uid, target_uid, full_comm, current->pid);
|
|
||||||
|
|
||||||
sulog_add_entry(log_buf, strlen(log_buf), manager_uid, DEDUP_MANAGER_OP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_sulog_report_syscall(uid_t uid, const char *comm, const char *syscall, const char *args)
|
|
||||||
{
|
|
||||||
char log_buf[SULOG_ENTRY_MAX_LEN];
|
|
||||||
char timestamp[32];
|
|
||||||
char full_comm[SULOG_COMM_LEN];
|
|
||||||
|
|
||||||
if (!sulog_enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
get_timestamp(timestamp, sizeof(timestamp));
|
|
||||||
ksu_get_cmdline(full_comm, comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
sanitize_string(full_comm, sizeof(full_comm));
|
|
||||||
|
|
||||||
snprintf(log_buf, sizeof(log_buf),
|
|
||||||
"[%s] SYSCALL: UID=%d COMM=%s SYSCALL=%s ARGS=%s PID=%d\n",
|
|
||||||
timestamp, uid, full_comm, syscall ? syscall : "unknown",
|
|
||||||
args ? args : "none", current->pid);
|
|
||||||
|
|
||||||
sulog_add_entry(log_buf, strlen(log_buf), uid, DEDUP_SYSCALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ksu_sulog_init(void)
|
|
||||||
{
|
|
||||||
if (ksu_register_feature_handler(&sulog_handler)) {
|
|
||||||
pr_err("Failed to register sulog feature handler\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
sulog_workqueue = alloc_workqueue("ksu_sulog", WQ_UNBOUND | WQ_HIGHPRI, 1);
|
|
||||||
if (!sulog_workqueue) {
|
|
||||||
pr_err("sulog: failed to create workqueue\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT_WORK(&sulog_work, sulog_work_handler);
|
|
||||||
pr_info("sulog: initialized successfully\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ksu_sulog_exit(void)
|
|
||||||
{
|
|
||||||
struct sulog_entry *entry, *tmp;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
ksu_unregister_feature_handler(KSU_FEATURE_SULOG);
|
|
||||||
|
|
||||||
sulog_enabled = false;
|
|
||||||
|
|
||||||
if (sulog_workqueue) {
|
|
||||||
flush_workqueue(sulog_workqueue);
|
|
||||||
destroy_workqueue(sulog_workqueue);
|
|
||||||
sulog_workqueue = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dedup_lock, flags);
|
|
||||||
list_for_each_entry_safe(entry, tmp, &sulog_queue, list) {
|
|
||||||
list_del(&entry->list);
|
|
||||||
kfree(entry);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&dedup_lock, flags);
|
|
||||||
|
|
||||||
pr_info("sulog: cleaned up successfully\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __SULOG_GATE
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
#ifndef __KSU_SULOG_H
|
|
||||||
#define __KSU_SULOG_H
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/crc32.h> // needed for function dedup_calc_hash
|
|
||||||
|
|
||||||
#define __SULOG_GATE 1
|
|
||||||
|
|
||||||
#if __SULOG_GATE
|
|
||||||
|
|
||||||
extern struct timezone sys_tz;
|
|
||||||
|
|
||||||
#define SULOG_PATH "/data/adb/ksu/log/sulog.log"
|
|
||||||
#define SULOG_MAX_SIZE (32 * 1024 * 1024) // 128MB
|
|
||||||
#define SULOG_ENTRY_MAX_LEN 512
|
|
||||||
#define SULOG_COMM_LEN 256
|
|
||||||
#define DEDUP_SECS 10
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0)
|
|
||||||
static inline size_t strlcpy(char *dest, const char *src, size_t size)
|
|
||||||
{
|
|
||||||
return strscpy(dest, src, size);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define KSU_STRSCPY(dst, src, size) \
|
|
||||||
do { \
|
|
||||||
if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) { \
|
|
||||||
strscpy(dst, src, size); \
|
|
||||||
} else { \
|
|
||||||
strlcpy(dst, src, size); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
|
|
||||||
#include <linux/rtc.h>
|
|
||||||
|
|
||||||
static inline void time64_to_tm(time64_t totalsecs, int offset, struct tm *result)
|
|
||||||
{
|
|
||||||
struct rtc_time rtc_tm;
|
|
||||||
rtc_time64_to_tm(totalsecs, &rtc_tm);
|
|
||||||
|
|
||||||
result->tm_sec = rtc_tm.tm_sec;
|
|
||||||
result->tm_min = rtc_tm.tm_min;
|
|
||||||
result->tm_hour = rtc_tm.tm_hour;
|
|
||||||
result->tm_mday = rtc_tm.tm_mday;
|
|
||||||
result->tm_mon = rtc_tm.tm_mon;
|
|
||||||
result->tm_year = rtc_tm.tm_year;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct dedup_key {
|
|
||||||
u32 crc;
|
|
||||||
uid_t uid;
|
|
||||||
u8 type;
|
|
||||||
u8 _pad[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dedup_entry {
|
|
||||||
struct dedup_key key;
|
|
||||||
u64 ts_ns;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
DEDUP_SU_GRANT = 0,
|
|
||||||
DEDUP_SU_ATTEMPT,
|
|
||||||
DEDUP_PERM_CHECK,
|
|
||||||
DEDUP_MANAGER_OP,
|
|
||||||
DEDUP_SYSCALL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline u32 dedup_calc_hash(const char *content, size_t len)
|
|
||||||
{
|
|
||||||
return crc32(0, content, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sulog_entry {
|
|
||||||
struct list_head list;
|
|
||||||
char content[SULOG_ENTRY_MAX_LEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
void ksu_sulog_report_su_grant(uid_t uid, const char *comm, const char *method);
|
|
||||||
void ksu_sulog_report_su_attempt(uid_t uid, const char *comm, const char *target_path, bool success);
|
|
||||||
void ksu_sulog_report_permission_check(uid_t uid, const char *comm, bool allowed);
|
|
||||||
void ksu_sulog_report_manager_operation(const char *operation, uid_t manager_uid, uid_t target_uid);
|
|
||||||
void ksu_sulog_report_syscall(uid_t uid, const char *comm, const char *syscall, const char *args);
|
|
||||||
|
|
||||||
int ksu_sulog_init(void);
|
|
||||||
void ksu_sulog_exit(void);
|
|
||||||
#endif // __SULOG_GATE
|
|
||||||
|
|
||||||
#endif /* __KSU_SULOG_H */
|
|
||||||
1072
kernel/supercalls.c
@@ -1,197 +0,0 @@
|
|||||||
#ifndef __KSU_H_SUPERCALLS
|
|
||||||
#define __KSU_H_SUPERCALLS
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/ioctl.h>
|
|
||||||
#include "ksu.h"
|
|
||||||
#include "app_profile.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_KPM
|
|
||||||
#include "kpm/kpm.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Magic numbers for reboot hook to install fd
|
|
||||||
#define KSU_INSTALL_MAGIC1 0xDEADBEEF
|
|
||||||
#define KSU_INSTALL_MAGIC2 0xCAFEBABE
|
|
||||||
|
|
||||||
// Command structures for ioctl
|
|
||||||
|
|
||||||
struct ksu_become_daemon_cmd {
|
|
||||||
__u8 token[65]; // Input: daemon token (null-terminated)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_get_info_cmd {
|
|
||||||
__u32 version; // Output: KERNEL_SU_VERSION
|
|
||||||
__u32 flags; // Output: flags (bit 0: MODULE mode)
|
|
||||||
__u32 features; // Output: max feature ID supported
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_report_event_cmd {
|
|
||||||
__u32 event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc.
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_set_sepolicy_cmd {
|
|
||||||
__u64 cmd; // Input: sepolicy command
|
|
||||||
__aligned_u64 arg; // Input: sepolicy argument pointer
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_check_safemode_cmd {
|
|
||||||
__u8 in_safe_mode; // Output: true if in safe mode, false otherwise
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_get_allow_list_cmd {
|
|
||||||
__u32 uids[128]; // Output: array of allowed/denied UIDs
|
|
||||||
__u32 count; // Output: number of UIDs in array
|
|
||||||
__u8 allow; // Input: true for allow list, false for deny list
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_uid_granted_root_cmd {
|
|
||||||
__u32 uid; // Input: target UID to check
|
|
||||||
__u8 granted; // Output: true if granted, false otherwise
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_uid_should_umount_cmd {
|
|
||||||
__u32 uid; // Input: target UID to check
|
|
||||||
__u8 should_umount; // Output: true if should umount, false otherwise
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_get_manager_uid_cmd {
|
|
||||||
__u32 uid; // Output: manager UID
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_get_app_profile_cmd {
|
|
||||||
struct app_profile profile; // Input/Output: app profile structure
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_set_app_profile_cmd {
|
|
||||||
struct app_profile profile; // Input: app profile structure
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_get_feature_cmd {
|
|
||||||
__u32 feature_id; // Input: feature ID (enum ksu_feature_id)
|
|
||||||
__u64 value; // Output: feature value/state
|
|
||||||
__u8 supported; // Output: true if feature is supported, false otherwise
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_set_feature_cmd {
|
|
||||||
__u32 feature_id; // Input: feature ID (enum ksu_feature_id)
|
|
||||||
__u64 value; // Input: feature value/state to set
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_get_wrapper_fd_cmd {
|
|
||||||
__u32 fd; // Input: userspace fd
|
|
||||||
__u32 flags; // Input: flags of userspace fd
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_manage_mark_cmd {
|
|
||||||
__u32 operation; // Input: KSU_MARK_*
|
|
||||||
__s32 pid; // Input: target pid (0 for all processes)
|
|
||||||
__u32 result; // Output: for get operation - mark status or reg_count
|
|
||||||
};
|
|
||||||
|
|
||||||
#define KSU_MARK_GET 1
|
|
||||||
#define KSU_MARK_MARK 2
|
|
||||||
#define KSU_MARK_UNMARK 3
|
|
||||||
#define KSU_MARK_REFRESH 4
|
|
||||||
|
|
||||||
struct ksu_nuke_ext4_sysfs_cmd {
|
|
||||||
__aligned_u64 arg; // Input: mnt pointer
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_add_try_umount_cmd {
|
|
||||||
__aligned_u64 arg; // char ptr, this is the mountpoint
|
|
||||||
__u32 flags; // this is the flag we use for it
|
|
||||||
__u8 mode; // denotes what to do with it 0:wipe_list 1:add_to_list 2:delete_entry
|
|
||||||
};
|
|
||||||
|
|
||||||
#define KSU_UMOUNT_WIPE 0 // ignore everything and wipe list
|
|
||||||
#define KSU_UMOUNT_ADD 1 // add entry (path + flags)
|
|
||||||
#define KSU_UMOUNT_DEL 2 // delete entry, strcmp
|
|
||||||
|
|
||||||
|
|
||||||
// Other command structures
|
|
||||||
struct ksu_get_full_version_cmd {
|
|
||||||
char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_hook_type_cmd {
|
|
||||||
char hook_type[32]; // Output: hook type string
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_enable_kpm_cmd {
|
|
||||||
__u8 enabled; // Output: true if KPM is enabled
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_dynamic_manager_cmd {
|
|
||||||
struct dynamic_manager_user_config config; // Input/Output: dynamic manager config
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_get_managers_cmd {
|
|
||||||
struct manager_list_info manager_info; // Output: manager list information
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ksu_enable_uid_scanner_cmd {
|
|
||||||
__u32 operation; // Input: operation type (UID_SCANNER_OP_GET_STATUS, UID_SCANNER_OP_TOGGLE, UID_SCANNER_OP_CLEAR_ENV)
|
|
||||||
__u32 enabled; // Input: enable or disable (for UID_SCANNER_OP_TOGGLE)
|
|
||||||
void __user *status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS)
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
|
||||||
struct ksu_manual_su_cmd {
|
|
||||||
__u32 option; // Input: operation type (MANUAL_SU_OP_GENERATE_TOKEN, MANUAL_SU_OP_ESCALATE, MANUAL_SU_OP_ADD_PENDING)
|
|
||||||
__u32 target_uid; // Input: target UID
|
|
||||||
__u32 target_pid; // Input: target PID
|
|
||||||
char token_buffer[33]; // Input/Output: token buffer
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// IOCTL command definitions
|
|
||||||
#define KSU_IOCTL_GRANT_ROOT _IOC(_IOC_NONE, 'K', 1, 0)
|
|
||||||
#define KSU_IOCTL_GET_INFO _IOC(_IOC_READ, 'K', 2, 0)
|
|
||||||
#define KSU_IOCTL_REPORT_EVENT _IOC(_IOC_WRITE, 'K', 3, 0)
|
|
||||||
#define KSU_IOCTL_SET_SEPOLICY _IOC(_IOC_READ|_IOC_WRITE, 'K', 4, 0)
|
|
||||||
#define KSU_IOCTL_CHECK_SAFEMODE _IOC(_IOC_READ, 'K', 5, 0)
|
|
||||||
#define KSU_IOCTL_GET_ALLOW_LIST _IOC(_IOC_READ|_IOC_WRITE, 'K', 6, 0)
|
|
||||||
#define KSU_IOCTL_GET_DENY_LIST _IOC(_IOC_READ|_IOC_WRITE, 'K', 7, 0)
|
|
||||||
#define KSU_IOCTL_UID_GRANTED_ROOT _IOC(_IOC_READ|_IOC_WRITE, 'K', 8, 0)
|
|
||||||
#define KSU_IOCTL_UID_SHOULD_UMOUNT _IOC(_IOC_READ|_IOC_WRITE, 'K', 9, 0)
|
|
||||||
#define KSU_IOCTL_GET_MANAGER_UID _IOC(_IOC_READ, 'K', 10, 0)
|
|
||||||
#define KSU_IOCTL_GET_APP_PROFILE _IOC(_IOC_READ|_IOC_WRITE, 'K', 11, 0)
|
|
||||||
#define KSU_IOCTL_SET_APP_PROFILE _IOC(_IOC_WRITE, 'K', 12, 0)
|
|
||||||
#define KSU_IOCTL_GET_FEATURE _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0)
|
|
||||||
#define KSU_IOCTL_SET_FEATURE _IOC(_IOC_WRITE, 'K', 14, 0)
|
|
||||||
#define KSU_IOCTL_GET_WRAPPER_FD _IOC(_IOC_WRITE, 'K', 15, 0)
|
|
||||||
#define KSU_IOCTL_MANAGE_MARK _IOC(_IOC_READ|_IOC_WRITE, 'K', 16, 0)
|
|
||||||
#define KSU_IOCTL_NUKE_EXT4_SYSFS _IOC(_IOC_WRITE, 'K', 17, 0)
|
|
||||||
#define KSU_IOCTL_ADD_TRY_UMOUNT _IOC(_IOC_WRITE, 'K', 18, 0)
|
|
||||||
// Other IOCTL command definitions
|
|
||||||
#define KSU_IOCTL_GET_FULL_VERSION _IOC(_IOC_READ, 'K', 100, 0)
|
|
||||||
#define KSU_IOCTL_HOOK_TYPE _IOC(_IOC_READ, 'K', 101, 0)
|
|
||||||
#define KSU_IOCTL_ENABLE_KPM _IOC(_IOC_READ, 'K', 102, 0)
|
|
||||||
#define KSU_IOCTL_DYNAMIC_MANAGER _IOC(_IOC_READ|_IOC_WRITE, 'K', 103, 0)
|
|
||||||
#define KSU_IOCTL_GET_MANAGERS _IOC(_IOC_READ|_IOC_WRITE, 'K', 104, 0)
|
|
||||||
#define KSU_IOCTL_ENABLE_UID_SCANNER _IOC(_IOC_READ|_IOC_WRITE, 'K', 105, 0)
|
|
||||||
#ifdef CONFIG_KSU_MANUAL_SU
|
|
||||||
#define KSU_IOCTL_MANUAL_SU _IOC(_IOC_READ|_IOC_WRITE, 'K', 106, 0)
|
|
||||||
#endif
|
|
||||||
#define KSU_IOCTL_UMOUNT_MANAGER _IOC(_IOC_READ|_IOC_WRITE, 'K', 107, 0)
|
|
||||||
|
|
||||||
// IOCTL handler types
|
|
||||||
typedef int (*ksu_ioctl_handler_t)(void __user *arg);
|
|
||||||
typedef bool (*ksu_perm_check_t)(void);
|
|
||||||
|
|
||||||
// IOCTL command mapping
|
|
||||||
struct ksu_ioctl_cmd_map {
|
|
||||||
unsigned int cmd;
|
|
||||||
const char *name;
|
|
||||||
ksu_ioctl_handler_t handler;
|
|
||||||
ksu_perm_check_t perm_check; // Permission check function
|
|
||||||
};
|
|
||||||
|
|
||||||
// Install KSU fd to current process
|
|
||||||
int ksu_install_fd(void);
|
|
||||||
|
|
||||||
void ksu_supercalls_init(void);
|
|
||||||
void ksu_supercalls_exit(void);
|
|
||||||
|
|
||||||
#endif // __KSU_H_SUPERCALLS
|
|
||||||