Compare commits

..

1 Commits

Author SHA1 Message Date
weishu
5180e4add4 compile success for libsepl in kernel 2022-12-21 19:17:36 +07:00
719 changed files with 160232 additions and 45471 deletions

5
.github/FUNDING.yml vendored
View File

@@ -1,5 +0,0 @@
# These are supported funding model platforms
github: tiann
patreon: weishu
custom: https://vxposed.com/donate.html

View File

@@ -1,33 +0,0 @@
name: Contribute to Unofficially Supported Device
description: Add your device kernel source to KernelSU's Unofficially Supported Device List
title: "[Add Device]: "
labels: ["add-device"]
body:
- type: markdown
attributes:
value: |
Thanks for supporting KernelSU!
- type: input
id: repo-url
attributes:
label: Repository URL
description: Your repository URL
placeholder: https://github.com/tiann/KernelSU
validations:
required: true
- type: input
id: device
attributes:
label: Device
description: Please describe the device maintained by you.
placeholder: GKI 2.0 Device
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you should be the maintainer of the repository.
options:
- label: I'm the maintainer of this repository
required: true

View File

@@ -1,72 +0,0 @@
name: Bug report
description: Create a report to help us improve KernelSU
labels: [Bug]
body:
- type: checkboxes
attributes:
label: Please check before submitting an issue
options:
- label: I have searched the issues and haven't found anything relevant
required: true
- label: I will upload bugreport file in KernelSU Manager - Settings - Report log
required: true
- label: I know how to reproduce the issue which may not be specific to my device
required: false
- type: textarea
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: Steps to reproduce the behaviour
placeholder: |
- 1. Go to '...'
- 2. Click on '....'
- 3. Scroll down to '....'
- 4. See error
- type: textarea
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
- type: textarea
attributes:
label: Logs
description: If applicable, add crash or any other logs to help us figure out the problem.
- type: textarea
attributes:
label: Device info
value: |
- Device:
- OS Version:
- KernelSU Version:
- Kernel Version:
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: Add any other context about the problem here.

View File

@@ -1,11 +0,0 @@
name: Custom issue template
description: WARNING! If you are reporting a bug but use this template, the issue will be closed directly.
title: '[Custom]'
body:
- type: textarea
id: description
attributes:
label: "Describe your problem."
validations:
required: true

View File

@@ -1,40 +0,0 @@
name: Feature Request
description: "Suggest an idea for this project"
title: "[Feature]"
labels: "feature"
assignees: tiann
body:
- type: markdown
id: feature-info
attributes:
value: "## Feature Infomation"
- type: textarea
id: feature-main
validations:
required: true
attributes:
label: "Is your feature request related to a problem? Please describe."
description: "A clear and concise description of what the problem is."
placeholder: "I'm always frustrated when [...]"
- type: textarea
id: feature-solution
validations:
required: true
attributes:
label: "Describe the solution you'd like."
description: "A clear and concise description of what you want to happen."
- type: textarea
id: feature-describe
validations:
required: true
attributes:
label: "Describe alternatives you've considered."
description: "A clear and concise description of any alternative solutions or features you've considered."
- type: textarea
id: feature-extra
validations:
required: false
attributes:
label: "Additional context"
description: "Add any other context or screenshots about the feature request here."

View File

@@ -1,48 +0,0 @@
From f1e398602b989ac197cdd0fda4a7c4c323b03eb9 Mon Sep 17 00:00:00 2001
From: DozNaka <dozdguide@gmail.com>
Date: Mon, 11 Apr 2022 20:43:45 -0400
Subject: [PATCH] Makefile: Use CCACHE for faster compilation
---
Makefile | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index e8b8d5894..51e8aac6e 100644
--- a/Makefile
+++ b/Makefile
@@ -442,21 +442,21 @@ KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
# Make variables (CC, etc...)
CPP = $(CC) -E
ifneq ($(LLVM),)
-CC = clang
-LD = ld.lld
-AR = llvm-ar
+CC = $(CCACHE) clang
+LD = $(CCACHE) ld.lld
+AR = $(CCACHE) llvm-ar
NM = llvm-nm
-OBJCOPY = llvm-objcopy
-OBJDUMP = llvm-objdump
+OBJCOPY = $(CCACHE) llvm-objcopy
+OBJDUMP = $(CCACHE) llvm-objdump
READELF = llvm-readelf
STRIP = llvm-strip
else
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
-AR = $(CROSS_COMPILE)ar
+CC = $(CCACHE) $(CROSS_COMPILE)gcc
+LD = $(CCACHE) $(CROSS_COMPILE)ld
+AR = $(CCACHE) $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP = $(CROSS_COMPILE)objdump
+OBJCOPY = $(CCACHE) $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CCACHE) $(CROSS_COMPILE)objdump
READELF = $(CROSS_COMPILE)readelf
STRIP = $(CROSS_COMPILE)strip
endif
--
2.37.2

View File

@@ -1,48 +0,0 @@
From f1e398602b989ac197cdd0fda4a7c4c323b03eb9 Mon Sep 17 00:00:00 2001
From: DozNaka <dozdguide@gmail.com>
Date: Mon, 11 Apr 2022 20:43:45 -0400
Subject: [PATCH] Makefile: Use CCACHE for faster compilation
---
Makefile | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index e8b8d5894..51e8aac6e 100644
--- a/Makefile
+++ b/Makefile
@@ -442,21 +442,21 @@ KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
# Make variables (CC, etc...)
CPP = $(CC) -E
ifneq ($(LLVM),)
-CC = clang
-LD = ld.lld
-AR = llvm-ar
+CC = $(CCACHE) clang
+LD = $(CCACHE) ld.lld
+AR = $(CCACHE) llvm-ar
NM = llvm-nm
-OBJCOPY = llvm-objcopy
-OBJDUMP = llvm-objdump
+OBJCOPY = $(CCACHE) llvm-objcopy
+OBJDUMP = $(CCACHE) llvm-objdump
READELF = llvm-readelf
STRIP = llvm-strip
else
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
-AR = $(CROSS_COMPILE)ar
+CC = $(CCACHE) $(CROSS_COMPILE)gcc
+LD = $(CCACHE) $(CROSS_COMPILE)ld
+AR = $(CCACHE) $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP = $(CROSS_COMPILE)objdump
+OBJCOPY = $(CCACHE) $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CCACHE) $(CROSS_COMPILE)objdump
READELF = $(CROSS_COMPILE)readelf
STRIP = $(CROSS_COMPILE)strip
endif
--
2.37.2

View File

@@ -1,64 +0,0 @@
#!/bin/bash
set -euo pipefail
build_from_image() {
export TITLE
TITLE=kernel-aarch64-${1//Image-/}
echo "[+] title: $TITLE"
export PATCH_LEVEL
PATCH_LEVEL=$(echo "$1" | awk -F_ '{ print $2}')
echo "[+] patch level: $PATCH_LEVEL"
echo '[+] Download prebuilt ramdisk'
GKI_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-"${PATCH_LEVEL}"_r1.zip
FALLBACK_URL=https://dl.google.com/android/gki/gki-certified-boot-android12-5.10-2023-01_r1.zip
status=$(curl -sL -w "%{http_code}" "$GKI_URL" -o /dev/null)
if [ "$status" = "200" ]; then
curl -Lo gki-kernel.zip "$GKI_URL"
else
echo "[+] $GKI_URL not found, using $FALLBACK_URL"
curl -Lo gki-kernel.zip "$FALLBACK_URL"
fi
unzip gki-kernel.zip && rm gki-kernel.zip
echo '[+] Unpack prebuilt boot.img'
BOOT_IMG=$(find . -maxdepth 1 -name "boot*.img")
$UNPACK_BOOTIMG --boot_img="$BOOT_IMG"
rm "$BOOT_IMG"
echo '[+] Building Image.gz'
$GZIP -n -k -f -9 Image >Image.gz
echo '[+] Building boot.img'
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Building boot-gz.img'
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Building boot-lz4.img'
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img --ramdisk out/ramdisk --os_version 12.0.0 --os_patch_level "${PATCH_LEVEL}"
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Compress images'
for image in boot*.img; do
$GZIP -n -f -9 "$image"
mv "$image".gz "${1//Image-/}"-"$image".gz
done
echo "[+] Images to upload"
find . -type f -name "*.gz"
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do
if [ -d "$dir" ]; then
echo "----- Building $dir -----"
cd "$dir"
build_from_image "$dir"
cd ..
fi
done

View File

@@ -1,43 +0,0 @@
#!/bin/bash
set -euo pipefail
build_from_image() {
export TITLE
TITLE=kernel-aarch64-${1//Image-/}
echo "[+] title: $TITLE"
echo '[+] Building Image.gz'
$GZIP -n -k -f -9 Image >Image.gz
echo '[+] Building boot.img'
$MKBOOTIMG --header_version 4 --kernel Image --output boot.img
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Building boot-gz.img'
$MKBOOTIMG --header_version 4 --kernel Image.gz --output boot-gz.img
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-gz.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Building boot-lz4.img'
$MKBOOTIMG --header_version 4 --kernel Image.lz4 --output boot-lz4.img
$AVBTOOL add_hash_footer --partition_name boot --partition_size $((64 * 1024 * 1024)) --image boot-lz4.img --algorithm SHA256_RSA2048 --key ../kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
echo '[+] Compress images'
for image in boot*.img; do
$GZIP -n -f -9 "$image"
mv "$image".gz "${1//Image-/}"-"$image".gz
done
echo '[+] Images to upload'
find . -type f -name "*.gz"
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do
if [ -d "$dir" ]; then
echo "----- Building $dir -----"
cd "$dir"
build_from_image "$dir"
cd ..
fi
done

View File

@@ -1,59 +0,0 @@
name: handle-add-device-issue
on:
issues:
types: [labeled]
jobs:
handle-add-device:
if: github.event.label.name == 'add-device'
runs-on: ubuntu-latest
env:
ISSUE_CONTENT: ${{ github.event.issue.body }}
steps:
- uses: actions/checkout@v4
- name: Parse issue body
id: handle-add-device
run: |
python3 scripts/add_device_handler.py website/docs/repos.json || true
- name: Commit
if: steps.handle-add-device.outputs.success == 'true'
run: |
git config --local user.name "GitHub Actions"
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add website/docs/repos.json
git commit -m "add device: ${{ steps.handle-add-device.outputs.device }}"
- name: Make pull request
if: steps.handle-add-device.outputs.success == 'true'
id: cpr
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
title: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
body: |
${{ steps.handle-add-device.outputs.device }} has been added to the website.
Related issue: ${{ github.event.issue.html_url }}
branch: "add-device-${{ github.event.issue.number }}"
labels: add-device
delete-branch: true
- name: Check outputs
if: ${{ steps.cpr.outputs.pull-request-number }}
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- uses: Kernel-SU/actions-comment-on-issue@master
if: ${{ steps.cpr.outputs.pull-request-number }}
with:
message: "Automatically created pull request: ${{ steps.cpr.outputs.pull-request-url }}"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: Kernel-SU/actions-comment-on-issue@master
if: steps.handle-add-device.outputs.success != 'true'
with:
message: "Cannot create pull request. Please check the issue content. Or you can create a pull request manually."
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: close issue
uses: peter-evans/close-issue@v1
with:
issue-number: ${{ github.event.issue.number }}
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,31 +0,0 @@
name: Build debug kernel
on:
workflow_dispatch:
jobs:
build-debug-kernel-a12:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.185
tag: android12-5.10-2023-09
os_patch_level: 2023-09
patch_path: "5.10"
debug: true
build-debug-kernel-a13:
strategy:
matrix:
include:
- version: "5.10"
sub_level: 187
os_patch_level: 2023-08
- version: "5.15"
sub_level: 119
os_patch_level: 2023-09
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
version_name: android13-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: true

View File

@@ -1,132 +0,0 @@
name: Build Kernel - Android 12
on:
push:
branches: ["main", "ci"]
paths:
- ".github/workflows/build-kernel-a12.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build_a12.sh"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-a12.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build-a12.sh"
- "kernel/**"
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request'
strategy:
matrix:
include:
- sub_level: 66
os_patch_level: 2022-01
- sub_level: 81
os_patch_level: 2022-03
- sub_level: 101
os_patch_level: 2022-05
- sub_level: 110
os_patch_level: 2022-07
- sub_level: 117
os_patch_level: 2022-09
- sub_level: 136
os_patch_level: 2022-11
- sub_level: 149
os_patch_level: 2023-01
- sub_level: 160
os_patch_level: 2023-03
- sub_level: 168
os_patch_level: 2023-05
- sub_level: 177
os_patch_level: 2023-07
- sub_level: 185
os_patch_level: 2023-09
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"
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@v3
- 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-2023
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==1.31.1
- 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: Bot session cache
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- 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@v3
with:
name: boot-images-android12
path: Image-android12*/*.img.gz
check-build-kernel:
if: github.event_name == 'pull_request'
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.177
tag: android12-5.10-2023-06
os_patch_level: 2023-06
patch_path: "5.10"

View File

@@ -1,164 +0,0 @@
name: Build Kernel - Android 13
on:
push:
branches: ["main", "ci"]
paths:
- ".github/workflows/build-kernel-a13.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build_a13.sh"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-a13.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build-a13.sh"
- "kernel/**"
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request'
strategy:
matrix:
include:
- version: "5.10"
sub_level: 107
os_patch_level: 2022-11
- version: "5.10"
sub_level: 149
os_patch_level: 2023-01
- version: "5.10"
sub_level: 157
os_patch_level: 2023-03
- version: "5.10"
sub_level: 168
os_patch_level: 2023-05
- version: "5.10"
sub_level: 177
os_patch_level: 2023-06
- version: "5.10"
sub_level: 186
os_patch_level: 2023-08
- version: "5.10"
sub_level: 186
os_patch_level: 2023-09
- version: "5.10"
sub_level: 189
os_patch_level: 2023-10
- version: "5.15"
sub_level: 41
os_patch_level: 2022-11
- version: "5.15"
sub_level: 74
os_patch_level: 2023-01
- version: "5.15"
sub_level: 78
os_patch_level: 2023-03
- version: "5.15"
sub_level: 94
os_patch_level: 2023-05
- version: "5.15"
sub_level: 104
os_patch_level: 2023-07
- version: "5.15"
sub_level: 119
os_patch_level: 2023-09
- version: "5.15"
sub_level: 123
os_patch_level: 2023-10
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 }}
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@v3
- 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-2023
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==1.31.1
- 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: Bot session cache
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- 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@v3
with:
name: boot-images-android13
path: Image-android13*/*.img.gz
check-build-kernel:
if: github.event_name == 'pull_request'
strategy:
matrix:
include:
- version: "5.10"
sub_level: 189
os_patch_level: 2023-10
- version: "5.15"
sub_level: 123
os_patch_level: 2023-10
uses: ./.github/workflows/gki-kernel.yml
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 }}

View File

@@ -1,122 +0,0 @@
name: Build Kernel - Android 14
on:
push:
branches: ["main", "ci"]
paths:
- ".github/workflows/build-kernel-a14.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build_a13.sh"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-a14.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build-a13.sh"
- "kernel/**"
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request'
strategy:
matrix:
include:
- version: "5.15"
sub_level: 110
os_patch_level: 2023-09
- version: "6.1"
sub_level: 25
os_patch_level: 2023-10
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 }}
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@v3
- 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-2023
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==1.31.1
- 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: Bot session cache
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- 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@v3
with:
name: boot-images-android14
path: Image-android14*/*.img.gz
check-build-kernel:
if: github.event_name == 'pull_request'
strategy:
matrix:
include:
- version: "5.15"
sub_level: 110
os_patch_level: 2023-09
uses: ./.github/workflows/gki-kernel.yml
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 }}

View File

@@ -1,147 +0,0 @@
name: Build Kernel - ChromeOS ARCVM
on:
push:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-arcvm.yml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-arcvm.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build:
strategy:
matrix:
arch: [x86_64]
version: ["5.10.178"]
include:
- arch: x86_64
git_tag: chromeos-5.10-arcvm
file_name: "bzImage"
name: Build ChromeOS ARCVM kernel
runs-on: ubuntu-20.04
env:
LTO: thin
ROOT_DIR: /
KERNEL_DIR: ${{ github.workspace }}/kernel
steps:
- name: Install Build Tools
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends bc \
bison build-essential ca-certificates flex git gnupg \
libelf-dev libssl-dev lsb-release software-properties-common wget \
libncurses-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu nuget gzip \
rsync python3 device-tree-compiler
sudo ln -s --force python3 /usr/bin/python
export LLVM_VERSION=12
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
rm ./llvm.sh
sudo ln -s --force /usr/bin/clang-$LLVM_VERSION /usr/bin/clang
sudo ln -s --force /usr/bin/ld.lld-$LLVM_VERSION /usr/bin/ld.lld
sudo ln -s --force /usr/bin/llvm-objdump-$LLVM_VERSION /usr/bin/llvm-objdump
sudo ln -s --force /usr/bin/llvm-ar-$LLVM_VERSION /usr/bin/llvm-ar
sudo ln -s --force /usr/bin/llvm-nm-$LLVM_VERSION /usr/bin/llvm-nm
sudo ln -s --force /usr/bin/llvm-strip-$LLVM_VERSION /usr/bin/llvm-strip
sudo ln -s --force /usr/bin/llvm-objcopy-$LLVM_VERSION /usr/bin/llvm-objcopy
sudo ln -s --force /usr/bin/llvm-readelf-$LLVM_VERSION /usr/bin/llvm-readelf
sudo ln -s --force /usr/bin/clang++-$LLVM_VERSION /usr/bin/clang++
- name: Checkout KernelSU
uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: Setup kernel source
run: git clone https://chromium.googlesource.com/chromiumos/third_party/kernel.git -b ${{ matrix.git_tag }} --depth=1
- name: Setup KernelSU
working-directory: kernel
run: |
echo "[+] KernelSU setup"
KERNEL_ROOT=$GITHUB_WORKSPACE/kernel
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.10/*.patch
echo "[+] Patch script/setlocalversion"
sed -i 's/-dirty//g' $KERNEL_ROOT/scripts/setlocalversion
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: Build Kernel
working-directory: kernel
run: |
set -a && . build.config.gki.x86_64; set +a
export DEFCONFIG=x86_64_arcvm_defconfig
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
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} mrproper
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} ${DEFCONFIG} < /dev/null
scripts/config --file .config -e LTO_CLANG -d LTO_NONE -e LTO_CLANG_THIN -d LTO_CLANG_FULL -e THINLTO
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} -j$(nproc) bzImage modules prepare-objtool
echo "file_path=${PWD}/arch/x86/boot/bzImage" >> $GITHUB_ENV
- name: Upload kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
uses: actions/upload-artifact@v3
with:
name: kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
path: "${{ env.file_path }}"
- name: Bot session cache
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Post to Telegram
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
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 }}
run: |
TITLE=kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
echo "[+] title: $TITLE"
export TITLE
export VERSION="${{ env.kernelsu_version }}"
echo "[+] Compress images"
gzip -n -f -9 "${{ env.file_path }}"
echo "[+] Image to upload"
ls -l "${{ env.file_path }}.gz"
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
pip3 install telethon==1.31.1
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
fi

View File

@@ -1,141 +0,0 @@
name: Build Kernel - WSA
on:
push:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build:
strategy:
matrix:
arch: [x86_64, arm64]
version: ["5.15.94.2", "5.15.104.1", "5.15.104.2", "5.15.104.3", "5.15.104.4"]
name: Build WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
runs-on: ubuntu-20.04
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_HARDLINK: "true"
steps:
- name: Install Build Tools
uses: awalsh128/cache-apt-pkgs-action@v1
with:
packages: bc bison build-essential flex libelf-dev binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu gzip ccache
version: 1.0
- name: Cache LLVM
id: cache-llvm
uses: actions/cache@v3
with:
path: ./llvm
key: llvm-12.0.1
- name: Setup LLVM
uses: KyleMayes/install-llvm-action@v1
with:
version: "12.0.1"
force-version: true
ubuntu-version: "16.04"
cached: ${{ steps.cache-llvm.outputs.cache-hit }}
- name: Checkout KernelSU
uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: Setup kernel source
uses: actions/checkout@v4
with:
repository: microsoft/WSA-Linux-Kernel
ref: android-lts/latte-2/${{ matrix.version }}
path: WSA-Linux-Kernel
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: WSA-Kernel-${{ matrix.version }}-${{ matrix.arch }}
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
max-size: 2G
- name: Setup KernelSU
working-directory: WSA-Linux-Kernel
run: |
echo "[+] KernelSU setup"
KERNEL_ROOT=$GITHUB_WORKSPACE/WSA-Linux-Kernel
echo "[+] KERNEL_ROOT: $KERNEL_ROOT"
echo "[+] Copy KernelSU driver to $KERNEL_ROOT/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $KERNEL_ROOT/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch
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: Build Kernel
working-directory: WSA-Linux-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
declare -A ARCH_MAP=(["x86_64"]="x64" ["arm64"]="arm64")
cp configs/wsa/config-wsa-${ARCH_MAP[${{ matrix.arch }}]} .config
make olddefconfig
declare -A FILE_NAME=(["x86_64"]="bzImage" ["arm64"]="Image")
make -j`nproc` LLVM=1 ARCH=${{ matrix.arch }} $(if [ "${{ matrix.arch }}" == "arm64" ]; then echo CROSS_COMPILE=aarch64-linux-gnu; fi) ${FILE_NAME[${{ matrix.arch }}]} CCACHE="/usr/bin/ccache"
declare -A ARCH_MAP_FILE=(["x86_64"]="x86" ["arm64"]="arm64")
echo "file_path=WSA-Linux-Kernel/arch/${ARCH_MAP_FILE[${{ matrix.arch }}]}/boot/${FILE_NAME[${{ matrix.arch }}]}" >> $GITHUB_ENV
- name: Upload kernel-${{ matrix.arch }}-${{ matrix.version }}
uses: actions/upload-artifact@v3
with:
name: kernel-WSA-${{ matrix.arch }}-${{ matrix.version }}
path: "${{ env.file_path }}"
- name: Bot session cache
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Post to Telegram
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref_type == 'tag'
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 }}
run: |
TITLE=kernel-${{ matrix.arch }}-WSA-${{ matrix.version }}
echo "[+] title: $TITLE"
export TITLE
export VERSION="${{ env.kernelsu_version }}"
echo "[+] Compress images"
gzip -n -f -9 "${{ env.file_path }}"
echo "[+] Image to upload"
ls -l "${{ env.file_path }}.gz"
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
pip3 install telethon==1.31.1
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
fi

86
.github/workflows/build-kernel.yml vendored Normal file
View File

@@ -0,0 +1,86 @@
name: Build Kernel
on:
push:
branches: [ "main" ]
paths:
- 'kernel/**'
pull_request:
branches: [ "main" ]
paths:
- 'kernel/**'
jobs:
build:
strategy:
matrix:
include:
- version: android12-5.10-81
tag: android12-5.10-2022-03
os_version: 12.0.0
os_patch_level: 2022-03
- version: android12-5.10-101
tag: android12-5.10-2022-05
os_version: 12.0.0
os_patch_level: 2022-05
- version: android12-5.10-110
tag: android12-5.10-2022-07
os_version: 12.0.0
os_patch_level: 2022-07
- version: android12-5.10-136
tag: android12-5.10-2022-11
os_version: 12.0.0
os_patch_level: 2022-11
name: Build aarch64-${{ matrix.version }}
runs-on: ubuntu-latest
steps:
- name: Download kernel source
run: |
git clone https://gerrit.googlesource.com/git-repo
mkdir android-kernel && cd android-kernel
../git-repo/repo init -u https://android.googlesource.com/kernel/manifest -b common-${{ matrix.tag }}
../git-repo/repo sync
curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -
curl -Lo gki-kernel.zip https://dl.google.com/android/gki/gki-certified-boot-${{ matrix.tag }}_r1.zip
unzip gki-kernel.zip
tools/mkbootimg/unpack_bootimg.py --boot_img=$(find . -maxdepth 1 -name "*.img")
- name: Build boot.img
working-directory: android-kernel
run: BUILD_BOOT_IMG=1 SKIP_VENDOR_BOOT=1 KERNEL_BINARY=Image GKI_RAMDISK_PREBUILT_BINARY=out/ramdisk AVB_SIGN_BOOT_IMG=1 AVB_BOOT_PARTITION_SIZE=$((64*1024*1024)) AVB_BOOT_ALGORITHM=SHA256_RSA2048 AVB_BOOT_KEY=prebuilts/kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem BOOT_IMAGE_HEADER_VERSION=4 LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
- name: Build boot-lz4.img
working-directory: android-kernel
run: |
tools/mkbootimg/mkbootimg.py --header_version 4 --kernel ./out/android12-5.10/dist/Image.lz4 --ramdisk out/ramdisk --output ./out/android12-5.10/dist/boot-lz4.img --os_version ${{ matrix.os_version }} --os_patch_level ${{ matrix.os_patch_level }}
./build/build-tools/path/linux-x86/avbtool add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image out/android12-5.10/dist/boot-lz4.img --algorithm SHA256_RSA2048 --key ./prebuilts/kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
- name: Build boot-gz.img
working-directory: android-kernel
run: |
cat out/android12-5.10/dist/Image | ./prebuilts/build-tools/path/linux-x86/gzip -n -f -9 > out/android12-5.10/dist/Image.gz
tools/mkbootimg/mkbootimg.py --header_version 4 --kernel ./out/android12-5.10/dist/Image.gz --ramdisk out/ramdisk --output ./out/android12-5.10/dist/boot-gz.img --os_version ${{ matrix.os_version }} --os_patch_level ${{ matrix.os_patch_level }}
./build/build-tools/path/linux-x86/avbtool add_hash_footer --partition_name boot --partition_size $((64*1024*1024)) --image out/android12-5.10/dist/boot-gz.img --algorithm SHA256_RSA2048 --key ./prebuilts/kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
- name: Upload Image.gz
uses: actions/upload-artifact@v3
with:
name: kernel-aarch64-${{ matrix.version }}-Image.gz
path: android-kernel/out/*/dist/Image.gz
- name: Upload boot.img
uses: actions/upload-artifact@v3
with:
name: kernel-aarch64-${{ matrix.version }}-boot.img
path: android-kernel/out/*/dist/boot.img
- name: Upload boot-lz4.img
uses: actions/upload-artifact@v3
with:
name: kernel-aarch64-${{ matrix.version }}-boot-lz4.img
path: android-kernel/out/*/dist/boot-lz4.img
- name: Upload boot-gz.img
uses: actions/upload-artifact@v3
with:
name: kernel-aarch64-${{ matrix.version }}-boot-gz.img
path: android-kernel/out/*/dist/boot-gz.img

View File

@@ -1,25 +0,0 @@
name: Build KSUD
on:
push:
branches: [ "main", "ci" ]
paths:
- '.github/workflows/build-ksud.yml'
- '.github/workflows/ksud.yml'
- 'userspace/ksud/**'
pull_request:
branches: [ "main" ]
paths:
- '.github/workflows/build-ksud.yml'
- '.github/workflows/ksud.yml'
- 'userspace/ksud/**'
jobs:
build:
strategy:
matrix:
include:
- target: aarch64-linux-android
- target: x86_64-linux-android
- target: x86_64-pc-windows-gnu # only for build
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}

View File

@@ -1,129 +1,44 @@
name: Build Manager
on:
push:
branches: [ "main" ]
paths:
- '.github/workflows/build-manager.yml'
paths:
- 'manager/**'
- 'userspace/ksud/**'
pull_request:
branches: [ "main" ]
paths:
paths:
- 'manager/**'
workflow_call:
jobs:
build-ksud:
strategy:
matrix:
include:
- target: aarch64-linux-android
- target: x86_64-linux-android
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
build-manager:
needs: build-ksud
build:
runs-on: ubuntu-latest
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_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}' >> gradle.properties
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> gradle.properties
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> gradle.properties
echo KEYSTORE_FILE='../key.jks' >> gradle.properties
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
fi
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
- name: Download arm64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-aarch64-linux-android
path: .
- name: Download x86_64 ksud
uses: actions/download-artifact@v3
with:
name: ksud-x86_64-linux-android
path: .
- name: Copy ksud to app jniLibs
run: |
mkdir -p app/src/main/jniLibs/arm64-v8a
mkdir -p app/src/main/jniLibs/x86_64
cp -f ../aarch64-linux-android/release/ksud ../manager/app/src/main/jniLibs/arm64-v8a/libksud.so
cp -f ../x86_64-linux-android/release/ksud ../manager/app/src/main/jniLibs/x86_64/libksud.so
- name: Build with Gradle
run: |
echo 'org.gradle.parallel=true' >> gradle.properties
echo 'org.gradle.vfs.watch=true' >> gradle.properties
echo 'org.gradle.jvmargs=-Xmx2048m' >> gradle.properties
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@v3
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Bot session cache
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
id: bot_session_cache
uses: actions/cache@v3
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: ${{ 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 }}
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")
pip3 install telethon==1.31.1
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
fi
- uses: actions/checkout@v3
- name: set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: gradle
- name: Extract keystore
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
run: |
if [ ! -z "${{ secrets.KEYSTORE }}" ]; then
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}' >> sign.properties
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> sign.properties
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> sign.properties
echo KEYSTORE_FILE='../key.jks' >> sign.properties
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
fi
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Upload build artifact
uses: actions/upload-artifact@v2
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk

View File

@@ -1,64 +0,0 @@
name: Build SU
on:
push:
branches: [ "main", "ci" ]
paths:
- '.github/workflows/build-su.yml'
- 'userspace/su/**'
- 'scripts/ksubot.py'
pull_request:
branches: [ "main" ]
paths:
- 'userspace/su/**'
jobs:
build-su:
name: Build userspace su
runs-on: ubuntu-latest
steps:
- 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
- uses: nttld/setup-ndk@v1
with:
ndk-version: r25c
- name: Build su
working-directory: ./userspace/su
run: ndk-build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3
with:
name: su
path: ./userspace/su/libs
- name: Bot session cache
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
id: bot_session_cache
uses: actions/cache@v3
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: ${{ 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 }}
TITLE: SU
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
export VERSION=$(git rev-list --count HEAD)
pip3 install telethon==1.31.1
mv ./userspace/su/libs/arm64-v8a/su su-arm64
mv ./userspace/su/libs/x86_64/su su-x86_64
python3 scripts/ksubot.py su-arm64 su-x86_64
fi

28
.github/workflows/build-userspace.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Build Userspace
on:
push:
branches: [ "main" ]
paths:
- 'userspace/**'
pull_request:
branches: [ "main" ]
paths:
- 'userspace/**'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: nttld/setup-ndk@v1
with:
ndk-version: r25b
local-cache: true
- name: Build with NDK
working-directory: ./userspace
run: ndk-build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3
with:
name: su
path: ./userspace/libs

View File

@@ -1,37 +0,0 @@
name: Clippy check
on:
push:
branches:
- main
paths:
- '.github/workflows/clippy.yml'
- 'userspace/ksud/**'
pull_request:
branches:
- main
paths:
- '.github/workflows/clippy.yml'
- 'userspace/ksud/**'
env:
RUSTFLAGS: '-Dwarnings'
jobs:
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
- run: rustup default 1.67.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
- name: Install cross
run: cargo install cross
- name: Run clippy
run: |
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

View File

@@ -1,67 +0,0 @@
name: Deploy Website
on:
push:
branches:
- main
- website
paths:
- '.github/workflows/deploy-website.yml'
- 'website/**'
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: pages
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./website
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: yarn # or pnpm / yarn
cache-dependency-path: website/yarn.lock
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build with VitePress
run: |
yarn docs:build
touch docs/.vitepress/dist/.nojekyll
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: website/docs/.vitepress/dist
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
name: Deploy
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2

View File

@@ -1,203 +0,0 @@
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: true
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
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-latest
env:
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
CCACHE_NOHASHDIR: "true"
CCACHE_HARDLINK: "true"
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 -b common-${{ inputs.tag }} --repo-rev=v2.16
REMOTE_BRANCH=$(git ls-remote https://android.googlesource.com/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
grep -q "kernelsu" $DRIVER_MAKEFILE || echo "obj-y += kernelsu/" >> $DRIVER_MAKEFILE
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"
echo "ccflags-y += -DCONFIG_KSU_DEBUG" >> $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.2
with:
key: gki-kernel-aarch64-${{ inputs.version_name }}
max-size: 2G
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
- 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 boot.img
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
CCACHE="/usr/bin/ccache" LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
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
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/
- name: Upload Image and Image.gz
uses: actions/upload-artifact@v3
with:
name: Image-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
path: ./output/*
- name: Upload AnyKernel3
uses: actions/upload-artifact@v3
with:
name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
path: ./AnyKernel3/*

View File

@@ -1,36 +0,0 @@
name: Build ksud
on:
workflow_call:
inputs:
target:
required: true
type: string
use_cache:
required: false
type: boolean
default: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
- run: rustup default 1.67.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: userspace/ksud
cache-targets: false
- name: Install cross
run: cargo install cross
- name: Build ksud
run: cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml
- name: Upload ksud artifact
uses: actions/upload-artifact@v3
with:
name: ksud-${{ inputs.target }}
path: userspace/ksud/target/**/release/ksud

View File

