You've already forked KernelSU
mirror of
https://github.com/tiann/KernelSU.git
synced 2025-08-27 23:46:34 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5180e4add4 |
5
.github/FUNDING.yml
vendored
5
.github/FUNDING.yml
vendored
@@ -1,5 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: tiann
|
||||
patreon: weishu
|
||||
custom: https://vxposed.com/donate.html
|
||||
33
.github/ISSUE_TEMPLATE/add_device.yml
vendored
33
.github/ISSUE_TEMPLATE/add_device.yml
vendored
@@ -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
|
||||
72
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
72
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -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.
|
||||
11
.github/ISSUE_TEMPLATE/custom.yml
vendored
11
.github/ISSUE_TEMPLATE/custom.yml
vendored
@@ -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
|
||||
|
||||
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
64
.github/scripts/build_a12.sh
vendored
64
.github/scripts/build_a12.sh
vendored
@@ -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
|
||||
43
.github/scripts/build_a13.sh
vendored
43
.github/scripts/build_a13.sh
vendored
@@ -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
|
||||
59
.github/workflows/add-device.yml
vendored
59
.github/workflows/add-device.yml
vendored
@@ -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 }}
|
||||
31
.github/workflows/build-debug-kernel.yml
vendored
31
.github/workflows/build-debug-kernel.yml
vendored
@@ -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
|
||||
132
.github/workflows/build-kernel-a12.yml
vendored
132
.github/workflows/build-kernel-a12.yml
vendored
@@ -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"
|
||||
164
.github/workflows/build-kernel-a13.yml
vendored
164
.github/workflows/build-kernel-a13.yml
vendored
@@ -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 }}
|
||||
122
.github/workflows/build-kernel-a14.yml
vendored
122
.github/workflows/build-kernel-a14.yml
vendored
@@ -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 }}
|
||||
147
.github/workflows/build-kernel-arcvm.yml
vendored
147
.github/workflows/build-kernel-arcvm.yml
vendored
@@ -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
|
||||
141
.github/workflows/build-kernel-wsa.yml
vendored
141
.github/workflows/build-kernel-wsa.yml
vendored
@@ -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
86
.github/workflows/build-kernel.yml
vendored
Normal 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
|
||||
25
.github/workflows/build-ksud.yml
vendored
25
.github/workflows/build-ksud.yml
vendored
@@ -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 }}
|
||||
145
.github/workflows/build-manager.yml
vendored
145
.github/workflows/build-manager.yml
vendored
@@ -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
|
||||
|
||||
|
||||
64
.github/workflows/build-su.yml
vendored
64
.github/workflows/build-su.yml
vendored
@@ -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
28
.github/workflows/build-userspace.yml
vendored
Normal 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
|
||||
|
||||
37
.github/workflows/clippy.yml
vendored
37
.github/workflows/clippy.yml
vendored
@@ -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
|
||||
67
.github/workflows/deploy-website.yml
vendored
67
.github/workflows/deploy-website.yml
vendored
@@ -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
|
||||
203
.github/workflows/gki-kernel.yml
vendored
203
.github/workflows/gki-kernel.yml
vendored
@@ -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/*
|
||||
36
.github/workflows/ksud.yml
vendored
36
.github/workflows/ksud.yml
vendored
@@ -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
|
||||
77
.github/workflows/release.yml
vendored
77
.github/workflows/release.yml
vendored
@@ -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
|
||||
33
.github/workflows/rustfmt.yml
vendored
33
.github/workflows/rustfmt.yml
vendored
@@ -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
|
||||
27
.github/workflows/shellcheck.yml
vendored
27
.github/workflows/shellcheck.yml
vendored
@@ -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
2
.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
.idea
|
||||
.vscode
|
||||
31
README.md
Normal file
31
README.md
Normal 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)
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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 技巧。
|
||||
@@ -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)**.
|
||||
@@ -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.
|
||||
@@ -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): कुछ रूटकिट कौशल।
|
||||
@@ -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 のスキル
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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 實作。
|
||||
@@ -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` và `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 .
|
||||
@@ -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): כמה יכולות רוט.
|
||||
@@ -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
|
||||
...
|
||||
@@ -1,4 +0,0 @@
|
||||
Diagnostics:
|
||||
UnusedIncludes: Strict
|
||||
ClangTidy:
|
||||
Remove: bugprone-sizeof-expression
|
||||
@@ -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.
|
||||
|
||||
339
kernel/LICENSE
339
kernel/LICENSE
@@ -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.
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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] = {};
|
||||
@@ -1,2 +0,0 @@
|
||||
register_kprobe
|
||||
unregister_kprobe
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
305
kernel/ksu.c
305
kernel/ksu.c
@@ -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+才需要导出命名空间
|
||||
|
||||
98
kernel/ksu.h
98
kernel/ksu.h
@@ -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
|
||||
567
kernel/ksud.c
567
kernel/ksud.c
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
@@ -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,
|
||||
};
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
obj-y += 5.10/
|
||||
@@ -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
BIN
kernel/libsepol/.DS_Store
vendored
Normal file
Binary file not shown.
7
kernel/libsepol/.gitignore
vendored
Normal file
7
kernel/libsepol/.gitignore
vendored
Normal 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
504
kernel/libsepol/COPYING
Normal 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
48
kernel/libsepol/Makefile
Normal 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
1
kernel/libsepol/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
3.4
|
||||
BIN
kernel/libsepol/cil/.DS_Store
vendored
Normal file
BIN
kernel/libsepol/cil/.DS_Store
vendored
Normal file
Binary file not shown.
14
kernel/libsepol/cil/.gitignore
vendored
Normal file
14
kernel/libsepol/cil/.gitignore
vendored
Normal 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
|
||||
86
kernel/libsepol/cil/include/cil/cil.h
Normal file
86
kernel/libsepol/cil/include/cil/cil.h
Normal 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
|
||||
2906
kernel/libsepol/cil/src/cil.c
Normal file
2906
kernel/libsepol/cil/src/cil.c
Normal file
File diff suppressed because it is too large
Load Diff
5217
kernel/libsepol/cil/src/cil_binary.c
Normal file
5217
kernel/libsepol/cil/src/cil_binary.c
Normal file
File diff suppressed because it is too large
Load Diff
477
kernel/libsepol/cil/src/cil_binary.h
Normal file
477
kernel/libsepol/cil/src/cil_binary.h
Normal 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_
|
||||
6623
kernel/libsepol/cil/src/cil_build_ast.c
Normal file
6623
kernel/libsepol/cil/src/cil_build_ast.c
Normal file
File diff suppressed because it is too large
Load Diff
239
kernel/libsepol/cil/src/cil_build_ast.h
Normal file
239
kernel/libsepol/cil/src/cil_build_ast.h
Normal 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_ */
|
||||
2144
kernel/libsepol/cil/src/cil_copy_ast.c
Normal file
2144
kernel/libsepol/cil/src/cil_copy_ast.c
Normal file
File diff suppressed because it is too large
Load Diff
120
kernel/libsepol/cil/src/cil_copy_ast.h
Normal file
120
kernel/libsepol/cil/src/cil_copy_ast.h
Normal 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
|
||||
391
kernel/libsepol/cil/src/cil_find.c
Normal file
391
kernel/libsepol/cil/src/cil_find.c
Normal 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;
|
||||
}
|
||||
40
kernel/libsepol/cil/src/cil_find.h
Normal file
40
kernel/libsepol/cil/src/cil_find.h
Normal 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
|
||||
194
kernel/libsepol/cil/src/cil_flavor.h
Normal file
194
kernel/libsepol/cil/src/cil_flavor.h
Normal 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_ */
|
||||
143
kernel/libsepol/cil/src/cil_fqn.c
Normal file
143
kernel/libsepol/cil/src/cil_fqn.c
Normal 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
Reference in New Issue
Block a user