@@ -1,77 +0,0 @@
name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
jobs:
build-manager:
uses: ./.github/workflows/build-manager.yml
secrets: inherit
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-wsa-kernel:
uses: ./.github/workflows/build-kernel-wsa.yml
secrets: inherit
build-arcvm-kernel:
uses: ./.github/workflows/build-kernel-arcvm.yml
secrets: inherit
release:
needs:
- build-manager
- build-a12-kernel
- build-a13-kernel
- build-a14-kernel
- build-wsa-kernel
- build-arcvm-kernel
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Zip AnyKernel3
run: |
for dir in AnyKernel3-*; do
if [ -d "$dir" ]; then
echo "----- Zip $dir -----"
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
fi
done
- name: Zip WSA kernel
run: |
for dir in kernel-WSA-*; do
if [ -d "$dir" ]; then
echo "------ Zip $dir ----------"
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
fi
done
- name: Zip ChromeOS ARCVM kernel
run: |
for dir in kernel-ARCVM-*; do
if [ -d "$dir" ]; then
echo "------ Zip $dir ----------"
(cd $dir && zip -r9 "$dir".zip ./* -x .git .gitignore ./*.zip && mv *.zip ..)
fi
done
- name: Display structure of downloaded files
run: ls -R
- name: release
uses: softprops/action-gh-release@v1
with:
files: |
manager/*.apk
AnyKernel3-*.zip
boot-images-*/Image-*/*.img.gz
kernel-WSA*.zip
kernel-ARCVM*.zip

View File

@@ -1,33 +0,0 @@
name: Rustfmt check
on:
push:
branches:
- 'main'
paths:
- '.github/workflows/rustfmt.yml'
- 'userspace/ksud/**'
pull_request:
branches:
- 'main'
paths:
- '.github/workflows/rustfmt.yml'
- 'userspace/ksud/**'
permissions:
checks: write
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- uses: LoliGothick/rustfmt-check@master
with:
token: ${{ github.token }}
working-directory: userspace/ksud

View File

@@ -1,27 +0,0 @@
name: ShellCheck
on:
push:
branches:
- 'main'
paths:
- '.github/workflows/shellcheck.yml'
- '**/*.sh'
pull_request:
branches:
- 'main'
paths:
- '.github/workflows/shellcheck.yml'
- '**/*.sh'
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@2.0.0
with:
ignore_names: gradlew
ignore_paths: ./userspace/ksud/src/installer.sh

2
.gitignore vendored
View File

@@ -1,2 +0,0 @@
.idea
.vscode

31
README.md Normal file
View File

@@ -0,0 +1,31 @@
# KernelSU
A Kernel based root solution for Android GKI.
## Usage
1. Flash a custom kernel with KernelSU, you can build it yourself or use prebuilt boot.img.
2. Install Manager App and enjoy :)
## Build
### Build GKI Kernel
1. Download the GKI source first, you can refer the [GKI build instruction](https://source.android.com/docs/setup/build/building-kernels)
2. cd `<GKI kernel source dir>`
3. `curl -LSs "https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh" | bash -`
4. Build the kernel.
### Build the Manager App
Just open Android Studio and import the project.
## License
[GPL-3](http://www.gnu.org/copyleft/gpl.html)
## Credits
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)
- [genuine](https://github.com/brevent/genuine/)
- [Diamorphine](https://github.com/m0nad/Diamorphine)

View File

@@ -1,7 +0,0 @@
# Reporting Security Issues
The KernelSU team and community take security bugs in KernelSU seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/tiann/KernelSU/security/advisories/new) tab, or you can mailto [weishu](mailto:twsxtd@gmail.com) directly.
The KernelSU team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.

View File

@@ -1,46 +0,0 @@
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
A Kernel-based root solution for Android devices.
## Features
1. Kernel-based `su` and root access management.
2. Module system based on overlayfs.
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Lock up the root power in a cage.
## Compatibility State
KernelSU officially supports Android GKI 2.0 devices (kernel 5.10+). Older kernels (4.14+) are also compatible, but the kernel will have to be built manually.
With this, WSA, ChromeOS, and container-based Android are all supported.
Currently, only `arm64-v8a` and `x86_64` are supported.
## Usage
- [Installation Instruction](https://kernelsu.org/guide/installation.html)
- [How to build?](https://kernelsu.org/guide/how-to-build.html)
- [Official Website](https://kernelsu.org/)
## Translation
To help translate KernelSU or improve existing translations, please use [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR of Manager's translation is no longer accepted, because it will conflict with Weblate.
## Discussion
- Telegram: [@KernelSU](https://t.me/KernelSU)
## License
- Files under the `kernel` directory are [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- All other parts except the `kernel` directory are [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Credits
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): the KernelSU idea.
- [Magisk](https://github.com/topjohnwu/Magisk): the powerful root tool.
- [genuine](https://github.com/brevent/genuine/): apk v2 signature validation.
- [Diamorphine](https://github.com/m0nad/Diamorphine): some rootkit skills.

View File

@@ -1,44 +0,0 @@
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
一个 Android 上基于内核的 root 方案。
## 特性
- 基于内核的 su 和权限管理。
- 基于 overlayfs 的模块系统。
- [App Profile](https://kernelsu.org/guide/app-profile.html): 把 Root 权限关进笼子里。
## 兼容状态
KernelSU 官方支持 GKI 2.0 的设备内核版本5.10以上旧内核也是兼容的最低4.14+),不过需要自己编译内核。
WSA, ChromeOS 和运行在容器上的 Android 也可以与 KernelSU 一起工作。
目前支持架构 : `arm64-v8a``x86_64`
## 使用方法
- [安装教程](https://kernelsu.org/zh_CN/guide/installation.html)
- [如何构建?](https://kernelsu.org/zh_CN/guide/how-to-build.html)
## 参与翻译
要将 KernelSU 翻译成您的语言,或完善现有的翻译,请使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。
## 讨论
- Telegram: [@KernelSU](https://t.me/KernelSU)
## 许可证
- 目录 `kernel` 下所有文件为 [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目录的其他部分均为 [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## 鸣谢
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的灵感。
- [Magisk](https://github.com/topjohnwu/Magisk):强大的 root 工具箱。
- [genuine](https://github.com/brevent/genuine/)apk v2 签名验证。
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。

View File

@@ -1,47 +0,0 @@
[ 🇬🇧 English](README.md) | 🇪🇸 **Español** | [🇨🇳 简体中文](README_CN.md) | [🇹🇼 繁體中文](README_TW.md) | [ 🇯🇵 日本語](README_JP.md) | [🇵🇱 Polski](README_PL.md) | [🇧🇷 Portuguese-Brazil](README_PT-BR.md) | [🇹🇷 Türkçe](README_TR.md) | [🇷🇺Русский](README_RU.md) | [🇻🇳Tiếng Việt](README_VI.md) | [ɪᴅ indonesia](README_ID.md) | [עברית](README_iw.md) | [🇮🇳हिंदी](README_IN.md)
<div style="display: flex; align-items: center;">
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="">
<div style="margin-left: 20px;">
<span style="font-size: large; "><b>KernelSU</b></span>
<br>
<span style="font-size: medium; "><i>Una solución root basada en el kernel para dispositivos Android.</i></span>
</div>
</div>
## 🚀 Características
**1.** Binario `su` basado en el kernel y gestión de acceso root.<br/>
**2.** Sistema de módulos basado en **OverlayFS**.
## ✅ Estado de compatibilidad
**KernelSU** soporta de forma oficial dispositivos Android con **GKI 2.0** (a partir de la versión **5.10** del kernel). Los kernels antiguos (a partir de la versión **4.14**) también son compatibles, pero necesitas compilarlos por tu cuenta.
El **Subsistema de Windows para Android (WSA)** e implementaciones de Android basadas en contenedores, como **Waydroid**, también deberían funcionar con **KernelSU** integrado.
Actualmente se soportan las siguientes **ABIs**: `arm64-v8a`; `x86_64`.
## 📖 Uso
[¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
## 🔨 Compilación
[¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
## 💬 Discusión
- Telegram: [@KernelSU](https://t.me/KernelSU)
## ⚖️ Licencia
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Todas las demás partes, a excepción del directorio `kernel`, están licenciados bajo [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html).
## 👥 Créditos
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de **KernelSU**.
- [genuine](https://github.com/brevent/genuine/): la validación del **esquema de firmas APK v2**.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algunas habilidades de rootkit.
- [Magisk](https://github.com/topjohnwu/Magisk): la implementación de la **política de SELinux (SEPolicy)**.

View File

@@ -1,45 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portugis-Brasil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | **Indonesia** | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
Solusi root berbasis Kernel untuk perangkat Android.
## Fitur
1. Manajemen akses root dan `su` berbasis kernel.
2. Sistem modul berdasarkan overlayfs.
3. [Profil Aplikasi](https://kernelsu.org/guide/app-profile.html): Kunci daya root di dalam sangkar.
## Status Kompatibilitas
KernelSU secara resmi mendukung perangkat Android GKI 2.0 (dengan kernel 5.10+), kernel lama (4.14+) juga kompatibel, tetapi Anda perlu membuat kernel sendiri.
WSA, ChromeOS, dan Android berbasis wadah juga dapat bekerja dengan KernelSU terintegrasi.
Dan ABI yang didukung saat ini adalah: `arm64-v8a` dan `x86_64`
## Penggunaan
- [Petunjuk Instalasi](https://kernelsu.org/guide/installation.html)
- [Bagaimana cara membuat?](https://kernelsu.org/guide/how-to-build.html)
- [Situs Web Resmi](https://kernelsu.org/)
## Terjemahan
Untuk menerjemahkan KernelSU ke dalam bahasa Anda atau menyempurnakan terjemahan yang sudah ada, harap gunakan [Weblat](https://hosted.weblate.org/engage/kernelsu/).
## Diskusi
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Lisensi
- File di bawah direktori `kernel` adalah [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Kredit
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ide KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): alat root yang ampuh.
- [genuine](https://github.com/brevent/genuine/): validasi tanda tangan apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): beberapa keterampilan rootkit.

View File

@@ -1,51 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | **हिंदी**
<div style="display: flex; align-items: center;">
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="">
<div style="margin-left: 20px;">
<span style="font-size: large; "><b>KernelSU</b></span>
<br>
<span style="font-size: medium; "><i>Android उपकरणों के लिए कर्नेल-आधारित रूट समाधान।</i></span>
</div>
</div>
## विशेषताएँ
1. कर्नेल-आधारित `su` और रूट एक्सेस प्रबंधन।
2. Overlayfs पर आधारित मॉड्यूल प्रणाली।
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Root शक्ति को पिंजरे में बंद कर दो।
## अनुकूलता अवस्था
KernelSU आधिकारिक तौर पर Android GKI 2.0 डिवाइस (कर्नेल 5.10+) का समर्थन करता है। पुराने कर्नेल (4.14+) भी संगत हैं, लेकिन कर्नेल को मैन्युअल रूप से बनाना होगा।
इसके साथ, WSA, ChromeOS और कंटेनर-आधारित Android सभी समर्थित हैं।
वर्तमान में, केवल `arm64-v8a` और `x86_64` समर्थित हैं।
## प्रयोग
- [स्थापना निर्देश](https://kernelsu.org/guide/installation.html)
- [कैसे बनाना है ?](https://kernelsu.org/guide/how-to-build.html)
- [आधिकारिक वेबसाइट](https://kernelsu.org/)
## अनुवाद करना
KernelSU का अनुवाद करने या मौजूदा अनुवादों को बेहतर बनाने में सहायता के लिए, कृपया इसका उपयोग करें [Weblate](https://hosted.weblate.org/engage/kernelsu/).
## बहस
- Telegram: [@KernelSU](https://t.me/KernelSU)
## लाइसेंस
- `Kernel` निर्देशिका के अंतर्गत फ़ाइलें हैं [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `Kernel` निर्देशिका को छोड़कर अन्य सभी भाग हैं [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## आभार सूची
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU विचार।
- [Magisk](https://github.com/topjohnwu/Magisk): शक्तिशाली root उपकरण।
- [genuine](https://github.com/brevent/genuine/): apk v2 हस्ताक्षर सत्यापन।
- [Diamorphine](https://github.com/m0nad/Diamorphine): कुछ रूटकिट कौशल।

View File

@@ -1,47 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
Android におけるカーネルベースの root ソリューションです。
## 特徴
1. カーネルベースの `su` と権限管理
2. OverlayFS に基づくモジュールシステム
3. [アプリのプロファイル](https://kernelsu.org/guide/app-profile.html): root の権限をケージ内に閉じ込めます。
## 対応状況
KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上を公式にサポートしています。古いカーネル4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。
WSA 、ChromeOS とコンテナ上で動作する Android でも KernelSU を統合して動かせます。
現在サポートしているアーキテクチャは `arm64-v8a` および `x86_64` です。
## 使用方法
- [インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html)
- [ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html)
- [公式サイト](https://kernelsu.org)
## 翻訳
KernelSU をあなたの言語に翻訳するか、既存の翻訳を改善するには、[Weblate](https://hosted.weblate.org/engage/kernelsu/) を使用してください。Manager翻訳した PR は、Weblate と競合するため受け入れられなくなりました。
## ディスカッション
- Telegram: [@KernelSU](https://t.me/KernelSU)
## ライセンス
- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## クレジット
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU のアイデア元
- [Magisk](https://github.com/topjohnwu/Magisk):強力な root ツール
- [genuine](https://github.com/brevent/genuine/)apk v2 の署名検証
- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル

View File

@@ -1,42 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | **Polski** | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
Rozwiązanie root oparte na jądrze dla urządzeń z systemem Android.
## Cechy
1. Oparte na jądrze `su` i zarządzanie dostępem roota.
2. System modułów oparty na overlayfs.
## Kompatybilność
KernelSU oficjalnie obsługuje urządzenia z Androidem GKI 2.0 (z jądrem 5.10+), starsze jądra (4.14+) są również kompatybilne, ale musisz sam skompilować jądro.
WSA i Android oparty na kontenerach również powinny działać ze zintegrowanym KernelSU.
Aktualnie obsługiwane ABI to : `arm64-v8a` i `x86_64`.
## Użycie
[Instalacja](https://kernelsu.org/guide/installation.html)
## Kompilacja
[Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
## Dyskusja
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Licencja
- Pliki w katalogu `kernel` są na licencji [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Podziękowania
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): pomysłodawca KernelSU.
- [genuine](https://github.com/brevent/genuine/): walidacja podpisu apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): cenna znajomość rootkitów.
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.

View File

@@ -1,46 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | **Português (Brasil)** | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
Uma solução root baseada em kernel para dispositivos Android.
## Características
1. `su` e gerenciamento de acesso root baseado em kernel.
2. Sistema modular baseado em overlayfs.
3. [Perfil do Aplicativo](https://kernelsu.org/pt_BR/guide/app-profile.html): Tranque o poder root em uma gaiola.
## Estado de Compatibilidade
O KernelSU oferece suporte oficial a dispositivos Android GKI 2.0 (kernel 5.10+). Kernels mais antigos (4.14+) também são compatíveis, mas o kernel terá que ser construído manualmente.
Com isso, WSA, ChromeOS e Android baseado em contêiner são todos suportados.
Atualmente, apenas `arm64-v8a` e `x86_64` são suportados.
## Uso
- [Instalação](https://kernelsu.org/pt_BR/guide/installation.html)
- [Como construir o KernelSU?](https://kernelsu.org/pt_BR/guide/how-to-build.html)
- [Site oficial](https://kernelsu.org/pt_BR/)
## Tradução
Para contribuir com a tradução do KernelSU ou aprimorar traduções existentes, por favor, utilize o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Gerenciador não são mais aceitos, pois podem entrar em conflito com o Weblate.
## Discussão
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Licença
- Os arquivos no diretório `kernel` são [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Todas as outras partes, exceto o diretório `kernel` são [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Créditos
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): a ideia do KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): a poderosa ferramenta root.
- [genuine](https://github.com/brevent/genuine/): validação de assinatura apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algumas habilidades de rootkit.

View File

@@ -1,42 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | **Русский** | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
Решение на основе ядра root для Android-устройств.
## Особенности
1. Управление `su` и root-доступом на основе ядра.
2. Система модулей на основе overlayfs.
## Совместимость
KernelSU официально поддерживает устройства на базе Android GKI 2.0 (с ядром 5.10+), старые ядра (4.14+) также совместимы, но для этого необходимо собрать ядро самостоятельно.
WSA и Android на основе контейнеров также должны работать с интегрированным KernelSU.
В настоящее время поддерживаются следующие ABI: `arm64-v8a` и `x86_64`.
## Использование
[Установка](https://kernelsu.org/ru_RU/guide/installation.html)
## Сборка
[Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
## Обсуждение
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Лицензия
- Файлы в директории `kernel` - [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Все остальные части, кроме директории `kernel` - [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Благодарности
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): идея KernelSU.
- [genuine](https://github.com/brevent/genuine/): проверка подписи apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): некоторые навыки руткита.
- [Magisk](https://github.com/topjohnwu/Magisk): реализация sepolicy.

View File

@@ -1,45 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | **Türkçe** | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
Android cihazlar için kernel tabanlı bir root çözümü.
## Özellikler
1. Kernel-tabanlı `su` ve root erişimi yönetimi.
2. Overlayfs'ye dayalı modül sistemi.
3. [Uygulama profili](https://kernelsu.org/guide/app-profile.html): Root gücünü bir kafese kapatın.
## Uyumluluk Durumu
KernelSU resmi olarak Android GKI 2.0 cihazlarını ( 5.10+ kernelli) destekler, eski kernellerle de (4.14+) uyumludur, ancak kerneli kendinizin inşaa etmesi gerekir.
WSA ve konteyner tabanlı Android'in de, KernelSU ile entegre olarak da çalışması gerekmektedir.
Ve desteklenen mevcut ABI'ler : `arm64-v8a` ve `x86_64`
## Kullanım
- [Yükleme](https://kernelsu.org/guide/installation.html)
- [Nasıl inşa edilir?](https://kernelsu.org/guide/how-to-build.html)
- [Resmi WEB sitesi](https://kernelsu.org/)
## Çeviri
KernelSU'yu kendi dilinize çevirmek veya varolan bir çeviriyi geliştirmek istiyorsanız, lütfen [Weblate](https://hosted.weblate.org/engage/kernelsu/)'i kullanın.
## Tartışma
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Lisans
- `kernel` klasöründeki dosyalar [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) lisansı altındadır.
- `kernel` klasörü dışındaki bütün diğer bölümler [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
## Krediler
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): KernelSU fikri.
- [Magisk](https://github.com/topjohnwu/Magisk): güçlü root aracı.
- [genuine](https://github.com/brevent/genuine/): apk v2 imza doğrulama.
- [Diamorphine](https://github.com/m0nad/Diamorphine): bazı rootkit becerileri.

View File

@@ -1,42 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
一個基於核心的 Android 裝置 Root 解決方案
## 功能
- 基於核心的 Su 和 Root 存取權管理。
- 基於 Overlayfs 的模組系統。
## 相容性狀態
KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+);舊版核心同樣相容 (最低 4.14+),但需要自行編譯核心。
WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
目前支援架構:`arm64-v8a``x86_64`
## 使用方法
[安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
## 建置
[如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
### 討論
- Telegram[@KernelSU](https://t.me/KernelSU)
## 授權
- 目錄 `kernel` 下所有檔案為 [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目錄的其他部分均為 [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## 致謝
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的靈感。
- [genuine](https://github.com/brevent/genuine/)apk v2 簽章驗證。
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 實作。

View File

@@ -1,45 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | **Tiếng Việt** | [Indonesia](README_ID.md) | [עברית](README_iw.md) | [हिंदी](README_IN.md)
# KernelSU
Giải pháp root thông qua thay đổi trên Kernel hệ điều hành cho các thiết bị Android.
## Tính năng
1. Hỗ trợ gói thực thi `su` và quản lý quyền root.
2. Hệ thống mô-đun thông qua overlayfs.
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Hạn chế quyền root của ứng dụng.
## Tình trạng tương thích
KernelSU chính thức hỗ trợ các thiết bị Android với kernel GKI 2.0 (phiên bản kernel 5.10+), các phiên bản kernel cũ hơn (4.14+) cũng tương thích, nhưng bạn cần phải tự biên dịch.
WSA, ChromeOS và Android dựa trên container(container-based) cũng được hỗ trợ bởi KernelSU.
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a``x86_64`
## Sử dụng
- [Hướng dẫn cài đặt](https://kernelsu.org/vi_VN/guide/installation.html)
- [Cách để build?](https://kernelsu.org/vi_VN/guide/how-to-build.html)
- [Website Chính Thức](https://kernelsu.org/vi_VN/)
## Hỗ trợ dịch
Nếu bạn muốn hỗ trợ dịch KernelSU sang một ngôn ngữ khác hoặc cải thiện các bản dịch trước, vui lòng sử dụng [Weblate](https://hosted.weblate.org/engage/kernelsu/).
## Thảo luận
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Giấy phép
- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- Tất cả các thành phần khác ngoại trừ thư mục `kernel` dùng giấy phép [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## Lời cảm ơn
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): ý tưởng cho KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): công cụ root mạnh mẽ.
- [genuine](https://github.com/brevent/genuine/): phương pháp xác thực apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit .

View File

@@ -1,45 +0,0 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [Polski](README_PL.md) | [Portuguese-Brazil](README_PT-BR.md) | [Türkçe](README_TR.md) | [Русский](README_RU.md) | [Tiếng Việt](README_VI.md) | [Indonesia](README_ID.md) | **עברית** | [हिंदी](README_IN.md)
# KernelSU
פתרון לניהול root מבוסס על Kernel עבור מכשירי Android.
## תכונות
1. ניהול root ו־`su` מבוססים על Kernel.
2. מערכת מודולים מבוססת overlayfs.
3. [פרופיל אפליקציה](https://kernelsu.org/guide/app-profile.html): נעילת גישת root בכלוב.
## מצב תאימות
KernelSU תומך במכשירי Android GKI 2.0 (kernel 5.10+) באופן רשמי. לליבות ישנות (4.14+) יש גם תאימות, אך יידרש לבנות את הליבה באופן ידני.
באמצעות זה, תמיכה זמינה גם ל-WSA, ChromeOS ומכשירי Android המבוססים על מיכלים.
כרגע, רק `arm64-v8a` ו־`x86_64` נתמכים.
## שימוש
- [הוראות התקנה](https://kernelsu.org/guide/installation.html)
- [איך לבנות?](https://kernelsu.org/guide/how-to-build.html)
- [האתר רשמי](https://kernelsu.org/)
## תרגום
כדי לעזור בתרגום של KernelSU או לשפר תרגומים קיימים, יש להשתמש ב-[Weblate](https://hosted.weblate.org/engage/kernelsu/).
## דיון
- Telegram: [@KernelSU](https://t.me/KernelSU)
## רשיון
- קבצים תחת הספרייה `kernel` מוגנים על פי [GPL-2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- כל החלקים האחרים, למעט הספרייה `kernel`, מוגנים על פי [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html)
## קרדיטים
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): הרעיון של KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): הכלי הסופר חזק לניהול root.
- [genuine](https://github.com/brevent/genuine/): אימות חתימת apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): כמה יכולות רוט.

View File

@@ -1,548 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 4.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
#AfterExternBlock: false # Unknown to clang-format-5.0
BeforeCatch: false
BeforeElse: false
IndentBraces: false
#SplitEmptyFunction: true # Unknown to clang-format-4.0
#SplitEmptyRecord: true # Unknown to clang-format-4.0
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
#FixNamespaceComments: false # Unknown to clang-format-4.0
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | sort | uniq
ForEachMacros:
- 'apei_estatus_for_each_section'
- 'ata_for_each_dev'
- 'ata_for_each_link'
- '__ata_qc_for_each'
- 'ata_qc_for_each'
- 'ata_qc_for_each_raw'
- 'ata_qc_for_each_with_internal'
- 'ax25_for_each'
- 'ax25_uid_for_each'
- '__bio_for_each_bvec'
- 'bio_for_each_bvec'
- 'bio_for_each_bvec_all'
- 'bio_for_each_integrity_vec'
- '__bio_for_each_segment'
- 'bio_for_each_segment'
- 'bio_for_each_segment_all'
- 'bio_list_for_each'
- 'bip_for_each_vec'
- 'bitmap_for_each_clear_region'
- 'bitmap_for_each_set_region'
- 'blkg_for_each_descendant_post'
- 'blkg_for_each_descendant_pre'
- 'blk_queue_for_each_rl'
- 'bond_for_each_slave'
- 'bond_for_each_slave_rcu'
- 'bpf_for_each_spilled_reg'
- 'btree_for_each_safe128'
- 'btree_for_each_safe32'
- 'btree_for_each_safe64'
- 'btree_for_each_safel'
- 'card_for_each_dev'
- 'cgroup_taskset_for_each'
- 'cgroup_taskset_for_each_leader'
- 'cpufreq_for_each_entry'
- 'cpufreq_for_each_entry_idx'
- 'cpufreq_for_each_valid_entry'
- 'cpufreq_for_each_valid_entry_idx'
- 'css_for_each_child'
- 'css_for_each_descendant_post'
- 'css_for_each_descendant_pre'
- 'device_for_each_child_node'
- 'dma_fence_chain_for_each'
- 'do_for_each_ftrace_op'
- 'drm_atomic_crtc_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane_state'
- 'drm_atomic_for_each_plane_damage'
- 'drm_client_for_each_connector_iter'
- 'drm_client_for_each_modeset'
- 'drm_connector_for_each_possible_encoder'
- 'drm_for_each_bridge_in_chain'
- 'drm_for_each_connector_iter'
- 'drm_for_each_crtc'
- 'drm_for_each_encoder'
- 'drm_for_each_encoder_mask'
- 'drm_for_each_fb'
- 'drm_for_each_legacy_plane'
- 'drm_for_each_plane'
- 'drm_for_each_plane_mask'
- 'drm_for_each_privobj'
- 'drm_mm_for_each_hole'
- 'drm_mm_for_each_node'
- 'drm_mm_for_each_node_in_range'
- 'drm_mm_for_each_node_safe'
- 'flow_action_for_each'
- 'for_each_active_dev_scope'
- 'for_each_active_drhd_unit'
- 'for_each_active_iommu'
- 'for_each_aggr_pgid'
- 'for_each_available_child_of_node'
- 'for_each_bio'
- 'for_each_board_func_rsrc'
- 'for_each_bvec'
- 'for_each_card_auxs'
- 'for_each_card_auxs_safe'
- 'for_each_card_components'
- 'for_each_card_dapms'
- 'for_each_card_pre_auxs'
- 'for_each_card_prelinks'
- 'for_each_card_rtds'
- 'for_each_card_rtds_safe'
- 'for_each_card_widgets'
- 'for_each_card_widgets_safe'
- 'for_each_cgroup_storage_type'
- 'for_each_child_of_node'
- 'for_each_clear_bit'
- 'for_each_clear_bit_from'
- 'for_each_cmsghdr'
- 'for_each_compatible_node'
- 'for_each_component_dais'
- 'for_each_component_dais_safe'
- 'for_each_comp_order'
- 'for_each_console'
- 'for_each_cpu'
- 'for_each_cpu_and'
- 'for_each_cpu_not'
- 'for_each_cpu_wrap'
- 'for_each_dapm_widgets'
- 'for_each_dev_addr'
- 'for_each_dev_scope'
- 'for_each_displayid_db'
- 'for_each_dma_cap_mask'
- 'for_each_dpcm_be'
- 'for_each_dpcm_be_rollback'
- 'for_each_dpcm_be_safe'
- 'for_each_dpcm_fe'
- 'for_each_drhd_unit'
- 'for_each_dss_dev'
- 'for_each_efi_memory_desc'
- 'for_each_efi_memory_desc_in_map'
- 'for_each_element'
- 'for_each_element_extid'
- 'for_each_element_id'
- 'for_each_endpoint_of_node'
- 'for_each_evictable_lru'
- 'for_each_fib6_node_rt_rcu'
- 'for_each_fib6_walker_rt'
- 'for_each_free_mem_pfn_range_in_zone'
- 'for_each_free_mem_pfn_range_in_zone_from'
- 'for_each_free_mem_range'
- 'for_each_free_mem_range_reverse'
- 'for_each_func_rsrc'
- 'for_each_hstate'
- 'for_each_if'
- 'for_each_iommu'
- 'for_each_ip_tunnel_rcu'
- 'for_each_irq_nr'
- 'for_each_link_codecs'
- 'for_each_link_cpus'
- 'for_each_link_platforms'
- 'for_each_lru'
- 'for_each_matching_node'
- 'for_each_matching_node_and_match'
- 'for_each_member'
- 'for_each_mem_region'
- 'for_each_memblock_type'
- 'for_each_memcg_cache_index'
- 'for_each_mem_pfn_range'
- '__for_each_mem_range'
- 'for_each_mem_range'
- '__for_each_mem_range_rev'
- 'for_each_mem_range_rev'
- 'for_each_migratetype_order'
- 'for_each_msi_entry'
- 'for_each_msi_entry_safe'
- 'for_each_net'
- 'for_each_net_continue_reverse'
- 'for_each_netdev'
- 'for_each_netdev_continue'
- 'for_each_netdev_continue_rcu'
- 'for_each_netdev_continue_reverse'
- 'for_each_netdev_feature'
- 'for_each_netdev_in_bond_rcu'
- 'for_each_netdev_rcu'
- 'for_each_netdev_reverse'
- 'for_each_netdev_safe'
- 'for_each_net_rcu'
- 'for_each_new_connector_in_state'
- 'for_each_new_crtc_in_state'
- 'for_each_new_mst_mgr_in_state'
- 'for_each_new_plane_in_state'
- 'for_each_new_private_obj_in_state'
- 'for_each_node'
- 'for_each_node_by_name'
- 'for_each_node_by_type'
- 'for_each_node_mask'
- 'for_each_node_state'
- 'for_each_node_with_cpus'
- 'for_each_node_with_property'
- 'for_each_nonreserved_multicast_dest_pgid'
- 'for_each_of_allnodes'
- 'for_each_of_allnodes_from'
- 'for_each_of_cpu_node'
- 'for_each_of_pci_range'
- 'for_each_old_connector_in_state'
- 'for_each_old_crtc_in_state'
- 'for_each_old_mst_mgr_in_state'
- 'for_each_oldnew_connector_in_state'
- 'for_each_oldnew_crtc_in_state'
- 'for_each_oldnew_mst_mgr_in_state'
- 'for_each_oldnew_plane_in_state'
- 'for_each_oldnew_plane_in_state_reverse'
- 'for_each_oldnew_private_obj_in_state'
- 'for_each_old_plane_in_state'
- 'for_each_old_private_obj_in_state'
- 'for_each_online_cpu'
- 'for_each_online_node'
- 'for_each_online_pgdat'
- 'for_each_pci_bridge'
- 'for_each_pci_dev'
- 'for_each_pci_msi_entry'
- 'for_each_pcm_streams'
- 'for_each_physmem_range'
- 'for_each_populated_zone'
- 'for_each_possible_cpu'
- 'for_each_present_cpu'
- 'for_each_prime_number'
- 'for_each_prime_number_from'
- 'for_each_process'
- 'for_each_process_thread'
- 'for_each_property_of_node'
- 'for_each_registered_fb'
- 'for_each_requested_gpio'
- 'for_each_requested_gpio_in_range'
- 'for_each_reserved_mem_range'
- 'for_each_reserved_mem_region'
- 'for_each_rtd_codec_dais'
- 'for_each_rtd_codec_dais_rollback'
- 'for_each_rtd_components'
- 'for_each_rtd_cpu_dais'
- 'for_each_rtd_cpu_dais_rollback'
- 'for_each_rtd_dais'
- 'for_each_set_bit'
- 'for_each_set_bit_from'
- 'for_each_set_clump8'
- 'for_each_sg'
- 'for_each_sg_dma_page'
- 'for_each_sg_page'
- 'for_each_sgtable_dma_page'
- 'for_each_sgtable_dma_sg'
- 'for_each_sgtable_page'
- 'for_each_sgtable_sg'
- 'for_each_sibling_event'
- 'for_each_subelement'
- 'for_each_subelement_extid'
- 'for_each_subelement_id'
- '__for_each_thread'
- 'for_each_thread'
- 'for_each_unicast_dest_pgid'
- 'for_each_wakeup_source'
- 'for_each_zone'
- 'for_each_zone_zonelist'
- 'for_each_zone_zonelist_nodemask'
- 'fwnode_for_each_available_child_node'
- 'fwnode_for_each_child_node'
- 'fwnode_graph_for_each_endpoint'
- 'gadget_for_each_ep'
- 'genradix_for_each'
- 'genradix_for_each_from'
- 'hash_for_each'
- 'hash_for_each_possible'
- 'hash_for_each_possible_rcu'
- 'hash_for_each_possible_rcu_notrace'
- 'hash_for_each_possible_safe'
- 'hash_for_each_rcu'
- 'hash_for_each_safe'
- 'hctx_for_each_ctx'
- 'hlist_bl_for_each_entry'
- 'hlist_bl_for_each_entry_rcu'
- 'hlist_bl_for_each_entry_safe'
- 'hlist_for_each'
- 'hlist_for_each_entry'
- 'hlist_for_each_entry_continue'
- 'hlist_for_each_entry_continue_rcu'
- 'hlist_for_each_entry_continue_rcu_bh'
- 'hlist_for_each_entry_from'
- 'hlist_for_each_entry_from_rcu'
- 'hlist_for_each_entry_rcu'
- 'hlist_for_each_entry_rcu_bh'
- 'hlist_for_each_entry_rcu_notrace'
- 'hlist_for_each_entry_safe'
- '__hlist_for_each_rcu'
- 'hlist_for_each_safe'
- 'hlist_nulls_for_each_entry'
- 'hlist_nulls_for_each_entry_from'
- 'hlist_nulls_for_each_entry_rcu'
- 'hlist_nulls_for_each_entry_safe'
- 'i3c_bus_for_each_i2cdev'
- 'i3c_bus_for_each_i3cdev'
- 'ide_host_for_each_port'
- 'ide_port_for_each_dev'
- 'ide_port_for_each_present_dev'
- 'idr_for_each_entry'
- 'idr_for_each_entry_continue'
- 'idr_for_each_entry_continue_ul'
- 'idr_for_each_entry_ul'
- 'in_dev_for_each_ifa_rcu'
- 'in_dev_for_each_ifa_rtnl'
- 'inet_bind_bucket_for_each'
- 'inet_lhash2_for_each_icsk_rcu'
- 'key_for_each'
- 'key_for_each_safe'
- 'klp_for_each_func'
- 'klp_for_each_func_safe'
- 'klp_for_each_func_static'
- 'klp_for_each_object'
- 'klp_for_each_object_safe'
- 'klp_for_each_object_static'
- 'kunit_suite_for_each_test_case'
- 'kvm_for_each_memslot'
- 'kvm_for_each_vcpu'
- 'list_for_each'
- 'list_for_each_codec'
- 'list_for_each_codec_safe'
- 'list_for_each_continue'
- 'list_for_each_entry'
- 'list_for_each_entry_continue'
- 'list_for_each_entry_continue_rcu'
- 'list_for_each_entry_continue_reverse'
- 'list_for_each_entry_from'
- 'list_for_each_entry_from_rcu'
- 'list_for_each_entry_from_reverse'
- 'list_for_each_entry_lockless'
- 'list_for_each_entry_rcu'
- 'list_for_each_entry_reverse'
- 'list_for_each_entry_safe'
- 'list_for_each_entry_safe_continue'
- 'list_for_each_entry_safe_from'
- 'list_for_each_entry_safe_reverse'
- 'list_for_each_prev'
- 'list_for_each_prev_safe'
- 'list_for_each_safe'
- 'llist_for_each'
- 'llist_for_each_entry'
- 'llist_for_each_entry_safe'
- 'llist_for_each_safe'
- 'mci_for_each_dimm'
- 'media_device_for_each_entity'
- 'media_device_for_each_intf'
- 'media_device_for_each_link'
- 'media_device_for_each_pad'
- 'nanddev_io_for_each_page'
- 'netdev_for_each_lower_dev'
- 'netdev_for_each_lower_private'
- 'netdev_for_each_lower_private_rcu'
- 'netdev_for_each_mc_addr'
- 'netdev_for_each_uc_addr'
- 'netdev_for_each_upper_dev_rcu'
- 'netdev_hw_addr_list_for_each'
- 'nft_rule_for_each_expr'
- 'nla_for_each_attr'
- 'nla_for_each_nested'
- 'nlmsg_for_each_attr'
- 'nlmsg_for_each_msg'
- 'nr_neigh_for_each'
- 'nr_neigh_for_each_safe'
- 'nr_node_for_each'
- 'nr_node_for_each_safe'
- 'of_for_each_phandle'
- 'of_property_for_each_string'
- 'of_property_for_each_u32'
- 'pci_bus_for_each_resource'
- 'pcm_for_each_format'
- 'ping_portaddr_for_each_entry'
- 'plist_for_each'
- 'plist_for_each_continue'
- 'plist_for_each_entry'
- 'plist_for_each_entry_continue'
- 'plist_for_each_entry_safe'
- 'plist_for_each_safe'
- 'pnp_for_each_card'
- 'pnp_for_each_dev'
- 'protocol_for_each_card'
- 'protocol_for_each_dev'
- 'queue_for_each_hw_ctx'
- 'radix_tree_for_each_slot'
- 'radix_tree_for_each_tagged'
- 'rbtree_postorder_for_each_entry_safe'
- 'rdma_for_each_block'
- 'rdma_for_each_port'
- 'rdma_umem_for_each_dma_block'
- 'resource_list_for_each_entry'
- 'resource_list_for_each_entry_safe'
- 'rhl_for_each_entry_rcu'
- 'rhl_for_each_rcu'
- 'rht_for_each'
- 'rht_for_each_entry'
- 'rht_for_each_entry_from'
- 'rht_for_each_entry_rcu'
- 'rht_for_each_entry_rcu_from'
- 'rht_for_each_entry_safe'
- 'rht_for_each_from'
- 'rht_for_each_rcu'
- 'rht_for_each_rcu_from'
- '__rq_for_each_bio'
- 'rq_for_each_bvec'
- 'rq_for_each_segment'
- 'scsi_for_each_prot_sg'
- 'scsi_for_each_sg'
- 'sctp_for_each_hentry'
- 'sctp_skb_for_each'
- 'shdma_for_each_chan'
- '__shost_for_each_device'
- 'shost_for_each_device'
- 'sk_for_each'
- 'sk_for_each_bound'
- 'sk_for_each_entry_offset_rcu'
- 'sk_for_each_from'
- 'sk_for_each_rcu'
- 'sk_for_each_safe'
- 'sk_nulls_for_each'
- 'sk_nulls_for_each_from'
- 'sk_nulls_for_each_rcu'
- 'snd_array_for_each'
- 'snd_pcm_group_for_each_entry'
- 'snd_soc_dapm_widget_for_each_path'
- 'snd_soc_dapm_widget_for_each_path_safe'
- 'snd_soc_dapm_widget_for_each_sink_path'
- 'snd_soc_dapm_widget_for_each_source_path'
- 'tb_property_for_each'
- 'tcf_exts_for_each_action'
- 'udp_portaddr_for_each_entry'
- 'udp_portaddr_for_each_entry_rcu'
- 'usb_hub_for_each_child'
- 'v4l2_device_for_each_subdev'
- 'v4l2_m2m_for_each_dst_buf'
- 'v4l2_m2m_for_each_dst_buf_safe'
- 'v4l2_m2m_for_each_src_buf'
- 'v4l2_m2m_for_each_src_buf_safe'
- 'virtio_device_for_each_vq'
- 'while_for_each_ftrace_op'
- 'xa_for_each'
- 'xa_for_each_marked'
- 'xa_for_each_range'
- 'xa_for_each_start'
- 'xas_for_each'
- 'xas_for_each_conflict'
- 'xas_for_each_marked'
- 'xbc_array_for_each_value'
- 'xbc_for_each_key_value'
- 'xbc_node_for_each_array_value'
- 'xbc_node_for_each_child'
- 'xbc_node_for_each_key_value'
- 'zorro_for_each_dev'
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
#SortUsingDeclarations: false # Unknown to clang-format-4.0
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

View File

@@ -1,4 +0,0 @@
Diagnostics:
UnusedIncludes: Strict
ClangTidy:
Remove: bugprone-sizeof-expression

View File

@@ -1,17 +1,6 @@
menu "KernelSU"
config KSU
tristate "KernelSU function support"
depends on OVERLAY_FS
tristate "KernelSU module"
default y
depends on KPROBES
help
Enable kernel-level root privileges on Android System.
config KSU_DEBUG
bool "KernelSU debug mode"
depends on KSU
default n
help
Enable KernelSU debug mode
endmenu
This is the KSU privilege driver for android system.

View File

@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -1,47 +1,15 @@
obj-y += ksu.o
obj-y += allowlist.o
kernelsu-objs := apk_sign.o
obj-y += kernelsu.o
obj-y += apk_sign.o
obj-y += module_api.o
obj-y += sucompat.o
obj-y += uid_observer.o
obj-y += manager.o
obj-y += core_hook.o
obj-y += ksud.o
obj-y += embed_ksud.o
obj-y += kernel_compat.o
obj-y += selinux/
obj-y += ksufs/
# .git is a text file while the module is imported by 'git submodule add'.
ifeq ($(shell test -e $(srctree)/$(src)/../.git; echo $$?),0)
KSU_GIT_VERSION := $(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin git rev-list --count HEAD)
# ksu_version: major * 10000 + git version + 200 for historical reasons
$(eval KSU_VERSION=$(shell expr 10000 + $(KSU_GIT_VERSION) + 200))
$(info -- KernelSU version: $(KSU_VERSION))
ccflags-y += -DKSU_VERSION=$(KSU_VERSION)
else # If there is no .git file, the default version will be passed.
$(warning "KSU_GIT_VERSION not defined! It is better to make KernelSU a git submodule!")
ccflags-y += -DKSU_VERSION=16
endif
obj-y += libsepol/
ifndef KSU_EXPECTED_SIZE
KSU_EXPECTED_SIZE := 0x033b
endif
ifndef KSU_EXPECTED_HASH
KSU_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6
endif
ifdef KSU_MANAGER_PACKAGE
ccflags-y += -DKSU_MANAGER_PACKAGE=\"$(KSU_MANAGER_PACKAGE)\"
$(info -- KernelSU Manager package name: $(KSU_MANAGER_PACKAGE))
endif
$(info -- KernelSU Manager signature size: $(KSU_EXPECTED_SIZE))
$(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\"
EXPECTED_SIZE := 0x033b
EXPECTED_HASH := 0xb0b91415
ccflags-y += -DEXPECTED_SIZE=$(EXPECTED_SIZE)
ccflags-y += -DEXPECTED_HASH=$(EXPECTED_HASH)
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement
ccflags-y += -Wno-macro-redefined -Wno-declaration-after-statement

View File

@@ -1,517 +1,262 @@
#include "ksu.h"
#include "linux/compiler.h"
#include "linux/fs.h"
#include "linux/gfp.h"
#include "linux/kernel.h"
#include "linux/list.h"
#include "linux/printk.h"
#include "linux/slab.h"
#include "linux/types.h"
#include "linux/version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#include "linux/compiler_types.h"
#endif
#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/memory.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/uidgid.h>
#include "klog.h" // IWYU pragma: keep
#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/fs_struct.h>
#include <linux/namei.h>
#include <linux/rcupdate.h>
#include <linux/delay.h> // msleep
#include "klog.h"
#include "selinux/selinux.h"
#include "kernel_compat.h"
#include "allowlist.h"
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 3 // u32
#define KSU_APP_PROFILE_PRESERVE_UID 9999 // NOBODY_UID
#define KSU_DEFAULT_SELINUX_DOMAIN "u:r:su:s0"
static DEFINE_MUTEX(allowlist_mutex);
// default profiles, these may be used frequently, so we cache it
static struct root_profile default_root_profile;
static struct non_root_profile default_non_root_profile;
static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly __aligned(PAGE_SIZE);
static int allow_list_pointer __read_mostly = 0;
static void remove_uid_from_arr(uid_t uid)
{
int *temp_arr;
int i, j;
if (allow_list_pointer == 0)
return;
temp_arr = kmalloc(sizeof(allow_list_arr), GFP_KERNEL);
if (temp_arr == NULL) {
pr_err("%s: unable to allocate memory\n", __func__);
return;
}
for (i = j = 0; i < allow_list_pointer; i++) {
if (allow_list_arr[i] == uid)
continue;
temp_arr[j++] = allow_list_arr[i];
}
allow_list_pointer = j;
for (; j < ARRAY_SIZE(allow_list_arr); j++)
temp_arr[j] = -1;
memcpy(&allow_list_arr, temp_arr, PAGE_SIZE);
kfree(temp_arr);
}
static void init_default_profiles()
{
default_root_profile.uid = 0;
default_root_profile.gid = 0;
default_root_profile.groups_count = 1;
default_root_profile.groups[0] = 0;
memset(&default_root_profile.capabilities, 0xff,
sizeof(default_root_profile.capabilities));
default_root_profile.namespaces = 0;
strcpy(default_root_profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
// This means that we will umount modules by default!
default_non_root_profile.umount_modules = true;
}
#define FILE_FORMAT_VERSION 1 // u32
struct perm_data {
struct list_head list;
struct app_profile profile;
struct list_head list;
uid_t uid;
bool allow;
};
static struct list_head allow_list;
static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly __aligned(PAGE_SIZE);
#define BITMAP_UID_MAX ((sizeof(allow_list_bitmap) * BITS_PER_BYTE) - 1)
#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
#define KERNEL_SU_ALLOWLIST "/data/adb/.ksu_allowlist"
static struct workqueue_struct *ksu_workqueue;
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)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
pr_info("ksu_show_allow_list\n");
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("uid :%d, allow: %d\n", p->profile.current_uid,
p->profile.allow_su);
}
struct file *permissive_filp_open(const char * path, int flags, umode_t mode) {
struct file* fp;
// fixme: u:r:kernel:s0 don't have permission to write /data/adb...
bool enforcing = getenforce();
if (enforcing) setenforce(false);
fp = filp_open(path, flags, mode);
if (enforcing) setenforce(true);
return fp;
}
#ifdef CONFIG_KSU_DEBUG
static void ksu_grant_root_to_shell()
{
struct app_profile profile = {
.allow_su = true,
.current_uid = 2000,
};
strcpy(profile.key, "com.android.shell");
strcpy(profile.rp_config.profile.selinux_domain, KSU_DEFAULT_SELINUX_DOMAIN);
ksu_set_app_profile(&profile, false);
bool ksu_allow_uid(uid_t uid, bool allow) {
// find the node first!
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool result = false;
list_for_each(pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("ksu_allow_uid :%d, allow: %d\n", p->uid, p->allow);
if (uid == p->uid) {
p->allow = allow;
result = true;
goto exit;
}
}
// not found, alloc a new node!
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
if (!p) {
pr_err("alloc allow node failed.\n");
return false;
}
p->uid = uid;
p->allow = allow;
list_add_tail(&p->list, &allow_list);
result = true;
exit:
persistent_allow_list();
return result;
}
bool ksu_is_allow_uid(uid_t uid) {
struct perm_data *p = NULL;
struct list_head *pos = NULL;
if (uid == 0) {
// already root
return true;
}
list_for_each(pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
// pr_info("is_allow_uid uid :%d, allow: %d\n", p->uid, p->allow);
if (uid == p->uid) {
return p->allow;
}
}
return false;
}
bool ksu_get_allow_list(int *array, int *length, bool allow) {
struct perm_data *p = NULL;
struct list_head *pos = NULL;
int i = 0;
list_for_each(pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
if (p->allow == allow) {
array[i++] = p->uid;
}
}
*length = i;
return true;
}
void do_persistent_allow_list(struct work_struct *work) {
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
struct perm_data *p = NULL;
struct list_head *pos = NULL;
loff_t off = 0;
struct file *fp = permissive_filp_open(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
if (IS_ERR(fp)) {
pr_err("save_allow_list creat file failed: %d\n", PTR_ERR(fp));
return;
}
// store magic and version
if (kernel_write(fp, &magic, sizeof(magic), &off) != sizeof(magic)) {
pr_err("save_allow_list write magic failed.\n");
goto exit;
}
if (kernel_write(fp, &version, sizeof(version), &off) != sizeof(version)) {
pr_err("save_allow_list write version failed.\n");
goto exit;
}
list_for_each(pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("save allow list uid :%d, allow: %d\n", p->uid, p->allow);
kernel_write(fp, &p->uid, sizeof(p->uid), &off);
kernel_write(fp, &p->allow, sizeof(p->allow), &off);
}
exit:
filp_close(fp, 0);
}
void do_load_allow_list(struct work_struct *work) {
loff_t off = 0;
ssize_t ret = 0;
struct file *fp = NULL;
u32 magic;
u32 version;
fp = filp_open("/data/adb/", O_RDONLY, 0);
if (IS_ERR(fp)) {
int errno = PTR_ERR(fp);
pr_err("load_allow_list open '/data/adb': %d\n", PTR_ERR(fp));
if (errno == -ENOENT) {
msleep(2000);
queue_work(ksu_workqueue, &ksu_load_work);
return;
} else {
pr_info("load_allow list dir exist now!");
}
} else {
filp_close(fp, 0);
}
#if 1
// load allowlist now!
fp = permissive_filp_open(KERNEL_SU_ALLOWLIST, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("load_allow_list open file failed: %d\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) {
u32 uid;
bool allow = false;
ret = kernel_read(fp, &uid, sizeof(uid), &off);
if (ret <= 0) {
pr_info("load_allow_list read err: %d\n", ret);
break;
}
ret = kernel_read(fp, &allow, sizeof(allow), &off);
pr_info("load_allow_uid: %d, allow: %d\n", uid, allow);
ksu_allow_uid(uid, allow);
}
exit:
filp_close(fp, 0);
#endif
bool ksu_get_app_profile(struct app_profile *profile)
{
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);
bool uid_match = profile->current_uid == p->profile.current_uid;
if (uid_match) {
// found it, override it with ours
memcpy(profile, &p->profile, sizeof(*profile));
found = true;
goto exit;
}
}
exit:
return found;
}
static inline bool forbid_system_uid(uid_t uid) {
#define SHELL_UID 2000
#define SYSTEM_UID 1000
return uid < SHELL_UID && uid != SYSTEM_UID;
}
static bool profile_valid(struct app_profile *profile)
{
if (!profile) {
return false;
}
if (forbid_system_uid(profile->current_uid)) {
pr_err("uid lower than 2000 is unsupported: %d\n", profile->current_uid);
return false;
}
if (profile->version < KSU_APP_PROFILE_VER) {
pr_info("Unsupported profile version: %d\n", profile->version);
return false;
}
if (profile->allow_su) {
if (profile->rp_config.profile.groups_count > KSU_MAX_GROUPS) {
return false;
}
if (strlen(profile->rp_config.profile.selinux_domain) == 0) {
return false;
}
}
return true;
}
bool ksu_set_app_profile(struct app_profile *profile, bool persist)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
bool result = false;
if (!profile_valid(profile)) {
pr_err("Failed to set app profile: invalid profile!\n");
return false;
}
list_for_each (pos, &allow_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
if (profile->current_uid == p->profile.current_uid &&
!strcmp(profile->key, p->profile.key)) {
// found it, just override it all!
memcpy(&p->profile, profile, sizeof(*profile));
result = true;
goto out;
}
}
// not found, alloc a new node!
p = (struct perm_data *)kmalloc(sizeof(struct perm_data), GFP_KERNEL);
if (!p) {
pr_err("ksu_set_app_profile alloc failed\n");
return false;
}
memcpy(&p->profile, profile, sizeof(*profile));
if (profile->allow_su) {
pr_info("set root profile, key: %s, uid: %d, gid: %d, context: %s\n",
profile->key, profile->current_uid,
profile->rp_config.profile.gid,
profile->rp_config.profile.selinux_domain);
} else {
pr_info("set app profile, key: %s, uid: %d, umount modules: %d\n",
profile->key, profile->current_uid,
profile->nrp_config.profile.umount_modules);
}
list_add_tail(&p->list, &allow_list);
out:
if (profile->current_uid <= BITMAP_UID_MAX) {
if (profile->allow_su)
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] |= 1 << (profile->current_uid % BITS_PER_BYTE);
else
allow_list_bitmap[profile->current_uid / BITS_PER_BYTE] &= ~(1 << (profile->current_uid % BITS_PER_BYTE));
} else {
if (profile->allow_su) {
/*
* 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");
WARN_ON(1);
return false;
}
allow_list_arr[allow_list_pointer++] = profile->current_uid;
} else {
remove_uid_from_arr(profile->current_uid);
}
}
result = true;
// check if the default profiles is changed, cache it to a single struct to accelerate access.
if (unlikely(!strcmp(profile->key, "$"))) {
// set default non root profile
memcpy(&default_non_root_profile, &profile->nrp_config.profile,
sizeof(default_non_root_profile));
}
if (unlikely(!strcmp(profile->key, "#"))) {
// set default root profile
memcpy(&default_root_profile, &profile->rp_config.profile,
sizeof(default_root_profile));
}
if (persist)
persistent_allow_list();
return result;
}
bool __ksu_is_allow_uid(uid_t uid)
{
int i;
if (unlikely(uid == 0)) {
// already root, but only allow our domain.
return is_ksu_domain();
}
if (forbid_system_uid(uid)) {
// do not bother going through the list if it's system
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;
}
}
return false;
}
bool ksu_uid_should_umount(uid_t uid)
{
struct app_profile profile = { .current_uid = uid };
bool found = ksu_get_app_profile(&profile);
if (!found) {
// no app profile found, it must be non root app
return default_non_root_profile.umount_modules;
}
if (profile.allow_su) {
// if found and it is granted to su, we shouldn't umount for it
return false;
} else {
// found an app profile
if (profile.nrp_config.use_default) {
return default_non_root_profile.umount_modules;
} else {
return profile.nrp_config.profile.umount_modules;
}
}
}
struct root_profile *ksu_get_root_profile(uid_t uid)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
if (uid == p->profile.current_uid && p->profile.allow_su) {
if (!p->profile.rp_config.use_default) {
return &p->profile.rp_config.profile;
}
}
}
// use default profile
return &default_root_profile;
}
bool ksu_get_allow_list(int *array, int *length, bool allow)
{
struct perm_data *p = NULL;
struct list_head *pos = NULL;
int i = 0;
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
// pr_info("get_allow_list uid: %d allow: %d\n", p->uid, p->allow);
if (p->profile.allow_su == allow) {
array[i++] = p->profile.current_uid;
}
}
*length = i;
return true;
}
void do_save_allow_list(struct work_struct *work)
{
u32 magic = FILE_MAGIC;
u32 version = FILE_FORMAT_VERSION;
struct perm_data *p = NULL;
struct list_head *pos = NULL;
loff_t off = 0;
struct file *fp =
ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT, 0644);
if (IS_ERR(fp)) {
pr_err("save_allow_list create file failed: %ld\n", PTR_ERR(fp));
return;
}
// store magic and version
if (ksu_kernel_write_compat(fp, &magic, sizeof(magic), &off) !=
sizeof(magic)) {
pr_err("save_allow_list write magic failed.\n");
goto exit;
}
if (ksu_kernel_write_compat(fp, &version, sizeof(version), &off) !=
sizeof(version)) {
pr_err("save_allow_list write version failed.\n");
goto exit;
}
list_for_each (pos, &allow_list) {
p = list_entry(pos, struct perm_data, list);
pr_info("save allow list, name: %s uid :%d, allow: %d\n",
p->profile.key, p->profile.current_uid,
p->profile.allow_su);
ksu_kernel_write_compat(fp, &p->profile, sizeof(p->profile),
&off);
}
exit:
filp_close(fp, 0);
}
void do_load_allow_list(struct work_struct *work)
{
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 = ksu_filp_open_compat(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 (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);
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();
}
static int init_work(void) {
ksu_workqueue = alloc_workqueue("kernelsu_work_queue", 0, 0);
INIT_WORK(&ksu_save_work, do_persistent_allow_list);
INIT_WORK(&ksu_load_work, do_load_allow_list);
return 0;
}
// make sure allow list works cross boot
bool persistent_allow_list(void)
{
return ksu_queue_work(&ksu_save_work);
bool persistent_allow_list(void) {
queue_work(ksu_workqueue, &ksu_save_work);
return true;
}
bool ksu_load_allow_list(void)
{
return ksu_queue_work(&ksu_load_work);
bool ksu_load_allow_list(void) {
queue_work(ksu_workqueue, &ksu_load_work);
return true;
}
void ksu_allowlist_init(void)
{
int i;
bool ksu_allowlist_init(void) {
BUILD_BUG_ON(sizeof(allow_list_bitmap) != PAGE_SIZE);
BUILD_BUG_ON(sizeof(allow_list_arr) != PAGE_SIZE);
INIT_LIST_HEAD(&allow_list);
for (i = 0; i < ARRAY_SIZE(allow_list_arr); i++)
allow_list_arr[i] = -1;
init_work();
INIT_LIST_HEAD(&allow_list);
// start load allow list, we load it before app_process exec now, refer: sucompat#execve_handler_pre
// ksu_load_allow_list();
INIT_WORK(&ksu_save_work, do_save_allow_list);
INIT_WORK(&ksu_load_work, do_load_allow_list);
init_default_profiles();
return true;
}
void ksu_allowlist_exit(void)
{
struct perm_data *np = NULL;
struct perm_data *n = NULL;
bool ksu_allowlist_exit(void) {
do_save_allow_list(NULL);
destroy_workqueue(ksu_workqueue);
// free allowlist
mutex_lock(&allowlist_mutex);
list_for_each_entry_safe (np, n, &allow_list, list) {
list_del(&np->list);
kfree(np);
}
mutex_unlock(&allowlist_mutex);
}
return true;
}

View File

@@ -1,27 +1,16 @@
#ifndef __KSU_H_ALLOWLIST
#define __KSU_H_ALLOWLIST
#include "linux/types.h"
#include "ksu.h"
bool ksu_allowlist_init();
void ksu_allowlist_init(void);
bool ksu_allowlist_exit();
void ksu_allowlist_exit(void);
bool ksu_is_allow_uid(uid_t uid);
bool ksu_allow_uid(uid_t uid, bool allow);
bool ksu_get_allow_list(int* array, int* length, bool allow);
bool ksu_load_allow_list(void);
void ksu_show_allow_list(void);
bool __ksu_is_allow_uid(uid_t uid);
#define ksu_is_allow_uid(uid) unlikely(__ksu_is_allow_uid(uid))
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);
bool ksu_get_app_profile(struct app_profile *);
bool ksu_set_app_profile(struct app_profile *, bool persist);
bool ksu_uid_should_umount(uid_t uid);
struct root_profile *ksu_get_root_profile(uid_t uid);
#endif
#endif

View File

@@ -1,335 +1,117 @@
#include "linux/err.h"
#include "linux/fs.h"
#include "linux/gfp.h"
#include "linux/kernel.h"
#include "linux/moduleparam.h"
#include <linux/fs.h>
#include "apk_sign.h"
#include "klog.h" // IWYU pragma: keep
#include "kernel_compat.h"
#include "crypto/hash.h"
#include "linux/slab.h"
#include "linux/version.h"
#include "klog.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
#include "crypto/sha2.h"
static int check_v2_signature(char* path, unsigned expected_size, unsigned expected_hash) {
unsigned char buffer[0x11] = {0};
u32 size4;
u64 size8, size_of_block;
loff_t pos;
int sign = -1;
struct file* fp = filp_open(path, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("open %s error.", path);
return PTR_ERR(fp);
}
sign = 1;
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
for (int i = 0;; ++i) {
unsigned short n;
pos = generic_file_llseek(fp, -i - 2, SEEK_END);
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;
// offset
kernel_read(fp, &size4, 0x4, &pos);
pos = size4 - 0x18;
kernel_read(fp, &size8, 0x8, &pos);
kernel_read(fp, buffer, 0x10, &pos);
if (strcmp((char *) buffer, "APK Sig Block 42")) {
goto clean;
}
pos = size4 - (size8 + 0x8);
kernel_read(fp, &size_of_block, 0x8, &pos);
if (size_of_block != size8) {
goto clean;
}
for (;;) {
uint32_t id;
uint32_t offset;
kernel_read(fp, &size8, 0x8, &pos); // sequence length
if (size8 == size_of_block) {
break;
}
kernel_read(fp, &id, 0x4, &pos); // id
offset = 4;
pr_info("id: 0x%08x\n", id);
if ((id ^ 0xdeadbeefu) == 0xafa439f5u || (id ^ 0xdeadbeefu) == 0x2efed62f) {
kernel_read(fp, &size4, 0x4, &pos); // signer-sequence length
kernel_read(fp, &size4, 0x4, &pos); // signer length
kernel_read(fp, &size4, 0x4, &pos); // signed data length
offset += 0x4 * 3;
kernel_read(fp, &size4, 0x4, &pos); // digests-sequence length
pos += size4;
offset += 0x4 + size4;
kernel_read(fp, &size4, 0x4, &pos); // certificates length
kernel_read(fp, &size4, 0x4, &pos); // certificate length
offset += 0x4 * 2;
#if 0
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
kernel_read(fp, &c, 0x1, &pos);
hash = 31 * hash + c;
}
offset += size4;
pr_info(" size: 0x%04x, hash: 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
#else
#include "crypto/sha.h"
if (size4 == expected_size) {
int hash = 1;
signed char c;
for (unsigned i = 0; i < size4; ++i) {
kernel_read(fp, &c, 0x1, &pos);
hash = 31 * hash + c;
}
offset += size4;
if ((((unsigned) hash) ^ 0x14131211u) == expected_hash) {
sign = 0;
break;
}
}
// don't try again.
break;
#endif
}
pos += (size8 - offset);
}
struct sdesc {
struct shash_desc shash;
char ctx[];
};
static struct sdesc *init_sdesc(struct crypto_shash *alg)
{
struct sdesc *sdesc;
int size;
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
sdesc = kmalloc(size, GFP_KERNEL);
if (!sdesc)
return ERR_PTR(-ENOMEM);
sdesc->shash.tfm = alg;
return sdesc;
}
static int calc_hash(struct crypto_shash *alg, const unsigned char *data,
unsigned int datalen, unsigned char *digest)
{
struct sdesc *sdesc;
int ret;
sdesc = init_sdesc(alg);
if (IS_ERR(sdesc)) {
pr_info("can't alloc sdesc\n");
return PTR_ERR(sdesc);
}
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
kfree(sdesc);
return ret;
}
static int ksu_sha256(const unsigned char *data, unsigned int datalen,
unsigned char *digest)
{
struct crypto_shash *alg;
char *hash_alg_name = "sha256";
int ret;
alg = crypto_alloc_shash(hash_alg_name, 0, 0);
if (IS_ERR(alg)) {
pr_info("can't alloc alg %s\n", hash_alg_name);
return PTR_ERR(alg);
}
ret = calc_hash(alg, data, datalen, digest);
crypto_free_shash(alg);
return ret;
}
static bool check_block(struct file *fp, u32 *size4, loff_t *pos, u32 *offset,
unsigned expected_size, const char *expected_sha256)
{
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer-sequence length
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signer length
ksu_kernel_read_compat(fp, size4, 0x4, pos); // signed data length
*offset += 0x4 * 3;
ksu_kernel_read_compat(fp, size4, 0x4, pos); // digests-sequence length
*pos += *size4;
*offset += 0x4 + *size4;
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificates length
ksu_kernel_read_compat(fp, size4, 0x4, pos); // certificate length
*offset += 0x4 * 2;
if (*size4 == expected_size) {
*offset += *size4;
#define CERT_MAX_LENGTH 1024
char cert[CERT_MAX_LENGTH];
if (*size4 > CERT_MAX_LENGTH) {
pr_info("cert length overlimit\n");
return false;
}
ksu_kernel_read_compat(fp, cert, *size4, pos);
unsigned char digest[SHA256_DIGEST_SIZE];
if (IS_ERR(ksu_sha256(cert, *size4, digest))) {
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\n", hash_str,
expected_sha256);
if (strcmp(expected_sha256, hash_str) == 0) {
return true;
}
}
return false;
}
struct zip_entry_header {
uint32_t signature;
uint16_t version;
uint16_t flags;
uint16_t compression;
uint16_t mod_time;
uint16_t mod_date;
uint32_t crc32;
uint32_t compressed_size;
uint32_t uncompressed_size;
uint16_t file_name_length;
uint16_t extra_field_length;
} __attribute__((packed));
// This is a necessary but not sufficient condition, but it is enough for us
static bool has_v1_signature_file(struct file *fp)
{
struct zip_entry_header header;
const char MANIFEST[] = "META-INF/MANIFEST.MF";
loff_t pos = 0;
while (ksu_kernel_read_compat(fp, &header,
sizeof(struct zip_entry_header), &pos) ==
sizeof(struct zip_entry_header)) {
if (header.signature != 0x04034b50) {
// ZIP magic: 'PK'
return false;
}
// Read the entry file name
if (header.file_name_length == sizeof(MANIFEST) - 1) {
char fileName[sizeof(MANIFEST)];
ksu_kernel_read_compat(fp, fileName,
header.file_name_length, &pos);
fileName[header.file_name_length] = '\0';
// Check if the entry matches META-INF/MANIFEST.MF
if (strncmp(MANIFEST, fileName, sizeof(MANIFEST) - 1) ==
0) {
return true;
}
} else {
// Skip the entry file name
pos += header.file_name_length;
}
// Skip to the next entry
pos += header.extra_field_length + header.compressed_size;
}
return false;
}
static __always_inline bool check_v2_signature(char *path,
unsigned expected_size,
const char *expected_sha256)
{
unsigned char buffer[0x11] = { 0 };
u32 size4;
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 i;
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("open %s error.\n", path);
return PTR_ERR(fp);
}
// disable inotify for this file
fp->f_mode |= FMODE_NONOTIFY;
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
for (i = 0;; ++i) {
unsigned short n;
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;
}
}
pos += 12;
// offset
ksu_kernel_read_compat(fp, &size4, 0x4, &pos);
pos = size4 - 0x18;
ksu_kernel_read_compat(fp, &size8, 0x8, &pos);
ksu_kernel_read_compat(fp, buffer, 0x10, &pos);
if (strcmp((char *)buffer, "APK Sig Block 42")) {
goto clean;
}
pos = size4 - (size8 + 0x8);
ksu_kernel_read_compat(fp, &size_of_block, 0x8, &pos);
if (size_of_block != size8) {
goto clean;
}
for (;;) {
uint32_t id;
uint32_t offset;
ksu_kernel_read_compat(fp, &size8, 0x8,
&pos); // sequence length
if (size8 == size_of_block) {
break;
}
ksu_kernel_read_compat(fp, &id, 0x4, &pos); // id
offset = 4;
pr_info("id: 0x%08x\n", id);
if (id == 0x7109871au) {
v2_signing_blocks++;
v2_signing_valid =
check_block(fp, &size4, &pos, &offset,
expected_size, expected_sha256);
} 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;
}
pos += (size8 - offset);
}
if (v2_signing_blocks != 1) {
pr_err("Unexpected v2 signature count: %d\n",
v2_signing_blocks);
v2_signing_valid = false;
}
if (v2_signing_valid) {
int has_v1_signing = has_v1_signature_file(fp);
if (has_v1_signing) {
pr_err("Unexpected v1 signature scheme found!\n");
filp_close(fp, 0);
return false;
}
}
clean:
filp_close(fp, 0);
filp_close(fp, 0);
if (v3_signing_exist || v3_1_signing_exist) {
pr_err("Unexpected v3 signature scheme found!\n");
return false;
}
return v2_signing_valid;
return sign;
}
#ifdef CONFIG_KSU_DEBUG
unsigned ksu_expected_size = EXPECTED_SIZE;
const char *ksu_expected_hash = EXPECTED_HASH;
#include "manager.h"
static int set_expected_size(const char *val, const struct kernel_param *kp)
{
int rv = param_set_uint(val, kp);
ksu_invalidate_manager_uid();
pr_info("ksu_expected_size set to %x\n", ksu_expected_size);
return rv;
}
static int set_expected_hash(const char *val, const struct kernel_param *kp)
{
pr_info("set_expected_hash: %s\n", val);
int rv = param_set_charp(val, kp);
ksu_invalidate_manager_uid();
pr_info("ksu_expected_hash set to %s\n", ksu_expected_hash);
return rv;
}
static struct kernel_param_ops expected_size_ops = {
.set = set_expected_size,
.get = param_get_uint,
};
static struct kernel_param_ops expected_hash_ops = {
.set = set_expected_hash,
.get = param_get_charp,
.free = param_free_charp,
};
module_param_cb(ksu_expected_size, &expected_size_ops, &ksu_expected_size,
S_IRUSR | S_IWUSR);
module_param_cb(ksu_expected_hash, &expected_hash_ops, &ksu_expected_hash,
S_IRUSR | S_IWUSR);
bool is_manager_apk(char *path)
{
return check_v2_signature(path, ksu_expected_size, ksu_expected_hash);
}
#else
bool is_manager_apk(char *path)
{
return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
}
#endif
int is_manager_apk(char* path) {
return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
}

View File

@@ -1,8 +1,7 @@
#ifndef __KSU_H_APK_V2_SIGN
#define __KSU_H_APK_V2_SIGN
#include "linux/types.h"
// return 0 if signature match
int is_manager_apk(char* path);
bool is_manager_apk(char *path);
#endif
#endif

View File

@@ -1,28 +1,21 @@
#ifndef __KSU_H_ARCH
#define __KSU_H_ARCH
#include "linux/version.h"
#if defined(__aarch64__)
#define __PT_PARM1_REG regs[0]
#define __PT_PARM2_REG regs[1]
#define __PT_PARM3_REG regs[2]
#define __PT_SYSCALL_PARM4_REG regs[3]
#define __PT_CCALL_PARM4_REG regs[3]
#define __PT_PARM4_REG regs[3]
#define __PT_PARM5_REG regs[4]
#define __PT_PARM6_REG regs[5]
#define __PT_RET_REG regs[30]
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
#define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */
#define __PT_RC_REG regs[0]
#define __PT_SP_REG sp
#define __PT_IP_REG pc
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
#define PRCTL_SYMBOL "__arm64_sys_prctl"
#else
#define PRCTL_SYMBOL "sys_prctl"
#endif
#elif defined(__x86_64__)
@@ -30,20 +23,16 @@
#define __PT_PARM2_REG si
#define __PT_PARM3_REG dx
/* syscall uses r10 for PARM4 */
#define __PT_SYSCALL_PARM4_REG r10
#define __PT_CCALL_PARM4_REG cx
#define __PT_PARM4_REG r10
// #define __PT_PARM4_REG cx
#define __PT_PARM5_REG r8
#define __PT_PARM6_REG r9
#define __PT_RET_REG sp
#define __PT_FP_REG bp
#define __PT_RC_REG ax
#define __PT_SP_REG sp
#define __PT_IP_REG ip
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
#define PRCTL_SYMBOL "__x64_sys_prctl"
#else
#define PRCTL_SYMBOL "sys_prctl"
#endif
#else
#error "Unsupported arch"
@@ -57,14 +46,13 @@
#define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG)
#define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG)
#define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG)
#define PT_REGS_SYSCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_SYSCALL_PARM4_REG)
#define PT_REGS_CCALL_PARM4(x) (__PT_REGS_CAST(x)->__PT_CCALL_PARM4_REG)
#define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG)
#define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG)
#define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG)
#define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG)
#define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG)
#define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG)
#define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG)
#define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG)
#endif
#endif

View File

@@ -1,720 +0,0 @@
#include "linux/capability.h"
#include "linux/cred.h"
#include "linux/dcache.h"
#include "linux/err.h"
#include "linux/init.h"
#include "linux/init_task.h"
#include "linux/kernel.h"
#include "linux/kprobes.h"
#include "linux/lsm_hooks.h"
#include "linux/nsproxy.h"
#include "linux/path.h"
#include "linux/printk.h"
#include "linux/uaccess.h"
#include "linux/uidgid.h"
#include "linux/version.h"
#include "linux/mount.h"
#include "linux/fs.h"
#include "linux/namei.h"
#include "linux/rcupdate.h"
#include "allowlist.h"
#include "arch.h"
#include "core_hook.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "ksud.h"
#include "manager.h"
#include "selinux/selinux.h"
#include "uid_observer.h"
#include "kernel_compat.h"
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
static inline bool is_allow_su()
{
if (is_manager()) {
// we are manager, allow!
return true;
}
return ksu_is_allow_uid(current_uid().val);
}
static inline bool is_isolated_uid(uid_t uid)
{
#define FIRST_ISOLATED_UID 99000
#define LAST_ISOLATED_UID 99999
#define FIRST_APP_ZYGOTE_ISOLATED_UID 90000
#define LAST_APP_ZYGOTE_ISOLATED_UID 98999
uid_t appid = uid % 100000;
return (appid >= FIRST_ISOLATED_UID && appid <= LAST_ISOLATED_UID) ||
(appid >= FIRST_APP_ZYGOTE_ISOLATED_UID &&
appid <= LAST_APP_ZYGOTE_ISOLATED_UID);
}
static struct group_info root_groups = { .usage = ATOMIC_INIT(2) };
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;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
group_info->gid[i] = kgid;
#else
GROUP_AT(group_info, i) = kgid;
#endif
}
groups_sort(group_info);
set_groups(cred, group_info);
}
void escape_to_root(void)
{
struct cred *cred;
cred = (struct cred *)__task_cred(current);
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
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;
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_inheritable, &profile->capabilities.effective,
sizeof(cred->cap_inheritable));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
memcpy(&cred->cap_ambient, &profile->capabilities.effective,
sizeof(cred->cap_ambient));
// disable seccomp
#if defined(CONFIG_GENERIC_ENTRY) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
current_thread_info()->syscall_work &= ~SYSCALL_WORK_SECCOMP;
#else
current_thread_info()->flags &= ~(TIF_SECCOMP | _TIF_SECCOMP);
#endif
#ifdef CONFIG_SECCOMP
current->seccomp.mode = 0;
current->seccomp.filter = NULL;
#else
#endif
setup_groups(profile, cred);
setup_selinux(profile->selinux_domain);
}
int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
{
if (!current->mm) {
// skip kernel threads
return 0;
}
if (current_uid().val != 1000) {
// skip non system uid
return 0;
}
if (!old_dentry || !new_dentry) {
return 0;
}
// /data/system/packages.list.tmp -> /data/system/packages.list
if (strcmp(new_dentry->d_iname, "packages.list")) {
return 0;
}
char path[128];
char *buf = dentry_path_raw(new_dentry, path, sizeof(path));
if (IS_ERR(buf)) {
pr_err("dentry_path_raw failed.\n");
return 0;
}
if (strcmp(buf, "/system/packages.list")) {
return 0;
}
pr_info("renameat: %s -> %s, new path: %s\n", old_dentry->d_iname,
new_dentry->d_iname, buf);
update_uid();
return 0;
}
int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
// if success, we modify the arg5 as result!
u32 *result = (u32 *)arg5;
u32 reply_ok = KERNEL_SU_OPTION;
if (KERNEL_SU_OPTION != option) {
return 0;
}
// always ignore isolated app uid
if (is_isolated_uid(current_uid().val)) {
return 0;
}
static uid_t last_failed_uid = -1;
if (last_failed_uid == current_uid().val) {
return 0;
}
// pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
if (arg2 == CMD_BECOME_MANAGER) {
// quick check
if (is_manager()) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("become_manager: prctl reply error\n");
}
return 0;
}
if (ksu_is_manager_uid_valid()) {
pr_info("manager already exist: %d\n",
ksu_get_manager_uid());
return 0;
}
// someone wants to be root manager, just check it!
// arg3 should be `/data/user/<userId>/<manager_package_name>`
char param[128];
if (ksu_strncpy_from_user_nofault(param, arg3, sizeof(param)) ==
-EFAULT) {
#ifdef CONFIG_KSU_DEBUG
pr_err("become_manager: copy param err\n");
#endif
return 0;
}
// for user 0, it is /data/data
// for user 999, it is /data/user/999
const char *prefix;
char prefixTmp[64];
int userId = current_uid().val / 100000;
if (userId == 0) {
prefix = "/data/data";
} else {
snprintf(prefixTmp, sizeof(prefixTmp), "/data/user/%d",
userId);
prefix = prefixTmp;
}
if (startswith(param, (char *)prefix) != 0) {
pr_info("become_manager: invalid param: %s\n", param);
return 0;
}
// stat the param, app must have permission to do this
// otherwise it may fake the path!
struct path path;
if (kern_path(param, LOOKUP_DIRECTORY, &path)) {
pr_err("become_manager: kern_path err\n");
return 0;
}
if (path.dentry->d_inode->i_uid.val != current_uid().val) {
pr_err("become_manager: path uid != current uid\n");
path_put(&path);
return 0;
}
char *pkg = param + strlen(prefix);
pr_info("become_manager: param pkg: %s\n", pkg);
bool success = become_manager(pkg);
if (success) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("become_manager: prctl reply error\n");
}
}
path_put(&path);
return 0;
}
if (arg2 == CMD_GRANT_ROOT) {
if (is_allow_su()) {
pr_info("allow root for: %d\n", current_uid().val);
escape_to_root();
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("grant_root: prctl reply error\n");
}
}
return 0;
}
// Both root manager and root processes should be allowed to get version
if (arg2 == CMD_GET_VERSION) {
if (is_manager() || 0 == current_uid().val) {
u32 version = KERNEL_SU_VERSION;
if (copy_to_user(arg3, &version, sizeof(version))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
}
return 0;
}
if (arg2 == CMD_REPORT_EVENT) {
if (0 != current_uid().val) {
return 0;
}
switch (arg3) {
case EVENT_POST_FS_DATA: {
static bool post_fs_data_lock = false;
if (!post_fs_data_lock) {
post_fs_data_lock = true;
pr_info("post-fs-data triggered\n");
on_post_fs_data();
}
break;
}
case EVENT_BOOT_COMPLETED: {
static bool boot_complete_lock = false;
if (!boot_complete_lock) {
boot_complete_lock = true;
pr_info("boot_complete triggered\n");
}
break;
}
default:
break;
}
return 0;
}
if (arg2 == CMD_SET_SEPOLICY) {
if (0 != current_uid().val) {
return 0;
}
if (!handle_sepolicy(arg3, arg4)) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("sepolicy: prctl reply error\n");
}
}
return 0;
}
if (arg2 == CMD_CHECK_SAFEMODE) {
if (!is_manager() && 0 != current_uid().val) {
return 0;
}
if (ksu_is_safe_mode()) {
pr_warn("safemode enabled!\n");
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("safemode: prctl reply error\n");
}
}
return 0;
}
if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) {
if (is_manager() || 0 == current_uid().val) {
u32 array[128];
u32 array_length;
bool success =
ksu_get_allow_list(array, &array_length,
arg2 == CMD_GET_ALLOW_LIST);
if (success) {
if (!copy_to_user(arg4, &array_length,
sizeof(array_length)) &&
!copy_to_user(arg3, array,
sizeof(u32) * array_length)) {
if (copy_to_user(result, &reply_ok,
sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n",
arg2);
}
} else {
pr_err("prctl copy allowlist error\n");
}
}
}
return 0;
}
if (arg2 == CMD_UID_GRANTED_ROOT || arg2 == CMD_UID_SHOULD_UMOUNT) {
if (is_manager() || 0 == current_uid().val) {
uid_t target_uid = (uid_t)arg3;
bool allow = false;
if (arg2 == CMD_UID_GRANTED_ROOT) {
allow = ksu_is_allow_uid(target_uid);
} else if (arg2 == CMD_UID_SHOULD_UMOUNT) {
allow = ksu_uid_should_umount(target_uid);
} else {
pr_err("unknown cmd: %lu\n", arg2);
}
if (!copy_to_user(arg4, &allow, sizeof(allow))) {
if (copy_to_user(result, &reply_ok,
sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n",
arg2);
}
} else {
pr_err("prctl copy err, cmd: %lu\n", arg2);
}
}
return 0;
}
// all other cmds are for 'root manager'
if (!is_manager()) {
last_failed_uid = current_uid().val;
return 0;
}
// we are already manager
if (arg2 == CMD_GET_APP_PROFILE) {
struct app_profile profile;
if (copy_from_user(&profile, arg3, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
bool success = ksu_get_app_profile(&profile);
if (success) {
if (copy_to_user(arg3, &profile, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
}
return 0;
}
if (arg2 == CMD_SET_APP_PROFILE) {
struct app_profile profile;
if (copy_from_user(&profile, arg3, sizeof(profile))) {
pr_err("copy profile failed\n");
return 0;
}
// todo: validate the params
if (ksu_set_app_profile(&profile, true)) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
}
return 0;
}
return 0;
}
static bool is_appuid(kuid_t uid)
{
#define PER_USER_RANGE 100000
#define FIRST_APPLICATION_UID 10000
#define LAST_APPLICATION_UID 19999
uid_t appid = uid.val % PER_USER_RANGE;
return appid >= FIRST_APPLICATION_UID && appid <= LAST_APPLICATION_UID;
}
static bool should_umount(struct path *path)
{
if (!path) {
return false;
}
if (current->nsproxy->mnt_ns == init_nsproxy.mnt_ns) {
pr_info("ignore global mnt namespace process: %d\n",
current_uid().val);
return false;
}
if (path->mnt && path->mnt->mnt_sb && path->mnt->mnt_sb->s_type) {
const char *fstype = path->mnt->mnt_sb->s_type->name;
return strcmp(fstype, "overlay") == 0;
}
return false;
}
static void ksu_umount_mnt(struct path *path, int flags)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
int err = path_umount(path, flags);
if (err) {
pr_info("umount %s failed: %d\n", path->dentry->d_iname, err);
}
#else
// TODO: umount for non GKI kernel
#endif
}
static void try_umount(const char *mnt, bool check_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.
return;
}
// we are only interest in some specific mounts
if (check_mnt && !should_umount(&path)) {
return;
}
ksu_umount_mnt(&path, flags);
}
int ksu_handle_setuid(struct cred *new, const struct cred *old)
{
if (!new || !old) {
return 0;
}
kuid_t new_uid = new->uid;
kuid_t old_uid = old->uid;
if (0 != old_uid.val) {
// old process is not root, ignore it.
return 0;
}
if (!is_appuid(new_uid) || is_isolated_uid(new_uid.val)) {
// pr_info("handle setuid ignore non application or isolated uid: %d\n", new_uid.val);
return 0;
}
if (ksu_is_allow_uid(new_uid.val)) {
// pr_info("handle setuid ignore allowed application: %d\n", new_uid.val);
return 0;
}
if (!ksu_uid_should_umount(new_uid.val)) {
return 0;
} else {
#ifdef CONFIG_KSU_DEBUG
pr_info("uid: %d should not umount!\n", current_uid().val);
#endif
}
// 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!
bool is_zygote_child = is_zygote(old->security);
if (!is_zygote_child) {
pr_info("handle umount ignore non zygote child: %d\n", current->pid);
return 0;
}
// umount the target mnt
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val, current->pid);
// fixme: use `collect_mounts` and `iterate_mount` to iterate all mountpoint and
// filter the mountpoint whose target is `/data/adb`
try_umount("/system", true, 0);
try_umount("/vendor", true, 0);
try_umount("/product", true, 0);
try_umount("/data/adb/modules", false, MNT_DETACH);
return 0;
}
// Init functons
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
struct pt_regs *real_regs = (struct pt_regs *)PT_REGS_PARM1(regs);
#else
struct pt_regs *real_regs = regs;
#endif
int option = (int)PT_REGS_PARM1(real_regs);
unsigned long arg2 = (unsigned long)PT_REGS_PARM2(real_regs);
unsigned long arg3 = (unsigned long)PT_REGS_PARM3(real_regs);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
// PRCTL_SYMBOL is the arch-specificed one, which receive raw pt_regs from syscall
unsigned long arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs);
#else
// PRCTL_SYMBOL is the common one, called by C convention in do_syscall_64
// https://elixir.bootlin.com/linux/v4.15.18/source/arch/x86/entry/common.c#L287
unsigned long arg4 = (unsigned long)PT_REGS_CCALL_PARM4(real_regs);
#endif
unsigned long arg5 = (unsigned long)PT_REGS_PARM5(real_regs);
return ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
}
static struct kprobe prctl_kp = {
.symbol_name = PRCTL_SYMBOL,
.pre_handler = handler_pre,
};
static int renameat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
// https://elixir.bootlin.com/linux/v5.12-rc1/source/include/linux/fs.h
struct renamedata *rd = PT_REGS_PARM1(regs);
struct dentry *old_entry = rd->old_dentry;
struct dentry *new_entry = rd->new_dentry;
#else
struct dentry *old_entry = (struct dentry *)PT_REGS_PARM2(regs);
struct dentry *new_entry = (struct dentry *)PT_REGS_CCALL_PARM4(regs);
#endif
return ksu_handle_rename(old_entry, new_entry);
}
static struct kprobe renameat_kp = {
.symbol_name = "vfs_rename",
.pre_handler = renameat_handler_pre,
};
__maybe_unused int ksu_kprobe_init(void)
{
int rc = 0;
rc = register_kprobe(&prctl_kp);
if (rc) {
pr_info("prctl kprobe failed: %d.\n", rc);
return rc;
}
rc = register_kprobe(&renameat_kp);
pr_info("renameat kp: %d\n", rc);
return rc;
}
__maybe_unused int ksu_kprobe_exit(void)
{
unregister_kprobe(&prctl_kp);
unregister_kprobe(&renameat_kp);
return 0;
}
static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
ksu_handle_prctl(option, arg2, arg3, arg4, arg5);
return -ENOSYS;
}
// kernel 4.4 and 4.9
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
static int ksu_key_permission(key_ref_t key_ref, const struct cred *cred,
unsigned perm)
{
if (init_session_keyring != NULL) {
return 0;
}
if (strcmp(current->comm, "init")) {
// we are only interested in `init` process
return 0;
}
init_session_keyring = cred->session_keyring;
pr_info("kernel_compat: got init_session_keyring\n");
return 0;
}
#endif
static int ksu_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
struct inode *new_inode, struct dentry *new_dentry)
{
return ksu_handle_rename(old_dentry, new_dentry);
}
static int ksu_task_fix_setuid(struct cred *new, const struct cred *old,
int flags)
{
return ksu_handle_setuid(new, old);
}
static struct security_hook_list ksu_hooks[] = {
LSM_HOOK_INIT(task_prctl, ksu_task_prctl),
LSM_HOOK_INIT(inode_rename, ksu_inode_rename),
LSM_HOOK_INIT(task_fix_setuid, ksu_task_fix_setuid),
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
LSM_HOOK_INIT(key_permission, ksu_key_permission)
#endif
};
void __init ksu_lsm_hook_init(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks), "ksu");
#else
// https://elixir.bootlin.com/linux/v4.10.17/source/include/linux/lsm_hooks.h#L1892
security_add_hooks(ksu_hooks, ARRAY_SIZE(ksu_hooks));
#endif
}
void __init ksu_core_init(void)
{
#ifndef MODULE
pr_info("ksu_lsm_hook_init\n");
ksu_lsm_hook_init();
#else
pr_info("ksu_kprobe_init\n");
ksu_kprobe_init();
#endif
}
void ksu_core_exit(void)
{
#ifndef MODULE
pr_info("ksu_kprobe_exit\n");
ksu_kprobe_exit();
#endif
}

View File

@@ -1,9 +0,0 @@
#ifndef __KSU_H_KSU_CORE
#define __KSU_H_KSU_CORE
#include "linux/init.h"
void __init ksu_core_init(void);
void ksu_core_exit(void);
#endif

View File

@@ -1,5 +0,0 @@
// WARNING: THIS IS A STUB FILE
// This file will be regenerated by CI
unsigned int ksud_size = 0;
const char ksud[0] = {};

View File

@@ -1,2 +0,0 @@
register_kprobe
unregister_kprobe

View File

@@ -1,28 +0,0 @@
#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

View File

@@ -1,178 +0,0 @@
#include "linux/version.h"
#include "linux/fs.h"
#include "linux/nsproxy.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
#include "linux/sched/task.h"
#include "linux/uaccess.h"
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
#include "linux/uaccess.h"
#include "linux/sched.h"
#else
#include "linux/sched.h"
#endif
#include "klog.h" // IWYU pragma: keep
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#include "linux/key.h"
#include "linux/errno.h"
#include "linux/cred.h"
struct key *init_session_keyring = NULL;
static inline int install_session_keyring(struct key *keyring)
{
struct cred *new;
int ret;
new = prepare_creds();
if (!new)
return -ENOMEM;
ret = install_session_keyring_to_cred(new, keyring);
if (ret < 0) {
abort_creds(new);
return ret;
}
return commit_creds(new);
}
#endif
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)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
if (init_session_keyring != NULL && !current_cred()->session_keyring &&
(current->flags & PF_WQ_WORKER)) {
pr_info("installing init session keyring for older kernel\n");
install_session_keyring(init_session_keyring);
}
#endif
// 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)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_read(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_read(p, offset, (char *)buf, count);
if (pos && result > 0) {
*pos = offset + result;
}
return result;
#endif
}
ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count,
loff_t *pos)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_write(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_write(p, buf, count, offset);
if (pos && result > 0) {
*pos = offset + result;
}
return result;
#endif
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count)
{
return strncpy_from_user_nofault(dst, unsafe_addr, count);
}
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count)
{
return strncpy_from_unsafe_user(dst, unsafe_addr, count);
}
#else
// Copied from: https://elixir.bootlin.com/linux/v4.9.337/source/mm/maccess.c#L201
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count)
{
mm_segment_t old_fs = get_fs();
long ret;
if (unlikely(count <= 0))
return 0;
set_fs(USER_DS);
pagefault_disable();
ret = strncpy_from_user(dst, unsafe_addr, count);
pagefault_enable();
set_fs(old_fs);
if (ret >= count) {
ret = count;
dst[ret - 1] = '\0';
} else if (ret > 0) {
ret++;
}
return ret;
}
#endif

View File

@@ -1,24 +0,0 @@
#ifndef __KSU_H_KERNEL_COMPAT
#define __KSU_H_KERNEL_COMPAT
#include "linux/fs.h"
#include "linux/key.h"
#include "linux/version.h"
extern long ksu_strncpy_from_user_nofault(char *dst,
const void __user *unsafe_addr,
long count);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
extern struct key *init_session_keyring;
#endif
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

View File

@@ -1,11 +1,9 @@
#ifndef __KSU_H_KLOG
#define __KSU_H_KLOG
#include <linux/printk.h>
#ifdef pr_fmt
#undef pr_fmt
#define pr_fmt(fmt) "KernelSU: " fmt
#endif
#endif
#endif

View File

@@ -1,86 +1,277 @@
#include "linux/fs.h"
#include "linux/module.h"
#include "linux/workqueue.h"
#include "linux/uidgid.h"
#include <linux/cpu.h>
#include <linux/memory.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm-generic/errno-base.h>
#include <linux/rcupdate.h>
#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/fs_struct.h>
#include <linux/namei.h>
#include <linux/delay.h> // mslepp
#include "selinux/selinux.h"
#include "klog.h"
#include "apk_sign.h"
#include "allowlist.h"
#include "arch.h"
#include "core_hook.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "uid_observer.h"
static struct workqueue_struct *ksu_workqueue;
#define KERNEL_SU_VERSION 3
bool ksu_queue_work(struct work_struct *work)
{
return queue_work(ksu_workqueue, work);
}
#define KERNEL_SU_OPTION 0xDEADBEEF
extern int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags);
#define CMD_GRANT_ROOT 0
extern int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
void *argv, void *envp, int *flags);
#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
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 escape_to_root() {
struct cred* cred;
extern void ksu_enable_sucompat();
extern void ksu_enable_ksud();
cred = (struct cred *)__task_cred(current);
int __init kernelsu_init(void)
{
#ifdef CONFIG_KSU_DEBUG
pr_alert("*************************************************************");
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
pr_alert("** **");
pr_alert("** You are running KernelSU in DEBUG mode **");
pr_alert("** **");
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
pr_alert("*************************************************************");
memset(&cred->uid, 0, sizeof(cred->uid));
memset(&cred->gid, 0, sizeof(cred->gid));
memset(&cred->suid, 0, sizeof(cred->suid));
memset(&cred->euid, 0, sizeof(cred->euid));
memset(&cred->egid, 0, sizeof(cred->egid));
memset(&cred->fsuid, 0, sizeof(cred->fsuid));
memset(&cred->fsgid, 0, sizeof(cred->fsgid));
memset(&cred->cap_inheritable, 0xff, sizeof(cred->cap_inheritable));
memset(&cred->cap_permitted, 0xff, sizeof(cred->cap_permitted));
memset(&cred->cap_effective, 0xff, sizeof(cred->cap_effective));
memset(&cred->cap_bset, 0xff, sizeof(cred->cap_bset));
memset(&cred->cap_ambient, 0xff, sizeof(cred->cap_ambient));
// disable seccomp
#ifdef CONFIG_GENERIC_ENTRY
current_thread_info()->syscall_work &= ~SYSCALL_WORK_SECCOMP;
#else
current_thread_info()->flags &= ~TIF_SECCOMP;
#endif
current->seccomp.mode = 0;
current->seccomp.filter = NULL;
ksu_core_init();
setup_selinux();
}
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
int startswith(char* s, char* prefix) {
return strncmp(s, prefix, strlen(prefix));
}
int endswith(const char *s, const char *t)
{
size_t slen = strlen(s);
size_t tlen = strlen(t);
if (tlen > slen) return 1;
return strcmp(s + slen - tlen, t);
}
static uid_t __manager_uid;
static bool is_manager() {
return __manager_uid == current_uid().val;
}
static bool become_manager() {
struct fdtable *files_table;
int i = 0;
struct path files_path;
char *cwd;
char *buf;
bool result = false;
if (__manager_uid != 0) {
pr_info("manager already exist: %d\n", __manager_uid);
return true;
}
buf = (char *) kmalloc(GFP_KERNEL, PATH_MAX);
if (!buf) {
pr_err("kalloc path failed.\n");
return false;
}
files_table = files_fdtable(current->files);
// todo: use iterate_fd
while(files_table->fd[i] != NULL) {
files_path = files_table->fd[i]->f_path;
if (!d_is_reg(files_path.dentry)) {
i++;
continue;
}
cwd = d_path(&files_path, buf, PATH_MAX);
if (startswith(cwd, "/data/app/") == 0 && endswith(cwd, "/base.apk") == 0) {
// we have found the apk!
pr_info("found apk: %s", cwd);
if (is_manager_apk(cwd) == 0) {
// check passed
uid_t uid = current_uid().val;
pr_info("manager uid: %d\n", uid);
__manager_uid = uid;
result = true;
goto clean;
} else {
pr_info("manager signature invalid!");
}
break;
}
i++;
}
clean:
kfree(buf);
return result;
}
static bool is_allow_su() {
uid_t uid = current_uid().val;
if (uid == __manager_uid) {
// we are manager, allow!
return true;
}
return ksu_is_allow_uid(uid);
}
extern void enable_sucompat();
static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
struct pt_regs* real_regs = (struct pt_regs*) PT_REGS_PARM1(regs);
int option = (int) PT_REGS_PARM1(real_regs);
unsigned long arg2 = (unsigned long) PT_REGS_PARM2(real_regs);
unsigned long arg3 = (unsigned long) PT_REGS_PARM3(real_regs);
unsigned long arg4 = (unsigned long) PT_REGS_PARM4(real_regs);
unsigned long arg5 = (unsigned long) PT_REGS_PARM5(real_regs);
// if success, we modify the arg5 as result!
u32* result = (u32*) arg5;
u32 reply_ok = KERNEL_SU_OPTION;
if (KERNEL_SU_OPTION != option) {
return 0;
}
pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
if (arg2 == CMD_BECOME_MANAGER) {
// someone wants to be root manager, just check it!
bool success = become_manager();
if (success) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error\n");
}
}
return 0;
}
if (arg2 == CMD_GRANT_ROOT) {
if (is_allow_su()) {
pr_info("allow root for: %d\n", current_uid());
escape_to_root();
} else {
pr_info("deny root for: %d\n", current_uid());
// add it to deny list!
ksu_allow_uid(current_uid().val, false);
}
return 0;
}
// all other cmds are for 'root manager'
if (!is_manager()) {
pr_info("Only manager can do cmd: %d\n", arg2);
return 0;
}
// we are already manager
if (arg2 == CMD_ALLOW_SU || arg2 == CMD_DENY_SU) {
bool allow = arg2 == CMD_ALLOW_SU;
bool success = false;
uid_t uid = (uid_t) arg3;
success = ksu_allow_uid(uid, allow);
if (success) {
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
}
} else if (arg2 == CMD_GET_ALLOW_LIST || arg2 == CMD_GET_DENY_LIST) {
u32 array[128];
u32 array_length;
bool success = ksu_get_allow_list(array, &array_length, arg2 == CMD_GET_ALLOW_LIST);
if (success) {
if (!copy_to_user(arg4, &array_length, sizeof(array_length)) &&
!copy_to_user(arg3, array, sizeof(u32) * array_length)) {
if (!copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
} else {
pr_err("prctl copy allowlist error\n");
}
}
} else if (arg2 == CMD_GET_VERSION) {
u32 version = KERNEL_SU_VERSION;
if (copy_to_user(arg3, &version, sizeof(version))) {
pr_err("prctl reply error, cmd: %d\n", arg2);
}
}
return 0;
}
static struct kprobe kp = {
.symbol_name = PRCTL_SYMBOL,
.pre_handler = handler_pre,
};
int kernelsu_init(void){
int rc = 0;
ksu_allowlist_init();
ksu_uid_observer_init();
rc = register_kprobe(&kp);
if (rc) {
pr_info("prctl kprobe failed: %d, please check your kernel config.\n", rc);
return rc;
}
#ifdef CONFIG_KPROBES
ksu_enable_sucompat();
ksu_enable_ksud();
#else
pr_alert("KPROBES is disabled, KernelSU may not work, please check https://kernelsu.org/guide/how-to-integrate-for-non-gki.html");
#endif
enable_sucompat();
return 0;
}
void kernelsu_exit(void)
{
void kernelsu_exit(void){
// should never happen...
unregister_kprobe(&kp);
ksu_allowlist_exit();
ksu_uid_observer_exit();
destroy_workqueue(ksu_workqueue);
ksu_core_exit();
}
module_init(kernelsu_init);
module_exit(kernelsu_exit);
#ifndef CONFIG_KPROBES
#error("`CONFIG_KPROBES` must be enabled for KernelSU!")
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("weishu");
MODULE_DESCRIPTION("Android KernelSU");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
#endif
MODULE_DESCRIPTION("Android GKI KernelSU");
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); // 5+才需要导出命名空间

View File

@@ -1,98 +0,0 @@
#ifndef __KSU_H_KSU
#define __KSU_H_KSU
#include "linux/types.h"
#include "linux/workqueue.h"
#define KERNEL_SU_VERSION KSU_VERSION
#define KERNEL_SU_OPTION 0xDEADBEEF
#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 EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2
#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;
};
};
bool ksu_queue_work(struct work_struct *work);
static inline int startswith(char *s, char *prefix)
{
return strncmp(s, prefix, strlen(prefix));
}
static inline int endswith(const char *s, const char *t)
{
size_t slen = strlen(s);
size_t tlen = strlen(t);
if (tlen > slen)
return 1;
return strcmp(s + slen - tlen, t);
}
#endif

View File

@@ -1,567 +0,0 @@
#include "asm/current.h"
#include "linux/compat.h"
#include "linux/dcache.h"
#include "linux/err.h"
#include "linux/fs.h"
#include "linux/input-event-codes.h"
#include "linux/kprobes.h"
#include "linux/printk.h"
#include "linux/types.h"
#include "linux/uaccess.h"
#include "linux/version.h"
#include "linux/workqueue.h"
#include "allowlist.h"
#include "arch.h"
#include "klog.h" // IWYU pragma: keep
#include "ksud.h"
#include "kernel_compat.h"
#include "selinux/selinux.h"
static const char KERNEL_SU_RC[] =
"\n"
"on post-fs-data\n"
" start logd\n"
// We should wait for the post-fs-data finish
" exec u:r:su:s0 root -- " KSUD_PATH " post-fs-data\n"
"\n"
"on nonencrypted\n"
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
"\n"
"on property:vold.decrypt=trigger_restart_framework\n"
" exec u:r:su:s0 root -- " KSUD_PATH " services\n"
"\n"
"on property:sys.boot_completed=1\n"
" exec u:r:su:s0 root -- " KSUD_PATH " boot-completed\n"
"\n"
"\n";
static void stop_vfs_read_hook();
static void stop_execve_hook();
static void stop_input_hook();
#ifdef CONFIG_KPROBES
static struct work_struct stop_vfs_read_work;
static struct work_struct stop_execve_hook_work;
static struct work_struct stop_input_hook_work;
#else
bool ksu_vfs_read_hook __read_mostly = true;
bool ksu_execveat_hook __read_mostly = true;
bool ksu_input_hook __read_mostly = true;
#endif
void on_post_fs_data(void)
{
static bool done = false;
if (done) {
pr_info("on_post_fs_data already done\n");
return;
}
done = true;
pr_info("on_post_fs_data!\n");
ksu_load_allow_list();
// sanity check, this may influence the performance
stop_input_hook();
}
#define MAX_ARG_STRINGS 0x7FFFFFFF
struct user_arg_ptr {
#ifdef CONFIG_COMPAT
bool is_compat;
#endif
union {
const char __user *const __user *native;
#ifdef CONFIG_COMPAT
const compat_uptr_t __user *compat;
#endif
} ptr;
};
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
{
const char __user *native;
#ifdef CONFIG_COMPAT
if (unlikely(argv.is_compat)) {
compat_uptr_t compat;
if (get_user(compat, argv.ptr.compat + nr))
return ERR_PTR(-EFAULT);
return compat_ptr(compat);
}
#endif
if (get_user(native, argv.ptr.native + nr))
return ERR_PTR(-EFAULT);
return native;
}
/*
* count() counts the number of strings in array ARGV.
*/
/*
* Make sure old GCC compiler can use __maybe_unused,
* Test passed in 4.4.x ~ 4.9.x when use GCC.
*/
static int __maybe_unused count(struct user_arg_ptr argv, int max)
{
int i = 0;
if (argv.ptr.native != NULL) {
for (;;) {
const char __user *p = get_user_arg_ptr(argv, i);
if (!p)
break;
if (IS_ERR(p))
return -EFAULT;
if (i >= max)
return -E2BIG;
++i;
if (fatal_signal_pending(current))
return -ERESTARTNOHAND;
cond_resched();
}
}
return i;
}
// IMPORTANT NOTE: the call from execve_handler_pre WON'T provided correct value for envp and flags in GKI version
int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
struct user_arg_ptr *argv, struct user_arg_ptr *envp, int *flags)
{
#ifndef CONFIG_KPROBES
if (!ksu_execveat_hook) {
return 0;
}
#endif
struct filename *filename;
static const char app_process[] = "/system/bin/app_process";
static bool first_app_process = true;
/* This applies to versions Android 10+ */
static const char system_bin_init[] = "/system/bin/init";
/* This applies to versions between Android 6 ~ 9 */
static const char old_system_init[] = "/init";
static bool init_second_stage_executed = false;
if (!filename_ptr)
return 0;
filename = *filename_ptr;
if (IS_ERR(filename)) {
return 0;
}
if (unlikely(!memcmp(filename->name, system_bin_init,
sizeof(system_bin_init) - 1) && argv)) {
// /system/bin/init executed
int argc = count(*argv, MAX_ARG_STRINGS);
pr_info("/system/bin/init argc: %d\n", argc);
if (argc > 1 && !init_second_stage_executed) {
const char __user *p = get_user_arg_ptr(*argv, 1);
if (p && !IS_ERR(p)) {
char first_arg[16];
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
pr_info("/system/bin/init first arg: %s\n", first_arg);
if (!strcmp(first_arg, "second_stage")) {
pr_info("/system/bin/init second_stage executed\n");
apply_kernelsu_rules();
init_second_stage_executed = true;
ksu_android_ns_fs_check();
}
} else {
pr_err("/system/bin/init parse args err!\n");
}
}
} else if (unlikely(!memcmp(filename->name, old_system_init,
sizeof(old_system_init) - 1) && argv)) {
// /init executed
int argc = count(*argv, MAX_ARG_STRINGS);
pr_info("/init argc: %d\n", argc);
if (argc > 1 && !init_second_stage_executed) {
/* This applies to versions between Android 6 ~ 7 */
const char __user *p = get_user_arg_ptr(*argv, 1);
if (p && !IS_ERR(p)) {
char first_arg[16];
ksu_strncpy_from_user_nofault(first_arg, p, sizeof(first_arg));
pr_info("/init first arg: %s\n", first_arg);
if (!strcmp(first_arg, "--second-stage")) {
pr_info("/init second_stage executed\n");
apply_kernelsu_rules();
init_second_stage_executed = true;
ksu_android_ns_fs_check();
}
} else {
pr_err("/init parse args err!\n");
}
} else if (argc == 1 && !init_second_stage_executed && envp) {
/* This applies to versions between Android 8 ~ 9 */
int envc = count(*envp, MAX_ARG_STRINGS);
if (envc > 0) {
int n;
for (n = 1; n <= envc; n++) {
const char __user *p = get_user_arg_ptr(*envp, n);
if (!p || IS_ERR(p)) {
continue;
}
char env[256];
// Reading environment variable strings from user space
if (ksu_strncpy_from_user_nofault(env, p, sizeof(env)) < 0)
continue;
// Parsing environment variable names and values
char *env_name = env;
char *env_value = strchr(env, '=');
if (env_value == NULL)
continue;
// Replace equal sign with string terminator
*env_value = '\0';
env_value++;
// Check if the environment variable name and value are matching
if (!strcmp(env_name, "INIT_SECOND_STAGE") && (!strcmp(env_value, "1") || !strcmp(env_value, "true"))) {
pr_info("/init second_stage executed\n");
apply_kernelsu_rules();
init_second_stage_executed = true;
ksu_android_ns_fs_check();
}
}
}
}
}
if (unlikely(first_app_process &&
!memcmp(filename->name, app_process, sizeof(app_process) - 1))) {
first_app_process = false;
pr_info("exec app_process, /data prepared, second_stage: %d\n", init_second_stage_executed);
on_post_fs_data(); // we keep this for old ksud
stop_execve_hook();
}
return 0;
}
static ssize_t (*orig_read)(struct file *, char __user *, size_t, loff_t *);
static ssize_t (*orig_read_iter)(struct kiocb *, struct iov_iter *);
static struct file_operations fops_proxy;
static ssize_t read_count_append = 0;
static ssize_t read_proxy(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
bool first_read = file->f_pos == 0;
ssize_t ret = orig_read(file, buf, count, pos);
if (first_read) {
pr_info("read_proxy append %ld + %ld\n", ret, read_count_append);
ret += read_count_append;
}
return ret;
}
static ssize_t read_iter_proxy(struct kiocb *iocb, struct iov_iter *to)
{
bool first_read = iocb->ki_pos == 0;
ssize_t ret = orig_read_iter(iocb, to);
if (first_read) {
pr_info("read_iter_proxy append %ld + %ld\n", ret,
read_count_append);
ret += read_count_append;
}
return ret;
}
int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
size_t *count_ptr, loff_t **pos)
{
#ifndef CONFIG_KPROBES
if (!ksu_vfs_read_hook) {
return 0;
}
#endif
struct file *file;
char __user *buf;
size_t count;
if (strcmp(current->comm, "init")) {
// we are only interest in `init` process
return 0;
}
file = *file_ptr;
if (IS_ERR(file)) {
return 0;
}
if (!d_is_reg(file->f_path.dentry)) {
return 0;
}
const char *short_name = file->f_path.dentry->d_name.name;
if (strcmp(short_name, "atrace.rc")) {
// we are only interest `atrace.rc` file name file
return 0;
}
char path[256];
char *dpath = d_path(&file->f_path, path, sizeof(path));
if (IS_ERR(dpath)) {
return 0;
}
if (strcmp(dpath, "/system/etc/init/atrace.rc")) {
return 0;
}
// we only process the first read
static bool rc_inserted = false;
if (rc_inserted) {
// we don't need this kprobe, unregister it!
stop_vfs_read_hook();
return 0;
}
rc_inserted = true;
// now we can sure that the init process is reading
// `/system/etc/init/atrace.rc`
buf = *buf_ptr;
count = *count_ptr;
size_t rc_count = strlen(KERNEL_SU_RC);
pr_info("vfs_read: %s, comm: %s, count: %zu, rc_count: %zu\n", dpath,
current->comm, count, rc_count);
if (count < rc_count) {
pr_err("count: %zu < rc_count: %zu\n", count, rc_count);
return 0;
}
size_t ret = copy_to_user(buf, KERNEL_SU_RC, rc_count);
if (ret) {
pr_err("copy ksud.rc failed: %zu\n", ret);
return 0;
}
// we've succeed to insert ksud.rc, now we need to proxy the read and modify the result!
// But, we can not modify the file_operations directly, because it's in read-only memory.
// We just replace the whole file_operations with a proxy one.
memcpy(&fops_proxy, file->f_op, sizeof(struct file_operations));
orig_read = file->f_op->read;
if (orig_read) {
fops_proxy.read = read_proxy;
}
orig_read_iter = file->f_op->read_iter;
if (orig_read_iter) {
fops_proxy.read_iter = read_iter_proxy;
}
// replace the file_operations
file->f_op = &fops_proxy;
read_count_append = rc_count;
*buf_ptr = buf + rc_count;
*count_ptr = count - rc_count;
return 0;
}
static unsigned int volumedown_pressed_count = 0;
static bool is_volumedown_enough(unsigned int count)
{
return count >= 3;
}
int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
int *value)
{
#ifndef CONFIG_KPROBES
if (!ksu_input_hook) {
return 0;
}
#endif
if (*type == EV_KEY && *code == KEY_VOLUMEDOWN) {
int val = *value;
pr_info("KEY_VOLUMEDOWN val: %d\n", val);
if (val) {
// key pressed, count it
volumedown_pressed_count += 1;
if (is_volumedown_enough(volumedown_pressed_count)) {
stop_input_hook();
}
}
}
return 0;
}
bool ksu_is_safe_mode()
{
static bool safe_mode = false;
if (safe_mode) {
// don't need to check again, userspace may call multiple times
return true;
}
// stop hook first!
stop_input_hook();
pr_info("volumedown_pressed_count: %d\n", volumedown_pressed_count);
if (is_volumedown_enough(volumedown_pressed_count)) {
// pressed over 3 times
pr_info("KEY_VOLUMEDOWN pressed max times, safe mode detected!\n");
safe_mode = true;
return true;
}
return false;
}
#ifdef CONFIG_KPROBES
// https://elixir.bootlin.com/linux/v5.10.158/source/fs/exec.c#L1864
static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
int *fd = (int *)&PT_REGS_PARM1(regs);
struct filename **filename_ptr =
(struct filename **)&PT_REGS_PARM2(regs);
struct user_arg_ptr argv;
#ifdef CONFIG_COMPAT
argv.is_compat = PT_REGS_PARM3(regs);
if (unlikely(argv.is_compat)) {
argv.ptr.compat = PT_REGS_CCALL_PARM4(regs);
} else {
argv.ptr.native = PT_REGS_CCALL_PARM4(regs);
}
#else
argv.ptr.native = PT_REGS_PARM3(regs);
#endif
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}
static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct file **file_ptr = (struct file **)&PT_REGS_PARM1(regs);
char __user **buf_ptr = (char **)&PT_REGS_PARM2(regs);
size_t *count_ptr = (size_t *)&PT_REGS_PARM3(regs);
loff_t **pos_ptr = (loff_t **)&PT_REGS_CCALL_PARM4(regs);
return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr);
}
static int input_handle_event_handler_pre(struct kprobe *p,
struct pt_regs *regs)
{
unsigned int *type = (unsigned int *)&PT_REGS_PARM2(regs);
unsigned int *code = (unsigned int *)&PT_REGS_PARM3(regs);
int *value = (int *)&PT_REGS_CCALL_PARM4(regs);
return ksu_handle_input_handle_event(type, code, value);
}
static struct kprobe execve_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
.symbol_name = "do_execveat_common",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
.symbol_name = "__do_execve_file",
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
.symbol_name = "do_execveat_common",
#endif
.pre_handler = execve_handler_pre,
};
static struct kprobe vfs_read_kp = {
.symbol_name = "vfs_read",
.pre_handler = read_handler_pre,
};
static struct kprobe input_handle_event_kp = {
.symbol_name = "input_handle_event",
.pre_handler = input_handle_event_handler_pre,
};
static void do_stop_vfs_read_hook(struct work_struct *work)
{
unregister_kprobe(&vfs_read_kp);
}
static void do_stop_execve_hook(struct work_struct *work)
{
unregister_kprobe(&execve_kp);
}
static void do_stop_input_hook(struct work_struct *work)
{
unregister_kprobe(&input_handle_event_kp);
}
#endif
static void stop_vfs_read_hook()
{
#ifdef CONFIG_KPROBES
bool ret = schedule_work(&stop_vfs_read_work);
pr_info("unregister vfs_read kprobe: %d!\n", ret);
#else
ksu_vfs_read_hook = false;
pr_info("stop vfs_read_hook\n");
#endif
}
static void stop_execve_hook()
{
#ifdef CONFIG_KPROBES
bool ret = schedule_work(&stop_execve_hook_work);
pr_info("unregister execve kprobe: %d!\n", ret);
#else
ksu_execveat_hook = false;
pr_info("stop execve_hook\n");
#endif
}
static void stop_input_hook()
{
static bool input_hook_stopped = false;
if (input_hook_stopped) {
return;
}
input_hook_stopped = true;
#ifdef CONFIG_KPROBES
bool ret = schedule_work(&stop_input_hook_work);
pr_info("unregister input kprobe: %d!\n", ret);
#else
ksu_input_hook = false;
pr_info("stop input_hook\n");
#endif
}
// ksud: module support
void ksu_enable_ksud()
{
#ifdef CONFIG_KPROBES
int ret;
ret = register_kprobe(&execve_kp);
pr_info("ksud: execve_kp: %d\n", ret);
ret = register_kprobe(&vfs_read_kp);
pr_info("ksud: vfs_read_kp: %d\n", ret);
ret = register_kprobe(&input_handle_event_kp);
pr_info("ksud: input_handle_event_kp: %d\n", ret);
INIT_WORK(&stop_vfs_read_work, do_stop_vfs_read_hook);
INIT_WORK(&stop_execve_hook_work, do_stop_execve_hook);
INIT_WORK(&stop_input_hook_work, do_stop_input_hook);
#endif
}

View File

@@ -1,10 +0,0 @@
#ifndef __KSU_H_KSUD
#define __KSU_H_KSUD
#define KSUD_PATH "/data/adb/ksud"
void on_post_fs_data(void);
bool ksu_is_safe_mode(void);
#endif

View File

@@ -1,126 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
config OVERLAY_FS
tristate "Overlay filesystem support"
select EXPORTFS
help
An overlay filesystem combines two filesystems - an 'upper' filesystem
and a 'lower' filesystem. When a name exists in both filesystems, the
object in the 'upper' filesystem is visible while the object in the
'lower' filesystem is either hidden or, in the case of directories,
merged with the 'upper' object.
For more information see Documentation/filesystems/overlayfs.rst
config OVERLAY_FS_REDIRECT_DIR
bool "Overlayfs: turn on redirect directory feature by default"
depends on OVERLAY_FS
help
If this config option is enabled then overlay filesystems will use
redirects when renaming directories by default. In this case it is
still possible to turn off redirects globally with the
"redirect_dir=off" module option or on a filesystem instance basis
with the "redirect_dir=off" mount option.
Note, that redirects are not backward compatible. That is, mounting
an overlay which has redirects on a kernel that doesn't support this
feature will have unexpected results.
If unsure, say N.
config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW
bool "Overlayfs: follow redirects even if redirects are turned off"
default y
depends on OVERLAY_FS
help
Disable this to get a possibly more secure configuration, but that
might not be backward compatible with previous kernels.
If backward compatibility is not an issue, then it is safe and
recommended to say N here.
For more information, see Documentation/filesystems/overlayfs.rst
If unsure, say Y.
config OVERLAY_FS_INDEX
bool "Overlayfs: turn on inodes index feature by default"
depends on OVERLAY_FS
help
If this config option is enabled then overlay filesystems will use
the index directory to map lower inodes to upper inodes by default.
In this case it is still possible to turn off index globally with the
"index=off" module option or on a filesystem instance basis with the
"index=off" mount option.
The inodes index feature prevents breaking of lower hardlinks on copy
up.
Note, that the inodes index feature is not backward compatible.
That is, mounting an overlay which has an inodes index on a kernel
that doesn't support this feature will have unexpected results.
If unsure, say N.
config OVERLAY_FS_NFS_EXPORT
bool "Overlayfs: turn on NFS export feature by default"
depends on OVERLAY_FS
depends on OVERLAY_FS_INDEX
depends on !OVERLAY_FS_METACOPY
help
If this config option is enabled then overlay filesystems will use
the index directory to decode overlay NFS file handles by default.
In this case, it is still possible to turn off NFS export support
globally with the "nfs_export=off" module option or on a filesystem
instance basis with the "nfs_export=off" mount option.
The NFS export feature creates an index on copy up of every file and
directory. This full index is used to detect overlay filesystems
inconsistencies on lookup, like redirect from multiple upper dirs to
the same lower dir. The full index may incur some overhead on mount
time, especially when verifying that directory file handles are not
stale.
Note, that the NFS export feature is not backward compatible.
That is, mounting an overlay which has a full index on a kernel
that doesn't support this feature will have unexpected results.
Most users should say N here and enable this feature on a case-by-
case basis with the "nfs_export=on" mount option.
Say N unless you fully understand the consequences.
config OVERLAY_FS_XINO_AUTO
bool "Overlayfs: auto enable inode number mapping"
default n
depends on OVERLAY_FS
depends on 64BIT
help
If this config option is enabled then overlay filesystems will use
unused high bits in undelying filesystem inode numbers to map all
inodes to a unified address space. The mapped 64bit inode numbers
might not be compatible with applications that expect 32bit inodes.
If compatibility with applications that expect 32bit inodes is not an
issue, then it is safe and recommended to say Y here.
For more information, see Documentation/filesystems/overlayfs.rst
If unsure, say N.
config OVERLAY_FS_METACOPY
bool "Overlayfs: turn on metadata only copy up feature by default"
depends on OVERLAY_FS
select OVERLAY_FS_REDIRECT_DIR
help
If this config option is enabled then overlay filesystems will
copy up only metadata where appropriate and data copy up will
happen when a file is opened for WRITE operation. It is still
possible to turn off this feature globally with the "metacopy=off"
module option or on a filesystem instance basis with the
"metacopy=off" mount option.
Note, that this feature is not backward compatible. That is,
mounting an overlay which has metacopy only inodes on a kernel
that doesn't support this feature will have unexpected results.
If unsure, say N.

View File

@@ -1,9 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the overlay filesystem.
#
obj-y += ksufs.o
ksufs-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \
copy_up.o export.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,870 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Overlayfs NFS export support.
*
* Amir Goldstein <amir73il@gmail.com>
*
* Copyright (C) 2017-2018 CTERA Networks. All Rights Reserved.
*/
#include <linux/fs.h>
#include <linux/cred.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/xattr.h>
#include <linux/exportfs.h>
#include <linux/ratelimit.h>
#include "overlayfs.h"
static int ksu_ovl_encode_maybe_copy_up(struct dentry *dentry)
{
int err;
if (ksu_ovl_dentry_upper(dentry))
return 0;
err = ksu_ovl_want_write(dentry);
if (!err) {
err = ksu_ovl_copy_up(dentry);
ksu_ovl_drop_write(dentry);
}
if (err) {
pr_warn_ratelimited("failed to copy up on encode (%pd2, err=%i)\n",
dentry, err);
}
return err;
}
/*
* Before encoding a non-upper directory file handle from real layer N, we need
* to check if it will be possible to reconnect an overlay dentry from the real
* lower decoded dentry. This is done by following the overlay ancestry up to a
* "layer N connected" ancestor and verifying that all parents along the way are
* "layer N connectable". If an ancestor that is NOT "layer N connectable" is
* found, we need to copy up an ancestor, which is "layer N connectable", thus
* making that ancestor "layer N connected". For example:
*
* layer 1: /a
* layer 2: /a/b/c
*
* The overlay dentry /a is NOT "layer 2 connectable", because if dir /a is
* copied up and renamed, upper dir /a will be indexed by lower dir /a from
* layer 1. The dir /a from layer 2 will never be indexed, so the algorithm (*)
* in ksu_ovl_lookup_real_ancestor() will not be able to lookup a connected overlay
* dentry from the connected lower dentry /a/b/c.
*
* To avoid this problem on decode time, we need to copy up an ancestor of
* /a/b/c, which is "layer 2 connectable", on encode time. That ancestor is
* /a/b. After copy up (and index) of /a/b, it will become "layer 2 connected"
* and when the time comes to decode the file handle from lower dentry /a/b/c,
* ksu_ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding
* a connected overlay dentry will be accomplished.
*
* (*) the algorithm in ksu_ovl_lookup_real_ancestor() can be improved to lookup an
* entry /a in the lower layers above layer N and find the indexed dir /a from
* layer 1. If that improvement is made, then the check for "layer N connected"
* will need to verify there are no redirects in lower layers above N. In the
* example above, /a will be "layer 2 connectable". However, if layer 2 dir /a
* is a target of a layer 1 redirect, then /a will NOT be "layer 2 connectable":
*
* layer 1: /A (redirect = /a)
* layer 2: /a/b/c
*/
/* Return the lowest layer for encoding a connectable file handle */
static int ksu_ovl_connectable_layer(struct dentry *dentry)
{
struct ksu_ovl_entry *oe = KSU_OVL_E(dentry);
/* We can get overlay root from root of any layer */
if (dentry == dentry->d_sb->s_root)
return oe->numlower;
/*
* If it's an unindexed merge dir, then it's not connectable with any
* lower layer
*/
if (ksu_ovl_dentry_upper(dentry) &&
!ksu_ovl_test_flag(KSU_OVL_INDEX, d_inode(dentry)))
return 0;
/* We can get upper/overlay path from indexed/lower dentry */
return oe->lowerstack[0].layer->idx;
}
/*
* @dentry is "connected" if all ancestors up to root or a "connected" ancestor
* have the same uppermost lower layer as the origin's layer. We may need to
* copy up a "connectable" ancestor to make it "connected". A "connected" dentry
* cannot become non "connected", so cache positive result in dentry flags.
*
* Return the connected origin layer or < 0 on error.
*/
static int ksu_ovl_connect_layer(struct dentry *dentry)
{
struct dentry *next, *parent = NULL;
int origin_layer;
int err = 0;
if (WARN_ON(dentry == dentry->d_sb->s_root) ||
WARN_ON(!ksu_ovl_dentry_lower(dentry)))
return -EIO;
origin_layer = KSU_OVL_E(dentry)->lowerstack[0].layer->idx;
if (ksu_ovl_dentry_test_flag(KSU_OVL_E_CONNECTED, dentry))
return origin_layer;
/* Find the topmost origin layer connectable ancestor of @dentry */
next = dget(dentry);
for (;;) {
parent = dget_parent(next);
if (WARN_ON(parent == next)) {
err = -EIO;
break;
}
/*
* If @parent is not origin layer connectable, then copy up
* @next which is origin layer connectable and we are done.
*/
if (ksu_ovl_connectable_layer(parent) < origin_layer) {
err = ksu_ovl_encode_maybe_copy_up(next);
break;
}
/* If @parent is connected or indexed we are done */
if (ksu_ovl_dentry_test_flag(KSU_OVL_E_CONNECTED, parent) ||
ksu_ovl_test_flag(KSU_OVL_INDEX, d_inode(parent)))
break;
dput(next);
next = parent;
}
dput(parent);
dput(next);
if (!err)
ksu_ovl_dentry_set_flag(KSU_OVL_E_CONNECTED, dentry);
return err ?: origin_layer;
}
/*
* We only need to encode origin if there is a chance that the same object was
* encoded pre copy up and then we need to stay consistent with the same
* encoding also after copy up. If non-pure upper is not indexed, then it was
* copied up before NFS export was enabled. In that case we don't need to worry
* about staying consistent with pre copy up encoding and we encode an upper
* file handle. Overlay root dentry is a private case of non-indexed upper.
*
* The following table summarizes the different file handle encodings used for
* different overlay object types:
*
* Object type | Encoding
* --------------------------------
* Pure upper | U
* Non-indexed upper | U
* Indexed upper | L (*)
* Non-upper | L (*)
*
* U = upper file handle
* L = lower file handle
*
* (*) Connecting an overlay dir from real lower dentry is not always
* possible when there are redirects in lower layers and non-indexed merge dirs.
* To mitigate those case, we may copy up the lower dir ancestor before encode
* a lower dir file handle.
*
* Return 0 for upper file handle, > 0 for lower file handle or < 0 on error.
*/
static int ksu_ovl_check_encode_origin(struct dentry *dentry)
{
struct ksu_ovl_fs *ofs = dentry->d_sb->s_fs_info;
/* Upper file handle for pure upper */
if (!ksu_ovl_dentry_lower(dentry))
return 0;
/*
* Upper file handle for non-indexed upper.
*
* Root is never indexed, so if there's an upper layer, encode upper for
* root.
*/
if (ksu_ovl_dentry_upper(dentry) &&
!ksu_ovl_test_flag(KSU_OVL_INDEX, d_inode(dentry)))
return 0;
/*
* Decoding a merge dir, whose origin's ancestor is under a redirected
* lower dir or under a non-indexed upper is not always possible.
* ksu_ovl_connect_layer() will try to make origin's layer "connected" by
* copying up a "connectable" ancestor.
*/
if (d_is_dir(dentry) && ksu_ovl_upper_mnt(ofs))
return ksu_ovl_connect_layer(dentry);
/* Lower file handle for indexed and non-upper dir/non-dir */
return 1;
}
static int ksu_ovl_dentry_to_fid(struct dentry *dentry, u32 *fid, int buflen)
{
struct ksu_ovl_fh *fh = NULL;
int err, enc_lower;
int len;
/*
* Check if we should encode a lower or upper file handle and maybe
* copy up an ancestor to make lower file handle connectable.
*/
err = enc_lower = ksu_ovl_check_encode_origin(dentry);
if (enc_lower < 0)
goto fail;
/* Encode an upper or lower file handle */
fh = ksu_ovl_encode_real_fh(enc_lower ? ksu_ovl_dentry_lower(dentry) :
ksu_ovl_dentry_upper(dentry), !enc_lower);
if (IS_ERR(fh))
return PTR_ERR(fh);
len = KSU_OVL_FH_LEN(fh);
if (len <= buflen)
memcpy(fid, fh, len);
err = len;
out:
kfree(fh);
return err;
fail:
pr_warn_ratelimited("failed to encode file handle (%pd2, err=%i)\n",
dentry, err);
goto out;
}
static int ksu_ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
struct inode *parent)
{
struct dentry *dentry;
int bytes, buflen = *max_len << 2;
/* TODO: encode connectable file handles */
if (parent)
return FILEID_INVALID;
dentry = d_find_any_alias(inode);
if (!dentry)
return FILEID_INVALID;
bytes = ksu_ovl_dentry_to_fid(dentry, fid, buflen);
dput(dentry);
if (bytes <= 0)
return FILEID_INVALID;
*max_len = bytes >> 2;
if (bytes > buflen)
return FILEID_INVALID;
return KSU_OVL_FILEID_V1;
}
/*
* Find or instantiate an overlay dentry from real dentries and index.
*/
static struct dentry *ksu_ovl_obtain_alias(struct super_block *sb,
struct dentry *upper_alias,
struct ksu_ovl_path *lowerpath,
struct dentry *index)
{
struct dentry *lower = lowerpath ? lowerpath->dentry : NULL;
struct dentry *upper = upper_alias ?: index;
struct dentry *dentry;
struct inode *inode;
struct ksu_ovl_entry *oe;
struct ksu_ovl_inode_params oip = {
.lowerpath = lowerpath,
.index = index,
.numlower = !!lower
};
/* We get overlay directory dentries with ksu_ovl_lookup_real() */
if (d_is_dir(upper ?: lower))
return ERR_PTR(-EIO);
oip.upperdentry = dget(upper);
inode = ksu_ovl_get_inode(sb, &oip);
if (IS_ERR(inode)) {
dput(upper);
return ERR_CAST(inode);
}
if (upper)
ksu_ovl_set_flag(KSU_OVL_UPPERDATA, inode);
dentry = d_find_any_alias(inode);
if (dentry)
goto out_iput;
dentry = d_alloc_anon(inode->i_sb);
if (unlikely(!dentry))
goto nomem;
oe = ksu_ovl_alloc_entry(lower ? 1 : 0);
if (!oe)
goto nomem;
if (lower) {
oe->lowerstack->dentry = dget(lower);
oe->lowerstack->layer = lowerpath->layer;
}
dentry->d_fsdata = oe;
if (upper_alias)
ksu_ovl_dentry_set_upper_alias(dentry);
ksu_ovl_dentry_update_reval(dentry, upper,
DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
return d_instantiate_anon(dentry, inode);
nomem:
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
out_iput:
iput(inode);
return dentry;
}
/* Get the upper or lower dentry in stach whose on layer @idx */
static struct dentry *ksu_ovl_dentry_real_at(struct dentry *dentry, int idx)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
int i;
if (!idx)
return ksu_ovl_dentry_upper(dentry);
for (i = 0; i < oe->numlower; i++) {
if (oe->lowerstack[i].layer->idx == idx)
return oe->lowerstack[i].dentry;
}
return NULL;
}
/*
* Lookup a child overlay dentry to get a connected overlay dentry whose real
* dentry is @real. If @real is on upper layer, we lookup a child overlay
* dentry with the same name as the real dentry. Otherwise, we need to consult
* index for lookup.
*/
static struct dentry *ksu_ovl_lookup_real_one(struct dentry *connected,
struct dentry *real,
const struct ksu_ovl_layer *layer)
{
struct inode *dir = d_inode(connected);
struct dentry *this, *parent = NULL;
struct name_snapshot name;
int err;
/*
* Lookup child overlay dentry by real name. The dir mutex protects us
* from racing with overlay rename. If the overlay dentry that is above
* real has already been moved to a parent that is not under the
* connected overlay dir, we return -ECHILD and restart the lookup of
* connected real path from the top.
*/
inode_lock_nested(dir, I_MUTEX_PARENT);
err = -ECHILD;
parent = dget_parent(real);
if (ksu_ovl_dentry_real_at(connected, layer->idx) != parent)
goto fail;
/*
* We also need to take a snapshot of real dentry name to protect us
* from racing with underlying layer rename. In this case, we don't
* care about returning ESTALE, only from dereferencing a free name
* pointer because we hold no lock on the real dentry.
*/
take_dentry_name_snapshot(&name, real);
this = lookup_one_len(name.name.name, connected, name.name.len);
release_dentry_name_snapshot(&name);
err = PTR_ERR(this);
if (IS_ERR(this)) {
goto fail;
} else if (!this || !this->d_inode) {
dput(this);
err = -ENOENT;
goto fail;
} else if (ksu_ovl_dentry_real_at(this, layer->idx) != real) {
dput(this);
err = -ESTALE;
goto fail;
}
out:
dput(parent);
inode_unlock(dir);
return this;
fail:
pr_warn_ratelimited("failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n",
real, layer->idx, connected, err);
this = ERR_PTR(err);
goto out;
}
static struct dentry *ksu_ovl_lookup_real(struct super_block *sb,
struct dentry *real,
const struct ksu_ovl_layer *layer);
/*
* Lookup an indexed or hashed overlay dentry by real inode.
*/
static struct dentry *ksu_ovl_lookup_real_inode(struct super_block *sb,
struct dentry *real,
const struct ksu_ovl_layer *layer)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
struct dentry *index = NULL;
struct dentry *this = NULL;
struct inode *inode;
/*
* Decoding upper dir from index is expensive, so first try to lookup
* overlay dentry in inode/dcache.
*/
inode = ksu_ovl_lookup_inode(sb, real, !layer->idx);
if (IS_ERR(inode))
return ERR_CAST(inode);
if (inode) {
this = d_find_any_alias(inode);
iput(inode);
}
/*
* For decoded lower dir file handle, lookup index by origin to check
* if lower dir was copied up and and/or removed.
*/
if (!this && layer->idx && ofs->indexdir && !WARN_ON(!d_is_dir(real))) {
index = ksu_ovl_lookup_index(ofs, NULL, real, false);
if (IS_ERR(index))
return index;
}
/* Get connected upper overlay dir from index */
if (index) {
struct dentry *upper = ksu_ovl_index_upper(ofs, index);
dput(index);
if (IS_ERR_OR_NULL(upper))
return upper;
/*
* ksu_ovl_lookup_real() in lower layer may call recursively once to
* ksu_ovl_lookup_real() in upper layer. The first level call walks
* back lower parents to the topmost indexed parent. The second
* recursive call walks back from indexed upper to the topmost
* connected/hashed upper parent (or up to root).
*/
this = ksu_ovl_lookup_real(sb, upper, &ofs->layers[0]);
dput(upper);
}
if (IS_ERR_OR_NULL(this))
return this;
if (ksu_ovl_dentry_real_at(this, layer->idx) != real) {
dput(this);
this = ERR_PTR(-EIO);
}
return this;
}
/*
* Lookup an indexed or hashed overlay dentry, whose real dentry is an
* ancestor of @real.
*/
static struct dentry *ksu_ovl_lookup_real_ancestor(struct super_block *sb,
struct dentry *real,
const struct ksu_ovl_layer *layer)
{
struct dentry *next, *parent = NULL;
struct dentry *ancestor = ERR_PTR(-EIO);
if (real == layer->mnt->mnt_root)
return dget(sb->s_root);
/* Find the topmost indexed or hashed ancestor */
next = dget(real);
for (;;) {
parent = dget_parent(next);
/*
* Lookup a matching overlay dentry in inode/dentry
* cache or in index by real inode.
*/
ancestor = ksu_ovl_lookup_real_inode(sb, next, layer);
if (ancestor)
break;
if (parent == layer->mnt->mnt_root) {
ancestor = dget(sb->s_root);
break;
}
/*
* If @real has been moved out of the layer root directory,
* we will eventully hit the real fs root. This cannot happen
* by legit overlay rename, so we return error in that case.
*/
if (parent == next) {
ancestor = ERR_PTR(-EXDEV);
break;
}
dput(next);
next = parent;
}
dput(parent);
dput(next);
return ancestor;
}
/*
* Lookup a connected overlay dentry whose real dentry is @real.
* If @real is on upper layer, we lookup a child overlay dentry with the same
* path the real dentry. Otherwise, we need to consult index for lookup.
*/
static struct dentry *ksu_ovl_lookup_real(struct super_block *sb,
struct dentry *real,
const struct ksu_ovl_layer *layer)
{
struct dentry *connected;
int err = 0;
connected = ksu_ovl_lookup_real_ancestor(sb, real, layer);
if (IS_ERR(connected))
return connected;
while (!err) {
struct dentry *next, *this;
struct dentry *parent = NULL;
struct dentry *real_connected = ksu_ovl_dentry_real_at(connected,
layer->idx);
if (real_connected == real)
break;
/* Find the topmost dentry not yet connected */
next = dget(real);
for (;;) {
parent = dget_parent(next);
if (parent == real_connected)
break;
/*
* If real has been moved out of 'real_connected',
* we will not find 'real_connected' and hit the layer
* root. In that case, we need to restart connecting.
* This game can go on forever in the worst case. We
* may want to consider taking s_vfs_rename_mutex if
* this happens more than once.
*/
if (parent == layer->mnt->mnt_root) {
dput(connected);
connected = dget(sb->s_root);
break;
}
/*
* If real file has been moved out of the layer root
* directory, we will eventully hit the real fs root.
* This cannot happen by legit overlay rename, so we
* return error in that case.
*/
if (parent == next) {
err = -EXDEV;
break;
}
dput(next);
next = parent;
}
if (!err) {
this = ksu_ovl_lookup_real_one(connected, next, layer);
if (IS_ERR(this))
err = PTR_ERR(this);
/*
* Lookup of child in overlay can fail when racing with
* overlay rename of child away from 'connected' parent.
* In this case, we need to restart the lookup from the
* top, because we cannot trust that 'real_connected' is
* still an ancestor of 'real'. There is a good chance
* that the renamed overlay ancestor is now in cache, so
* ksu_ovl_lookup_real_ancestor() will find it and we can
* continue to connect exactly from where lookup failed.
*/
if (err == -ECHILD) {
this = ksu_ovl_lookup_real_ancestor(sb, real,
layer);
err = PTR_ERR_OR_ZERO(this);
}
if (!err) {
dput(connected);
connected = this;
}
}
dput(parent);
dput(next);
}
if (err)
goto fail;
return connected;
fail:
pr_warn_ratelimited("failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n",
real, layer->idx, connected, err);
dput(connected);
return ERR_PTR(err);
}
/*
* Get an overlay dentry from upper/lower real dentries and index.
*/
static struct dentry *ksu_ovl_get_dentry(struct super_block *sb,
struct dentry *upper,
struct ksu_ovl_path *lowerpath,
struct dentry *index)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
const struct ksu_ovl_layer *layer = upper ? &ofs->layers[0] : lowerpath->layer;
struct dentry *real = upper ?: (index ?: lowerpath->dentry);
/*
* Obtain a disconnected overlay dentry from a non-dir real dentry
* and index.
*/
if (!d_is_dir(real))
return ksu_ovl_obtain_alias(sb, upper, lowerpath, index);
/* Removed empty directory? */
if ((real->d_flags & DCACHE_DISCONNECTED) || d_unhashed(real))
return ERR_PTR(-ENOENT);
/*
* If real dentry is connected and hashed, get a connected overlay
* dentry whose real dentry is @real.
*/
return ksu_ovl_lookup_real(sb, real, layer);
}
static struct dentry *ksu_ovl_upper_fh_to_d(struct super_block *sb,
struct ksu_ovl_fh *fh)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
struct dentry *dentry;
struct dentry *upper;
if (!ksu_ovl_upper_mnt(ofs))
return ERR_PTR(-EACCES);
upper = ksu_ovl_decode_real_fh(fh, ksu_ovl_upper_mnt(ofs), true);
if (IS_ERR_OR_NULL(upper))
return upper;
dentry = ksu_ovl_get_dentry(sb, upper, NULL, NULL);
dput(upper);
return dentry;
}
static struct dentry *ksu_ovl_lower_fh_to_d(struct super_block *sb,
struct ksu_ovl_fh *fh)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
struct ksu_ovl_path origin = { };
struct ksu_ovl_path *stack = &origin;
struct dentry *dentry = NULL;
struct dentry *index = NULL;
struct inode *inode;
int err;
/* First lookup overlay inode in inode cache by origin fh */
err = ksu_ovl_check_origin_fh(ofs, fh, false, NULL, &stack);
if (err)
return ERR_PTR(err);
if (!d_is_dir(origin.dentry) ||
!(origin.dentry->d_flags & DCACHE_DISCONNECTED)) {
inode = ksu_ovl_lookup_inode(sb, origin.dentry, false);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_err;
if (inode) {
dentry = d_find_any_alias(inode);
iput(inode);
if (dentry)
goto out;
}
}
/* Then lookup indexed upper/whiteout by origin fh */
if (ofs->indexdir) {
index = ksu_ovl_get_index_fh(ofs, fh);
err = PTR_ERR(index);
if (IS_ERR(index)) {
index = NULL;
goto out_err;
}
}
/* Then try to get a connected upper dir by index */
if (index && d_is_dir(index)) {
struct dentry *upper = ksu_ovl_index_upper(ofs, index);
err = PTR_ERR(upper);
if (IS_ERR_OR_NULL(upper))
goto out_err;
dentry = ksu_ovl_get_dentry(sb, upper, NULL, NULL);
dput(upper);
goto out;
}
/* Find origin.dentry again with ksu_ovl_acceptable() layer check */
if (d_is_dir(origin.dentry)) {
dput(origin.dentry);
origin.dentry = NULL;
err = ksu_ovl_check_origin_fh(ofs, fh, true, NULL, &stack);
if (err)
goto out_err;
}
if (index) {
err = ksu_ovl_verify_origin(ofs, index, origin.dentry, false);
if (err)
goto out_err;
}
/* Get a connected non-upper dir or disconnected non-dir */
dentry = ksu_ovl_get_dentry(sb, NULL, &origin, index);
out:
dput(origin.dentry);
dput(index);
return dentry;
out_err:
dentry = ERR_PTR(err);
goto out;
}
static struct ksu_ovl_fh *ksu_ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
{
struct ksu_ovl_fh *fh;
/* If on-wire inner fid is aligned - nothing to do */
if (fh_type == KSU_OVL_FILEID_V1)
return (struct ksu_ovl_fh *)fid;
if (fh_type != KSU_OVL_FILEID_V0)
return ERR_PTR(-EINVAL);
if (buflen <= KSU_OVL_FH_WIRE_OFFSET)
return ERR_PTR(-EINVAL);
fh = kzalloc(buflen, GFP_KERNEL);
if (!fh)
return ERR_PTR(-ENOMEM);
/* Copy unaligned inner fh into aligned buffer */
memcpy(&fh->fb, fid, buflen - KSU_OVL_FH_WIRE_OFFSET);
return fh;
}
static struct dentry *ksu_ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type)
{
struct dentry *dentry = NULL;
struct ksu_ovl_fh *fh = NULL;
int len = fh_len << 2;
unsigned int flags = 0;
int err;
fh = ksu_ovl_fid_to_fh(fid, len, fh_type);
err = PTR_ERR(fh);
if (IS_ERR(fh))
goto out_err;
err = ksu_ovl_check_fh_len(fh, len);
if (err)
goto out_err;
flags = fh->fb.flags;
dentry = (flags & KSU_OVL_FH_FLAG_PATH_UPPER) ?
ksu_ovl_upper_fh_to_d(sb, fh) :
ksu_ovl_lower_fh_to_d(sb, fh);
err = PTR_ERR(dentry);
if (IS_ERR(dentry) && err != -ESTALE)
goto out_err;
out:
/* We may have needed to re-align KSU_OVL_FILEID_V0 */
if (!IS_ERR_OR_NULL(fh) && fh != (void *)fid)
kfree(fh);
return dentry;
out_err:
pr_warn_ratelimited("failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n",
fh_len, fh_type, flags, err);
dentry = ERR_PTR(err);
goto out;
}
static struct dentry *ksu_ovl_fh_to_parent(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type)
{
pr_warn_ratelimited("connectable file handles not supported; use 'no_subtree_check' exportfs option.\n");
return ERR_PTR(-EACCES);
}
static int ksu_ovl_get_name(struct dentry *parent, char *name,
struct dentry *child)
{
/*
* ksu_ovl_fh_to_dentry() returns connected dir overlay dentries and
* ksu_ovl_fh_to_parent() is not implemented, so we should not get here.
*/
WARN_ON_ONCE(1);
return -EIO;
}
static struct dentry *ksu_ovl_get_parent(struct dentry *dentry)
{
/*
* ksu_ovl_fh_to_dentry() returns connected dir overlay dentries, so we
* should not get here.
*/
WARN_ON_ONCE(1);
return ERR_PTR(-EIO);
}
const struct export_operations ksu_ovl_export_operations = {
.encode_fh = ksu_ovl_encode_fh,
.fh_to_dentry = ksu_ovl_fh_to_dentry,
.fh_to_parent = ksu_ovl_fh_to_parent,
.get_name = ksu_ovl_get_name,
.get_parent = ksu_ovl_get_parent,
};

View File

@@ -1,809 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Red Hat, Inc.
*/
#include <linux/cred.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/xattr.h>
#include <linux/uio.h>
#include <linux/uaccess.h>
#include <linux/splice.h>
#include <linux/security.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include "overlayfs.h"
#define KSU_OVL_IOCB_MASK (IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC)
struct ksu_ovl_aio_req {
struct kiocb iocb;
refcount_t ref;
struct kiocb *orig_iocb;
struct fd fd;
};
static struct kmem_cache *ksu_ovl_aio_request_cachep;
static char ksu_ovl_whatisit(struct inode *inode, struct inode *realinode)
{
if (realinode != ksu_ovl_inode_upper(inode))
return 'l';
if (ksu_ovl_has_upperdata(inode))
return 'u';
else
return 'm';
}
/* No atime modificaton nor notify on underlying */
#define KSU_OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
static struct file *ksu_ovl_open_realfile(const struct file *file,
struct inode *realinode)
{
struct inode *inode = file_inode(file);
struct file *realfile;
const struct cred *old_cred;
int flags = file->f_flags | KSU_OVL_OPEN_FLAGS;
int acc_mode = ACC_MODE(flags);
int err;
if (flags & O_APPEND)
acc_mode |= MAY_APPEND;
old_cred = ksu_ovl_override_creds(inode->i_sb);
err = inode_permission(realinode, MAY_OPEN | acc_mode);
if (err) {
realfile = ERR_PTR(err);
} else if (old_cred && !inode_owner_or_capable(realinode)) {
realfile = ERR_PTR(-EPERM);
} else {
realfile = open_with_fake_path(&file->f_path, flags, realinode,
current_cred());
}
ksu_ovl_revert_creds(inode->i_sb, old_cred);
pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
file, file, ksu_ovl_whatisit(inode, realinode), file->f_flags,
realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
return realfile;
}
#define KSU_OVL_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT)
static int ksu_ovl_change_flags(struct file *file, unsigned int flags)
{
struct inode *inode = file_inode(file);
int err;
flags |= KSU_OVL_OPEN_FLAGS;
/* If some flag changed that cannot be changed then something's amiss */
if (WARN_ON((file->f_flags ^ flags) & ~KSU_OVL_SETFL_MASK))
return -EIO;
flags &= KSU_OVL_SETFL_MASK;
if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode))
return -EPERM;
if (flags & O_DIRECT) {
if (!file->f_mapping->a_ops ||
!file->f_mapping->a_ops->direct_IO)
return -EINVAL;
}
if (file->f_op->check_flags) {
err = file->f_op->check_flags(flags);
if (err)
return err;
}
spin_lock(&file->f_lock);
file->f_flags = (file->f_flags & ~KSU_OVL_SETFL_MASK) | flags;
spin_unlock(&file->f_lock);
return 0;
}
static int ksu_ovl_real_fdget_meta(const struct file *file, struct fd *real,
bool allow_meta)
{
struct inode *inode = file_inode(file);
struct inode *realinode;
real->flags = 0;
real->file = file->private_data;
if (allow_meta)
realinode = ksu_ovl_inode_real(inode);
else
realinode = ksu_ovl_inode_realdata(inode);
/* Has it been copied up since we'd opened it? */
if (unlikely(file_inode(real->file) != realinode)) {
real->flags = FDPUT_FPUT;
real->file = ksu_ovl_open_realfile(file, realinode);
return PTR_ERR_OR_ZERO(real->file);
}
/* Did the flags change since open? */
if (unlikely((file->f_flags ^ real->file->f_flags) & ~KSU_OVL_OPEN_FLAGS))
return ksu_ovl_change_flags(real->file, file->f_flags);
return 0;
}
static int ksu_ovl_real_fdget(const struct file *file, struct fd *real)
{
if (d_is_dir(file_dentry(file))) {
real->flags = 0;
real->file = ksu_ovl_dir_real_file(file, false);
return PTR_ERR_OR_ZERO(real->file);
}
return ksu_ovl_real_fdget_meta(file, real, false);
}
static int ksu_ovl_open(struct inode *inode, struct file *file)
{
struct file *realfile;
int err;
err = ksu_ovl_maybe_copy_up(file_dentry(file), file->f_flags);
if (err)
return err;
/* No longer need these flags, so don't pass them on to underlying fs */
file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
realfile = ksu_ovl_open_realfile(file, ksu_ovl_inode_realdata(inode));
if (IS_ERR(realfile))
return PTR_ERR(realfile);
file->private_data = realfile;
return 0;
}
static int ksu_ovl_release(struct inode *inode, struct file *file)
{
fput(file->private_data);
return 0;
}
static loff_t ksu_ovl_llseek(struct file *file, loff_t offset, int whence)
{
struct inode *inode = file_inode(file);
struct fd real;
const struct cred *old_cred;
loff_t ret;
/*
* The two special cases below do not need to involve real fs,
* so we can optimizing concurrent callers.
*/
if (offset == 0) {
if (whence == SEEK_CUR)
return file->f_pos;
if (whence == SEEK_SET)
return vfs_setpos(file, 0, 0);
}
ret = ksu_ovl_real_fdget(file, &real);
if (ret)
return ret;
/*
* Overlay file f_pos is the master copy that is preserved
* through copy up and modified on read/write, but only real
* fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose
* limitations that are more strict than ->s_maxbytes for specific
* files, so we use the real file to perform seeks.
*/
ksu_ovl_inode_lock(inode);
real.file->f_pos = file->f_pos;
old_cred = ksu_ovl_override_creds(inode->i_sb);
ret = vfs_llseek(real.file, offset, whence);
ksu_ovl_revert_creds(inode->i_sb, old_cred);
file->f_pos = real.file->f_pos;
ksu_ovl_inode_unlock(inode);
fdput(real);
return ret;
}
static void ksu_ovl_file_accessed(struct file *file)
{
struct inode *inode, *upperinode;
if (file->f_flags & O_NOATIME)
return;
inode = file_inode(file);
upperinode = ksu_ovl_inode_upper(inode);
if (!upperinode)
return;
if ((!timespec64_equal(&inode->i_mtime, &upperinode->i_mtime) ||
!timespec64_equal(&inode->i_ctime, &upperinode->i_ctime))) {
inode->i_mtime = upperinode->i_mtime;
inode->i_ctime = upperinode->i_ctime;
}
touch_atime(&file->f_path);
}
static inline void ksu_ovl_aio_put(struct ksu_ovl_aio_req *aio_req)
{
if (refcount_dec_and_test(&aio_req->ref)) {
fdput(aio_req->fd);
kmem_cache_free(ksu_ovl_aio_request_cachep, aio_req);
}
}
static void ksu_ovl_aio_cleanup_handler(struct ksu_ovl_aio_req *aio_req)
{
struct kiocb *iocb = &aio_req->iocb;
struct kiocb *orig_iocb = aio_req->orig_iocb;
if (iocb->ki_flags & IOCB_WRITE) {
struct inode *inode = file_inode(orig_iocb->ki_filp);
/* Actually acquired in ksu_ovl_write_iter() */
__sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb,
SB_FREEZE_WRITE);
file_end_write(iocb->ki_filp);
ksu_ovl_copyattr(ksu_ovl_inode_real(inode), inode);
}
orig_iocb->ki_pos = iocb->ki_pos;
ksu_ovl_aio_put(aio_req);
}
static void ksu_ovl_aio_rw_complete(struct kiocb *iocb, long res, long res2)
{
struct ksu_ovl_aio_req *aio_req = container_of(iocb,
struct ksu_ovl_aio_req, iocb);
struct kiocb *orig_iocb = aio_req->orig_iocb;
ksu_ovl_aio_cleanup_handler(aio_req);
orig_iocb->ki_complete(orig_iocb, res, res2);
}
static ssize_t ksu_ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{
struct file *file = iocb->ki_filp;
struct fd real;
const struct cred *old_cred;
ssize_t ret;
if (!iov_iter_count(iter))
return 0;
ret = ksu_ovl_real_fdget(file, &real);
if (ret)
return ret;
ret = -EINVAL;
if (iocb->ki_flags & IOCB_DIRECT &&
(!real.file->f_mapping->a_ops ||
!real.file->f_mapping->a_ops->direct_IO))
goto out_fdput;
old_cred = ksu_ovl_override_creds(file_inode(file)->i_sb);
if (is_sync_kiocb(iocb)) {
ret = vfs_iter_read(real.file, iter, &iocb->ki_pos,
iocb_to_rw_flags(iocb->ki_flags,
KSU_OVL_IOCB_MASK));
} else {
struct ksu_ovl_aio_req *aio_req;
ret = -ENOMEM;
aio_req = kmem_cache_zalloc(ksu_ovl_aio_request_cachep, GFP_KERNEL);
if (!aio_req)
goto out;
aio_req->fd = real;
real.flags = 0;
aio_req->orig_iocb = iocb;
kiocb_clone(&aio_req->iocb, iocb, real.file);
aio_req->iocb.ki_complete = ksu_ovl_aio_rw_complete;
refcount_set(&aio_req->ref, 2);
ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
ksu_ovl_aio_put(aio_req);
if (ret != -EIOCBQUEUED)
ksu_ovl_aio_cleanup_handler(aio_req);
}
out:
ksu_ovl_revert_creds(file_inode(file)->i_sb, old_cred);
ksu_ovl_file_accessed(file);
out_fdput:
fdput(real);
return ret;
}
static ssize_t ksu_ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
{
struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(file);
struct fd real;
const struct cred *old_cred;
ssize_t ret;
int ifl = iocb->ki_flags;
if (!iov_iter_count(iter))
return 0;
inode_lock(inode);
/* Update mode */
ksu_ovl_copyattr(ksu_ovl_inode_real(inode), inode);
ret = file_remove_privs(file);
if (ret)
goto out_unlock;
ret = ksu_ovl_real_fdget(file, &real);
if (ret)
goto out_unlock;
ret = -EINVAL;
if (iocb->ki_flags & IOCB_DIRECT &&
(!real.file->f_mapping->a_ops ||
!real.file->f_mapping->a_ops->direct_IO))
goto out_fdput;
if (!ksu_ovl_should_sync(KSU_OVL_FS(inode->i_sb)))
ifl &= ~(IOCB_DSYNC | IOCB_SYNC);
old_cred = ksu_ovl_override_creds(file_inode(file)->i_sb);
if (is_sync_kiocb(iocb)) {
file_start_write(real.file);
ret = vfs_iter_write(real.file, iter, &iocb->ki_pos,
iocb_to_rw_flags(ifl, KSU_OVL_IOCB_MASK));
file_end_write(real.file);
/* Update size */
ksu_ovl_copyattr(ksu_ovl_inode_real(inode), inode);
} else {
struct ksu_ovl_aio_req *aio_req;
ret = -ENOMEM;
aio_req = kmem_cache_zalloc(ksu_ovl_aio_request_cachep, GFP_KERNEL);
if (!aio_req)
goto out;
file_start_write(real.file);
/* Pacify lockdep, same trick as done in aio_write() */
__sb_writers_release(file_inode(real.file)->i_sb,
SB_FREEZE_WRITE);
aio_req->fd = real;
real.flags = 0;
aio_req->orig_iocb = iocb;
kiocb_clone(&aio_req->iocb, iocb, real.file);
aio_req->iocb.ki_flags = ifl;
aio_req->iocb.ki_complete = ksu_ovl_aio_rw_complete;
refcount_set(&aio_req->ref, 2);
ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
ksu_ovl_aio_put(aio_req);
if (ret != -EIOCBQUEUED)
ksu_ovl_aio_cleanup_handler(aio_req);
}
out:
ksu_ovl_revert_creds(file_inode(file)->i_sb, old_cred);
out_fdput:
fdput(real);
out_unlock:
inode_unlock(inode);
return ret;
}
/*
* Calling iter_file_splice_write() directly from overlay's f_op may deadlock
* due to lock order inversion between pipe->mutex in iter_file_splice_write()
* and file_start_write(real.file) in ksu_ovl_write_iter().
*
* So do everything ksu_ovl_write_iter() does and call iter_file_splice_write() on
* the real file.
*/
static ssize_t ksu_ovl_splice_write(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags)
{
struct fd real;
const struct cred *old_cred;
struct inode *inode = file_inode(out);
struct inode *realinode = ksu_ovl_inode_real(inode);
ssize_t ret;
inode_lock(inode);
/* Update mode */
ksu_ovl_copyattr(realinode, inode);
ret = file_remove_privs(out);
if (ret)
goto out_unlock;
ret = ksu_ovl_real_fdget(out, &real);
if (ret)
goto out_unlock;
old_cred = ksu_ovl_override_creds(inode->i_sb);
file_start_write(real.file);
ret = iter_file_splice_write(pipe, real.file, ppos, len, flags);
file_end_write(real.file);
/* Update size */
ksu_ovl_copyattr(realinode, inode);
ksu_ovl_revert_creds(inode->i_sb, old_cred);
fdput(real);
out_unlock:
inode_unlock(inode);
return ret;
}
static int ksu_ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
struct fd real;
const struct cred *old_cred;
int ret;
ret = ksu_ovl_sync_status(KSU_OVL_FS(file_inode(file)->i_sb));
if (ret <= 0)
return ret;
ret = ksu_ovl_real_fdget_meta(file, &real, !datasync);
if (ret)
return ret;
/* Don't sync lower file for fear of receiving EROFS error */
if (file_inode(real.file) == ksu_ovl_inode_upper(file_inode(file))) {
old_cred = ksu_ovl_override_creds(file_inode(file)->i_sb);
ret = vfs_fsync_range(real.file, start, end, datasync);
ksu_ovl_revert_creds(file_inode(file)->i_sb, old_cred);
}
fdput(real);
return ret;
}
static int ksu_ovl_mmap(struct file *file, struct vm_area_struct *vma)
{
struct file *realfile = file->private_data;
const struct cred *old_cred;
int ret;
if (!realfile->f_op->mmap)
return -ENODEV;
if (WARN_ON(file != vma->vm_file))
return -EIO;
vma->vm_file = get_file(realfile);
old_cred = ksu_ovl_override_creds(file_inode(file)->i_sb);
ret = call_mmap(vma->vm_file, vma);
ksu_ovl_revert_creds(file_inode(file)->i_sb, old_cred);
if (ret) {
/* Drop reference count from new vm_file value */
fput(realfile);
} else {
/* Drop reference count from previous vm_file value */
fput(file);
}
ksu_ovl_file_accessed(file);
return ret;
}
static long ksu_ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{
struct inode *inode = file_inode(file);
struct fd real;
const struct cred *old_cred;
int ret;
inode_lock(inode);
/* Update mode */
ksu_ovl_copyattr(ksu_ovl_inode_real(inode), inode);
ret = file_remove_privs(file);
if (ret)
goto out_unlock;
ret = ksu_ovl_real_fdget(file, &real);
if (ret)
goto out_unlock;
old_cred = ksu_ovl_override_creds(file_inode(file)->i_sb);
ret = vfs_fallocate(real.file, mode, offset, len);
ksu_ovl_revert_creds(file_inode(file)->i_sb, old_cred);
/* Update size */
ksu_ovl_copyattr(ksu_ovl_inode_real(inode), inode);
fdput(real);
out_unlock:
inode_unlock(inode);
return ret;
}
static int ksu_ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
{
struct fd real;
const struct cred *old_cred;
int ret;
ret = ksu_ovl_real_fdget(file, &real);
if (ret)
return ret;
old_cred = ksu_ovl_override_creds(file_inode(file)->i_sb);
ret = vfs_fadvise(real.file, offset, len, advice);
ksu_ovl_revert_creds(file_inode(file)->i_sb, old_cred);
fdput(real);
return ret;
}
static long ksu_ovl_real_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct fd real;
long ret;
ret = ksu_ovl_real_fdget(file, &real);
if (ret)
return ret;
ret = security_file_ioctl(real.file, cmd, arg);
if (!ret) {
/*
* Don't override creds, since we currently can't safely check
* permissions before doing so.
*/
ret = vfs_ioctl(real.file, cmd, arg);
}
fdput(real);
return ret;
}
static long ksu_ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
unsigned long arg)
{
long ret;
struct inode *inode = file_inode(file);
if (!inode_owner_or_capable(inode))
return -EACCES;
ret = mnt_want_write_file(file);
if (ret)
return ret;
inode_lock(inode);
/*
* Prevent copy up if immutable and has no CAP_LINUX_IMMUTABLE
* capability.
*/
ret = -EPERM;
if (!ksu_ovl_has_upperdata(inode) && IS_IMMUTABLE(inode) &&
!capable(CAP_LINUX_IMMUTABLE))
goto unlock;
ret = ksu_ovl_maybe_copy_up(file_dentry(file), O_WRONLY);
if (ret)
goto unlock;
ret = ksu_ovl_real_ioctl(file, cmd, arg);
ksu_ovl_copyflags(ksu_ovl_inode_real(inode), inode);
unlock:
inode_unlock(inode);
mnt_drop_write_file(file);
return ret;
}
long ksu_ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
switch (cmd) {
case FS_IOC_GETFLAGS:
case FS_IOC_FSGETXATTR:
ret = ksu_ovl_real_ioctl(file, cmd, arg);
break;
case FS_IOC_FSSETXATTR:
case FS_IOC_SETFLAGS:
ret = ksu_ovl_ioctl_set_flags(file, cmd, arg);
break;
default:
ret = -ENOTTY;
}
return ret;
}
#ifdef CONFIG_COMPAT
long ksu_ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case FS_IOC32_GETFLAGS:
cmd = FS_IOC_GETFLAGS;
break;
case FS_IOC32_SETFLAGS:
cmd = FS_IOC_SETFLAGS;
break;
default:
return -ENOIOCTLCMD;
}
return ksu_ovl_ioctl(file, cmd, arg);
}
#endif
enum ksu_ovl_copyop {
KSU_OVL_COPY,
KSU_OVL_CLONE,
KSU_OVL_DEDUPE,
};
static loff_t ksu_ovl_copyfile(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out,
loff_t len, unsigned int flags, enum ksu_ovl_copyop op)
{
struct inode *inode_out = file_inode(file_out);
struct fd real_in, real_out;
const struct cred *old_cred;
loff_t ret;
inode_lock(inode_out);
if (op != KSU_OVL_DEDUPE) {
/* Update mode */
ksu_ovl_copyattr(ksu_ovl_inode_real(inode_out), inode_out);
ret = file_remove_privs(file_out);
if (ret)
goto out_unlock;
}
ret = ksu_ovl_real_fdget(file_out, &real_out);
if (ret)
goto out_unlock;
ret = ksu_ovl_real_fdget(file_in, &real_in);
if (ret) {
fdput(real_out);
goto out_unlock;
}
old_cred = ksu_ovl_override_creds(file_inode(file_out)->i_sb);
switch (op) {
case KSU_OVL_COPY:
ret = vfs_copy_file_range(real_in.file, pos_in,
real_out.file, pos_out, len, flags);
break;
case KSU_OVL_CLONE:
ret = vfs_clone_file_range(real_in.file, pos_in,
real_out.file, pos_out, len, flags);
break;
case KSU_OVL_DEDUPE:
ret = vfs_dedupe_file_range_one(real_in.file, pos_in,
real_out.file, pos_out, len,
flags);
break;
}
ksu_ovl_revert_creds(file_inode(file_out)->i_sb, old_cred);
/* Update size */
ksu_ovl_copyattr(ksu_ovl_inode_real(inode_out), inode_out);
fdput(real_in);
fdput(real_out);
out_unlock:
inode_unlock(inode_out);
return ret;
}
static ssize_t ksu_ovl_copy_file_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out,
size_t len, unsigned int flags)
{
return ksu_ovl_copyfile(file_in, pos_in, file_out, pos_out, len, flags,
KSU_OVL_COPY);
}
static loff_t ksu_ovl_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)
{
enum ksu_ovl_copyop op;
if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
return -EINVAL;
if (remap_flags & REMAP_FILE_DEDUP)
op = KSU_OVL_DEDUPE;
else
op = KSU_OVL_CLONE;
/*
* Don't copy up because of a dedupe request, this wouldn't make sense
* most of the time (data would be duplicated instead of deduplicated).
*/
if (op == KSU_OVL_DEDUPE &&
(!ksu_ovl_inode_upper(file_inode(file_in)) ||
!ksu_ovl_inode_upper(file_inode(file_out))))
return -EPERM;
return ksu_ovl_copyfile(file_in, pos_in, file_out, pos_out, len,
remap_flags, op);
}
const struct file_operations ksu_ovl_file_operations = {
.open = ksu_ovl_open,
.release = ksu_ovl_release,
.llseek = ksu_ovl_llseek,
.read_iter = ksu_ovl_read_iter,
.write_iter = ksu_ovl_write_iter,
.fsync = ksu_ovl_fsync,
.mmap = ksu_ovl_mmap,
.fallocate = ksu_ovl_fallocate,
.fadvise = ksu_ovl_fadvise,
.unlocked_ioctl = ksu_ovl_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ksu_ovl_compat_ioctl,
#endif
.splice_read = generic_file_splice_read,
.splice_write = ksu_ovl_splice_write,
.copy_file_range = ksu_ovl_copy_file_range,
.remap_file_range = ksu_ovl_remap_file_range,
};
int __init ksu_ovl_aio_request_cache_init(void)
{
ksu_ovl_aio_request_cachep = kmem_cache_create("ksu_ovl_aio_req",
sizeof(struct ksu_ovl_aio_req),
0, SLAB_HWCACHE_ALIGN, NULL);
if (!ksu_ovl_aio_request_cachep)
return -ENOMEM;
return 0;
}
void ksu_ovl_aio_request_cache_destroy(void)
{
kmem_cache_destroy(ksu_ovl_aio_request_cachep);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,145 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
* Copyright (C) 2011 Novell Inc.
* Copyright (C) 2016 Red Hat, Inc.
*/
struct ksu_ovl_config {
char *lowerdir;
char *upperdir;
char *workdir;
bool default_permissions;
bool redirect_dir;
bool redirect_follow;
const char *redirect_mode;
bool index;
bool nfs_export;
int xino;
bool metacopy;
bool ksu_ovl_volatile;
bool override_creds;
};
struct ksu_ovl_sb {
struct super_block *sb;
dev_t pseudo_dev;
/* Unusable (conflicting) uuid */
bool bad_uuid;
/* Used as a lower layer (but maybe also as upper) */
bool is_lower;
};
struct ksu_ovl_layer {
struct vfsmount *mnt;
/* Trap in ovl inode cache */
struct inode *trap;
struct ksu_ovl_sb *fs;
/* Index of this layer in fs root (upper idx == 0) */
int idx;
/* One fsid per unique underlying sb (upper fsid == 0) */
int fsid;
};
struct ksu_ovl_path {
const struct ksu_ovl_layer *layer;
struct dentry *dentry;
};
/* private information held for overlayfs's superblock */
struct ksu_ovl_fs {
unsigned int numlayer;
/* Number of unique fs among layers including upper fs */
unsigned int numfs;
const struct ksu_ovl_layer *layers;
struct ksu_ovl_sb *fs;
/* workbasedir is the path at workdir= mount option */
struct dentry *workbasedir;
/* workdir is the 'work' directory under workbasedir */
struct dentry *workdir;
/* index directory listing overlay inodes by origin file handle */
struct dentry *indexdir;
long namelen;
/* pathnames of lower and upper dirs, for show_options */
struct ksu_ovl_config config;
/* creds of process who forced instantiation of super block */
const struct cred *creator_cred;
bool tmpfile;
bool noxattr;
/* Did we take the inuse lock? */
bool upperdir_locked;
bool workdir_locked;
bool share_whiteout;
/* Traps in ovl inode cache */
struct inode *workbasedir_trap;
struct inode *workdir_trap;
struct inode *indexdir_trap;
/* -1: disabled, 0: same fs, 1..32: number of unused ino bits */
int xino_mode;
/* For allocation of non-persistent inode numbers */
atomic_long_t last_ino;
/* Whiteout dentry cache */
struct dentry *whiteout;
/* r/o snapshot of upperdir sb's only taken on volatile mounts */
errseq_t errseq;
};
static inline struct vfsmount *ksu_ovl_upper_mnt(struct ksu_ovl_fs *ofs)
{
return ofs->layers[0].mnt;
}
static inline struct ksu_ovl_fs *KSU_OVL_FS(struct super_block *sb)
{
return (struct ksu_ovl_fs *)sb->s_fs_info;
}
static inline bool ksu_ovl_should_sync(struct ksu_ovl_fs *ofs)
{
return !ofs->config.ksu_ovl_volatile;
}
/* private information held for every overlayfs dentry */
struct ksu_ovl_entry {
union {
struct {
unsigned long flags;
};
struct rcu_head rcu;
};
unsigned numlower;
struct ksu_ovl_path lowerstack[];
};
struct ksu_ovl_entry *ksu_ovl_alloc_entry(unsigned int numlower);
static inline struct ksu_ovl_entry *KSU_OVL_E(struct dentry *dentry)
{
return (struct ksu_ovl_entry *) dentry->d_fsdata;
}
struct ksu_ovl_inode {
union {
struct ksu_ovl_dir_cache *cache; /* directory */
struct inode *lowerdata; /* regular file */
};
const char *redirect;
u64 version;
unsigned long flags;
struct inode vfs_inode;
struct dentry *__upperdentry;
struct inode *lower;
/* synchronize copy up and more */
struct mutex lock;
};
static inline struct ksu_ovl_inode *KSU_OVL_I(struct inode *inode)
{
return container_of(inode, struct ksu_ovl_inode, vfs_inode);
}
static inline struct dentry *ksu_ovl_upperdentry_dereference(struct ksu_ovl_inode *oi)
{
return READ_ONCE(oi->__upperdentry);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,551 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
*
* Copyright (C) 2011 Novell Inc.
*/
#include <linux/kernel.h>
#include <linux/uuid.h>
#include <linux/fs.h>
#include "ksu_ovl_entry.h"
#undef pr_fmt
#define pr_fmt(fmt) "ksufs: " fmt
enum ksu_ovl_path_type {
__KSU_OVL_PATH_UPPER = (1 << 0),
__KSU_OVL_PATH_MERGE = (1 << 1),
__KSU_OVL_PATH_ORIGIN = (1 << 2),
};
#define KSU_OVL_TYPE_UPPER(type) ((type) & __KSU_OVL_PATH_UPPER)
#define KSU_OVL_TYPE_MERGE(type) ((type) & __KSU_OVL_PATH_MERGE)
#define KSU_OVL_TYPE_ORIGIN(type) ((type) & __KSU_OVL_PATH_ORIGIN)
#define KSU_OVL_XATTR_PREFIX XATTR_TRUSTED_PREFIX "overlay."
enum ksu_ovl_xattr {
KSU_OVL_XATTR_OPAQUE,
KSU_OVL_XATTR_REDIRECT,
KSU_OVL_XATTR_ORIGIN,
KSU_OVL_XATTR_IMPURE,
KSU_OVL_XATTR_NLINK,
KSU_OVL_XATTR_UPPER,
KSU_OVL_XATTR_METACOPY,
};
enum ksu_ovl_inode_flag {
/* Pure upper dir that may contain non pure upper entries */
KSU_OVL_IMPURE,
/* Non-merge dir that may contain whiteout entries */
KSU_OVL_WHITEOUTS,
KSU_OVL_INDEX,
KSU_OVL_UPPERDATA,
/* Inode number will remain constant over copy up. */
KSU_OVL_CONST_INO,
};
enum ksu_ovl_entry_flag {
KSU_OVL_E_UPPER_ALIAS,
KSU_OVL_E_OPAQUE,
KSU_OVL_E_CONNECTED,
};
enum {
KSU_OVL_XINO_OFF,
KSU_OVL_XINO_AUTO,
KSU_OVL_XINO_ON,
};
/*
* The tuple (fh,uuid) is a universal unique identifier for a copy up origin,
* where:
* origin.fh - exported file handle of the lower file
* origin.uuid - uuid of the lower filesystem
*/
#define KSU_OVL_FH_VERSION 0
#define KSU_OVL_FH_MAGIC 0xfb
/* CPU byte order required for fid decoding: */
#define KSU_OVL_FH_FLAG_BIG_ENDIAN (1 << 0)
#define KSU_OVL_FH_FLAG_ANY_ENDIAN (1 << 1)
/* Is the real inode encoded in fid an upper inode? */
#define KSU_OVL_FH_FLAG_PATH_UPPER (1 << 2)
#define KSU_OVL_FH_FLAG_ALL (KSU_OVL_FH_FLAG_BIG_ENDIAN | KSU_OVL_FH_FLAG_ANY_ENDIAN | \
KSU_OVL_FH_FLAG_PATH_UPPER)
#if defined(__LITTLE_ENDIAN)
#define KSU_OVL_FH_FLAG_CPU_ENDIAN 0
#elif defined(__BIG_ENDIAN)
#define KSU_OVL_FH_FLAG_CPU_ENDIAN KSU_OVL_FH_FLAG_BIG_ENDIAN
#else
#error Endianness not defined
#endif
/* The type used to be returned by overlay exportfs for misaligned fid */
#define KSU_OVL_FILEID_V0 0xfb
/* The type returned by overlay exportfs for 32bit aligned fid */
#define KSU_OVL_FILEID_V1 0xf8
/* On-disk format for "origin" file handle */
struct ksu_ovl_fb {
u8 version; /* 0 */
u8 magic; /* 0xfb */
u8 len; /* size of this header + size of fid */
u8 flags; /* KSU_OVL_FH_FLAG_* */
u8 type; /* fid_type of fid */
uuid_t uuid; /* uuid of filesystem */
u32 fid[]; /* file identifier should be 32bit aligned in-memory */
} __packed;
/* In-memory and on-wire format for overlay file handle */
struct ksu_ovl_fh {
u8 padding[3]; /* make sure fb.fid is 32bit aligned */
union {
struct ksu_ovl_fb fb;
u8 buf[0];
};
} __packed;
#define KSU_OVL_FH_WIRE_OFFSET offsetof(struct ksu_ovl_fh, fb)
#define KSU_OVL_FH_LEN(fh) (KSU_OVL_FH_WIRE_OFFSET + (fh)->fb.len)
#define KSU_OVL_FH_FID_OFFSET (KSU_OVL_FH_WIRE_OFFSET + \
offsetof(struct ksu_ovl_fb, fid))
extern const char *ksu_ovl_xattr_table[];
static inline const char *ksu_ovl_xattr(struct ksu_ovl_fs *ofs, enum ksu_ovl_xattr ox)
{
return ksu_ovl_xattr_table[ox];
}
static inline int ksu_ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
{
int err = vfs_rmdir(dir, dentry);
pr_debug("rmdir(%pd2) = %i\n", dentry, err);
return err;
}
static inline int ksu_ovl_do_unlink(struct inode *dir, struct dentry *dentry)
{
int err = vfs_unlink(dir, dentry, NULL);
pr_debug("unlink(%pd2) = %i\n", dentry, err);
return err;
}
static inline int ksu_ovl_do_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
int err = vfs_link(old_dentry, dir, new_dentry, NULL);
pr_debug("link(%pd2, %pd2) = %i\n", old_dentry, new_dentry, err);
return err;
}
static inline int ksu_ovl_do_create(struct inode *dir, struct dentry *dentry,
umode_t mode)
{
int err = vfs_create(dir, dentry, mode, true);
pr_debug("create(%pd2, 0%o) = %i\n", dentry, mode, err);
return err;
}
static inline int ksu_ovl_do_mkdir(struct inode *dir, struct dentry *dentry,
umode_t mode)
{
int err = vfs_mkdir(dir, dentry, mode);
pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, err);
return err;
}
static inline int ksu_ovl_do_mknod(struct inode *dir, struct dentry *dentry,
umode_t mode, dev_t dev)
{
int err = vfs_mknod(dir, dentry, mode, dev);
pr_debug("mknod(%pd2, 0%o, 0%o) = %i\n", dentry, mode, dev, err);
return err;
}
static inline int ksu_ovl_do_symlink(struct inode *dir, struct dentry *dentry,
const char *oldname)
{
int err = vfs_symlink(dir, dentry, oldname);
pr_debug("symlink(\"%s\", %pd2) = %i\n", oldname, dentry, err);
return err;
}
static inline ssize_t ksu_ovl_do_getxattr(struct ksu_ovl_fs *ofs, struct dentry *dentry,
enum ksu_ovl_xattr ox, void *value,
size_t size)
{
const char *name = ksu_ovl_xattr(ofs, ox);
struct inode *ip = d_inode(dentry);
return __vfs_getxattr(dentry, ip, name, value, size, XATTR_NOSECURITY);
}
static inline int ksu_ovl_do_setxattr(struct ksu_ovl_fs *ofs, struct dentry *dentry,
enum ksu_ovl_xattr ox, const void *value,
size_t size)
{
const char *name = ksu_ovl_xattr(ofs, ox);
int err = vfs_setxattr(dentry, name, value, size, 0);
pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, 0) = %i\n",
dentry, name, min((int)size, 48), value, size, err);
return err;
}
static inline int ksu_ovl_do_removexattr(struct ksu_ovl_fs *ofs, struct dentry *dentry,
enum ksu_ovl_xattr ox)
{
const char *name = ksu_ovl_xattr(ofs, ox);
int err = vfs_removexattr(dentry, name);
pr_debug("removexattr(%pd2, \"%s\") = %i\n", dentry, name, err);
return err;
}
static inline int ksu_ovl_do_rename(struct inode *olddir, struct dentry *olddentry,
struct inode *newdir, struct dentry *newdentry,
unsigned int flags)
{
int err;
pr_debug("rename(%pd2, %pd2, 0x%x)\n", olddentry, newdentry, flags);
err = vfs_rename(olddir, olddentry, newdir, newdentry, NULL, flags);
if (err) {
pr_debug("...rename(%pd2, %pd2, ...) = %i\n",
olddentry, newdentry, err);
}
return err;
}
static inline int ksu_ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
{
int err = vfs_whiteout(dir, dentry);
pr_debug("whiteout(%pd2) = %i\n", dentry, err);
return err;
}
static inline struct dentry *ksu_ovl_do_tmpfile(struct dentry *dentry, umode_t mode)
{
struct dentry *ret = vfs_tmpfile(dentry, mode, 0);
int err = PTR_ERR_OR_ZERO(ret);
pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err);
return ret;
}
static inline bool ksu_ovl_open_flags_need_copy_up(int flags)
{
if (!flags)
return false;
return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC));
}
/* util.c */
int ksu_ovl_want_write(struct dentry *dentry);
void ksu_ovl_drop_write(struct dentry *dentry);
struct dentry *ksu_ovl_workdir(struct dentry *dentry);
const struct cred *ksu_ovl_override_creds(struct super_block *sb);
void ksu_ovl_revert_creds(struct super_block *sb, const struct cred *oldcred);
int ksu_ovl_can_decode_fh(struct super_block *sb);
struct dentry *ksu_ovl_indexdir(struct super_block *sb);
bool ksu_ovl_index_all(struct super_block *sb);
bool ksu_ovl_verify_lower(struct super_block *sb);
struct ksu_ovl_entry *ksu_ovl_alloc_entry(unsigned int numlower);
bool ksu_ovl_dentry_remote(struct dentry *dentry);
void ksu_ovl_dentry_update_reval(struct dentry *dentry, struct dentry *upperdentry,
unsigned int mask);
bool ksu_ovl_dentry_weird(struct dentry *dentry);
enum ksu_ovl_path_type ksu_ovl_path_type(struct dentry *dentry);
void ksu_ovl_path_upper(struct dentry *dentry, struct path *path);
void ksu_ovl_path_lower(struct dentry *dentry, struct path *path);
void ksu_ovl_path_lowerdata(struct dentry *dentry, struct path *path);
enum ksu_ovl_path_type ksu_ovl_path_real(struct dentry *dentry, struct path *path);
struct dentry *ksu_ovl_dentry_upper(struct dentry *dentry);
struct dentry *ksu_ovl_dentry_lower(struct dentry *dentry);
struct dentry *ksu_ovl_dentry_lowerdata(struct dentry *dentry);
const struct ksu_ovl_layer *ksu_ovl_layer_lower(struct dentry *dentry);
struct dentry *ksu_ovl_dentry_real(struct dentry *dentry);
struct dentry *ksu_ovl_i_dentry_upper(struct inode *inode);
struct inode *ksu_ovl_inode_upper(struct inode *inode);
struct inode *ksu_ovl_inode_lower(struct inode *inode);
struct inode *ksu_ovl_inode_lowerdata(struct inode *inode);
struct inode *ksu_ovl_inode_real(struct inode *inode);
struct inode *ksu_ovl_inode_realdata(struct inode *inode);
struct ksu_ovl_dir_cache *ksu_ovl_dir_cache(struct inode *inode);
void ksu_ovl_set_dir_cache(struct inode *inode, struct ksu_ovl_dir_cache *cache);
void ksu_ovl_dentry_set_flag(unsigned long flag, struct dentry *dentry);
void ksu_ovl_dentry_clear_flag(unsigned long flag, struct dentry *dentry);
bool ksu_ovl_dentry_test_flag(unsigned long flag, struct dentry *dentry);
bool ksu_ovl_dentry_is_opaque(struct dentry *dentry);
bool ksu_ovl_dentry_is_whiteout(struct dentry *dentry);
void ksu_ovl_dentry_set_opaque(struct dentry *dentry);
bool ksu_ovl_dentry_has_upper_alias(struct dentry *dentry);
void ksu_ovl_dentry_set_upper_alias(struct dentry *dentry);
bool ksu_ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags);
bool ksu_ovl_dentry_needs_data_copy_up_locked(struct dentry *dentry, int flags);
bool ksu_ovl_has_upperdata(struct inode *inode);
void ksu_ovl_set_upperdata(struct inode *inode);
bool ksu_ovl_redirect_dir(struct super_block *sb);
const char *ksu_ovl_dentry_get_redirect(struct dentry *dentry);
void ksu_ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
void ksu_ovl_inode_update(struct inode *inode, struct dentry *upperdentry);
void ksu_ovl_dir_modified(struct dentry *dentry, bool impurity);
u64 ksu_ovl_dentry_version_get(struct dentry *dentry);
bool ksu_ovl_is_whiteout(struct dentry *dentry);
struct file *ksu_ovl_path_open(struct path *path, int flags);
int ksu_ovl_copy_up_start(struct dentry *dentry, int flags);
void ksu_ovl_copy_up_end(struct dentry *dentry);
bool ksu_ovl_already_copied_up(struct dentry *dentry, int flags);
bool ksu_ovl_check_origin_xattr(struct ksu_ovl_fs *ofs, struct dentry *dentry);
bool ksu_ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
enum ksu_ovl_xattr ox);
int ksu_ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
enum ksu_ovl_xattr ox, const void *value, size_t size,
int xerr);
int ksu_ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry);
bool ksu_ovl_inuse_trylock(struct dentry *dentry);
void ksu_ovl_inuse_unlock(struct dentry *dentry);
bool ksu_ovl_is_inuse(struct dentry *dentry);
bool ksu_ovl_need_index(struct dentry *dentry);
int ksu_ovl_nlink_start(struct dentry *dentry);
void ksu_ovl_nlink_end(struct dentry *dentry);
int ksu_ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir);
int ksu_ovl_check_metacopy_xattr(struct ksu_ovl_fs *ofs, struct dentry *dentry);
bool ksu_ovl_is_metacopy_dentry(struct dentry *dentry);
char *ksu_ovl_get_redirect_xattr(struct ksu_ovl_fs *ofs, struct dentry *dentry,
int padding);
int ksu_ovl_sync_status(struct ksu_ovl_fs *ofs);
static inline void ksu_ovl_set_flag(unsigned long flag, struct inode *inode)
{
set_bit(flag, &KSU_OVL_I(inode)->flags);
}
static inline void ksu_ovl_clear_flag(unsigned long flag, struct inode *inode)
{
clear_bit(flag, &KSU_OVL_I(inode)->flags);
}
static inline bool ksu_ovl_test_flag(unsigned long flag, struct inode *inode)
{
return test_bit(flag, &KSU_OVL_I(inode)->flags);
}
static inline bool ksu_ovl_is_impuredir(struct super_block *sb,
struct dentry *dentry)
{
return ksu_ovl_check_dir_xattr(sb, dentry, KSU_OVL_XATTR_IMPURE);
}
/*
* With xino=auto, we do best effort to keep all inodes on same st_dev and
* d_ino consistent with st_ino.
* With xino=on, we do the same effort but we warn if we failed.
*/
static inline bool ksu_ovl_xino_warn(struct super_block *sb)
{
return KSU_OVL_FS(sb)->config.xino == KSU_OVL_XINO_ON;
}
/* All layers on same fs? */
static inline bool ksu_ovl_same_fs(struct super_block *sb)
{
return KSU_OVL_FS(sb)->xino_mode == 0;
}
/* All overlay inodes have same st_dev? */
static inline bool ksu_ovl_same_dev(struct super_block *sb)
{
return KSU_OVL_FS(sb)->xino_mode >= 0;
}
static inline unsigned int ksu_ovl_xino_bits(struct super_block *sb)
{
return ksu_ovl_same_dev(sb) ? KSU_OVL_FS(sb)->xino_mode : 0;
}
static inline void ksu_ovl_inode_lock(struct inode *inode)
{
mutex_lock(&KSU_OVL_I(inode)->lock);
}
static inline int ksu_ovl_inode_lock_interruptible(struct inode *inode)
{
return mutex_lock_interruptible(&KSU_OVL_I(inode)->lock);
}
static inline void ksu_ovl_inode_unlock(struct inode *inode)
{
mutex_unlock(&KSU_OVL_I(inode)->lock);
}
/* namei.c */
int ksu_ovl_check_fb_len(struct ksu_ovl_fb *fb, int fb_len);
static inline int ksu_ovl_check_fh_len(struct ksu_ovl_fh *fh, int fh_len)
{
if (fh_len < sizeof(struct ksu_ovl_fh))
return -EINVAL;
return ksu_ovl_check_fb_len(&fh->fb, fh_len - KSU_OVL_FH_WIRE_OFFSET);
}
struct dentry *ksu_ovl_decode_real_fh(struct ksu_ovl_fh *fh, struct vfsmount *mnt,
bool connected);
int ksu_ovl_check_origin_fh(struct ksu_ovl_fs *ofs, struct ksu_ovl_fh *fh, bool connected,
struct dentry *upperdentry, struct ksu_ovl_path **stackp);
int ksu_ovl_verify_set_fh(struct ksu_ovl_fs *ofs, struct dentry *dentry,
enum ksu_ovl_xattr ox, struct dentry *real, bool is_upper,
bool set);
struct dentry *ksu_ovl_index_upper(struct ksu_ovl_fs *ofs, struct dentry *index);
int ksu_ovl_verify_index(struct ksu_ovl_fs *ofs, struct dentry *index);
int ksu_ovl_get_index_name(struct dentry *origin, struct qstr *name);
struct dentry *ksu_ovl_get_index_fh(struct ksu_ovl_fs *ofs, struct ksu_ovl_fh *fh);
struct dentry *ksu_ovl_lookup_index(struct ksu_ovl_fs *ofs, struct dentry *upper,
struct dentry *origin, bool verify);
int ksu_ovl_path_next(int idx, struct dentry *dentry, struct path *path);
struct dentry *ksu_ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags);
bool ksu_ovl_lower_positive(struct dentry *dentry);
static inline int ksu_ovl_verify_origin(struct ksu_ovl_fs *ofs, struct dentry *upper,
struct dentry *origin, bool set)
{
return ksu_ovl_verify_set_fh(ofs, upper, KSU_OVL_XATTR_ORIGIN, origin,
false, set);
}
static inline int ksu_ovl_verify_upper(struct ksu_ovl_fs *ofs, struct dentry *index,
struct dentry *upper, bool set)
{
return ksu_ovl_verify_set_fh(ofs, index, KSU_OVL_XATTR_UPPER, upper, true, set);
}
/* readdir.c */
extern const struct file_operations ksu_ovl_dir_operations;
struct file *ksu_ovl_dir_real_file(const struct file *file, bool want_upper);
int ksu_ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
void ksu_ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
void ksu_ovl_cache_free(struct list_head *list);
void ksu_ovl_dir_cache_free(struct inode *inode);
int ksu_ovl_check_d_type_supported(struct path *realpath);
int ksu_ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
struct dentry *dentry, int level);
int ksu_ovl_indexdir_cleanup(struct ksu_ovl_fs *ofs);
/*
* Can we iterate real dir directly?
*
* Non-merge dir may contain whiteouts from a time it was a merge upper, before
* lower dir was removed under it and possibly before it was rotated from upper
* to lower layer.
*/
static inline bool ksu_ovl_dir_is_real(struct dentry *dir)
{
return !ksu_ovl_test_flag(KSU_OVL_WHITEOUTS, d_inode(dir));
}
/* inode.c */
int ksu_ovl_set_nlink_upper(struct dentry *dentry);
int ksu_ovl_set_nlink_lower(struct dentry *dentry);
unsigned int ksu_ovl_get_nlink(struct ksu_ovl_fs *ofs, struct dentry *lowerdentry,
struct dentry *upperdentry,
unsigned int fallback);
int ksu_ovl_setattr(struct dentry *dentry, struct iattr *attr);
int ksu_ovl_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags);
int ksu_ovl_permission(struct inode *inode, int mask);
int ksu_ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
const void *value, size_t size, int flags);
int ksu_ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
void *value, size_t size, int flags);
ssize_t ksu_ovl_listxattr(struct dentry *dentry, char *list, size_t size);
struct posix_acl *ksu_ovl_get_acl(struct inode *inode, int type);
int ksu_ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags);
bool ksu_ovl_is_private_xattr(struct super_block *sb, const char *name);
struct ksu_ovl_inode_params {
struct inode *newinode;
struct dentry *upperdentry;
struct ksu_ovl_path *lowerpath;
bool index;
unsigned int numlower;
char *redirect;
struct dentry *lowerdata;
};
void ksu_ovl_inode_init(struct inode *inode, struct ksu_ovl_inode_params *oip,
unsigned long ino, int fsid);
struct inode *ksu_ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev);
struct inode *ksu_ovl_lookup_inode(struct super_block *sb, struct dentry *real,
bool is_upper);
bool ksu_ovl_lookup_trap_inode(struct super_block *sb, struct dentry *dir);
struct inode *ksu_ovl_get_trap_inode(struct super_block *sb, struct dentry *dir);
struct inode *ksu_ovl_get_inode(struct super_block *sb,
struct ksu_ovl_inode_params *oip);
static inline void ksu_ovl_copyattr(struct inode *from, struct inode *to)
{
to->i_uid = from->i_uid;
to->i_gid = from->i_gid;
to->i_mode = from->i_mode;
to->i_atime = from->i_atime;
to->i_mtime = from->i_mtime;
to->i_ctime = from->i_ctime;
i_size_write(to, i_size_read(from));
}
static inline void ksu_ovl_copyflags(struct inode *from, struct inode *to)
{
unsigned int mask = S_SYNC | S_IMMUTABLE | S_APPEND | S_NOATIME;
inode_set_flags(to, from->i_flags & mask, mask);
}
/* dir.c */
extern const struct inode_operations ksu_ovl_dir_inode_operations;
int ksu_ovl_cleanup_and_whiteout(struct ksu_ovl_fs *ofs, struct inode *dir,
struct dentry *dentry);
struct ksu_ovl_cattr {
dev_t rdev;
umode_t mode;
const char *link;
struct dentry *hardlink;
};
#define KSU_OVL_CATTR(m) (&(struct ksu_ovl_cattr) { .mode = (m) })
int ksu_ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode);
struct dentry *ksu_ovl_create_real(struct inode *dir, struct dentry *newdentry,
struct ksu_ovl_cattr *attr);
int ksu_ovl_cleanup(struct inode *dir, struct dentry *dentry);
struct dentry *ksu_ovl_lookup_temp(struct dentry *workdir);
struct dentry *ksu_ovl_create_temp(struct dentry *workdir, struct ksu_ovl_cattr *attr);
/* file.c */
extern const struct file_operations ksu_ovl_file_operations;
int __init ksu_ovl_aio_request_cache_init(void);
void ksu_ovl_aio_request_cache_destroy(void);
long ksu_ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
long ksu_ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/* copy_up.c */
int ksu_ovl_copy_up(struct dentry *dentry);
int ksu_ovl_copy_up_with_data(struct dentry *dentry);
int ksu_ovl_maybe_copy_up(struct dentry *dentry, int flags);
int ksu_ovl_copy_xattr(struct super_block *sb, struct dentry *old,
struct dentry *new);
int ksu_ovl_set_attr(struct dentry *upper, struct kstat *stat);
struct ksu_ovl_fh *ksu_ovl_encode_real_fh(struct dentry *real, bool is_upper);
int ksu_ovl_set_origin(struct dentry *dentry, struct dentry *lower,
struct dentry *upper);
/* export.c */
extern const struct export_operations ksu_ovl_export_operations;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,974 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Novell Inc.
* Copyright (C) 2016 Red Hat, Inc.
*/
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/cred.h>
#include <linux/xattr.h>
#include <linux/exportfs.h>
#include <linux/uuid.h>
#include <linux/namei.h>
#include <linux/ratelimit.h>
#include "overlayfs.h"
int ksu_ovl_want_write(struct dentry *dentry)
{
struct ksu_ovl_fs *ofs = dentry->d_sb->s_fs_info;
return mnt_want_write(ksu_ovl_upper_mnt(ofs));
}
void ksu_ovl_drop_write(struct dentry *dentry)
{
struct ksu_ovl_fs *ofs = dentry->d_sb->s_fs_info;
mnt_drop_write(ksu_ovl_upper_mnt(ofs));
}
struct dentry *ksu_ovl_workdir(struct dentry *dentry)
{
struct ksu_ovl_fs *ofs = dentry->d_sb->s_fs_info;
return ofs->workdir;
}
const struct cred *ksu_ovl_override_creds(struct super_block *sb)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
if (!ofs->config.override_creds)
return NULL;
return override_creds(ofs->creator_cred);
}
void ksu_ovl_revert_creds(struct super_block *sb, const struct cred *old_cred)
{
if (old_cred)
revert_creds(old_cred);
}
/*
* Check if underlying fs supports file handles and try to determine encoding
* type, in order to deduce maximum inode number used by fs.
*
* Return 0 if file handles are not supported.
* Return 1 (FILEID_INO32_GEN) if fs uses the default 32bit inode encoding.
* Return -1 if fs uses a non default encoding with unknown inode size.
*/
int ksu_ovl_can_decode_fh(struct super_block *sb)
{
if (!sb->s_export_op || !sb->s_export_op->fh_to_dentry)
return 0;
return sb->s_export_op->encode_fh ? -1 : FILEID_INO32_GEN;
}
struct dentry *ksu_ovl_indexdir(struct super_block *sb)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
return ofs->indexdir;
}
/* Index all files on copy up. For now only enabled for NFS export */
bool ksu_ovl_index_all(struct super_block *sb)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
return ofs->config.nfs_export && ofs->config.index;
}
/* Verify lower origin on lookup. For now only enabled for NFS export */
bool ksu_ovl_verify_lower(struct super_block *sb)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
return ofs->config.nfs_export && ofs->config.index;
}
struct ksu_ovl_entry *ksu_ovl_alloc_entry(unsigned int numlower)
{
size_t size = offsetof(struct ksu_ovl_entry, lowerstack[numlower]);
struct ksu_ovl_entry *oe = kzalloc(size, GFP_KERNEL);
if (oe)
oe->numlower = numlower;
return oe;
}
bool ksu_ovl_dentry_remote(struct dentry *dentry)
{
return dentry->d_flags &
(DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
}
void ksu_ovl_dentry_update_reval(struct dentry *dentry, struct dentry *upperdentry,
unsigned int mask)
{
struct ksu_ovl_entry *oe = KSU_OVL_E(dentry);
unsigned int i, flags = 0;
if (upperdentry)
flags |= upperdentry->d_flags;
for (i = 0; i < oe->numlower; i++)
flags |= oe->lowerstack[i].dentry->d_flags;
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~mask;
dentry->d_flags |= flags & mask;
spin_unlock(&dentry->d_lock);
}
bool ksu_ovl_dentry_weird(struct dentry *dentry)
{
return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT |
DCACHE_MANAGE_TRANSIT |
DCACHE_OP_HASH |
DCACHE_OP_COMPARE);
}
enum ksu_ovl_path_type ksu_ovl_path_type(struct dentry *dentry)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
enum ksu_ovl_path_type type = 0;
if (ksu_ovl_dentry_upper(dentry)) {
type = __KSU_OVL_PATH_UPPER;
/*
* Non-dir dentry can hold lower dentry of its copy up origin.
*/
if (oe->numlower) {
if (ksu_ovl_test_flag(KSU_OVL_CONST_INO, d_inode(dentry)))
type |= __KSU_OVL_PATH_ORIGIN;
if (d_is_dir(dentry) ||
!ksu_ovl_has_upperdata(d_inode(dentry)))
type |= __KSU_OVL_PATH_MERGE;
}
} else {
if (oe->numlower > 1)
type |= __KSU_OVL_PATH_MERGE;
}
return type;
}
void ksu_ovl_path_upper(struct dentry *dentry, struct path *path)
{
struct ksu_ovl_fs *ofs = dentry->d_sb->s_fs_info;
path->mnt = ksu_ovl_upper_mnt(ofs);
path->dentry = ksu_ovl_dentry_upper(dentry);
}
void ksu_ovl_path_lower(struct dentry *dentry, struct path *path)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
if (oe->numlower) {
path->mnt = oe->lowerstack[0].layer->mnt;
path->dentry = oe->lowerstack[0].dentry;
} else {
*path = (struct path) { };
}
}
void ksu_ovl_path_lowerdata(struct dentry *dentry, struct path *path)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
if (oe->numlower) {
path->mnt = oe->lowerstack[oe->numlower - 1].layer->mnt;
path->dentry = oe->lowerstack[oe->numlower - 1].dentry;
} else {
*path = (struct path) { };
}
}
enum ksu_ovl_path_type ksu_ovl_path_real(struct dentry *dentry, struct path *path)
{
enum ksu_ovl_path_type type = ksu_ovl_path_type(dentry);
if (!KSU_OVL_TYPE_UPPER(type))
ksu_ovl_path_lower(dentry, path);
else
ksu_ovl_path_upper(dentry, path);
return type;
}
struct dentry *ksu_ovl_dentry_upper(struct dentry *dentry)
{
return ksu_ovl_upperdentry_dereference(KSU_OVL_I(d_inode(dentry)));
}
struct dentry *ksu_ovl_dentry_lower(struct dentry *dentry)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
return oe->numlower ? oe->lowerstack[0].dentry : NULL;
}
const struct ksu_ovl_layer *ksu_ovl_layer_lower(struct dentry *dentry)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
return oe->numlower ? oe->lowerstack[0].layer : NULL;
}
/*
* ksu_ovl_dentry_lower() could return either a data dentry or metacopy dentry
* dependig on what is stored in lowerstack[0]. At times we need to find
* lower dentry which has data (and not metacopy dentry). This helper
* returns the lower data dentry.
*/
struct dentry *ksu_ovl_dentry_lowerdata(struct dentry *dentry)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
return oe->numlower ? oe->lowerstack[oe->numlower - 1].dentry : NULL;
}
struct dentry *ksu_ovl_dentry_real(struct dentry *dentry)
{
return ksu_ovl_dentry_upper(dentry) ?: ksu_ovl_dentry_lower(dentry);
}
struct dentry *ksu_ovl_i_dentry_upper(struct inode *inode)
{
return ksu_ovl_upperdentry_dereference(KSU_OVL_I(inode));
}
struct inode *ksu_ovl_inode_upper(struct inode *inode)
{
struct dentry *upperdentry = ksu_ovl_i_dentry_upper(inode);
return upperdentry ? d_inode(upperdentry) : NULL;
}
struct inode *ksu_ovl_inode_lower(struct inode *inode)
{
return KSU_OVL_I(inode)->lower;
}
struct inode *ksu_ovl_inode_real(struct inode *inode)
{
return ksu_ovl_inode_upper(inode) ?: ksu_ovl_inode_lower(inode);
}
/* Return inode which contains lower data. Do not return metacopy */
struct inode *ksu_ovl_inode_lowerdata(struct inode *inode)
{
if (WARN_ON(!S_ISREG(inode->i_mode)))
return NULL;
return KSU_OVL_I(inode)->lowerdata ?: ksu_ovl_inode_lower(inode);
}
/* Return real inode which contains data. Does not return metacopy inode */
struct inode *ksu_ovl_inode_realdata(struct inode *inode)
{
struct inode *upperinode;
upperinode = ksu_ovl_inode_upper(inode);
if (upperinode && ksu_ovl_has_upperdata(inode))
return upperinode;
return ksu_ovl_inode_lowerdata(inode);
}
struct ksu_ovl_dir_cache *ksu_ovl_dir_cache(struct inode *inode)
{
return KSU_OVL_I(inode)->cache;
}
void ksu_ovl_set_dir_cache(struct inode *inode, struct ksu_ovl_dir_cache *cache)
{
KSU_OVL_I(inode)->cache = cache;
}
void ksu_ovl_dentry_set_flag(unsigned long flag, struct dentry *dentry)
{
set_bit(flag, &KSU_OVL_E(dentry)->flags);
}
void ksu_ovl_dentry_clear_flag(unsigned long flag, struct dentry *dentry)
{
clear_bit(flag, &KSU_OVL_E(dentry)->flags);
}
bool ksu_ovl_dentry_test_flag(unsigned long flag, struct dentry *dentry)
{
return test_bit(flag, &KSU_OVL_E(dentry)->flags);
}
bool ksu_ovl_dentry_is_opaque(struct dentry *dentry)
{
return ksu_ovl_dentry_test_flag(KSU_OVL_E_OPAQUE, dentry);
}
bool ksu_ovl_dentry_is_whiteout(struct dentry *dentry)
{
return !dentry->d_inode && ksu_ovl_dentry_is_opaque(dentry);
}
void ksu_ovl_dentry_set_opaque(struct dentry *dentry)
{
ksu_ovl_dentry_set_flag(KSU_OVL_E_OPAQUE, dentry);
}
/*
* For hard links and decoded file handles, it's possible for ksu_ovl_dentry_upper()
* to return positive, while there's no actual upper alias for the inode.
* Copy up code needs to know about the existence of the upper alias, so it
* can't use ksu_ovl_dentry_upper().
*/
bool ksu_ovl_dentry_has_upper_alias(struct dentry *dentry)
{
return ksu_ovl_dentry_test_flag(KSU_OVL_E_UPPER_ALIAS, dentry);
}
void ksu_ovl_dentry_set_upper_alias(struct dentry *dentry)
{
ksu_ovl_dentry_set_flag(KSU_OVL_E_UPPER_ALIAS, dentry);
}
static bool ksu_ovl_should_check_upperdata(struct inode *inode)
{
if (!S_ISREG(inode->i_mode))
return false;
if (!ksu_ovl_inode_lower(inode))
return false;
return true;
}
bool ksu_ovl_has_upperdata(struct inode *inode)
{
if (!ksu_ovl_should_check_upperdata(inode))
return true;
if (!ksu_ovl_test_flag(KSU_OVL_UPPERDATA, inode))
return false;
/*
* Pairs with smp_wmb() in ksu_ovl_set_upperdata(). Main user of
* ksu_ovl_has_upperdata() is ksu_ovl_copy_up_meta_inode_data(). Make sure
* if setting of KSU_OVL_UPPERDATA is visible, then effects of writes
* before that are visible too.
*/
smp_rmb();
return true;
}
void ksu_ovl_set_upperdata(struct inode *inode)
{
/*
* Pairs with smp_rmb() in ksu_ovl_has_upperdata(). Make sure
* if KSU_OVL_UPPERDATA flag is visible, then effects of write operations
* before it are visible as well.
*/
smp_wmb();
ksu_ovl_set_flag(KSU_OVL_UPPERDATA, inode);
}
/* Caller should hold ksu_ovl_inode->lock */
bool ksu_ovl_dentry_needs_data_copy_up_locked(struct dentry *dentry, int flags)
{
if (!ksu_ovl_open_flags_need_copy_up(flags))
return false;
return !ksu_ovl_test_flag(KSU_OVL_UPPERDATA, d_inode(dentry));
}
bool ksu_ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags)
{
if (!ksu_ovl_open_flags_need_copy_up(flags))
return false;
return !ksu_ovl_has_upperdata(d_inode(dentry));
}
bool ksu_ovl_redirect_dir(struct super_block *sb)
{
struct ksu_ovl_fs *ofs = sb->s_fs_info;
return ofs->config.redirect_dir && !ofs->noxattr;
}
const char *ksu_ovl_dentry_get_redirect(struct dentry *dentry)
{
return KSU_OVL_I(d_inode(dentry))->redirect;
}
void ksu_ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect)
{
struct ksu_ovl_inode *oi = KSU_OVL_I(d_inode(dentry));
kfree(oi->redirect);
oi->redirect = redirect;
}
void ksu_ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
{
struct inode *upperinode = d_inode(upperdentry);
WARN_ON(KSU_OVL_I(inode)->__upperdentry);
/*
* Make sure upperdentry is consistent before making it visible
*/
smp_wmb();
KSU_OVL_I(inode)->__upperdentry = upperdentry;
if (inode_unhashed(inode)) {
inode->i_private = upperinode;
__insert_inode_hash(inode, (unsigned long) upperinode);
}
}
static void ksu_ovl_dir_version_inc(struct dentry *dentry, bool impurity)
{
struct inode *inode = d_inode(dentry);
WARN_ON(!inode_is_locked(inode));
WARN_ON(!d_is_dir(dentry));
/*
* Version is used by readdir code to keep cache consistent.
* For merge dirs (or dirs with origin) all changes need to be noted.
* For non-merge dirs, cache contains only impure entries (i.e. ones
* which have been copied up and have origins), so only need to note
* changes to impure entries.
*/
if (!ksu_ovl_dir_is_real(dentry) || impurity)
KSU_OVL_I(inode)->version++;
}
void ksu_ovl_dir_modified(struct dentry *dentry, bool impurity)
{
/* Copy mtime/ctime */
ksu_ovl_copyattr(d_inode(ksu_ovl_dentry_upper(dentry)), d_inode(dentry));
ksu_ovl_dir_version_inc(dentry, impurity);
}
u64 ksu_ovl_dentry_version_get(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
WARN_ON(!inode_is_locked(inode));
return KSU_OVL_I(inode)->version;
}
bool ksu_ovl_is_whiteout(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
return inode && IS_WHITEOUT(inode);
}
struct file *ksu_ovl_path_open(struct path *path, int flags)
{
struct inode *inode = d_inode(path->dentry);
int err, acc_mode;
if (flags & ~(O_ACCMODE | O_LARGEFILE))
BUG();
switch (flags & O_ACCMODE) {
case O_RDONLY:
acc_mode = MAY_READ;
break;
case O_WRONLY:
acc_mode = MAY_WRITE;
break;
default:
BUG();
}
err = inode_permission(inode, acc_mode | MAY_OPEN);
if (err)
return ERR_PTR(err);
/* O_NOATIME is an optimization, don't fail if not permitted */
if (inode_owner_or_capable(inode))
flags |= O_NOATIME;
return dentry_open(path, flags, current_cred());
}
/* Caller should hold ksu_ovl_inode->lock */
static bool ksu_ovl_already_copied_up_locked(struct dentry *dentry, int flags)
{
bool disconnected = dentry->d_flags & DCACHE_DISCONNECTED;
if (ksu_ovl_dentry_upper(dentry) &&
(ksu_ovl_dentry_has_upper_alias(dentry) || disconnected) &&
!ksu_ovl_dentry_needs_data_copy_up_locked(dentry, flags))
return true;
return false;
}
bool ksu_ovl_already_copied_up(struct dentry *dentry, int flags)
{
bool disconnected = dentry->d_flags & DCACHE_DISCONNECTED;
/*
* Check if copy-up has happened as well as for upper alias (in
* case of hard links) is there.
*
* Both checks are lockless:
* - false negatives: will recheck under oi->lock
* - false positives:
* + ksu_ovl_dentry_upper() uses memory barriers to ensure the
* upper dentry is up-to-date
* + ksu_ovl_dentry_has_upper_alias() relies on locking of
* upper parent i_rwsem to prevent reordering copy-up
* with rename.
*/
if (ksu_ovl_dentry_upper(dentry) &&
(ksu_ovl_dentry_has_upper_alias(dentry) || disconnected) &&
!ksu_ovl_dentry_needs_data_copy_up(dentry, flags))
return true;
return false;
}
int ksu_ovl_copy_up_start(struct dentry *dentry, int flags)
{
struct inode *inode = d_inode(dentry);
int err;
err = ksu_ovl_inode_lock_interruptible(inode);
if (!err && ksu_ovl_already_copied_up_locked(dentry, flags)) {
err = 1; /* Already copied up */
ksu_ovl_inode_unlock(inode);
}
return err;
}
void ksu_ovl_copy_up_end(struct dentry *dentry)
{
ksu_ovl_inode_unlock(d_inode(dentry));
}
bool ksu_ovl_check_origin_xattr(struct ksu_ovl_fs *ofs, struct dentry *dentry)
{
ssize_t res;
res = ksu_ovl_do_getxattr(ofs, dentry, KSU_OVL_XATTR_ORIGIN, NULL, 0);
/* Zero size value means "copied up but origin unknown" */
if (res >= 0)
return true;
return false;
}
bool ksu_ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
enum ksu_ovl_xattr ox)
{
ssize_t res;
char val;
if (!d_is_dir(dentry))
return false;
res = ksu_ovl_do_getxattr(KSU_OVL_FS(sb), dentry, ox, &val, 1);
if (res == 1 && val == 'y')
return true;
return false;
}
#define KSU_OVL_XATTR_OPAQUE_POSTFIX "opaque"
#define KSU_OVL_XATTR_REDIRECT_POSTFIX "redirect"
#define KSU_OVL_XATTR_ORIGIN_POSTFIX "origin"
#define KSU_OVL_XATTR_IMPURE_POSTFIX "impure"
#define KSU_OVL_XATTR_NLINK_POSTFIX "nlink"
#define KSU_OVL_XATTR_UPPER_POSTFIX "upper"
#define KSU_OVL_XATTR_METACOPY_POSTFIX "metacopy"
#define KSU_OVL_XATTR_TAB_ENTRY(x) \
[x] = KSU_OVL_XATTR_PREFIX x ## _POSTFIX
const char *ksu_ovl_xattr_table[] = {
KSU_OVL_XATTR_TAB_ENTRY(KSU_OVL_XATTR_OPAQUE),
KSU_OVL_XATTR_TAB_ENTRY(KSU_OVL_XATTR_REDIRECT),
KSU_OVL_XATTR_TAB_ENTRY(KSU_OVL_XATTR_ORIGIN),
KSU_OVL_XATTR_TAB_ENTRY(KSU_OVL_XATTR_IMPURE),
KSU_OVL_XATTR_TAB_ENTRY(KSU_OVL_XATTR_NLINK),
KSU_OVL_XATTR_TAB_ENTRY(KSU_OVL_XATTR_UPPER),
KSU_OVL_XATTR_TAB_ENTRY(KSU_OVL_XATTR_METACOPY),
};
int ksu_ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
enum ksu_ovl_xattr ox, const void *value, size_t size,
int xerr)
{
int err;
struct ksu_ovl_fs *ofs = dentry->d_sb->s_fs_info;
if (ofs->noxattr)
return xerr;
err = ksu_ovl_do_setxattr(ofs, upperdentry, ox, value, size);
if (err == -EOPNOTSUPP) {
pr_warn("cannot set %s xattr on upper\n", ksu_ovl_xattr(ofs, ox));
ofs->noxattr = true;
return xerr;
}
return err;
}
int ksu_ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry)
{
int err;
if (ksu_ovl_test_flag(KSU_OVL_IMPURE, d_inode(dentry)))
return 0;
/*
* Do not fail when upper doesn't support xattrs.
* Upper inodes won't have origin nor redirect xattr anyway.
*/
err = ksu_ovl_check_setxattr(dentry, upperdentry, KSU_OVL_XATTR_IMPURE,
"y", 1, 0);
if (!err)
ksu_ovl_set_flag(KSU_OVL_IMPURE, d_inode(dentry));
return err;
}
/**
* Caller must hold a reference to inode to prevent it from being freed while
* it is marked inuse.
*/
bool ksu_ovl_inuse_trylock(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
bool locked = false;
spin_lock(&inode->i_lock);
if (!(inode->i_state & I_OVL_INUSE)) {
inode->i_state |= I_OVL_INUSE;
locked = true;
}
spin_unlock(&inode->i_lock);
return locked;
}
void ksu_ovl_inuse_unlock(struct dentry *dentry)
{
if (dentry) {
struct inode *inode = d_inode(dentry);
spin_lock(&inode->i_lock);
WARN_ON(!(inode->i_state & I_OVL_INUSE));
inode->i_state &= ~I_OVL_INUSE;
spin_unlock(&inode->i_lock);
}
}
bool ksu_ovl_is_inuse(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
bool inuse;
spin_lock(&inode->i_lock);
inuse = (inode->i_state & I_OVL_INUSE);
spin_unlock(&inode->i_lock);
return inuse;
}
/*
* Does this overlay dentry need to be indexed on copy up?
*/
bool ksu_ovl_need_index(struct dentry *dentry)
{
struct dentry *lower = ksu_ovl_dentry_lower(dentry);
if (!lower || !ksu_ovl_indexdir(dentry->d_sb))
return false;
/* Index all files for NFS export and consistency verification */
if (ksu_ovl_index_all(dentry->d_sb))
return true;
/* Index only lower hardlinks on copy up */
if (!d_is_dir(lower) && d_inode(lower)->i_nlink > 1)
return true;
return false;
}
/* Caller must hold KSU_OVL_I(inode)->lock */
static void ksu_ovl_cleanup_index(struct dentry *dentry)
{
struct dentry *indexdir = ksu_ovl_indexdir(dentry->d_sb);
struct inode *dir = indexdir->d_inode;
struct dentry *lowerdentry = ksu_ovl_dentry_lower(dentry);
struct dentry *upperdentry = ksu_ovl_dentry_upper(dentry);
struct dentry *index = NULL;
struct inode *inode;
struct qstr name = { };
int err;
err = ksu_ovl_get_index_name(lowerdentry, &name);
if (err)
goto fail;
inode = d_inode(upperdentry);
if (!S_ISDIR(inode->i_mode) && inode->i_nlink != 1) {
pr_warn_ratelimited("cleanup linked index (%pd2, ino=%lu, nlink=%u)\n",
upperdentry, inode->i_ino, inode->i_nlink);
/*
* We either have a bug with persistent union nlink or a lower
* hardlink was added while overlay is mounted. Adding a lower
* hardlink and then unlinking all overlay hardlinks would drop
* overlay nlink to zero before all upper inodes are unlinked.
* As a safety measure, when that situation is detected, set
* the overlay nlink to the index inode nlink minus one for the
* index entry itself.
*/
set_nlink(d_inode(dentry), inode->i_nlink - 1);
ksu_ovl_set_nlink_upper(dentry);
goto out;
}
inode_lock_nested(dir, I_MUTEX_PARENT);
index = lookup_one_len(name.name, indexdir, name.len);
err = PTR_ERR(index);
if (IS_ERR(index)) {
index = NULL;
} else if (ksu_ovl_index_all(dentry->d_sb)) {
/* Whiteout orphan index to block future open by handle */
err = ksu_ovl_cleanup_and_whiteout(KSU_OVL_FS(dentry->d_sb),
dir, index);
} else {
/* Cleanup orphan index entries */
err = ksu_ovl_cleanup(dir, index);
}
inode_unlock(dir);
if (err)
goto fail;
out:
kfree(name.name);
dput(index);
return;
fail:
pr_err("cleanup index of '%pd2' failed (%i)\n", dentry, err);
goto out;
}
/*
* Operations that change overlay inode and upper inode nlink need to be
* synchronized with copy up for persistent nlink accounting.
*/
int ksu_ovl_nlink_start(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
const struct cred *old_cred;
int err;
if (WARN_ON(!inode))
return -ENOENT;
/*
* With inodes index is enabled, we store the union overlay nlink
* in an xattr on the index inode. When whiting out an indexed lower,
* we need to decrement the overlay persistent nlink, but before the
* first copy up, we have no upper index inode to store the xattr.
*
* As a workaround, before whiteout/rename over an indexed lower,
* copy up to create the upper index. Creating the upper index will
* initialize the overlay nlink, so it could be dropped if unlink
* or rename succeeds.
*
* TODO: implement metadata only index copy up when called with
* ksu_ovl_copy_up_flags(dentry, O_PATH).
*/
if (ksu_ovl_need_index(dentry) && !ksu_ovl_dentry_has_upper_alias(dentry)) {
err = ksu_ovl_copy_up(dentry);
if (err)
return err;
}
err = ksu_ovl_inode_lock_interruptible(inode);
if (err)
return err;
if (d_is_dir(dentry) || !ksu_ovl_test_flag(KSU_OVL_INDEX, inode))
goto out;
old_cred = ksu_ovl_override_creds(dentry->d_sb);
/*
* The overlay inode nlink should be incremented/decremented IFF the
* upper operation succeeds, along with nlink change of upper inode.
* Therefore, before link/unlink/rename, we store the union nlink
* value relative to the upper inode nlink in an upper inode xattr.
*/
err = ksu_ovl_set_nlink_upper(dentry);
ksu_ovl_revert_creds(dentry->d_sb, old_cred);
out:
if (err)
ksu_ovl_inode_unlock(inode);
return err;
}
void ksu_ovl_nlink_end(struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
if (ksu_ovl_test_flag(KSU_OVL_INDEX, inode) && inode->i_nlink == 0) {
const struct cred *old_cred;
old_cred = ksu_ovl_override_creds(dentry->d_sb);
ksu_ovl_cleanup_index(dentry);
ksu_ovl_revert_creds(dentry->d_sb, old_cred);
}
ksu_ovl_inode_unlock(inode);
}
int ksu_ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir)
{
/* Workdir should not be the same as upperdir */
if (workdir == upperdir)
goto err;
/* Workdir should not be subdir of upperdir and vice versa */
if (lock_rename(workdir, upperdir) != NULL)
goto err_unlock;
return 0;
err_unlock:
unlock_rename(workdir, upperdir);
err:
pr_err("failed to lock workdir+upperdir\n");
return -EIO;
}
/* err < 0, 0 if no metacopy xattr, 1 if metacopy xattr found */
int ksu_ovl_check_metacopy_xattr(struct ksu_ovl_fs *ofs, struct dentry *dentry)
{
ssize_t res;
/* Only regular files can have metacopy xattr */
if (!S_ISREG(d_inode(dentry)->i_mode))
return 0;
res = ksu_ovl_do_getxattr(ofs, dentry, KSU_OVL_XATTR_METACOPY, NULL, 0);
if (res < 0) {
if (res == -ENODATA || res == -EOPNOTSUPP)
return 0;
goto out;
}
return 1;
out:
pr_warn_ratelimited("failed to get metacopy (%zi)\n", res);
return res;
}
bool ksu_ovl_is_metacopy_dentry(struct dentry *dentry)
{
struct ksu_ovl_entry *oe = dentry->d_fsdata;
if (!d_is_reg(dentry))
return false;
if (ksu_ovl_dentry_upper(dentry)) {
if (!ksu_ovl_has_upperdata(d_inode(dentry)))
return true;
return false;
}
return (oe->numlower > 1);
}
char *ksu_ovl_get_redirect_xattr(struct ksu_ovl_fs *ofs, struct dentry *dentry,
int padding)
{
int res;
char *s, *next, *buf = NULL;
res = ksu_ovl_do_getxattr(ofs, dentry, KSU_OVL_XATTR_REDIRECT, NULL, 0);
if (res == -ENODATA || res == -EOPNOTSUPP)
return NULL;
if (res < 0)
goto fail;
if (res == 0)
goto invalid;
buf = kzalloc(res + padding + 1, GFP_KERNEL);
if (!buf)
return ERR_PTR(-ENOMEM);
res = ksu_ovl_do_getxattr(ofs, dentry, KSU_OVL_XATTR_REDIRECT, buf, res);
if (res < 0)
goto fail;
if (res == 0)
goto invalid;
if (buf[0] == '/') {
for (s = buf; *s++ == '/'; s = next) {
next = strchrnul(s, '/');
if (s == next)
goto invalid;
}
} else {
if (strchr(buf, '/') != NULL)
goto invalid;
}
return buf;
invalid:
pr_warn_ratelimited("invalid redirect (%s)\n", buf);
res = -EINVAL;
goto err_free;
fail:
pr_warn_ratelimited("failed to get redirect (%i)\n", res);
err_free:
kfree(buf);
return ERR_PTR(res);
}
/*
* ksu_ovl_sync_status() - Check fs sync status for volatile mounts
*
* Returns 1 if this is not a volatile mount and a real sync is required.
*
* Returns 0 if syncing can be skipped because mount is volatile, and no errors
* have occurred on the upperdir since the mount.
*
* Returns -errno if it is a volatile mount, and the error that occurred since
* the last mount. If the error code changes, it'll return the latest error
* code.
*/
int ksu_ovl_sync_status(struct ksu_ovl_fs *ofs)
{
struct vfsmount *mnt;
if (ksu_ovl_should_sync(ofs))
return 1;
mnt = ksu_ovl_upper_mnt(ofs);
if (!mnt)
return 0;
return errseq_check(&mnt->mnt_sb->s_wb_err, ofs->errseq);
}

View File

@@ -1 +0,0 @@
obj-y += 5.10/

View File

@@ -1,60 +0,0 @@
# KSUFS
based on overlayfs
## Step1
```bash
sed -i 's/ovl_/ksu_ovl_/g' *
sed -i 's/OVL_/KSU_OVL_/g' *
mv ovl_entry.h ksu_ovl_entry.h
sed -i 's/I_KSU_OVL_INUSE/I_OVL_INUSE/g' *
```
## Step2
overlayfs.h:
#define pr_fmt(fmt) "overlayfs: " fmt
#define pr_fmt(fmt) "ksufs: " fmt
## Step3
```c
static struct file_system_type ksu_ovl_fs_type = {
.owner = THIS_MODULE,
.name = "overlay",
.mount = ksu_ovl_mount,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("overlay");
```
```c
static struct file_system_type ksu_ovl_fs_type = {
.owner = THIS_MODULE,
.name = "ksufs",
.mount = ksu_ovl_mount,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("ksufs");
```
## Step4
ksu_ovl_getattr:
if (err)
if (true)
## Step5
Makefile:
obj-y += ksufs.o
ksufs-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \
copy_up.o export.o

BIN
kernel/libsepol/.DS_Store vendored Normal file

Binary file not shown.

7
kernel/libsepol/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
utils/chkcon
utils/sepol_check_access
utils/sepol_compute_av
utils/sepol_compute_member
utils/sepol_compute_relabel
utils/sepol_validate_transition
libsepol.map

504
kernel/libsepol/COPYING Normal file
View File

@@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

48
kernel/libsepol/Makefile Normal file
View File

@@ -0,0 +1,48 @@
obj-y += src/assertion.o
obj-y += src/avrule_block.o
obj-y += src/avtab.o
obj-y += src/boolean_record.o
obj-y += src/booleans.o
obj-y += src/conditional.o
obj-y += src/constraint.o
obj-y += src/context.o
obj-y += src/context_record.o
obj-y += src/debug.o
obj-y += src/ebitmap.o
obj-y += src/expand.o
obj-y += src/handle.o
obj-y += src/hashtab.o
obj-y += src/hierarchy.o
# obj-y += src/ibendport_record.o
# obj-y += src/ibendports.o
# obj-y += src/ibpkey_record.o
# obj-y += src/ibpkeys.o
# obj-y += src/iface_record.o
# obj-y += src/interfaces.o
# obj-y += src/kernel_to_cil.o
# obj-y += src/kernel_to_common.o
# obj-y += src/kernel_to_conf.o
obj-y += src/link.o
obj-y += src/mls.o
obj-y += src/module.o
# obj-y += src/module_to_cil.o
obj-y += src/node_record.o
obj-y += src/nodes.o
obj-y += src/optimize.o
obj-y += src/polcaps.o
obj-y += src/policydb.o
obj-y += src/policydb_convert.o
obj-y += src/policydb_public.o
obj-y += src/policydb_validate.o
obj-y += src/port_record.o
obj-y += src/ports.o
obj-y += src/services.o
obj-y += src/sidtab.o
obj-y += src/symtab.o
obj-y += src/user_record.o
obj-y += src/users.o
obj-y += src/util.o
obj-y += src/write.o
obj-y += src/inet_ntop.o
ccflags-y += -I $(srctree)/$(src)/include

1
kernel/libsepol/VERSION Normal file
View File

@@ -0,0 +1 @@
3.4

BIN
kernel/libsepol/cil/.DS_Store vendored Normal file

Binary file not shown.

14
kernel/libsepol/cil/.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
*.swp
*.gcda
*.gcno
*.o
*.a
src/cil_lexer.c
unit_tests
cov
secilc
docs/pdf/
docs/html/
docs/man8/
policy.*
file_contexts

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#ifndef CIL_H_
#define CIL_H_
#include <sepol/policydb/policydb.h>
#ifdef __cplusplus
extern "C" {
#endif
struct cil_db;
typedef struct cil_db cil_db_t;
extern void cil_db_init(cil_db_t **db);
extern void cil_db_destroy(cil_db_t **db);
extern int cil_add_file(cil_db_t *db, const char *name, const char *data, size_t size);
extern int cil_compile(cil_db_t *db);
extern int cil_build_policydb(cil_db_t *db, sepol_policydb_t **sepol_db);
extern int cil_userprefixes_to_string(cil_db_t *db, char **out, size_t *size);
extern int cil_selinuxusers_to_string(cil_db_t *db, char **out, size_t *size);
extern int cil_filecons_to_string(cil_db_t *db, char **out, size_t *size);
extern void cil_set_disable_dontaudit(cil_db_t *db, int disable_dontaudit);
extern void cil_set_multiple_decls(cil_db_t *db, int multiple_decls);
extern void cil_set_qualified_names(struct cil_db *db, int qualified_names);
extern void cil_set_disable_neverallow(cil_db_t *db, int disable_neverallow);
extern void cil_set_preserve_tunables(cil_db_t *db, int preserve_tunables);
extern int cil_set_handle_unknown(cil_db_t *db, int handle_unknown);
extern void cil_set_mls(cil_db_t *db, int mls);
extern void cil_set_attrs_expand_generated(struct cil_db *db, int attrs_expand_generated);
extern void cil_set_attrs_expand_size(struct cil_db *db, unsigned attrs_expand_size);
extern void cil_set_target_platform(cil_db_t *db, int target_platform);
extern void cil_set_policy_version(cil_db_t *db, int policy_version);
extern void cil_write_policy_conf(FILE *out, struct cil_db *db);
extern int cil_write_parse_ast(FILE *out, cil_db_t *db);
extern int cil_write_build_ast(FILE *out, cil_db_t *db);
extern int cil_write_resolve_ast(FILE *out, cil_db_t *db);
enum cil_log_level {
CIL_ERR = 1,
CIL_WARN,
CIL_INFO
};
extern void cil_set_log_level(enum cil_log_level lvl);
extern void cil_set_log_handler(void (*handler)(int lvl, const char *msg));
#ifdef __GNUC__
__attribute__ ((format(printf, 2, 3)))
#endif
extern void cil_log(enum cil_log_level lvl, const char *msg, ...);
extern void cil_set_malloc_error_handler(void (*handler)(void));
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,477 @@
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#ifndef _CIL_BINARY_H_
#define _CIL_BINARY_H_
#include <sepol/policydb/policydb.h>
#include "cil_internal.h"
#include "cil_tree.h"
#include "cil_list.h"
/**
* Create a binary policydb from the cil db.
*
* @param[in] db The cil database.
* @param[in] pdb The policy database.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_binary_create(const struct cil_db *db, sepol_policydb_t **pdb);
/**
* Create a pre allocated binary policydb from the cil db.
*
* It is assumed that pdb has been allocated and initialized so that fields such
* as policy type and version are set appropriately. It is recommended that
* instead of calling this, one instead calls cil_binary_create, which will
* properly allocate and initialize the pdb and then calls this function. This
* function is used to maintain binary backwards compatibility.
*
* @param[in] db The cil database.
* @param[in] pdb The policy database.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_binary_create_allocated_pdb(const struct cil_db *db, sepol_policydb_t *pdb);
/**
* Insert cil common structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the common into.
* @param[in] datum The cil_common datum.
* @param[out] common_out The sepol common to send back.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_common_to_policydb(policydb_t *pdb, struct cil_class *cil_common, common_datum_t **common_out);
/**
* Insert cil class structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the class into.
* @param[in] datum The cil_class datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_class_to_policydb(policydb_t *pdb, struct cil_class *cil_class);
/**
* Insert cil role structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the role into.
* @param[in] datum The cil_role datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_role_to_policydb(policydb_t *pdb, struct cil_role *cil_role);
/**
* Insert cil roletype structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the roletype into.
* @param[in] db The cil database
* @param[in] datum The cil_roletype datum.
*
* @return SEPOL_OK upon success or SEPOL_ERR otherwise.
*/
int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_role *role);
/**
* Insert cil type structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the type into.
* @param[in] datum The cil_type datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[]);
/**
* Insert cil typealias structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the typealias into.
* @param[in] datum The cil_typealias datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_typealias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias);
/**
* Insert cil typepermissive structure into sepol policydb.
* The function looks up the previously inserted type and flips the bit
* in the permssive types bitmap that corresponds to that type's value.
*
* @param[in] pdb The policy database to insert the typepermissive into.
* @param[in] datum The cil_typepermissive datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *cil_typeperm);
/**
* Insert cil attribute structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the attribute into.
* @param[in] datum The cil_attribute datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[]);
/**
* Insert cil attribute structure into sepol type->attribute bitmap.
* The function calls helper functions to loop over the attributes lists
* of types and negative types. If either of the lists contain an attribute,
* the helper functions will recurse into the attribute and record the
* attribute's types and negative types. There is no minimum depth.
*
* @param[in] pdb The policy database that contains the type->attribute bitmap.
* @param[in] db The cil database
* @param[in] node The tree node that contains the cil_attribute.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_typeattribute_to_bitmap(policydb_t *pdb, const struct cil_db *cdb, struct cil_typeattribute *cil_attr);
/**
* Insert cil policycap structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the policycap into.
* @param[in] node The tree node that contains the cil_policycap.
*
* @return SEPOL_OK upon success or SEPOL_ERR upon error.
*/
int cil_policycap_to_policydb(policydb_t *pdb, struct cil_policycap *cil_polcap);
/**
* Insert cil user structure into sepol policydb.
*
* @param[in] pdb THe policy database to insert the user into.
* @param[in] node The tree node that contains the cil_user.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user);
/**
* Insert cil userrole structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the userrole into.
* @param[in] db The cil database
* @param[in] datum The cil_user
*
* @return SEPOL_OK upon success or SEPOL_ERR otherwise.
*/
int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user);
/**
* Insert cil bool structure into sepol policydb.
*
* @param[in] pdb THe policy database to insert the bool into.
* @param[in] datum The cil_bool datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_bool_to_policydb(policydb_t *pdb, struct cil_bool *cil_bool);
/**
* Insert all ordered cil category structures into sepol policydb.
*
* @param[in] pdb The policy database to insert the categories into.
* @param[in] db The cil database that contains the category order list.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_catorder_to_policydb(policydb_t *pdb, const struct cil_db *db);
/**
* Insert cil category alias structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the category alias into.
* @param[in] datum The cil_catalias datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_catalias_to_policydb(policydb_t *pdb, struct cil_alias *cil_alias);
/**
* Insert the cil sensitivityorder into sepol policydb.
*
* @param[in] pdb The policy database to insert the sensitivityorder into.
* @param[in] db the cil database that contains the sensitivityorder list.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_sensitivityorder_to_policydb(policydb_t *pdb, const struct cil_db *db);
/**
* Insert cil type rule structure into sepol policydb. This includes
* typetransition, typechange, and typemember.
*
* @param[in] pdb The policy database to insert the type rule into.
* @param[in] datum The cil_type_rule datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_type_rule *cil_rule);
/**
* Insert cil avrule structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the avrule into.
* @param[in] datum The cil_avrule datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule);
/**
* Insert cil booleanif structure into sepol policydb. This populates the
* policydb conditional list. Each conditional node contains an expression
* and true/false avtab_ptr lists that point into te_cond_avtab.
*
* @param[in] pdb The policy database to insert the booleanif into.
* @param[in] node The cil_booleanif node.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node);
/**
* Insert cil role transition structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the role transition into.
* @param[in] datum The cil_role_trans datum.
*
* @return SEPOL_OK upon success or SEPOL_ERR upon error.
*/
int cil_roletrans_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roletransition *roletrans, hashtab_t role_trans_table);
/**
* Insert cil role allow structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the role allow into.
* @param[in] datum The cil_role_allow datum.
*
* @return SEPOL_OK upon success or SEPOL_ERR upon error.
*/
int cil_roleallow_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_roleallow *roleallow);
/**
* Insert cil file transition structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the file transition into.
* @param[in] datum The cil_nametypetransition datum.
*
* @return SEPOL_OK upon success or SEPOL_ERR upon error.
*/
int cil_typetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_nametypetransition *typetrans);
/**
* Insert cil constrain/mlsconstrain structure(s) into sepol policydb.
*
* @param[in] pdb The policy database to insert the (mls)constrain into.
* @param[in] datum The cil_(mls)constrain datum.
*
* @return SEPOL_OK upon success or SEPOL_ERR upon error.
*/
int cil_constrain_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_constrain *cil_constrain);
/**
* Define sepol level.
* Associates the sepol level (sensitivity) with categories.
* Looks at the cil_sens structure for a list of cil_cats to
* associate the sensitivity with.
* Sets the sepol level as defined in the sepol policy database.
*
* @param[in] pdb The policy database that holds the sepol level.
* @param[in] datum The cil_sens datum.
*
* @return SEPOL_OK upon success or SEPOL_ERR upon error.
*/
int cil_sepol_level_define(policydb_t *pdb, struct cil_sens *cil_sens);
/**
* Insert cil rangetransition structure into sepol policydb.
*
* @param[in] pdb The policy database to insert the rangetransition into.
* @param[in] datum The cil_rangetransition datum.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_rangetransition_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_rangetransition *rangetrans);
/**
* Insert cil ibpkeycon structure into sepol policydb.
* The function is given a structure containing the sorted ibpkeycons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the ibpkeycon into.
* @param[in] node The cil_sort structure that contains the sorted ibpkeycons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_ibpkeycon_to_policydb(policydb_t *pdb, struct cil_sort *ibpkeycons);
/**
* Insert cil idbev structure into sepol policydb.
* The function is given a structure containing the sorted ibendportcons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the pkeycon into.
* @param[in] node The cil_sort structure that contains the sorted ibendportcons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_ibendportcon_to_policydb(policydb_t *pdb, struct cil_sort *pkeycons);
/**
* Insert cil portcon structure into sepol policydb.
* The function is given a structure containing the sorted portcons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the portcon into.
* @param[in] node The cil_sort structure that contains the sorted portcons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_portcon_to_policydb(policydb_t *pdb, struct cil_sort *portcons);
/**
* Insert cil netifcon structure into sepol policydb.
* The function is given a structure containing the sorted netifcons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the netifcon into.
* @param[in] node The cil_sort structure that contains the sorted netifcons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_netifcon_to_policydb(policydb_t *pdb, struct cil_sort *netifcons);
/**
* Insert cil nodecon structure into sepol policydb.
* The function is given a structure containing the sorted nodecons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the nodecon into.
* @param[in] node The cil_sort structure that contains the sorted nodecons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_nodecon_to_policydb(policydb_t *pdb, struct cil_sort *nodecons);
/**
* Insert cil fsuse structure into sepol policydb.
* The function is given a structure containing the sorted fsuses and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the fsuse into.
* @param[in] node The cil_sort structure that contains the sorted fsuses.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_fsuse_to_policydb(policydb_t *pdb, struct cil_sort *fsuses);
/**
* Insert cil genfscon structure into sepol policydb.
* The function is given a structure containing the sorted genfscons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the genfscon into.
* @param[in] node The cil_sort structure that contains the sorted genfscons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_genfscon_to_policydb(policydb_t *pdb, struct cil_sort *genfscons);
/**
* Insert cil pirqcon structure into sepol policydb.
* The function is given a structure containing the sorted pirqcons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the pirqcon into.
* @param[in] node The cil_sort structure that contains the sorted pirqcons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_pirqcon_to_policydb(policydb_t *pdb, struct cil_sort *pirqcons);
/**
* Insert cil iomemcon structure into sepol policydb.
* The function is given a structure containing the sorted iomemcons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the iomemcon into.
* @param[in] node The cil_sort structure that contains the sorted iomemcons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_iomemcon_to_policydb(policydb_t *pdb, struct cil_sort *iomemcons);
/**
* Insert cil ioportcon structure into sepol policydb.
* The function is given a structure containing the sorted ioportcons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the ioportcon into.
* @param[in] node The cil_sort structure that contains the sorted ioportcons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_ioportcon_to_policydb(policydb_t *pdb, struct cil_sort *ioportcons);
/**
* Insert cil pcidevicecon structure into sepol policydb.
* The function is given a structure containing the sorted pcidevicecons and
* loops over this structure inserting them into the policy database.
*
* @param[in] pdb The policy database to insert the pcidevicecon into.
* @param[in] node The cil_sort structure that contains the sorted pcidevicecons.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_pcidevicecon_to_policydb(policydb_t *pdb, struct cil_sort *pcidevicecons);
/**
* Create an mls level using a cil level.
* The function is given a structure containing the a cil_level and
* outputs a created mls_level_t.
*
* @param[in] pdb The policy database to use to get sepol level from cil_level's sensitivity.
* @param[in] cil_level The cil_level that will be used to create an mls_level_t.
* @param[out] mls_level The mls_level that is created.
*
* @return SEPOL_OK upon success or an error otherwise.
*/
int cil_level_to_mls_level(policydb_t *pdb, struct cil_level *cil_level, mls_level_t *mls_level);
#endif //_CIL_BINARY_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,239 @@
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#ifndef CIL_BUILD_AST_H_
#define CIL_BUILD_AST_H_
#include <stdint.h>
#include "cil_internal.h"
#include "cil_flavor.h"
#include "cil_tree.h"
#include "cil_list.h"
int cil_add_decl_to_symtab(struct cil_db *db, symtab_t *symtab, hashtab_key_t key, struct cil_symtab_datum *datum, struct cil_tree_node *node);
int cil_gen_node(struct cil_db *db, struct cil_tree_node *ast_node, struct cil_symtab_datum *datum, hashtab_key_t key, enum cil_sym_index sflavor, enum cil_flavor nflavor);
int cil_parse_to_list(struct cil_tree_node *parse_cl_head, struct cil_list *ast_cl, enum cil_flavor flavor);
int cil_gen_block(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint16_t is_abstract);
void cil_destroy_block(struct cil_block *block);
int cil_gen_blockinherit(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_blockinherit(struct cil_blockinherit *inherit);
int cil_gen_blockabstract(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_blockabstract(struct cil_blockabstract *abstract);
int cil_gen_in(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_in(struct cil_in *in);
int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_class(struct cil_class *class);
int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_classorder(struct cil_classorder *classorder);
int cil_gen_perm(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms);
void cil_destroy_perm(struct cil_perm *perm);
int cil_gen_perm_nodes(struct cil_db *db, struct cil_tree_node *current_perm, struct cil_tree_node *ast_node, enum cil_flavor flavor, unsigned int *num_perms);
int cil_fill_perms(struct cil_tree_node *start_perm, struct cil_list **perm_strs);
int cil_fill_classperms(struct cil_tree_node *parse_current, struct cil_classperms **cp);
void cil_destroy_classperms(struct cil_classperms *cp);
void cil_fill_classperms_set(struct cil_tree_node *parse_current, struct cil_classperms_set **cp_set);
void cil_destroy_classperms_set(struct cil_classperms_set *cp_set);
int cil_fill_classperms_list(struct cil_tree_node *parse_current, struct cil_list **expr_list);
void cil_destroy_classperms_list(struct cil_list **cp_list);
int cil_gen_classpermission(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_classpermission(struct cil_classpermission *cp);
int cil_gen_classpermissionset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_classpermissionset(struct cil_classpermissionset *cps);
int cil_gen_map_class(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
int cil_gen_classmapping(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_classmapping(struct cil_classmapping *mapping);
int cil_gen_common(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
int cil_gen_classcommon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_classcommon(struct cil_classcommon *clscom);
int cil_gen_sid(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_sid(struct cil_sid *sid);
int cil_gen_sidcontext(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_sidcontext(struct cil_sidcontext *sidcon);
int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_sidorder(struct cil_sidorder *sidorder);
int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_user(struct cil_user *user);
int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_userattribute(struct cil_userattribute *attr);
int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_userattributeset(struct cil_userattributeset *attrset);
int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_userlevel(struct cil_userlevel *usrlvl);
int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_userrange(struct cil_userrange *userrange);
int cil_gen_userbounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
int cil_gen_userprefix(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_userprefix(struct cil_userprefix *userprefix);
int cil_gen_selinuxuser(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
int cil_gen_selinuxuserdefault(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_selinuxuser(struct cil_selinuxuser *selinuxuser);
int cil_gen_role(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_role(struct cil_role *role);
int cil_gen_roletype(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_roletype(struct cil_roletype *roletype);
int cil_gen_userrole(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_userrole(struct cil_userrole *userrole);
int cil_gen_roletransition(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_roletransition(struct cil_roletransition *roletrans);
int cil_gen_roleallow(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_roleallow(struct cil_roleallow *roleallow);
int cil_gen_roleattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_roleattribute(struct cil_roleattribute *role);
int cil_gen_roleattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_roleattributeset(struct cil_roleattributeset *attrset);
int cil_gen_rolebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
void cil_destroy_avrule(struct cil_avrule *rule);
int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_permissionx(struct cil_permissionx *permx);
int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
void cil_destroy_type_rule(struct cil_type_rule *rule);
int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_type(struct cil_type *type);
int cil_gen_typeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_typeattribute(struct cil_typeattribute *type);
int cil_gen_bool(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunableif);
void cil_destroy_bool(struct cil_bool *boolean);
int cil_gen_tunable(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_tunable(struct cil_tunable *tunable);
int cil_gen_constrain_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **stack);
int cil_gen_expr(struct cil_tree_node *current, enum cil_flavor flavor, struct cil_list **stack);
int cil_gen_boolif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, int tunable_if);
void cil_destroy_boolif(struct cil_booleanif *bif);
int cil_gen_tunif(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_tunif(struct cil_tunableif *tif);
int cil_gen_condblock(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
void cil_destroy_condblock(struct cil_condblock *cb);
int cil_gen_alias(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
void cil_destroy_alias(struct cil_alias *alias);
int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
void cil_destroy_aliasactual(struct cil_aliasactual *aliasactual);
int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_typeattributeset(struct cil_typeattributeset *attrtypes);
int cil_gen_expandtypeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_expandtypeattribute(struct cil_expandtypeattribute *expandattr);
int cil_gen_typebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_typepermissive(struct cil_typepermissive *typeperm);
int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_name(struct cil_name *name);
void cil_destroy_typetransition(struct cil_nametypetransition *nametypetrans);
int cil_gen_rangetransition(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_rangetransition(struct cil_rangetransition *rangetrans);
int cil_gen_sensitivity(struct cil_db *idb, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_sensitivity(struct cil_sens *sens);
int cil_gen_category(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_category(struct cil_cat *cat);
int cil_set_to_list(struct cil_tree_node *parse_current, struct cil_list *ast_cl);
void cil_destroy_catset(struct cil_catset *catset);
int cil_gen_catorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_catorder(struct cil_catorder *catorder);
int cil_gen_sensitivityorder(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_sensitivityorder(struct cil_sensorder *sensorder);
int cil_gen_senscat(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_senscat(struct cil_senscat *senscat);
int cil_gen_level(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_level(struct cil_level *level);
int cil_fill_levelrange(struct cil_tree_node *low, struct cil_levelrange *lvlrange);
int cil_gen_levelrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_levelrange(struct cil_levelrange *lvlrange);
void cil_destroy_constrain_node(struct cil_tree_node *cons_node);
int cil_gen_constrain(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
void cil_destroy_constrain(struct cil_constrain *cons);
int cil_gen_validatetrans(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
void cil_destroy_validatetrans(struct cil_validatetrans *validtrans);
int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context);
int cil_gen_context(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_context(struct cil_context *context);
int cil_gen_filecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_filecon(struct cil_filecon *filecon);
int cil_gen_ibpkeycon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_ibpkeycon(struct cil_ibpkeycon *ibpkeycon);
int cil_gen_ibendportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_ibendportcon(struct cil_ibendportcon *ibendportcon);
int cil_gen_portcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_portcon(struct cil_portcon *portcon);
int cil_gen_nodecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_nodecon(struct cil_nodecon *nodecon);
int cil_gen_genfscon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_genfscon(struct cil_genfscon *genfscon);
int cil_gen_netifcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_netifcon(struct cil_netifcon *netifcon);
int cil_gen_pirqcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_pirqcon(struct cil_pirqcon *pirqcon);
int cil_gen_iomemcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_iomemcon(struct cil_iomemcon *iomemcon);
int cil_gen_ioportcon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_ioportcon(struct cil_ioportcon *ioportcon);
int cil_gen_pcidevicecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_pcidevicecon(struct cil_pcidevicecon *pcidevicecon);
int cil_gen_devicetreecon(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_devicetreecon(struct cil_devicetreecon *devicetreecon);
int cil_gen_fsuse(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_fsuse(struct cil_fsuse *fsuse);
void cil_destroy_param(struct cil_param *param);
int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_macro(struct cil_macro *macro);
int cil_gen_call(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_call(struct cil_call *call);
void cil_destroy_args(struct cil_args *args);
int cil_gen_optional(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_optional(struct cil_optional *optional);
int cil_gen_policycap(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_policycap(struct cil_policycap *polcap);
int cil_gen_ipaddr(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_ipaddr(struct cil_ipaddr *ipaddr);
int cil_gen_bounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
void cil_destroy_bounds(struct cil_bounds *bounds);
int cil_gen_default(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, enum cil_flavor flavor);
void cil_destroy_default(struct cil_default *def);
int cil_gen_handleunknown(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_handleunknown(struct cil_handleunknown *unk);
int cil_gen_mls(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_mls(struct cil_mls *mls);
int cil_gen_defaultrange(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_defaultrange(struct cil_defaultrange *def);
int cil_gen_src_info(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_src_info(struct cil_src_info *info);
int cil_fill_cats(struct cil_tree_node *curr, struct cil_cats **cats);
void cil_destroy_cats(struct cil_cats *cats);
int cil_fill_context(struct cil_tree_node *user_node, struct cil_context *context);
int cil_fill_integer(struct cil_tree_node *int_node, uint32_t *integer, int base);
int cil_fill_integer64(struct cil_tree_node *int_node, uint64_t *integer, int base);
int cil_fill_ipaddr(struct cil_tree_node *addr_node, struct cil_ipaddr *addr);
int cil_fill_level(struct cil_tree_node *sens, struct cil_level *level);
int cil_build_ast(struct cil_db *db, struct cil_tree_node *parse_tree, struct cil_tree_node *ast);
#endif /* CIL_BUILD_AST_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#ifndef CIL_COPY_H_
#define CIL_COPY_H_
#include "cil_internal.h"
#include "cil_tree.h"
#include "cil_symtab.h"
void cil_copy_list(struct cil_list *orig, struct cil_list **copy);
int cil_copy_expr(struct cil_db *db, struct cil_list *orig, struct cil_list **new);
int cil_copy_block(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_blockabstract(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_blockinherit(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_perm(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_class(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_classorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_classmapping(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_permset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
void cil_copy_classperms(struct cil_classperms *orig, struct cil_classperms **new);
void cil_copy_classperms_set(struct cil_classperms_set *orig, struct cil_classperms_set **new);
void cil_copy_classperms_list(struct cil_list *orig, struct cil_list **new);
int cil_copy_classpermission(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_classpermissionset(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab);
int cil_copy_common(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_classcommon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_sid(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_sidcontext(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_sidorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_user(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_userattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_userattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_userrole(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_userlevel(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_userrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_userbounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_userprefix(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_role(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_roletype(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_rolebounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_roleattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_roleattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_roleallow(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_type(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_typebounds(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_typepermissive(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_typeattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_typeattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_typealias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_nametypetransition(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_rangetransition(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_bool(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_avrule(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_type_rule(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_sens(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_sensalias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_cat(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_catalias(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_catset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_senscat(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_catorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_sensitivityorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
void cil_copy_fill_level(struct cil_db *db, struct cil_level *orig, struct cil_level **new);
int cil_copy_level(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
void cil_copy_fill_levelrange(struct cil_db *db, struct cil_levelrange *orig, struct cil_levelrange *new);
int cil_copy_levelrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
void cil_copy_fill_context(struct cil_db *db, struct cil_context *orig, struct cil_context *new);
int cil_copy_context(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_netifcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_genfscon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_filecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_nodecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_ibpkeycon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_portcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_pirqcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_iomemcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_ioportcon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_pcidevicecon(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_fsuse(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_exrp(struct cil_db *db, struct cil_list *orig, struct cil_list **new);
int cil_copy_constrain(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_validatetrans(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_call(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_optional(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
void cil_copy_fill_ipaddr(struct cil_ipaddr *orig, struct cil_ipaddr *new);
int cil_copy_ipaddr(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_boolif(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
int cil_copy_ast(struct cil_db *db, struct cil_tree_node *orig, struct cil_tree_node *dest);
#endif

View File

@@ -0,0 +1,391 @@
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#include <sepol/policydb/ebitmap.h>
#include "cil_internal.h"
#include "cil_find.h"
#include "cil_flavor.h"
#include "cil_list.h"
#include "cil_log.h"
#include "cil_symtab.h"
struct cil_args_find {
enum cil_flavor flavor;
void *target;
struct cil_list *matching;
int match_self;
};
static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
{
enum cil_flavor f1 = FLAVOR(d1);
enum cil_flavor f2 = FLAVOR(d2);
if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
struct cil_type *t1 = (struct cil_type *)d1;
struct cil_type *t2 = (struct cil_type *)d2;
if (t1->value == t2->value) {
return CIL_TRUE;
}
} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
struct cil_type *t = (struct cil_type *)d2;
if (ksu_ebitmap_get_bit(a->types, t->value)) {
return CIL_TRUE;
}
} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
struct cil_type *t = (struct cil_type *)d1;
struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
if (ksu_ebitmap_get_bit(a->types, t->value)) {
return CIL_TRUE;
}
} else {
/* Both are attributes */
struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
if (d1 == d2) {
return CIL_TRUE;
} else if (ebitmap_match_any(a1->types, a2->types)) {
return CIL_TRUE;
}
}
return CIL_FALSE;
}
static int cil_type_matches(ebitmap_t *matches, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
{
int rc = SEPOL_OK;
enum cil_flavor f1 = FLAVOR(d1);
enum cil_flavor f2 = FLAVOR(d2);
if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
struct cil_type *t1 = (struct cil_type *)d1;
struct cil_type *t2 = (struct cil_type *)d2;
if (t1->value == t2->value) {
ksu_ebitmap_set_bit(matches, t1->value, 1);
}
} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
struct cil_type *t = (struct cil_type *)d2;
if (ksu_ebitmap_get_bit(a->types, t->value)) {
ksu_ebitmap_set_bit(matches, t->value, 1);
}
} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
struct cil_type *t = (struct cil_type *)d1;
struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
if (ksu_ebitmap_get_bit(a->types, t->value)) {
ksu_ebitmap_set_bit(matches, t->value, 1);
}
} else {
/* Both are attributes */
struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
rc = ksu_ebitmap_and(matches, a1->types, a2->types);
}
return rc;
}
/* s1 is the src type that is matched with a self
* s2, and t2 are the source and type of the other rule
*/
static int cil_self_match_any(struct cil_symtab_datum *s1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2)
{
int rc;
struct cil_tree_node *n1 = NODE(s1);
if (n1->flavor != CIL_TYPEATTRIBUTE) {
rc = cil_type_match_any(s1, t2);
} else {
struct cil_typeattribute *a = (struct cil_typeattribute *)s1;
ebitmap_t map;
ebitmap_init(&map);
rc = cil_type_matches(&map, s2, t2);
if (rc < 0) {
ksu_ebitmap_destroy(&map);
goto exit;
}
if (map.node == NULL) {
rc = CIL_FALSE;
goto exit;
}
rc = ebitmap_match_any(&map, a->types);
ksu_ebitmap_destroy(&map);
}
exit:
return rc;
}
static int cil_classperms_match_any(struct cil_classperms *cp1, struct cil_classperms *cp2)
{
struct cil_class *c1 = cp1->class;
struct cil_class *c2 = cp2->class;
struct cil_list_item *i1, *i2;
if (&c1->datum != &c2->datum) return CIL_FALSE;
cil_list_for_each(i1, cp1->perms) {
struct cil_perm *p1 = i1->data;
cil_list_for_each(i2, cp2->perms) {
struct cil_perm *p2 = i2->data;
if (&p1->datum == &p2->datum) return CIL_TRUE;
}
}
return CIL_FALSE;
}
static int __cil_classperms_list_match_any(struct cil_classperms *cp1, struct cil_list *cpl2)
{
int rc;
struct cil_list_item *curr;
cil_list_for_each(curr, cpl2) {
if (curr->flavor == CIL_CLASSPERMS) {
struct cil_classperms *cp = curr->data;
if (FLAVOR(cp->class) == CIL_CLASS) {
rc = cil_classperms_match_any(cp1, cp);
if (rc == CIL_TRUE) return CIL_TRUE;
} else { /* MAP */
struct cil_list_item *i = NULL;
cil_list_for_each(i, cp->perms) {
struct cil_perm *cmp = i->data;
rc = __cil_classperms_list_match_any(cp1, cmp->classperms);
if (rc == CIL_TRUE) return CIL_TRUE;
}
}
} else { /* SET */
struct cil_classperms_set *cp_set = curr->data;
struct cil_classpermission *cp = cp_set->set;
rc = __cil_classperms_list_match_any(cp1, cp->classperms);
if (rc == CIL_TRUE) return CIL_TRUE;
}
}
return CIL_FALSE;
}
static int cil_classperms_list_match_any(struct cil_list *cpl1, struct cil_list *cpl2)
{
int rc;
struct cil_list_item *curr;
cil_list_for_each(curr, cpl1) {
if (curr->flavor == CIL_CLASSPERMS) {
struct cil_classperms *cp = curr->data;
if (FLAVOR(cp->class) == CIL_CLASS) {
rc = __cil_classperms_list_match_any(cp, cpl2);
if (rc == CIL_TRUE) return CIL_TRUE;
} else { /* MAP */
struct cil_list_item *i = NULL;
cil_list_for_each(i, cp->perms) {
struct cil_perm *cmp = i->data;
rc = cil_classperms_list_match_any(cmp->classperms, cpl2);
if (rc == CIL_TRUE) return CIL_TRUE;
}
}
} else { /* SET */
struct cil_classperms_set *cp_set = curr->data;
struct cil_classpermission *cp = cp_set->set;
rc = cil_classperms_list_match_any(cp->classperms, cpl2);
if (rc == CIL_TRUE) return CIL_TRUE;
}
}
return CIL_FALSE;
}
static void __add_classes_from_classperms_list(struct cil_list *classperms, struct cil_list *class_list)
{
struct cil_list_item *curr;
cil_list_for_each(curr, classperms) {
if (curr->flavor == CIL_CLASSPERMS) {
struct cil_classperms *cp = curr->data;
if (FLAVOR(cp->class) == CIL_CLASS) {
cil_list_append(class_list, CIL_CLASS, cp->class);
} else { /* MAP */
struct cil_list_item *i = NULL;
cil_list_for_each(i, cp->perms) {
struct cil_perm *cmp = i->data;
__add_classes_from_classperms_list(cmp->classperms, class_list);
}
}
} else { /* SET */
struct cil_classperms_set *cp_set = curr->data;
struct cil_classpermission *cp = cp_set->set;
__add_classes_from_classperms_list(cp->classperms, class_list);
}
}
}
static int __add_classes_from_map_perms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
{
struct cil_list *class_list = args;
struct cil_perm *cmp = (struct cil_perm *)d;
__add_classes_from_classperms_list(cmp->classperms, class_list);
return SEPOL_OK;
}
struct cil_list *cil_expand_class(struct cil_class *class)
{
struct cil_list *class_list;
cil_list_init(&class_list, CIL_CLASS);
if (FLAVOR(class) == CIL_CLASS) {
cil_list_append(class_list, CIL_CLASS, class);
} else { /* MAP */
cil_symtab_map(&class->perms, __add_classes_from_map_perms, class_list);
}
return class_list;
}
static int cil_permissionx_match_any(struct cil_permissionx *px1, struct cil_permissionx *px2)
{
int rc = CIL_FALSE;
struct cil_list *cl1 = NULL;
struct cil_list *cl2 = NULL;
if (px1->kind != px2->kind) goto exit;
if (!ebitmap_match_any(px1->perms, px2->perms)) goto exit;
cl1 = cil_expand_class(px1->obj);
cl2 = cil_expand_class(px2->obj);
if (!cil_list_match_any(cl1, cl2)) goto exit;
rc = CIL_TRUE;
exit:
cil_list_destroy(&cl1, CIL_FALSE);
cil_list_destroy(&cl2, CIL_FALSE);
return rc;
}
static int cil_find_matching_avrule(struct cil_tree_node *node, struct cil_avrule *avrule, struct cil_avrule *target, struct cil_list *matching, int match_self)
{
int rc = SEPOL_OK;
struct cil_symtab_datum *s1 = avrule->src;
struct cil_symtab_datum *t1 = avrule->tgt;
struct cil_symtab_datum *s2 = target->src;
struct cil_symtab_datum *t2 = target->tgt;
if (match_self != CIL_TRUE && avrule == target) goto exit;
if (avrule->rule_kind != target->rule_kind) goto exit;
if (avrule->is_extended != target->is_extended) goto exit;
if (!cil_type_match_any(s1, s2)) goto exit;
if (t1->fqn != CIL_KEY_SELF && t2->fqn != CIL_KEY_SELF) {
if (!cil_type_match_any(t1, t2)) goto exit;
} else {
if (t1->fqn == CIL_KEY_SELF && t2->fqn == CIL_KEY_SELF) {
/* The earlier check whether s1 and s2 matches is all that is needed */
} else if (t1->fqn == CIL_KEY_SELF) {
rc = cil_self_match_any(s1, s2, t2);
if (rc < 0) {
goto exit;
} else if (rc == CIL_FALSE) {
rc = SEPOL_OK;
goto exit;
}
} else if (t2->fqn == CIL_KEY_SELF) {
rc = cil_self_match_any(s2, s1, t1);
if (rc < 0) {
goto exit;
} else if (rc == CIL_FALSE) {
rc = SEPOL_OK;
goto exit;
}
}
}
if (!target->is_extended) {
if (cil_classperms_list_match_any(avrule->perms.classperms, target->perms.classperms)) {
cil_list_append(matching, CIL_NODE, node);
}
} else {
if (cil_permissionx_match_any(avrule->perms.x.permx, target->perms.x.permx)) {
cil_list_append(matching, CIL_NODE, node);
}
}
rc = SEPOL_OK;
exit:
return rc;
}
static int __cil_find_matching_avrule_in_ast(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
{
int rc = SEPOL_OK;
struct cil_args_find *args = extra_args;
if (node->flavor == CIL_BLOCK) {
struct cil_block *blk = node->data;
if (blk->is_abstract == CIL_TRUE) {
*finished = CIL_TREE_SKIP_HEAD;
goto exit;
}
} else if (node->flavor == CIL_MACRO) {
*finished = CIL_TREE_SKIP_HEAD;
goto exit;
} else if (node->flavor == CIL_AVRULE || node->flavor == CIL_AVRULEX) {
if (node->flavor == args->flavor) {
rc = cil_find_matching_avrule(node, node->data, args->target, args->matching, args->match_self);
}
}
exit:
return rc;
}
int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self)
{
int rc;
struct cil_args_find args;
args.flavor = flavor;
args.target = target;
args.matching = matching;
args.match_self = match_self;
rc = cil_tree_walk(current, __cil_find_matching_avrule_in_ast, NULL, NULL, &args);
if (rc) {
cil_log(CIL_ERR, "An error occurred while searching for avrule in AST\n");
}
return rc;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#include "cil_flavor.h"
#include "cil_tree.h"
#include "cil_list.h"
#ifndef CIL_FIND_H_
#define CIL_FIND_H_
int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self);
struct cil_list *cil_expand_class(struct cil_class *class);
#endif

View File

@@ -0,0 +1,194 @@
/*
* Copyright 2013 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#ifndef CIL_FLAVOR_H_
#define CIL_FLAVOR_H_
/*
Tree/list node types
*/
#define CIL_MIN_OP_OPERANDS 1000
#define CIL_MIN_DECLARATIVE 2000
enum cil_flavor {
CIL_NONE = 0,
CIL_ROOT,
CIL_NODE,
CIL_STRING,
CIL_DATUM,
CIL_LIST,
CIL_LIST_ITEM,
CIL_PARAM,
CIL_ARGS,
CIL_BLOCKINHERIT,
CIL_BLOCKABSTRACT,
CIL_IN,
CIL_CALL,
CIL_BOOLEANIF,
CIL_TUNABLEIF,
CIL_CONDBLOCK,
CIL_CONDTRUE,
CIL_CONDFALSE,
CIL_CLASSORDER,
CIL_CLASSCOMMON,
CIL_CLASSMAPPING,
CIL_CLASSPERMS,
CIL_CLASSPERMS_SET,
CIL_CLASSPERMISSIONSET,
CIL_USERPREFIX,
CIL_USERROLE,
CIL_USERATTRIBUTESET,
CIL_USERLEVEL,
CIL_USERRANGE,
CIL_USERBOUNDS,
CIL_SELINUXUSER,
CIL_SELINUXUSERDEFAULT,
CIL_ROLEATTRIBUTESET,
CIL_ROLETYPE,
CIL_ROLEBOUNDS,
CIL_TYPEATTRIBUTESET,
CIL_EXPANDTYPEATTRIBUTE,
CIL_TYPEALIASACTUAL,
CIL_TYPEBOUNDS,
CIL_TYPEPERMISSIVE,
CIL_SENSALIASACTUAL,
CIL_SENSITIVITYORDER,
CIL_SENSCAT,
CIL_CATALIASACTUAL,
CIL_CATORDER,
CIL_SIDORDER,
CIL_ROLEALLOW,
CIL_AVRULE,
CIL_AVRULEX,
CIL_ROLETRANSITION,
CIL_TYPE_RULE,
CIL_NAMETYPETRANSITION,
CIL_RANGETRANSITION,
CIL_CONSTRAIN,
CIL_MLSCONSTRAIN,
CIL_VALIDATETRANS,
CIL_MLSVALIDATETRANS,
CIL_SIDCONTEXT,
CIL_FSUSE,
CIL_FILECON,
CIL_PORTCON,
CIL_NODECON,
CIL_GENFSCON,
CIL_NETIFCON,
CIL_PIRQCON,
CIL_IOMEMCON,
CIL_IOPORTCON,
CIL_PCIDEVICECON,
CIL_DEVICETREECON,
CIL_DEFAULTUSER,
CIL_DEFAULTROLE,
CIL_DEFAULTTYPE,
CIL_DEFAULTRANGE,
CIL_HANDLEUNKNOWN,
CIL_MLS,
CIL_SRC_INFO,
CIL_IBPKEYCON,
CIL_IBENDPORTCON,
/*
* boolean constraint set catset
* dom X
* domby X
* incomp X
* eq X X
* ne X X
* and X X X X
* not X X X X
* or X X X X
* xor X X X
* all X X
* range X
*/
CIL_OP = CIL_MIN_OP_OPERANDS,
CIL_ALL,
CIL_AND,
CIL_OR,
CIL_XOR,
CIL_NOT,
CIL_EQ,
CIL_NEQ,
CIL_RANGE,
CIL_CONS_DOM,
CIL_CONS_DOMBY,
CIL_CONS_INCOMP,
CIL_CONS_OPERAND,
CIL_CONS_U1,
CIL_CONS_U2,
CIL_CONS_U3,
CIL_CONS_T1,
CIL_CONS_T2,
CIL_CONS_T3,
CIL_CONS_R1,
CIL_CONS_R2,
CIL_CONS_R3,
CIL_CONS_L1,
CIL_CONS_L2,
CIL_CONS_H1,
CIL_CONS_H2,
CIL_BLOCK = CIL_MIN_DECLARATIVE,
CIL_MACRO,
CIL_OPTIONAL,
CIL_BOOL,
CIL_TUNABLE,
CIL_PERM,
CIL_MAP_PERM,
CIL_COMMON,
CIL_CLASS,
CIL_MAP_CLASS,
CIL_CLASSPERMISSION,
CIL_USER,
CIL_USERATTRIBUTE,
CIL_ROLE,
CIL_ROLEATTRIBUTE,
CIL_TYPE,
CIL_TYPEATTRIBUTE,
CIL_TYPEALIAS,
CIL_SENS,
CIL_SENSALIAS,
CIL_CAT,
CIL_CATSET,
CIL_CATALIAS,
CIL_LEVEL,
CIL_LEVELRANGE,
CIL_SID,
CIL_NAME,
CIL_CONTEXT,
CIL_IPADDR,
CIL_POLICYCAP,
CIL_PERMISSIONX
};
#endif /* CIL_FLAVOR_H_ */

View File

@@ -0,0 +1,143 @@
/*
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of Tresys Technology, LLC.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cil_fqn.h"
#include "cil_internal.h"
#include "cil_log.h"
#include "cil_strpool.h"
#include "cil_symtab.h"
struct cil_fqn_args {
char prefix[CIL_MAX_NAME_LENGTH];
int len;
struct cil_tree_node *node;
};
static int __cil_fqn_qualify_decls(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
{
struct cil_fqn_args *fqn_args = args;
struct cil_symtab_datum *datum = (struct cil_symtab_datum *)d;
int newlen;
char prefix[CIL_MAX_NAME_LENGTH];
int rc = SEPOL_OK;
if (fqn_args->len == 0) {
goto exit;
}
newlen = fqn_args->len + strlen(datum->name);
if (newlen >= CIL_MAX_NAME_LENGTH) {
cil_log(CIL_INFO, "Fully qualified name for %s is too long\n", datum->name);
rc = SEPOL_ERR;
goto exit;
}
strcpy(prefix, fqn_args->prefix);
strcat(prefix, datum->name);
datum->fqn = cil_strpool_add(prefix);
exit:
return rc;
}
static int __cil_fqn_qualify_blocks(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
{
struct cil_fqn_args *fqn_args = args;
struct cil_fqn_args child_args;
struct cil_block *block = (struct cil_block *)d;
struct cil_symtab_datum *datum = (struct cil_symtab_datum *)block;
struct cil_tree_node *node = NODE(datum);
int i;
int rc = SEPOL_OK;
int newlen;
if (node->flavor != CIL_BLOCK) {
goto exit;
}
newlen = fqn_args->len + strlen(datum->name) + 1;
if (newlen >= CIL_MAX_NAME_LENGTH) {
cil_log(CIL_INFO, "Fully qualified name for block %s is too long\n", datum->name);
rc = SEPOL_ERR;
goto exit;
}
child_args.node = node;
child_args.len = newlen;
strcpy(child_args.prefix, fqn_args->prefix);
strcat(child_args.prefix, datum->name);
strcat(child_args.prefix, ".");
for (i=1; i<CIL_SYM_NUM; i++) {
switch (i) {
case CIL_SYM_CLASSPERMSETS:
case CIL_SYM_CONTEXTS:
case CIL_SYM_LEVELRANGES:
case CIL_SYM_IPADDRS:
case CIL_SYM_NAMES:
case CIL_SYM_PERMX:
/* These do not show up in the kernel policy */
break;
case CIL_SYM_POLICYCAPS:
/* Valid policy capability names are defined in libsepol */
break;
default:
rc = cil_symtab_map(&(block->symtab[i]), __cil_fqn_qualify_decls, &child_args);
if (rc != SEPOL_OK) {
goto exit;
}
break;
}
}
rc = cil_symtab_map(&(block->symtab[CIL_SYM_BLOCKS]), __cil_fqn_qualify_blocks, &child_args);
exit:
if (rc != SEPOL_OK) {
cil_tree_log(node, CIL_ERR,"Problem qualifying names in block");
}
return rc;
}
int cil_fqn_qualify(struct cil_tree_node *root_node)
{
struct cil_root *root = root_node->data;
struct cil_fqn_args fqn_args;
fqn_args.prefix[0] = '\0';
fqn_args.len = 0;
fqn_args.node = root_node;
return cil_symtab_map(&(root->symtab[CIL_SYM_BLOCKS]), __cil_fqn_qualify_blocks, &fqn_args);
}

Some files were not shown because too many files have changed in this diff Show More