Compare commits

..

2 Commits

Author SHA1 Message Date
Ylarod
e23f15aeb6 update 2023-11-14 11:58:21 +08:00
Ylarod
ae59b080ae ksufs 5.10 test 2023-11-14 11:21:59 +08:00
310 changed files with 18523 additions and 16900 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
*.bat eol=crlf

1
.github/FUNDING.yml vendored
View File

@@ -2,3 +2,4 @@
github: tiann
patreon: weishu
custom: https://vxposed.com/donate.html

View File

@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Feature Request
url: https://github.com/tiann/KernelSU/issues/1705
about: "We do not accept external Feature Requests, see this link for more details."

View File

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

View File

@@ -1,38 +0,0 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
groups:
actions:
patterns:
- "*"
- package-ecosystem: cargo
directory: userspace/ksud
schedule:
interval: daily
allow:
- dependency-type: "all"
groups:
crates:
patterns:
- "*"
- package-ecosystem: gradle
directory: manager
schedule:
interval: daily
groups:
maven:
patterns:
- "*"
- package-ecosystem: npm
directory: website
schedule:
interval: daily
allow:
- dependency-type: "all"
groups:
npm:
patterns:
- "*"

View File

@@ -1,71 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--https://ci.android.com/builds/submitted/9964412/kernel_virt_x86_64/latest/manifest_9964412.xml-->
<manifest>
<remote name="aosp" fetch="https://android.googlesource.com/" review="https://android.googlesource.com/" />
<default revision="master" remote="aosp" sync-j="4" />
<superproject name="kernel/superproject" remote="aosp" revision="common-android14-6.1" />
<project path="build/kernel" name="kernel/build" revision="b0377a072bb3f78cdacfd6d809914a9d1b0c0148">
<linkfile dest="tools/bazel" src="kleaf/bazel.sh" />
<linkfile dest="WORKSPACE" src="kleaf/bazel.WORKSPACE" />
<linkfile dest="build/build.sh" src="build.sh" />
<linkfile dest="build/build_abi.sh" src="build_abi.sh" />
<linkfile dest="build/build_test.sh" src="build_test.sh" />
<linkfile dest="build/build_utils.sh" src="build_utils.sh" />
<linkfile dest="build/config.sh" src="config.sh" />
<linkfile dest="build/envsetup.sh" src="envsetup.sh" />
<linkfile dest="build/_setup_env.sh" src="_setup_env.sh" />
<linkfile dest="build/multi-switcher.sh" src="multi-switcher.sh" />
<linkfile dest="build/abi" src="abi" />
<linkfile dest="build/static_analysis" src="static_analysis" />
</project>
<project path="common" name="kernel/common" revision="7e35917775b8b3e3346a87f294e334e258bf15e6">
<linkfile dest=".source_date_epoch_dir" src="." />
</project>
<project path="kernel/tests" name="kernel/tests" revision="c90a1c1b226b975cc31e709fa96fc1c6ecdbe272" />
<project path="kernel/configs" name="kernel/configs" revision="52a7267d6a9f9efabf3cb43839bb5e7f7ff05be3" />
<project path="common-modules/virtual-device" name="kernel/common-modules/virtual-device" revision="0d03de3246301028775f05ea388c2c444344a268" />
<project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" clone-depth="1" revision="4f7e5adc160ab726ac5bafb260de98e612904c50" />
<project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" clone-depth="1" revision="f7b0d5b0ee369864d5ac3e96ae24ec9e2b6a52da" />
<project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" clone-depth="1" revision="dc92e06585a7647bf739a2309a721b82fcfa01d4" />
<project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" clone-depth="1" revision="5611871963f54c688d3ac49e527aecdef21e8567" />
<project path="prebuilts/kernel-build-tools" name="kernel/prebuilts/build-tools" clone-depth="1" revision="2597cb1b5525e419b7fa806373be673054a68d29" />
<project path="tools/mkbootimg" name="platform/system/tools/mkbootimg" revision="2680066d0844544b3e78d6022cd21321d31837c3" />
<project path="prebuilts/bazel/linux-x86_64" name="platform/prebuilts/bazel/linux-x86_64" clone-depth="1" revision="4fdb9395071ff22118311d434d697c2b6fd887b4" />
<project path="prebuilts/jdk/jdk11" name="platform/prebuilts/jdk/jdk11" clone-depth="1" revision="491e6aa056676f29c4541f71bd738e4e876e4ba2" />
<project path="prebuilts/ndk-r23" name="toolchain/prebuilts/ndk/r23" clone-depth="1" revision="19ac7e4eded12adb99d4f613490dde6dd0e72664" />
<project path="external/bazel-skylib" name="platform/external/bazel-skylib" revision="f998e5dc13c03f0eae9e373263d3afff0932c738" />
<project path="build/bazel_common_rules" name="platform/build/bazel_common_rules" revision="707b2c5fe3d0d7d934a93e00a8a4062e83557831" />
<project path="external/stardoc" name="platform/external/stardoc" revision="e83f522ee95419e55d2c5654aa6e0143beeef595" />
<project path="external/python/absl-py" name="platform/external/python/absl-py" revision="393d0b1e3f0fea3e95944a2fd3282cc9f76d4f14" />
</manifest>

View File

@@ -1,89 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- https://ci.android.com/builds/submitted/11577653/kernel_virt_aarch64/latest/manifest_11577653.xml -->
<manifest>
<remote name="aosp" fetch="https://android.googlesource.com/" review="https://android.googlesource.com/" />
<default revision="main" remote="aosp" sync-j="4" />
<superproject name="kernel/superproject" remote="aosp" revision="common-android15-6.6" />
<project path="build/kernel" name="kernel/build" groups="ddk" revision="9a2196a1ec1048c2869750c9d3969c88ac18adcd">
<linkfile dest="tools/bazel" src="kleaf/bazel.sh" />
<linkfile dest="WORKSPACE" src="kleaf/bazel.WORKSPACE" />
<linkfile dest="MODULE.bazel" src="kleaf/bzlmod/bazel.MODULE.bazel" />
<linkfile dest="WORKSPACE.bzlmod" src="kleaf/bzlmod/bazel.WORKSPACE.bzlmod" />
</project>
<project path="common" name="kernel/common" revision="ac1a7c65ff1bc7ece5569d62f02b121b4f2364f8" />
<project path="kernel/common-patches" name="kernel/common-patches" revision="3807ce65081de12ef4baa2a04487306672685160">
<linkfile dest="common/patches" src="android-mainline" />
</project>
<project path="kernel/tests" name="kernel/tests" revision="ca9fd66f5b48abc92990c9c770f73380b428362b" />
<project path="kernel/configs" name="kernel/configs" revision="be625f2ccf377a75d0ea86c082c716c322b8d4c6" />
<project path="common-modules/virtual-device" name="kernel/common-modules/virtual-device" revision="60a24583ac921279e40a44f818040e40abb3ef46" />
<project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" revision="93a1369ba33743a87bdf0183373f590a36ff7cb1" clone-depth="1" groups="ddk" />
<project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" clone-depth="1" groups="ddk" revision="cef8f53bb61fbdb02dbf4d433004f6cb637c3bc6" />
<project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="5aca9957ab19d2668c7f1da1954bbe89652d5fed" />
<project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" clone-depth="1" revision="69f9fb9b8e75c6f1ff01f380d5251757785bb823" />
<project path="prebuilts/kernel-build-tools" name="kernel/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="b09295493adc8d804b6d24286660f6e451e387fd" />
<project path="prebuilts/rust" name="platform/prebuilts/rust" revision="adc0e5499c3ddac831ca596d12cbef8d9747f737" clone-depth="1" />
<project path="prebuilts/tradefed" name="platform/tools/tradefederation/prebuilts" clone-depth="1" revision="a76ca09c5593e22e65b0d823d508882c6c64c13e" />
<project path="prebuilts/asuite" name="platform/prebuilts/asuite" clone-depth="1" revision="24510f175cb313a92241500efee917c2930d5d30" />
<project path="tools/mkbootimg" name="platform/system/tools/mkbootimg" revision="28b7934249c2885db8b561f1439d74663fcdce93" />
<project path="prebuilts/jdk/jdk11" name="platform/prebuilts/jdk/jdk11" revision="c6c90521b7c317f13d41bbd9336a8d45ee202cec" clone-depth="1" groups="ddk" />
<project path="prebuilts/ndk-r26" name="toolchain/prebuilts/ndk/r26" clone-depth="1" groups="ddk" revision="e535051ebc04204cec44bde38f62385d63180388" />
<project path="external/bazel-skylib" name="platform/external/bazel-skylib" groups="ddk" revision="6b103c40d8113f001475d5e13672922ef2aa0e5a" />
<project path="build/bazel_common_rules" name="platform/build/bazel_common_rules" groups="ddk" revision="2a10807a06153b5862da0369f4b6b368afc2dd08" />
<project path="external/libcap-ng" name="platform/external/libcap-ng" revision="2bcc92ae19481dd2b8d3ce3abdfbbee49261abe6" />
<project path="external/libcap" name="platform/external/libcap" revision="d7d1a0a38c5be06a7e7d6391d140b54878836f48" />
<project path="external/stardoc" name="platform/external/stardoc" groups="ddk" revision="f31250f9f5b03834d9964aaee7a3794c1d73d4a2" />
<project path="external/python/absl-py" name="platform/external/python/absl-py" groups="ddk" revision="9ae5a78fc57c3cd539398373ae39601a8b923e62" />
<project path="external/bazelbuild-bazel-central-registry" name="platform/external/bazelbuild-bazel-central-registry" revision="3422f064566c274ea66633442521704d4a22486d" groups="ddk" />
<project path="external/bazelbuild-platforms" name="platform/external/bazelbuild-platforms" groups="ddk" revision="e352aabd0131f3ac3f340282a43ba85ffc3fe8fa" />
<project path="external/bazelbuild-apple_support" name="platform/external/bazelbuild-apple_support" groups="ddk" revision="f6003e1e3763f8aad9fb9acae79cfa5fff9ae988" />
<project path="external/bazelbuild-rules_cc" name="platform/external/bazelbuild-rules_cc" groups="ddk" revision="f0df148dbeb9b9ed3816aad328ebe7c65efaaa24" />
<project path="external/bazelbuild-rules_java" name="platform/external/bazelbuild-rules_java" groups="ddk" revision="8e548c7053dffd1717d565f0409a88992f401da1" />
<project path="external/bazelbuild-rules_license" name="platform/external/bazelbuild-rules_license" groups="ddk" revision="f578df4fd057ffe2023728444759535685631548" />
<project path="external/bazelbuild-rules_pkg" name="platform/external/bazelbuild-rules_pkg" groups="ddk" revision="429887dfd8db834498ad95e99043f771a3882af0" />
<project path="external/bazelbuild-rules_python" name="platform/external/bazelbuild-rules_python" groups="ddk" revision="f71847ac898655b67634bb14e77a7408c4fb5e00" />
<project path="external/bazelbuild-rules_rust" name="platform/external/bazelbuild-rules_rust" groups="ddk" revision="1520b49835be9122c2424231357d4db80069cc38" />
<project path="external/pigz" name="platform/external/pigz" groups="ddk" revision="9bc9fa17d499ddde88b77820f6d063e16c0cdd42" />
<project path="external/zlib" name="platform/external/zlib" groups="ddk" revision="eff168fd731068a3faddd9aae056875e10014a51" />
<project path="external/zopfli" name="platform/external/zopfli" groups="ddk" revision="36c79f00e5229800d2aaa13fc42c301ec8ef1153" />
</manifest>

View File

@@ -1,89 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- https://ci.android.com/builds/submitted/11577653/kernel_virt_x86_64/latest/manifest_11577653.xml -->
<manifest>
<remote name="aosp" fetch="https://android.googlesource.com/" review="https://android.googlesource.com/" />
<default revision="main" remote="aosp" sync-j="4" />
<superproject name="kernel/superproject" remote="aosp" revision="common-android15-6.6" />
<project path="build/kernel" name="kernel/build" groups="ddk" revision="9a2196a1ec1048c2869750c9d3969c88ac18adcd">
<linkfile dest="tools/bazel" src="kleaf/bazel.sh" />
<linkfile dest="WORKSPACE" src="kleaf/bazel.WORKSPACE" />
<linkfile dest="MODULE.bazel" src="kleaf/bzlmod/bazel.MODULE.bazel" />
<linkfile dest="WORKSPACE.bzlmod" src="kleaf/bzlmod/bazel.WORKSPACE.bzlmod" />
</project>
<project path="common" name="kernel/common" revision="ac1a7c65ff1bc7ece5569d62f02b121b4f2364f8" />
<project path="kernel/common-patches" name="kernel/common-patches" revision="3807ce65081de12ef4baa2a04487306672685160">
<linkfile dest="common/patches" src="android-mainline" />
</project>
<project path="kernel/tests" name="kernel/tests" revision="ca9fd66f5b48abc92990c9c770f73380b428362b" />
<project path="kernel/configs" name="kernel/configs" revision="be625f2ccf377a75d0ea86c082c716c322b8d4c6" />
<project path="common-modules/virtual-device" name="kernel/common-modules/virtual-device" revision="60a24583ac921279e40a44f818040e40abb3ef46" />
<project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" revision="93a1369ba33743a87bdf0183373f590a36ff7cb1" clone-depth="1" groups="ddk" />
<project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" clone-depth="1" groups="ddk" revision="cef8f53bb61fbdb02dbf4d433004f6cb637c3bc6" />
<project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="5aca9957ab19d2668c7f1da1954bbe89652d5fed" />
<project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" clone-depth="1" revision="69f9fb9b8e75c6f1ff01f380d5251757785bb823" />
<project path="prebuilts/kernel-build-tools" name="kernel/prebuilts/build-tools" clone-depth="1" groups="ddk" revision="b09295493adc8d804b6d24286660f6e451e387fd" />
<project path="prebuilts/rust" name="platform/prebuilts/rust" revision="adc0e5499c3ddac831ca596d12cbef8d9747f737" clone-depth="1" />
<project path="prebuilts/tradefed" name="platform/tools/tradefederation/prebuilts" clone-depth="1" revision="a76ca09c5593e22e65b0d823d508882c6c64c13e" />
<project path="prebuilts/asuite" name="platform/prebuilts/asuite" clone-depth="1" revision="24510f175cb313a92241500efee917c2930d5d30" />
<project path="tools/mkbootimg" name="platform/system/tools/mkbootimg" revision="28b7934249c2885db8b561f1439d74663fcdce93" />
<project path="prebuilts/jdk/jdk11" name="platform/prebuilts/jdk/jdk11" revision="c6c90521b7c317f13d41bbd9336a8d45ee202cec" clone-depth="1" groups="ddk" />
<project path="prebuilts/ndk-r26" name="toolchain/prebuilts/ndk/r26" clone-depth="1" groups="ddk" revision="e535051ebc04204cec44bde38f62385d63180388" />
<project path="external/bazel-skylib" name="platform/external/bazel-skylib" groups="ddk" revision="6b103c40d8113f001475d5e13672922ef2aa0e5a" />
<project path="build/bazel_common_rules" name="platform/build/bazel_common_rules" groups="ddk" revision="2a10807a06153b5862da0369f4b6b368afc2dd08" />
<project path="external/libcap-ng" name="platform/external/libcap-ng" revision="2bcc92ae19481dd2b8d3ce3abdfbbee49261abe6" />
<project path="external/libcap" name="platform/external/libcap" revision="d7d1a0a38c5be06a7e7d6391d140b54878836f48" />
<project path="external/stardoc" name="platform/external/stardoc" groups="ddk" revision="f31250f9f5b03834d9964aaee7a3794c1d73d4a2" />
<project path="external/python/absl-py" name="platform/external/python/absl-py" groups="ddk" revision="9ae5a78fc57c3cd539398373ae39601a8b923e62" />
<project path="external/bazelbuild-bazel-central-registry" name="platform/external/bazelbuild-bazel-central-registry" revision="3422f064566c274ea66633442521704d4a22486d" groups="ddk" />
<project path="external/bazelbuild-platforms" name="platform/external/bazelbuild-platforms" groups="ddk" revision="e352aabd0131f3ac3f340282a43ba85ffc3fe8fa" />
<project path="external/bazelbuild-apple_support" name="platform/external/bazelbuild-apple_support" groups="ddk" revision="f6003e1e3763f8aad9fb9acae79cfa5fff9ae988" />
<project path="external/bazelbuild-rules_cc" name="platform/external/bazelbuild-rules_cc" groups="ddk" revision="f0df148dbeb9b9ed3816aad328ebe7c65efaaa24" />
<project path="external/bazelbuild-rules_java" name="platform/external/bazelbuild-rules_java" groups="ddk" revision="8e548c7053dffd1717d565f0409a88992f401da1" />
<project path="external/bazelbuild-rules_license" name="platform/external/bazelbuild-rules_license" groups="ddk" revision="f578df4fd057ffe2023728444759535685631548" />
<project path="external/bazelbuild-rules_pkg" name="platform/external/bazelbuild-rules_pkg" groups="ddk" revision="429887dfd8db834498ad95e99043f771a3882af0" />
<project path="external/bazelbuild-rules_python" name="platform/external/bazelbuild-rules_python" groups="ddk" revision="f71847ac898655b67634bb14e77a7408c4fb5e00" />
<project path="external/bazelbuild-rules_rust" name="platform/external/bazelbuild-rules_rust" groups="ddk" revision="1520b49835be9122c2424231357d4db80069cc38" />
<project path="external/pigz" name="platform/external/pigz" groups="ddk" revision="9bc9fa17d499ddde88b77820f6d063e16c0cdd42" />
<project path="external/zlib" name="platform/external/zlib" groups="ddk" revision="eff168fd731068a3faddd9aae056875e10014a51" />
<project path="external/zopfli" name="platform/external/zopfli" groups="ddk" revision="36c79f00e5229800d2aaa13fc42c301ec8ef1153" />
</manifest>

View File

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

View File

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

View File

@@ -51,7 +51,7 @@ build_from_image() {
echo "[+] Images to upload"
find . -type f -name "*.gz"
# find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do

View File

@@ -30,7 +30,7 @@ build_from_image() {
echo '[+] Images to upload'
find . -type f -name "*.gz"
# find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
find . -type f -name "*.gz" -exec python3 "$GITHUB_WORKSPACE"/KernelSU/scripts/ksubot.py {} +
}
for dir in Image*; do

View File

@@ -26,7 +26,7 @@ jobs:
- name: Make pull request
if: steps.handle-add-device.outputs.success == 'true'
id: cpr
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "[add device]: ${{ steps.handle-add-device.outputs.device }}"
@@ -37,7 +37,6 @@ jobs:
branch: "add-device-${{ github.event.issue.number }}"
labels: add-device
delete-branch: true
sign-commits: true
- name: Check outputs
if: ${{ steps.cpr.outputs.pull-request-number }}
run: |
@@ -54,7 +53,7 @@ jobs:
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@v3
uses: peter-evans/close-issue@v1
with:
issue-number: ${{ github.event.issue.number }}
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,137 +0,0 @@
name: GKI Kernel Build
on:
workflow_call:
inputs:
version_name:
required: true
type: string
description: >
With SUBLEVEL of kernel,
for example: android12-5.10.66
arch:
required: true
type: string
description: >
Build arch: aarch64/x86_64
debug:
required: false
type: boolean
default: true
manifest_name:
required: false
type: string
description: >
Local repo manifest xml path,
typically for AVD kernel build.
secrets:
BOOT_SIGN_KEY:
required: false
CHAT_ID:
required: false
BOT_TOKEN:
required: false
MESSAGE_THREAD_ID:
required: false
jobs:
build:
name: Build ${{ inputs.version_name }}
runs-on: ubuntu-22.04
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@master
with:
root-reserve-mb: 8192
temp-reserve-mb: 2048
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
- uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: Setup need_upload
id: need_upload
run: |
if [ ! -z "${{ secrets.BOT_TOKEN }}" ]; then
echo "UPLOAD=true" >> $GITHUB_OUTPUT
else
echo "UPLOAD=false" >> $GITHUB_OUTPUT
fi
- name: Setup kernel source
run: |
echo "Free space:"
df -h
cd $GITHUB_WORKSPACE
sudo apt-get install repo -y
mkdir android-kernel && cd android-kernel
repo init --depth=1 -u https://android.googlesource.com/kernel/manifest -m "$GITHUB_WORKSPACE/KernelSU/.github/manifests/${{ inputs.manifest_name }}" --repo-rev=v2.16
repo --version
repo --trace sync -c -j$(nproc --all) --no-tags
df -h
- name: Setup KernelSU
env:
PATCH_PATH: ${{ inputs.patch_path }}
IS_DEBUG_KERNEL: ${{ inputs.debug }}
run: |
cd $GITHUB_WORKSPACE/android-kernel
echo "[+] KernelSU setup"
GKI_ROOT=$(pwd)
echo "[+] GKI_ROOT: $GKI_ROOT"
echo "[+] Copy KernelSU driver to $GKI_ROOT/common/drivers"
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply KernelSU patches"
cd $GKI_ROOT/common/ && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/$PATCH_PATH/*.patch || echo "[-] No patch found"
if [ "$IS_DEBUG_KERNEL" = "true" ]; then
echo "[+] Enable debug features for kernel"
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
fi
repo status
echo "[+] KernelSU setup done."
cd $GITHUB_WORKSPACE/KernelSU
VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "VERSION: $VERSION"
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
- name: Make working directory clean to avoid dirty
working-directory: android-kernel
run: |
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
git config --global user.email "bot@kernelsu.org"
git config --global user.name "KernelSUBot"
cd common/ && git add -A && git commit -a -m "Add KernelSU"
repo status
- name: Build kernel
working-directory: android-kernel
run: |
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
export KSU_EXPECTED_SIZE=${{ vars.EXPECTED_SIZE }}
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
fi
tools/bazel run --config=fast --config=stamp --lto=thin //common-modules/virtual-device:virtual_device_${{ inputs.arch }}_dist -- --dist_dir=dist
NAME=kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
TARGET_IMAGE=dist/bzImage
if [ ! -e $TARGET_IMAGE ]; then
TARGET_IMAGE=dist/Image
fi
mv $TARGET_IMAGE $NAME
echo "file_path=android-kernel/$NAME" >> $GITHUB_ENV
- name: Upload Kernel
uses: actions/upload-artifact@v4
with:
name: kernel-${{ inputs.arch }}-avd-${{ inputs.version_name }}-${{ env.kernelsu_version }}
path: "${{ env.file_path }}"

View File

@@ -7,9 +7,9 @@ jobs:
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.226
tag: android12-5.10-2024-11
os_patch_level: 2024-11
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:
@@ -17,11 +17,11 @@ jobs:
matrix:
include:
- version: "5.10"
sub_level: 223
os_patch_level: 2024-11
sub_level: 187
os_patch_level: 2023-08
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
sub_level: 119
os_patch_level: 2023-09
uses: ./.github/workflows/gki-kernel.yml
with:
version: android13-${{ matrix.version }}
@@ -29,34 +29,3 @@ jobs:
tag: android13-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: true
build-debug-kernel-a14:
strategy:
matrix:
include:
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
- version: "6.1"
sub_level: 115
os_patch_level: 2024-12
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 }}
patch_path: ${{ matrix.version }}
debug: true
build-debug-kernel-a15:
strategy:
matrix:
include:
- version: "6.6"
sub_level: 57
os_patch_level: 2024-12
uses: ./.github/workflows/gki-kernel.yml
with:
version: android15-${{ matrix.version }}
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
debug: true

View File

@@ -1,7 +1,7 @@
name: Build Kernel - Android 12
on:
push:
branches: ["main", "ci", "checkci"]
branches: ["main", "ci"]
paths:
- ".github/workflows/build-kernel-a12.yml"
- ".github/workflows/gki-kernel.yml"
@@ -17,20 +17,32 @@ on:
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
if: github.event_name != 'pull_request'
strategy:
matrix:
include:
- sub_level: 209
os_patch_level: 2024-05
- sub_level: 218
os_patch_level: 2024-08
- sub_level: 226
os_patch_level: 2024-11
- sub_level: 233
os_patch_level: 2025-02
- sub_level: 236
os_patch_level: 2025-05
- 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:
@@ -39,7 +51,6 @@ jobs:
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
@@ -53,7 +64,7 @@ jobs:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
- uses: actions/checkout@v4
with:
@@ -67,11 +78,11 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
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
pip3 install telethon==1.31.1
- name: Set boot sign key
env:
@@ -83,8 +94,7 @@ jobs:
- name: Bot session cache
id: bot_session_cache
uses: actions/cache@v4
if: false
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
@@ -106,17 +116,17 @@ jobs:
run: ls -R
- name: Upload images artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: boot-images-android12
path: Image-android12*/*.img.gz
check-build-kernel:
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
if: github.event_name == 'pull_request'
uses: ./.github/workflows/gki-kernel.yml
with:
version: android12-5.10
version_name: android12-5.10.223
tag: android12-5.10-2024-11
os_patch_level: 2024-11
patch_path: "5.10"
version_name: android12-5.10.177
tag: android12-5.10-2023-06
os_patch_level: 2023-06
patch_path: "5.10"

View File

@@ -1,7 +1,7 @@
name: Build Kernel - Android 13
on:
push:
branches: ["main", "ci", "checkci"]
branches: ["main", "ci"]
paths:
- ".github/workflows/build-kernel-a13.yml"
- ".github/workflows/gki-kernel.yml"
@@ -17,55 +17,55 @@ on:
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
if: github.event_name != 'pull_request'
strategy:
matrix:
include:
- version: "5.10"
sub_level: 209
os_patch_level: 2024-05
sub_level: 107
os_patch_level: 2022-11
- version: "5.10"
sub_level: 210
os_patch_level: 2024-06
- version: "5.10"
sub_level: 214
os_patch_level: 2024-07
- version: "5.10"
sub_level: 218
os_patch_level: 2024-08
- version: "5.10"
sub_level: 223
os_patch_level: 2024-11
- version: "5.10"
sub_level: 228
os_patch_level: 2025-01
- version: "5.10"
sub_level: 234
os_patch_level: 2025-03
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-07
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: 151
os_patch_level: 2024-08
sub_level: 41
os_patch_level: 2022-11
- version: "5.15"
sub_level: 153
os_patch_level: 2024-09
sub_level: 74
os_patch_level: 2023-01
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
sub_level: 78
os_patch_level: 2023-03
- version: "5.15"
sub_level: 178
os_patch_level: 2024-11
sub_level: 94
os_patch_level: 2023-05
- version: "5.15"
sub_level: 170
os_patch_level: 2025-01
sub_level: 104
os_patch_level: 2023-07
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
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:
@@ -74,7 +74,6 @@ jobs:
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
@@ -88,7 +87,7 @@ jobs:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
- uses: actions/checkout@v4
with:
@@ -102,11 +101,11 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
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
pip3 install telethon==1.31.1
- name: Set boot sign key
env:
@@ -118,8 +117,7 @@ jobs:
- name: Bot session cache
id: bot_session_cache
uses: actions/cache@v4
if: false
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
@@ -136,31 +134,31 @@ jobs:
echo "VERSION: $VERSION"
cd -
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
- name: Display structure of boot files
run: ls -R
- name: Upload images artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: boot-images-android13
path: Image-android13*/*.img.gz
check-build-kernel:
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
if: github.event_name == 'pull_request'
strategy:
matrix:
include:
- version: "5.10"
sub_level: 223
os_patch_level: 2024-11
sub_level: 189
os_patch_level: 2023-10
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
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 }}
patch_path: ${{ matrix.version }}

View File

@@ -1,7 +1,7 @@
name: Build Kernel - Android 14
on:
push:
branches: ["main", "ci", "checkci"]
branches: ["main", "ci"]
paths:
- ".github/workflows/build-kernel-a14.yml"
- ".github/workflows/gki-kernel.yml"
@@ -17,67 +17,16 @@ on:
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
if: github.event_name != 'pull_request'
strategy:
matrix:
include:
- version: "5.15"
sub_level: 148
os_patch_level: 2024-05
- version: "5.15"
sub_level: 149
os_patch_level: 2024-06
- version: "5.15"
sub_level: 153
os_patch_level: 2024-07
- version: "5.15"
sub_level: 158
os_patch_level: 2024-08
- version: "5.15"
sub_level: 164
os_patch_level: 2024-09
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
- version: "5.15"
sub_level: 170
os_patch_level: 2025-01
- version: "5.15"
sub_level: 178
os_patch_level: 2025-03
sub_level: 110
os_patch_level: 2023-09
- version: "6.1"
sub_level: 75
os_patch_level: 2024-05
- version: "6.1"
sub_level: 78
os_patch_level: 2024-06
- version: "6.1"
sub_level: 84
os_patch_level: 2024-07
- version: "6.1"
sub_level: 90
os_patch_level: 2024-08
- version: "6.1"
sub_level: 93
os_patch_level: 2024-09
- version: "6.1"
sub_level: 99
os_patch_level: 2024-10
- version: "6.1"
sub_level: 112
os_patch_level: 2024-11
- version: "6.1"
sub_level: 115
os_patch_level: 2024-12
- version: "6.1"
sub_level: 118
os_patch_level: 2025-01
- version: "6.1"
sub_level: 128
os_patch_level: 2025-03
- version: "6.1"
sub_level: 134
os_patch_level: 2025-05
sub_level: 25
os_patch_level: 2023-10
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
@@ -86,7 +35,6 @@ jobs:
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
@@ -100,7 +48,7 @@ jobs:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
- uses: actions/checkout@v4
with:
@@ -114,11 +62,11 @@ jobs:
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
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
pip3 install telethon==1.31.1
- name: Set boot sign key
env:
@@ -130,8 +78,7 @@ jobs:
- name: Bot session cache
id: bot_session_cache
uses: actions/cache@v4
if: false
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
@@ -148,31 +95,28 @@ jobs:
echo "VERSION: $VERSION"
cd -
bash $GITHUB_WORKSPACE/KernelSU/.github/scripts/build_a13.sh
- name: Display structure of boot files
run: ls -R
- name: Upload images artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: boot-images-android14
path: Image-android14*/*.img.gz
check-build-kernel:
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
if: github.event_name == 'pull_request'
strategy:
matrix:
include:
- version: "5.15"
sub_level: 167
os_patch_level: 2024-11
- version: "6.1"
sub_level: 115
os_patch_level: 2024-12
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 }}
patch_path: ${{ matrix.version }}

View File

@@ -1,148 +0,0 @@
name: Build Kernel - Android 15
on:
push:
branches: ["main", "ci", "checkci"]
paths:
- ".github/workflows/build-kernel-a15.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build_a13.sh"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-a15.yml"
- ".github/workflows/gki-kernel.yml"
- ".github/scripts/build-a13.sh"
- "kernel/**"
workflow_call:
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
strategy:
matrix:
include:
- version: "6.6"
sub_level: 30
os_patch_level: 2024-08
- version: "6.6"
sub_level: 46
os_patch_level: 2024-09
- version: "6.6"
sub_level: 50
os_patch_level: 2024-10
- version: "6.6"
sub_level: 56
os_patch_level: 2024-11
- version: "6.6"
sub_level: 57
os_patch_level: 2024-12
- version: "6.6"
sub_level: 58
os_patch_level: 2025-01
- version: "6.6"
sub_level: 66
os_patch_level: 2025-02
- version: "6.6"
sub_level: 77
os_patch_level: 2025-03
- version: "6.6"
sub_level: 82
os_patch_level: 2025-04
- version: "6.6"
sub_level: 87
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
secrets: inherit
with:
version: android15-${{ matrix.version }}
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}
upload-artifacts:
needs: build-kernel
runs-on: ubuntu-latest
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' || github.ref == 'refs/heads/ci' }}
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMMIT_URL: ${{ github.event.head_commit.url }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- uses: actions/checkout@v4
with:
path: KernelSU
fetch-depth: 0
- name: List artifacts
run: |
tree
- name: Download prebuilt toolchain
run: |
AOSP_MIRROR=https://android.googlesource.com
BRANCH=main-kernel-build-2024
git clone $AOSP_MIRROR/platform/prebuilts/build-tools -b $BRANCH --depth 1 build-tools
git clone $AOSP_MIRROR/kernel/prebuilts/build-tools -b $BRANCH --depth 1 kernel-build-tools
git clone $AOSP_MIRROR/platform/system/tools/mkbootimg -b $BRANCH --depth 1
pip3 install telethon
- name: Set boot sign key
env:
BOOT_SIGN_KEY: ${{ secrets.BOOT_SIGN_KEY }}
run: |
if [ ! -z "$BOOT_SIGN_KEY" ]; then
echo "$BOOT_SIGN_KEY" > ./kernel-build-tools/linux-x86/share/avb/testkey_rsa2048.pem
fi
- name: Bot session cache
id: bot_session_cache
uses: actions/cache@v4
if: false
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@v4
with:
name: boot-images-android15
path: Image-android15*/*.img.gz
check-build-kernel:
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
strategy:
matrix:
include:
- version: "6.6"
sub_level: 57
os_patch_level: 2024-12
uses: ./.github/workflows/gki-kernel.yml
with:
version: android15-${{ matrix.version }}
version_name: android15-${{ matrix.version }}.${{ matrix.sub_level }}
tag: android15-${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
patch_path: ${{ matrix.version }}

View File

@@ -1,7 +1,7 @@
name: Build Kernel - ChromeOS ARCVM
on:
push:
branches: ["main", "ci", "checkci"]
branches: ["main"]
paths:
- ".github/workflows/build-kernel-arcvm.yml"
- "kernel/**"
@@ -13,26 +13,19 @@ on:
workflow_call:
workflow_dispatch:
env:
git_tag: chromeos-5.10-arcvm
jobs:
build:
if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && !github.event.pull_request.draft)
strategy:
matrix:
arch: [x86_64]
version: ["5.10.178"]
include:
- arch: x86_64
kernel_image_name: bzImage
build_config: build.config.gki.x86_64
defconfig: x86_64_arcvm_defconfig
- arch: arm64
kernel_image_name: Image
build_config: build.config.gki.aarch64
defconfig: arm64_arcvm_defconfig
git_tag: chromeos-5.10-arcvm
file_name: "bzImage"
name: Build ChromeOS ARCVM kernel
runs-on: ubuntu-22.04
runs-on: ubuntu-20.04
env:
LTO: thin
ROOT_DIR: /
@@ -50,7 +43,7 @@ jobs:
sudo ln -s --force python3 /usr/bin/python
export LLVM_VERSION=14
export LLVM_VERSION=12
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
@@ -72,16 +65,7 @@ jobs:
fetch-depth: 0
- name: Setup kernel source
run: git clone https://chromium.googlesource.com/chromiumos/third_party/kernel.git -b ${{ env.git_tag }} --depth=1
- name: Extract version from Makefile
working-directory: kernel
run: |
VERSION=$(grep -E '^VERSION = ' Makefile | awk '{print $3}')
PATCHLEVEL=$(grep -E '^PATCHLEVEL = ' Makefile | awk '{print $3}')
SUBLEVEL=$(grep -E '^SUBLEVEL = ' Makefile | awk '{print $3}')
echo "ChromeOS ARCVM Linux kernel version: $VERSION.$PATCHLEVEL.$SUBLEVEL"
echo "version=$VERSION.$PATCHLEVEL.$SUBLEVEL" >> $GITHUB_ENV
run: git clone https://chromium.googlesource.com/chromiumos/third_party/kernel.git -b ${{ matrix.git_tag }} --depth=1
- name: Setup KernelSU
working-directory: kernel
@@ -94,30 +78,25 @@ jobs:
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$KERNEL_ROOT/drivers/Makefile
DRIVER_KCONFIG=$KERNEL_ROOT/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
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 "[-] No patch found"
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
KSU_VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "KernelSU version: $KSU_VERSION"
echo "kernelsu_version=$KSU_VERSION" >> $GITHUB_ENV
VERSION=$(($(git rev-list --count HEAD) + 10200))
echo "VERSION: $VERSION"
echo "kernelsu_version=$VERSION" >> $GITHUB_ENV
- name: Build Kernel
working-directory: kernel
env:
KERNEL_IMAGE_NAME: ${{ matrix.kernel_image_name }}
ARCH: ${{ matrix.arch }}
run: |
set -a && . ${{ matrix.build_config }}; set +a
export DEFCONFIG=${{ matrix.defconfig }}
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 }}
@@ -126,12 +105,43 @@ jobs:
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) ${KERNEL_IMAGE_NAME} modules prepare-objtool
ls -l -h ${PWD}/arch/${ARCH}/boot
echo "file_path=${PWD}/arch/${ARCH}/boot/${KERNEL_IMAGE_NAME}" >> $GITHUB_ENV
make LLVM=1 LLVM_IAS=1 DEPMOD=depmod DTC=dtc O=${PWD} -j$(nproc) bzImage modules prepare-objtool
- name: Upload kernel-ARCVM-${{ matrix.arch }}-${{ env.version }}
uses: actions/upload-artifact@v4
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 }}-${{ env.version }}
name: kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
path: "${{ env.file_path }}"
- name: Bot session cache
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
id: bot_session_cache
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
- name: Post to Telegram
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
env:
CHAT_ID: ${{ secrets.CHAT_ID }}
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMMIT_URL: ${{ github.event.head_commit.url }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
TITLE=kernel-ARCVM-${{ matrix.arch }}-${{ matrix.version }}
echo "[+] title: $TITLE"
export TITLE
export VERSION="${{ env.kernelsu_version }}"
echo "[+] Compress images"
gzip -n -f -9 "${{ env.file_path }}"
echo "[+] Image to upload"
ls -l "${{ env.file_path }}.gz"
if [ -n "${{ secrets.BOT_TOKEN }}" ]; then
pip3 install telethon==1.31.1
python3 "$GITHUB_WORKSPACE/KernelSU/scripts/ksubot.py" "${{ env.file_path }}.gz"
fi

View File

@@ -1,40 +0,0 @@
name: Build Kernel - AVD
on:
push:
branches: ["main", "ci", "checkci"]
paths:
- ".github/workflows/build-kernel-avd.yml"
- ".github/workflows/avd-kernel.yml"
- ".github/workflows/manifests/*xml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-avd.yml"
- ".github/workflows/avd-kernel.yml"
- ".github/workflows/manifests/*.xml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build-kernel:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
uses: ./.github/workflows/avd-kernel.yml
secrets: inherit
strategy:
matrix:
include:
- version: "android-14-avd_x86_64"
manifest: "android-14-avd_x86_64.xml"
arch: "x86_64"
- version: "android-15-avd_aarch64"
manifest: "android-15-avd_aarch64.xml"
arch: "aarch64"
- version: "android-15-avd_x86_64"
manifest: "android-15-avd_x86_64.xml"
arch: "x86_64"
with:
version_name: ${{ matrix.version }}
manifest_name: ${{ matrix.manifest }}
arch: ${{ matrix.arch }}
debug: true

View File

@@ -1,38 +1,141 @@
name: Build Kernel - WSA
on:
push:
branches: ["main", "ci", "checkci"]
branches: ["main"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- ".github/workflows/wsa-kernel.yml"
- "kernel/**"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-kernel-wsa.yml"
- ".github/workflows/wsa-kernel.yml"
- "kernel/**"
workflow_call:
workflow_dispatch:
jobs:
build:
if: github.event_name != 'pull_request' && github.ref != 'refs/heads/checkci'
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"]
uses: ./.github/workflows/wsa-kernel.yml
with:
arch: ${{ matrix.arch }}
version: ${{ matrix.version }}
check_build:
if: (github.event_name == 'pull_request' && !github.event.pull_request.draft) || github.ref == 'refs/heads/checkci'
uses: ./.github/workflows/wsa-kernel.yml
strategy:
matrix:
arch: [x86_64, arm64]
with:
arch: ${{ matrix.arch }}
version: "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

25
.github/workflows/build-ksud.yml vendored Normal file
View File

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

View File

@@ -1,41 +0,0 @@
name: Build LKM for KernelSU
on:
push:
branches: ["main", "ci", "checkci"]
paths:
- ".github/workflows/build-lkm.yml"
pull_request:
branches: ["main"]
paths:
- ".github/workflows/build-lkm.yml"
workflow_call:
jobs:
build-lkm:
strategy:
matrix:
include:
- version: "android12-5.10"
sub_level: 236
os_patch_level: 2025-05
- version: "android13-5.10"
sub_level: 234
os_patch_level: 2025-03
- version: "android13-5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "android14-5.15"
sub_level: 178
os_patch_level: 2025-03
- version: "android14-6.1"
sub_level: 134
os_patch_level: 2025-05
- version: "android15-6.6"
sub_level: 87
os_patch_level: 2025-05
uses: ./.github/workflows/gki-kernel.yml
with:
version: ${{ matrix.version }}
version_name: ${{ matrix.version }}.${{ matrix.sub_level }}
tag: ${{ matrix.version }}-${{ matrix.os_patch_level }}
os_patch_level: ${{ matrix.os_patch_level }}
build_lkm: true

View File

@@ -2,11 +2,10 @@ name: Build Manager
on:
push:
branches: [ "main", "ci" ]
branches: [ "main" ]
paths:
- '.github/workflows/build-manager.yml'
- 'manager/**'
- 'kernel/**'
- 'userspace/ksud/**'
pull_request:
branches: [ "main" ]
@@ -15,33 +14,15 @@ on:
workflow_call:
jobs:
build-lkm:
uses: ./.github/workflows/build-lkm.yml
secrets: inherit
build-ksud:
needs: build-lkm
strategy:
matrix:
include:
- target: aarch64-linux-android
os: ubuntu-latest
- target: x86_64-linux-android
os: ubuntu-latest
- target: x86_64-pc-windows-gnu # windows pc
os: ubuntu-latest
- target: x86_64-apple-darwin # Intel mac
os: macos-latest
- target: aarch64-apple-darwin # M chip mac
os: macos-latest
- target: aarch64-unknown-linux-musl # arm64 Linux
os: ubuntu-latest
- target: x86_64-unknown-linux-musl # x86 Linux
os: ubuntu-latest
uses: ./.github/workflows/ksud.yml
with:
target: ${{ matrix.target }}
os: ${{ matrix.os }}
build-manager:
needs: build-ksud
@@ -69,35 +50,32 @@ jobs:
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 }}'
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}'
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}'
echo KEYSTORE_FILE='key.jks'
} >> gradle.properties
echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks
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@v4
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 21
distribution: "temurin"
java-version: "17"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Setup Android SDK
uses: android-actions/setup-android@v3
uses: gradle/gradle-build-action@v2
with:
gradle-home-cache-cleanup: true
- name: Download arm64 ksud
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
with:
name: ksud-aarch64-linux-android
path: .
- name: Download x86_64 ksud
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
with:
name: ksud-x86_64-linux-android
path: .
@@ -111,33 +89,23 @@ jobs:
- name: Build with Gradle
run: |
{
echo 'org.gradle.parallel=true'
echo 'org.gradle.vfs.watch=true'
echo 'org.gradle.jvmargs=-Xmx2048m'
echo 'android.native.buildOutput=verbose'
} >> gradle.properties
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@v4
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
uses: actions/upload-artifact@v3
with:
name: manager
path: manager/app/build/outputs/apk/release/*.apk
- name: Upload mappings
uses: actions/upload-artifact@v4
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
with:
name: "mappings"
path: "manager/app/build/outputs/mapping/release/"
- name: Bot session cache
if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true'
id: bot_session_cache
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: scripts/ksubot.session
key: ${{ runner.os }}-bot-session
@@ -156,6 +124,6 @@ jobs:
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
pip3 install telethon==1.31.1
python3 $GITHUB_WORKSPACE/scripts/ksubot.py $APK
fi

View File

@@ -26,11 +26,39 @@ jobs:
else
echo "UPLOAD=false" >> $GITHUB_OUTPUT
fi
- uses: nttld/setup-ndk@v1
with:
ndk-version: r25c
- name: Build su
working-directory: ./userspace/su
run: $ANDROID_NDK/ndk-build
run: ndk-build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4
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

View File

@@ -22,16 +22,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: rustup update stable
# 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: |
RUSTFLAGS="" cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
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
cross clippy --manifest-path userspace/ksud/Cargo.toml --target x86_64-linux-android --release

View File

@@ -35,13 +35,13 @@ jobs:
with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: latest
node-version: 18
cache: yarn # or pnpm / yarn
cache-dependency-path: website/yarn.lock
- name: Setup Pages
uses: actions/configure-pages@v5
uses: actions/configure-pages@v3
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build with VitePress
@@ -49,7 +49,7 @@ jobs:
yarn docs:build
touch docs/.vitepress/dist/.nojekyll
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v2
with:
path: website/docs/.vitepress/dist
@@ -64,4 +64,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v2

View File

@@ -29,7 +29,7 @@ on:
for example: 2021-11
default: 2022-05
patch_path:
required: false
required: true
type: string
description: >
Directory name of .github/patches/<patch_path>
@@ -49,10 +49,6 @@ on:
required: false
type: boolean
default: false
build_lkm:
required: false
type: boolean
default: false
secrets:
BOOT_SIGN_KEY:
required: false
@@ -128,22 +124,13 @@ jobs:
ln -sf $GITHUB_WORKSPACE/KernelSU/kernel $GKI_ROOT/common/drivers/kernelsu
echo "[+] Add KernelSU driver to Makefile"
DRIVER_MAKEFILE=$GKI_ROOT/common/drivers/Makefile
DRIVER_KCONFIG=$GKI_ROOT/common/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply Compilation Patches"
if [ ! -e build/build.sh ]; then
GLIBC_VERSION=$(ldd --version 2>/dev/null | head -n 1 | awk '{print $NF}')
echo "GLIBC_VERSION: $GLIBC_VERSION"
if [ "$(printf '%s\n' "2.38" "$GLIBC_VERSION" | sort -V | head -n1)" = "2.38" ]; then
echo "Patching resolve_btfids/Makefile"
cd $GKI_ROOT/common/ && sed -i '/\$(Q)\$(MAKE) -C \$(SUBCMD_SRC) OUTPUT=\$(abspath \$(dir \$@))\/ \$(abspath \$@)/s//$(Q)$(MAKE) -C $(SUBCMD_SRC) EXTRA_CFLAGS="$(CFLAGS)" OUTPUT=$(abspath $(dir $@))\/ $(abspath $@)/' tools/bpf/resolve_btfids/Makefile || echo "No patch needed."
fi
fi
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"
printf "\nccflags-y += -DCONFIG_KSU_DEBUG\n" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
echo "ccflags-y += -DCONFIG_KSU_DEBUG" >> $GITHUB_WORKSPACE/KernelSU/kernel/Makefile
fi
repo status
echo "[+] KernelSU setup done."
@@ -161,55 +148,22 @@ jobs:
- name: Setup ccache
if: inputs.use_cache == true
uses: hendrikmuhs/ccache-action@v1
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: Setup for LKM
if: ${{ inputs.build_lkm == true }}
working-directory: android-kernel
run: |
pip install ast-grep-cli
sudo apt-get install llvm-15 -y
ast-grep -U -p '$$$ check_exports($$$) {$$$}' -r '' common/scripts/mod/modpost.c
ast-grep -U -p 'check_exports($$$);' -r '' common/scripts/mod/modpost.c
sed -i '/config KSU/,/help/{s/default y/default m/}' common/drivers/kernelsu/Kconfig
echo "drivers/kernelsu/kernelsu.ko" >> common/android/gki_aarch64_modules
# bazel build, android14-5.15, android14-6.1 use bazel
if [ ! -e build/build.sh ]; then
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
if [ -e common/modules.bzl ]; then
sed -i 's/_COMMON_GKI_MODULES_LIST = \[/_COMMON_GKI_MODULES_LIST = \[ "drivers\/kernelsu\/kernelsu.ko",/g' common/modules.bzl
fi
else
TARGET_FILE="build/kernel/build.sh"
if [ ! -e "$TARGET_FILE" ]; then
TARGET_FILE="build/build.sh"
fi
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' $TARGET_FILE || echo "No unknown symbol in $TARGET_FILE"
sed -i 's/if ! diff -u "\${KERNEL_DIR}\/\${MODULES_ORDER}" "\${OUT_DIR}\/modules\.order"; then/if false; then/g' $TARGET_FILE
sed -i 's@${ROOT_DIR}/build/abi/compare_to_symbol_list@echo@g' $TARGET_FILE
sed -i 's/needs unknown symbol/Dont abort when unknown symbol/g' build/kernel/*.sh || echo "No unknown symbol scripts found"
fi
- name: Make working directory clean to avoid dirty
working-directory: android-kernel
run: |
# Fix bazel build error
if [ -f common/BUILD.bazel ]; then
[ -f android/abi_gki_protected_exports_aarch64 ] || sed -i '/^[[:space:]]*"protected_exports_list"[[:space:]]*:[[:space:]]*"android\/abi_gki_protected_exports_aarch64",$/d' common/BUILD.bazel
fi
rm common/android/abi_gki_protected_exports_* || echo "No protected exports!"
git config --global user.email "bot@kernelsu.org"
git config --global user.name "KernelSUBot"
cd common/ && git add -A && git commit -a -m "Add KernelSU"
repo status
- name: Build Kernel/LKM
- name: Build boot.img
working-directory: android-kernel
run: |
if [ ! -z ${{ vars.EXPECTED_SIZE }} ] && [ ! -z ${{ vars.EXPECTED_HASH }} ]; then
@@ -217,11 +171,11 @@ jobs:
export KSU_EXPECTED_HASH=${{ vars.EXPECTED_HASH }}
fi
if [ -e build/build.sh ]; then
LTO=thin BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh CC="/usr/bin/ccache clang"
else
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: |
@@ -230,34 +184,20 @@ jobs:
OUTDIR=android-kernel/dist
fi
mkdir output
if [ "${{ inputs.build_lkm}}" = "true" ]; then
llvm-strip-15 -d $OUTDIR/kernelsu.ko
mv $OUTDIR/kernelsu.ko ./output/${{ inputs.version }}_kernelsu.ko
else
cp $OUTDIR/Image ./output/
cp $OUTDIR/Image.lz4 ./output/
git clone https://github.com/Kernel-SU/AnyKernel3
rm -rf ./AnyKernel3/.git
cp $OUTDIR/Image ./AnyKernel3/
fi
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@v4
if: ${{ inputs.build_lkm == false }}
uses: actions/upload-artifact@v3
with:
name: Image-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
path: ./output/*
- name: Upload AnyKernel3
if: ${{ inputs.build_lkm == false }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: AnyKernel3-${{ inputs.version_name }}_${{ inputs.os_patch_level }}
path: ./AnyKernel3/*
- name: Upload LKM
uses: actions/upload-artifact@v4
if: ${{ inputs.build_lkm == true }}
with:
name: ${{ inputs.version }}-lkm
path: ./output/*_kernelsu.ko

View File

@@ -5,53 +5,32 @@ on:
target:
required: true
type: string
os:
required: false
type: string
default: ubuntu-latest
pack_lkm:
required: false
type: boolean
default: true
use_cache:
required: false
type: boolean
default: true
jobs:
build:
runs-on: ${{ inputs.os }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Prepare LKM fies
if: ${{ inputs.pack_lkm }}
run: |
cp android*-lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/
- name: Setup rustup
run: |
rustup update stable
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
# 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: |
RUSTFLAGS="" cargo install cross --git https://github.com/cross-rs/cross --rev 66845c1
run: cargo install cross
- name: Build ksud
run: CROSS_NO_WARNINGS=0 cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml
run: cross build --target ${{ inputs.target }} --release --manifest-path ./userspace/ksud/Cargo.toml
- name: Upload ksud artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: ksud-${{ inputs.target }}
path: userspace/ksud/target/**/release/ksud*
path: userspace/ksud/target/**/release/ksud

View File

@@ -18,9 +18,6 @@ jobs:
build-a14-kernel:
uses: ./.github/workflows/build-kernel-a14.yml
secrets: inherit
build-a15-kernel:
uses: ./.github/workflows/build-kernel-a15.yml
secrets: inherit
build-wsa-kernel:
uses: ./.github/workflows/build-kernel-wsa.yml
secrets: inherit
@@ -38,21 +35,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Rename ksud
run: |
mkdir -p ksud
for dir in ./ksud-*; do
if [ -d "$dir" ]; then
echo "----- Rename $dir -----"
ksud_platform_name=$(basename "$dir")
find "$dir" -type f -name "ksud" -path "*/release/*" | while read -r ksud_file; do
if [ -f "$ksud_file" ]; then
mv "$ksud_file" "ksud/$ksud_platform_name"
fi
done
fi
done
uses: actions/download-artifact@v3
- name: Zip AnyKernel3
run: |
for dir in AnyKernel3-*; do
@@ -84,13 +67,11 @@ jobs:
run: ls -R
- name: release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
with:
files: |
manager/*.apk
android*-lkm/*_kernelsu.ko
AnyKernel3-*.zip
boot-images-*/Image-*/*.img.gz
kernel-WSA*.zip
kernel-ARCVM*.zip
ksud/ksud-*

View File

@@ -1,106 +0,0 @@
name: Build Kernel - WSA
on:
workflow_call:
inputs:
arch:
required: true
type: string
description: >
Build arch: x86_64 / arm64
version:
required: true
type: string
description: >
Build version
jobs:
build:
name: Build WSA-Kernel-${{ inputs.version }}-${{ inputs.arch }}
runs-on: ubuntu-22.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@v4
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/${{ inputs.version }}
path: WSA-Linux-Kernel
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: WSA-Kernel-${{ inputs.version }}-${{ inputs.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
DRIVER_KCONFIG=$KERNEL_ROOT/drivers/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo "[+] Apply KernelSU patches"
cd $KERNEL_ROOT && git apply $GITHUB_WORKSPACE/KernelSU/.github/patches/5.15/*.patch || echo "[-] No patch found"
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[${{ inputs.arch }}]} .config
make olddefconfig
declare -A FILE_NAME=(["x86_64"]="bzImage" ["arm64"]="Image")
make -j`nproc` LLVM=1 ARCH=${{ inputs.arch }} $(if [ "${{ inputs.arch }}" == "arm64" ]; then echo CROSS_COMPILE=aarch64-linux-gnu; fi) ${FILE_NAME[${{ inputs.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[${{ inputs.arch }}]}/boot/${FILE_NAME[${{ inputs.arch }}]}" >> $GITHUB_ENV
- name: Upload kernel-${{ inputs.arch }}-${{ inputs.version }}
uses: actions/upload-artifact@v4
with:
name: kernel-WSA-${{ inputs.arch }}-${{ inputs.version }}
path: "${{ env.file_path }}"

View File

@@ -1,36 +1,29 @@
**English** | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
**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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
A kernel-based root solution for Android devices.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
A Kernel-based root solution for Android devices.
## Features
1. Kernel-based `su` and root access management.
2. Module system based on [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
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
## Compatibility State
KernelSU officially supports Android GKI 2.0 devices (kernel 5.10+). Older kernels (4.14+) are also supported, but the kernel will need to be built manually.
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 the `arm64-v8a` and `x86_64` architectures are supported.
Currently, only `arm64-v8a` and `x86_64` are supported.
## Usage
- [Installation](https://kernelsu.org/guide/installation.html)
- [How to build](https://kernelsu.org/guide/how-to-build.html)
- [Official website](https://kernelsu.org/)
- [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
@@ -40,18 +33,14 @@ To help translate KernelSU or improve existing translations, please use [Weblate
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Security
For information on reporting security vulnerabilities in KernelSU, see [SECURITY.md](/SECURITY.md).
## License
- Files under the `kernel` directory are [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- All other parts except the `kernel` directory are [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- 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.
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): the KernelSU idea.
- [Magisk](https://github.com/topjohnwu/Magisk): the powerful root tool.
- [genuine](https://github.com/brevent/genuine/): apk v2 signature validation.
- [Diamorphine](https://github.com/m0nad/Diamorphine): some rootkit skills.

View File

@@ -1,22 +1,14 @@
[English](README.md) | [Español](README_ES.md) | **简体中文** | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
一个 Android 上基于内核的 root 方案。
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 特性
- 基于内核的 `su` 和权限管理。
- 基于 [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 的模块系统。
- [App Profile](https://kernelsu.org/zh_CN/guide/app-profile.html): 把 Root 权限关进笼子里。
- 基于内核的 su 和权限管理。
- 基于 overlayfs 的模块系统。
- [App Profile](https://kernelsu.org/guide/app-profile.html): 把 Root 权限关进笼子里。
## 兼容状态
@@ -24,30 +16,25 @@ KernelSU 官方支持 GKI 2.0 的设备内核版本5.10以上);旧内核
WSA, ChromeOS 和运行在容器上的 Android 也可以与 KernelSU 一起工作。
目前支持架构 : `arm64-v8a``x86_64`
目前支持架构 : `arm64-v8a``x86_64`
## 使用方法
- [安装教程](https://kernelsu.org/zh_CN/guide/installation.html)
- [如何构建?](https://kernelsu.org/zh_CN/guide/how-to-build.html)
- [官方网站](https://kernelsu.org/zh_CN/)
## 参与翻译
要将 KernelSU 翻译成您的语言,或完善现有的翻译,请使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。现已不再接受有关管理器翻译的PR因为这会与Weblate冲突。
要将 KernelSU 翻译成您的语言,或完善现有的翻译,请使用 [Weblate](https://hosted.weblate.org/engage/kernelsu/)。
## 讨论
- Telegram: [@KernelSU](https://t.me/KernelSU)
## 安全性
有关报告 KernelSU 安全漏洞的信息,请参阅 [SECURITY.md](/SECURITY.md)。
## 许可证
- 目录 `kernel` 下所有文件为 [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
-`kernel` 目录的其他部分均为 [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
- 目录 `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)
## 鸣谢

View File

@@ -1,56 +1,47 @@
[English](README.md) | **Español** | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[ 🇬🇧 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)
# KernelSU
<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>
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
## 🚀 Características
Una solución root basada en el kernel para dispositivos Android.
**1.** Binario `su` basado en el kernel y gestión de acceso root.<br/>
**2.** Sistema de módulos basado en **OverlayFS**.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localización-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Seguir-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/Licencia-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Características
1. Binario `su` basado en el kernel y gestión de acceso root.
2. Sistema de módulos basado en [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
## Estado de compatibilidad
## ✅ 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.
Con esto, WSA, ChromeOS y Android basado en contenedores están todos compatibles.
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, solo se admiten las arquitecturas `arm64-v8a` y `x86_64`.
Actualmente se soportan las siguientes **ABIs**: `arm64-v8a`; `x86_64`.
## Uso
## 📖 Uso
- [¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
- [¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
- [Site oficial](https://kernelsu.org/)
[¿Cómo instalarlo?](https://kernelsu.org/guide/installation.html)
## Traducción
## 🔨 Compilación
Para ayudar a traducir KernelSU o mejorar las traducciones existentes, utilice [Weblate](https://hosted.weblate.org/engage/kernelsu/). Ya no se aceptan PR de la traducción de Manager porque entrará en conflicto con Weblate.
[¿Cómo compilarlo?](https://kernelsu.org/guide/how-to-build.html)
## Discusión
## 💬 Discusión
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Seguridad
## ⚖️ Licencia
Para obtener información sobre cómo informar vulnerabilidades de seguridad en KernelSU, consulte [SECURITY.md](/SECURITY.md).
- 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).
## Licencia
## 👥 Créditos
- Los archivos bajo el directorio `kernel` están licenciados bajo [GPL-2-only](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-or-later](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.
- [Magisk](https://github.com/topjohnwu/Magisk): la poderosa herramienta root.
- [genuine](https://github.com/brevent/genuine/): validación de firma apk v2.
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): la idea de **KernelSU**.
- [genuine](https://github.com/brevent/genuine/): la validación del **esquema de firmas APK v2**.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algunas habilidades de rootkit.
- [Magisk](https://github.com/topjohnwu/Magisk): la implementación de la **política de SELinux (SEPolicy)**.

View File

@@ -1,21 +1,13 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Solusi root berbasis Kernel untuk perangkat Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Fitur
1. Manajemen akses root dan `su` berbasis kernel.
2. Sistem modul berdasarkan [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
2. Sistem modul berdasarkan overlayfs.
3. [Profil Aplikasi](https://kernelsu.org/guide/app-profile.html): Kunci daya root di dalam sangkar.
## Status Kompatibilitas
@@ -28,9 +20,9 @@ Dan ABI yang didukung saat ini adalah: `arm64-v8a` dan `x86_64`
## Penggunaan
- [Petunjuk Instalasi](https://kernelsu.org/id_ID/guide/installation.html)
- [Bagaimana cara membuat?](https://kernelsu.org/id_ID/guide/how-to-build.html)
- [Situs Web Resmi](https://kernelsu.org/id_ID/)
- [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
@@ -42,8 +34,8 @@ Untuk menerjemahkan KernelSU ke dalam bahasa Anda atau menyempurnakan terjemahan
## Lisensi
- File di bawah direktori `kernel` adalah [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Semua bagian lain kecuali direktori `kernel` adalah [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- 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

View File

@@ -1,21 +1,19 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | **हिंदी** | [Italiano](README_IT.md)
# KernelSU
[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) | **हिंदी**
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Android उपकरणों के लिए कर्नेल-आधारित रूट समाधान।
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
<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](https://en.wikipedia.org/wiki/OverlayFS) पर आधारित मॉड्यूल प्रणाली।
2. Overlayfs पर आधारित मॉड्यूल प्रणाली।
3. [App Profile](https://kernelsu.org/guide/app-profile.html): Root शक्ति को पिंजरे में बंद कर दो।
## अनुकूलता अवस्था
@@ -42,8 +40,8 @@ KernelSU का अनुवाद करने या मौजूदा अन
## लाइसेंस
- `Kernel` निर्देशिका के अंतर्गत फ़ाइलें हैं [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `Kernel` निर्देशिका को छोड़कर अन्य सभी भाग हैं [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
- `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)
## आभार सूची

View File

@@ -1,58 +0,0 @@
[English](REAME.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | **Italiano**
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Una soluzione per il root basata sul kernel per i dispositivi Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Canale Telegraml](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![Licenza componenti kernel: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![Licenza elementi non kern](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Funzionalità
1. `su` e accesso root basato sul kernel.
2. Sistema di moduli per la modifica del sistema basato su [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [App profile](https://kernelsu.org/guide/app-profile.html): Limita i poteri dell'accesso root a permessi specifici.
## Compatibilità
KernelSU supporta ufficialmente i dispositivi Android GKI 2.0 (kernel 5.10 o superiore). I kernel precedenti (kernel 4.14+) sono anche compatibili, ma il kernel deve essere compilato manualmente.
Questo implica che WSA, ChromeOS e tutti le varianti di Android basate su container e virtualizzazione sono supportate.
Allo stato attuale solo le architetture a 64-bit ARM (arm64-v8a) e x86 (x86_64) sono supportate.
## Utilizzo
- [Istruzioni per l'installazione](https://kernelsu.org/guide/installation.html)
- [Come compilare manualmente?](https://kernelsu.org/guide/how-to-build.html)
- [Sito web ufficiale](https://kernelsu.org/)
## Traduzioni
Per aiutare a tradurre KernelSU o migliorare le traduzioni esistenti, si è pregati di utilizzare
To help translate KernelSU or improve existing translations, please use [Weblate](https://hosted.weblate.org/engage/kernelsu/). Le richieste di pull delle traduzioni del manager non saranno più accettate perché sarebbero in conflitto con Weblate.
## Discussione
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Securezza
Per informazioni riguardo la segnalazione di vulnerabilità di sicurezza per KernelSU, leggi [SECURITY.md](/SECURITY.md).
## Licenza
- I file nella cartella `kernel` sono forniti secondo la licenza [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Tutte le altre parti, ad eccezione della certella `kernel`, seguono la licenza [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
## Riconoscimenti e attribuzioni
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): l'idea alla base di KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): la potente utilità per il root.
- [genuine](https://github.com/brevent/genuine/): verifica della firma apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): alcune capacità di rootkit.

View File

@@ -1,23 +1,16 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | **日本語** | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Android におけるカーネルベースの root ソリューションです。
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 特徴
1. カーネルベースの `su` と権限管理
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) に基づくモジュールシステム
1. カーネルベースの `su` と権限管理
2. OverlayFS に基づくモジュールシステム
3. [アプリのプロファイル](https://kernelsu.org/guide/app-profile.html): root の権限をケージ内に閉じ込めます。
## 対応状況
KernelSU は GKI 2.0 デバイス(カーネルバージョン 5.10 以上を公式にサポートしています。古いカーネル4.14以上)とも互換性がありますが、自分でカーネルをビルドする必要があります。
@@ -30,7 +23,7 @@ WSA 、ChromeOS とコンテナ上で動作する Android でも KernelSU を統
- [インストール方法はこちら](https://kernelsu.org/ja_JP/guide/installation.html)
- [ビルド方法はこちら](https://kernelsu.org/guide/how-to-build.html)
- [公式サイト](https://kernelsu.org/ja_JP/)
- [公式サイト](https://kernelsu.org)
## 翻訳
@@ -42,12 +35,13 @@ KernelSU をあなたの言語に翻訳するか、既存の翻訳を改善す
## ライセンス
- `kernel` ディレクトリの下にあるすべてのファイル: [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
- `kernel` ディレクトリ以外のすべてのファイル: [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html)
- `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 のスキル
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU のアイデア元
- [Magisk](https://github.com/topjohnwu/Magisk):強力な root ツール
- [genuine](https://github.com/brevent/genuine/)apk v2 の署名検証
- [Diamorphine](https://github.com/m0nad/Diamorphine): rootkit のスキル

View File

@@ -1,57 +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)](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) | [Italiano](README_IT.md)
# KernelSU
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
안드로이드 기기에서 사용되는 커널 기반 루팅 솔루션입니다.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 기능들
1. 커널 기반 `su` 및 루트 액세스 관리.
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS) 기반 모듈 시스템.
3. [App Profile](https://kernelsu.org/guide/app-profile.html): 루트 권한을 케이지에 가둡니다.
## 호환 상태
KernelSU는 공식적으로 안드로이드 GKI 2.0 디바이스(커널 5.10 이상)를 지원합니다. 오래된 커널(4.14 이상)도 사용할 수 있지만, 커널을 수동으로 빌드해야 합니다.
KernelSU는 WSA, ChromeOS, 컨테이너 기반 안드로이드 모두를 지원합니다.
현재는 `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/)를 이용해 주세요. 매니저의 번역은 Weblate와 충돌할 수 있으므로 더 이상 허용되지 않습니다.
## 토론
- 텔레그램: [@KernelSU](https://t.me/KernelSU)
## 보안
KernelSU의 보안 취약점 보고에 대한 자세한 내용은 [SECURITY.md](/SECURITY.md)를 참조하세요.
## 저작권
- `kernel` 디렉터리 아래의 파일은 [GPL-2.0 전용](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)입니다.
- `kernel` 디렉토리를 제외한 다른 모든 부분은 [GPL-3.0-이상](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): 강력한 루팅 도구.
- [genuine](https://github.com/brevent/genuine/): apk v2 서명 유효성 검사.
- [Diamorphine](https://github.com/m0nad/Diamorphine): 일부 rootkit 스킬.

View File

@@ -1,21 +1,13 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | **Polski** | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Rozwiązanie root oparte na jądrze dla urządzeń z systemem Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Cechy
1. Oparte na jądrze `su` i zarządzanie dostępem roota.
2. System modułów oparty na [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
2. System modułów oparty na overlayfs.
## Kompatybilność
@@ -27,29 +19,24 @@ Aktualnie obsługiwane ABI to : `arm64-v8a` i `x86_64`.
## Użycie
- [Instalacja](https://kernelsu.org/guide/installation.html)
- [Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
[Instalacja](https://kernelsu.org/guide/installation.html)
## Tłumaczenie
## Kompilacja
Aby pomóc w tłumaczeniu KernelSU lub ulepszyć istniejące tłumaczenia, użyj [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR tłumaczenia Managera nie jest już akceptowany, ponieważ będzie kolidował z Weblate.
[Jak skompilować?](https://kernelsu.org/guide/how-to-build.html)
## Dyskusja
- Telegram: [@KernelSU](https://t.me/KernelSU)
## Bezpieczeństwo
Informacje na temat zgłaszania luk w zabezpieczeniach w KernelSU można znaleźć w pliku [SECURITY.md](/SECURITY.md).
## Licencja
- Pliki w katalogu `kernel` są na licencji [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Wszystkie inne części poza katalogiem `kernel` są na licencji [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- 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.
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.
- [genuine](https://github.com/brevent/genuine/): walidacja podpisu apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): cenna znajomość rootkitów.
- [Magisk](https://github.com/topjohnwu/Magisk): implementacja sepolicy.

View File

@@ -1,57 +1,46 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Uma solução root baseada em kernel para dispositivos Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localização-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Seguir-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/Licença-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Características
1. `su` e gerenciamento de acesso root baseado em kernel.
2. Sistema de módulos baseado em [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
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
## 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 será necessário construir o kernel manualmente.
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 as arquiteturas `arm64-v8a` e `x86_64` são compatíveis.
Atualmente, apenas `arm64-v8a` e `x86_64` são suportados.
## Uso
- [Instalação](https://kernelsu.org/pt_BR/guide/installation.html)
- [Como compilar](https://kernelsu.org/pt_BR/guide/how-to-build.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, use o [Weblate](https://hosted.weblate.org/engage/kernelsu/). PR para a tradução do Manager não são mais aceitas, pois podem entrar em conflito com o Weblate.
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)
## Segurança
Para obter informações sobre como relatar vulnerabilidades de segurança do KernelSU, consulte [SECURITY.md](/SECURITY.md).
## Licença
- Os arquivos no diretório `kernel` são [GPL-2.0-only](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.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- 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.
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/): a ideia do KernelSU.
- [Magisk](https://github.com/topjohnwu/Magisk): a poderosa ferramenta root.
- [genuine](https://github.com/brevent/genuine/): validação de assinatura apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): algumas habilidades de rootkit.

View File

@@ -1,22 +1,13 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Решение на основе ядра root для Android-устройств.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## Особенности
1. Управление `su` и root-доступом на основе ядра.
2. Система модулей на основе [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
3. [Профиль приложений](https://kernelsu.org/ru_RU/guide/app-profile.html): Запри корневую силу в клетке.
2. Система модулей на основе overlayfs.
## Совместимость
@@ -28,9 +19,11 @@ WSA и Android на основе контейнеров также должны
## Использование
- [Установка](https://kernelsu.org/ru_RU/guide/installation.html)
- [Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
- [официальный сайт](https://kernelsu.org/ru_RU/)
[Установка](https://kernelsu.org/ru_RU/guide/installation.html)
## Сборка
[Как собрать?](https://kernelsu.org/ru_RU/guide/how-to-build.html)
## Обсуждение
@@ -38,12 +31,12 @@ WSA и Android на основе контейнеров также должны
## Лицензия
- Файлы в директории `kernel` [GPL-2-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- Все остальные части, кроме директории `kernel` [GPL-3-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- Файлы в директории `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): реализация sepolicy.
- [genuine](https://github.com/brevent/genuine/): проверка подписи apk v2.
- [Diamorphine](https://github.com/m0nad/Diamorphine): некоторые навыки руткита.
- [Magisk](https://github.com/topjohnwu/Magisk): реализация sepolicy.

View File

@@ -1,57 +1,45 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
Android cihazlar için kernel tabanlı root çözümü.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
Android cihazlar için kernel tabanlı bir root çözümü.
## Özellikler
1. Kernel-tabanlı `su` ve root erişimi yönetimi.
2. [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS)'ye dayalı modül sistemi.
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 derlemeniz gerekir.
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.
Bununla birlikte; WSA, ChromeOS ve konteyner tabanlı Android'in tamamı desteklenmektedir.
WSA ve konteyner tabanlı Android'in de, KernelSU ile entegre olarak da çalışması gerekmektedir.
Şimdilik sadece `arm64-v8a` ve `x86_64` desteklenmektedir.
Ve desteklenen mevcut ABI'ler : `arm64-v8a` ve `x86_64`
## Kullanım
- [Yükleme yönergeleri](https://kernelsu.org/guide/installation.html)
- [Nasıl derlenir?](https://kernelsu.org/guide/how-to-build.html)
- [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'nun başka dillere çevrilmesine veya mevcut çevirilerin iyileştirilmesine yardımcı olmak için lütfen [Weblate](https://hosted.weblate.org/engage/kernelsu/) kullanın. Yönetici uygulamasının PR ile çevirisi, Weblate ile çakışacağından artık kabul edilmeyecektir.
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)
## Güvenlik
KernelSU'daki güvenlik açıklarını bildirme hakkında bilgi için, bkz [SECURITY.md](/SECURITY.md).
## Lisans
- `kernel` klasöründeki dosyalar [GPL-2-only](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-veya-sonraki](https://www.gnu.org/licenses/gpl-3.0.html) lisansı altındadır.
- `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ğrulaması.
- [genuine](https://github.com/brevent/genuine/): apk v2 imza doğrulama.
- [Diamorphine](https://github.com/m0nad/Diamorphine): bazı rootkit becerileri.

View File

@@ -1,57 +1,42 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | **繁體中文** | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="標誌">
一個基於核心的 Android 裝置 Root 解決方案
一套基於 Android 裝置核心的 Root 解決方案。
## 功能
[![最新版本](https://img.shields.io/github/v/release/tiann/KernelSU?label=%e7%99%bc%e8%a1%8c%e7%89%88%e6%9c%ac&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/%e6%9c%ac%e5%9c%9f%e5%8c%96%e7%bf%bb%e8%ad%af-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![頻道](https://img.shields.io/badge/%e8%bf%bd%e8%b9%a4-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![授權條款《GPL v2》](https://img.shields.io/badge/%e6%8e%88%e6%ac%8a%e6%a2%9d%e6%ac%be-%E3%80%8AGPL%20v2%E3%80%8B-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub 授權條款](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
- 基於核心的 Su 和 Root 存取權管理。
- 基於 Overlayfs 的模組系統。
## 特色功能
## 相容性狀態
1. 以核心內 `su` 管理 Root 存取
2. 以 [OverlayFS](https://zh.wikipedia.org/zh-tw/OverlayFS) 運作模組系統。
3. [App Profile](https://kernelsu.org/zh_TW/guide/app-profile.html):使 Root 掌握的生殺大權受制於此。
KernelSU 官方支援 Android GKI 2.0 的裝置 (核心版本 5.10+);舊版核心同樣相容 (最低 4.14+),但需要自行編譯核心
## 相容事態
WSA 和執行在容器中的 Android 也可以與 KernelSU 一同運作。
理論上採以 Android GKI 2.0 的裝置(核心版本 5.10+),皆受 KernelSU 支援採以老舊核心版本4.14+)的裝置在手動建置核心後,亦受支援。
目前支援架構:`arm64-v8a``x86_64`
另可在 WSA、ChromeOS 一類的容器式 Android 中運作。
## 使用方法
目前僅適用 `arm64-v8a` 以及 `x86_64` 架構。
[安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
## 使用手冊
## 建置
- [安裝教學](https://kernelsu.org/zh_TW/guide/installation.html)
- [如何建置 KernelSU](https://kernelsu.org/zh_TW/guide/how-to-build.html)
- [官方網站](https://kernelsu.org/zh_TW/)
[如何建置?](https://kernelsu.org/zh_TW/guide/how-to-build.html)
## 多語翻譯
欲要協助 KernelSU 邁向多語化,抑或改進翻譯品質,請前往 [Weblate](https://hosted.weblate.org/engage/kernelsu/) 進行翻譯。為避免與 Weblate 上的翻譯發生衝突,現已不再受理翻譯相關的管理工具 PR。
## 綜合討論
### 討論
- Telegram[@KernelSU](https://t.me/KernelSU)
## 安全政策
## 授權
欲要得知、回報 KernelSU 的安全性漏洞,請參閱 [SECURITY.md](/SECURITY.md)
- 目錄 `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` 資料夾的檔案以[《GPL-2.0-only》](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)規範
- 非位於 `kernel` 資料夾的其他檔案以[《GPL-3.0-or-later》](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 技巧。
- [kernel-assisted-superuser](https://git.zx2c4.com/kernel-assisted-superuser/about/)KernelSU 的靈感
- [genuine](https://github.com/brevent/genuine/)apk v2 簽章驗證
- [Diamorphine](https://github.com/m0nad/Diamorphine):一些 rootkit 技巧。
- [Magisk](https://github.com/topjohnwu/Magisk)sepolicy 實作。

View File

@@ -1,21 +1,13 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
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.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## 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](https://en.wikipedia.org/wiki/OverlayFS).
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
@@ -24,7 +16,7 @@ KernelSU chính thức hỗ trợ các thiết bị Android với kernel GKI 2.0
WSA, ChromeOS và Android dựa trên container(container-based) cũng được hỗ trợ bởi KernelSU.
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a``x86_64`.
Hiên tại Giao diện nhị phân của ứng dụng (ABI) được hỗ trợ bao gồm `arm64-v8a``x86_64`
## Sử dụng
@@ -42,12 +34,12 @@ Nếu bạn muốn hỗ trợ dịch KernelSU sang một ngôn ngữ khác hoặ
## Giấy phép
- Tất cả các file trong thư mục `kernel` dùng giấy phép [GPL-2-only](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-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- 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.
- [Diamorphine](https://github.com/m0nad/Diamorphine): các phương pháp ẩn của rootkit .

View File

@@ -1,21 +1,13 @@
[English](README.md) | [Español](README_ES.md) | [简体中文](README_CN.md) | [繁體中文](README_TW.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Polski](README_PL.md) | [Português (Brasil)](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) | [Italiano](README_IT.md)
[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
<img src="https://kernelsu.org/logo.png" style="width: 96px;" alt="logo">
פתרון לניהול root מבוסס על Kernel עבור מכשירי Android.
[![Latest release](https://img.shields.io/github/v/release/tiann/KernelSU?label=Release&logo=github)](https://github.com/tiann/KernelSU/releases/latest)
[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/kernelsu)
[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/KernelSU)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg?logo=gnu)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![GitHub License](https://img.shields.io/github/license/tiann/KernelSU?logo=gnu)](/LICENSE)
## תכונות
1. ניהול root ו־`su` מבוססים על Kernel.
2. מערכת מודולים מבוססת [OverlayFS](https://en.wikipedia.org/wiki/OverlayFS).
2. מערכת מודולים מבוססת overlayfs.
3. [פרופיל אפליקציה](https://kernelsu.org/guide/app-profile.html): נעילת גישת root בכלוב.
## מצב תאימות
@@ -42,12 +34,12 @@ KernelSU תומך במכשירי Android GKI 2.0 (kernel 5.10+) באופן רש
## רשיון
- קבצים תחת הספרייה `kernel` מוגנים על פי [GPL-2.0-only](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html).
- כל החלקים האחרים, למעט הספרייה `kernel`, מוגנים על פי [GPL-3.0-or-later](https://www.gnu.org/licenses/gpl-3.0.html).
- קבצים תחת הספרייה `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): כמה יכולות רוט.
- [Diamorphine](https://github.com/m0nad/Diamorphine): כמה יכולות רוט.

View File

@@ -1,121 +0,0 @@
# Library for KernelSU's module WebUI
## Install
```sh
yarn add kernelsu
```
## API
### exec
Spawns a **root** shell and runs a command within that shell, returning a Promise that resolves with the `stdout` and `stderr` outputs upon completion.
- `command` `<string>` The command to run, with space-separated arguments.
- `options` `<Object>`
- `cwd` - Current working directory of the child process.
- `env` - Environment key-value pairs.
```javascript
import { exec } from 'kernelsu';
const { errno, stdout, stderr } = await exec('ls -l', { cwd: '/tmp' });
if (errno === 0) {
// success
console.log(stdout);
}
```
### spawn
Spawns a new process using the given `command` in **root** shell, with command-line arguments in `args`. If omitted, `args` defaults to an empty array.
Returns a `ChildProcess` instance. Instances of `ChildProcess` represent spawned child processes.
- `command` `<string>` The command to run.
- `args` `<string[]>` List of string arguments.
- `options` `<Object>`:
- `cwd` `<string>` - Current working directory of the child process.
- `env` `<Object>` - Environment key-value pairs.
Example of running `ls -lh /data`, capturing `stdout`, `stderr`, and the exit code:
```javascript
import { spawn } from 'kernelsu';
const ls = spawn('ls', ['-lh', '/data']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('exit', (code) => {
console.log(`child process exited with code ${code}`);
});
```
#### ChildProcess
##### Event 'exit'
- `code` `<number>` The exit code if the child process exited on its own.
The `'exit'` event is emitted when the child process ends. If the process exits, `code` contains the final exit code; otherwise, it is null.
##### Event 'error'
- `err` `<Error>` The error.
The `'error'` event is emitted whenever:
- The process could not be spawned.
- The process could not be killed.
##### `stdout`
A `Readable Stream` that represents the child process's `stdout`.
```javascript
const subprocess = spawn('ls');
subprocess.stdout.on('data', (data) => {
console.log(`Received chunk ${data}`);
});
```
#### `stderr`
A `Readable Stream` that represents the child process's `stderr`.
### fullScreen
Request the WebView enter/exit full screen.
```javascript
import { fullScreen } from 'kernelsu';
fullScreen(true);
```
### toast
Show a toast message.
```javascript
import { toast } from 'kernelsu';
toast('Hello, world!');
```
### moduleInfo
Get module info.
```javascript
import { moduleInfo } from 'kernelsu';
// print moduleId in console
console.log(moduleInfo());
```

48
js/index.d.ts vendored
View File

@@ -1,48 +0,0 @@
interface ExecOptions {
cwd?: string,
env?: { [key: string]: string }
}
interface ExecResults {
errno: number,
stdout: string,
stderr: string
}
declare function exec(command: string): Promise<ExecResults>;
declare function exec(command: string, options: ExecOptions): Promise<ExecResults>;
interface SpawnOptions {
cwd?: string,
env?: { [key: string]: string }
}
interface Stdio {
on(event: 'data', callback: (data: string) => void)
}
interface ChildProcess {
stdout: Stdio,
stderr: Stdio,
on(event: 'exit', callback: (code: number) => void)
on(event: 'error', callback: (err: any) => void)
}
declare function spawn(command: string): ChildProcess;
declare function spawn(command: string, args: string[]): ChildProcess;
declare function spawn(command: string, options: SpawnOptions): ChildProcess;
declare function spawn(command: string, args: string[], options: SpawnOptions): ChildProcess;
declare function fullScreen(isFullScreen: boolean);
declare function toast(message: string);
declare function moduleInfo(): string;
export {
exec,
spawn,
fullScreen,
toast,
moduleInfo
}

View File

@@ -1,119 +0,0 @@
let callbackCounter = 0;
function getUniqueCallbackName(prefix) {
return `${prefix}_callback_${Date.now()}_${callbackCounter++}`;
}
export function exec(command, options) {
if (typeof options === "undefined") {
options = {};
}
return new Promise((resolve, reject) => {
// Generate a unique callback function name
const callbackFuncName = getUniqueCallbackName("exec");
// Define the success callback function
window[callbackFuncName] = (errno, stdout, stderr) => {
resolve({ errno, stdout, stderr });
cleanup(callbackFuncName);
};
function cleanup(successName) {
delete window[successName];
}
try {
ksu.exec(command, JSON.stringify(options), callbackFuncName);
} catch (error) {
reject(error);
cleanup(callbackFuncName);
}
});
}
function Stdio() {
this.listeners = {};
}
Stdio.prototype.on = function (event, listener) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(listener);
};
Stdio.prototype.emit = function (event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach((listener) => listener(...args));
}
};
function ChildProcess() {
this.listeners = {};
this.stdin = new Stdio();
this.stdout = new Stdio();
this.stderr = new Stdio();
}
ChildProcess.prototype.on = function (event, listener) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(listener);
};
ChildProcess.prototype.emit = function (event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach((listener) => listener(...args));
}
};
export function spawn(command, args, options) {
if (typeof args === "undefined") {
args = [];
} else if (!(args instanceof Array)) {
// allow for (command, options) signature
options = args;
}
if (typeof options === "undefined") {
options = {};
}
const child = new ChildProcess();
const childCallbackName = getUniqueCallbackName("spawn");
window[childCallbackName] = child;
function cleanup(name) {
delete window[name];
}
child.on("exit", code => {
cleanup(childCallbackName);
});
try {
ksu.spawn(
command,
JSON.stringify(args),
JSON.stringify(options),
childCallbackName
);
} catch (error) {
child.emit("error", error);
cleanup(childCallbackName);
}
return child;
}
export function fullScreen(isFullScreen) {
ksu.fullScreen(isFullScreen);
}
export function toast(message) {
ksu.toast(message);
}
export function moduleInfo() {
return ksu.moduleInfo();
}

View File

@@ -1,26 +0,0 @@
{
"name": "kernelsu",
"version": "1.0.7",
"description": "Library for KernelSU's module WebUI",
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"test": "npm run test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tiann/KernelSU.git"
},
"keywords": [
"su",
"kernelsu",
"module",
"webui"
],
"author": "weishu",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/tiann/KernelSU/issues"
},
"homepage": "https://github.com/tiann/KernelSU#readme"
}

View File

@@ -1,14 +0,0 @@
alias bk := build_ksud
alias bm := build_manager
build_ksud:
cross build --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml
build_manager: build_ksud
cp userspace/ksud/target/aarch64-linux-android/release/ksud manager/app/src/main/jniLibs/arm64-v8a/libksud.so
cd manager && ./gradlew aDebug
clippy:
cargo fmt --manifest-path ./userspace/ksud/Cargo.toml
cross clippy --target x86_64-pc-windows-gnu --release --manifest-path ./userspace/ksud/Cargo.toml
cross clippy --target aarch64-linux-android --release --manifest-path ./userspace/ksud/Cargo.toml

View File

@@ -5,15 +5,13 @@ config KSU
depends on OVERLAY_FS
default y
help
Enable kernel-level root privileges on Android System.
To compile as a module, choose M here: the
module will be called kernelsu.
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.
Enable KernelSU debug mode
endmenu

View File

@@ -1,24 +1,20 @@
kernelsu-objs := ksu.o
kernelsu-objs += allowlist.o
kernelsu-objs += apk_sign.o
kernelsu-objs += sucompat.o
kernelsu-objs += throne_tracker.o
kernelsu-objs += core_hook.o
kernelsu-objs += ksud.o
kernelsu-objs += embed_ksud.o
kernelsu-objs += kernel_compat.o
kernelsu-objs += selinux/selinux.o
kernelsu-objs += selinux/sepolicy.o
kernelsu-objs += selinux/rules.o
ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h
obj-$(CONFIG_KSU) += kernelsu.o
obj-y += ksu.o
obj-y += allowlist.o
kernelsu-objs := apk_sign.o
obj-y += kernelsu.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)
$(shell cd $(srctree)/$(src); /usr/bin/env PATH="$$PATH":/usr/bin:/usr/local/bin [ -f ../.git/shallow ] && git fetch --unshallow)
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))
@@ -47,8 +43,5 @@ $(info -- KernelSU Manager signature hash: $(KSU_EXPECTED_HASH))
ccflags-y += -DEXPECTED_SIZE=$(KSU_EXPECTED_SIZE)
ccflags-y += -DEXPECTED_HASH=\"$(KSU_EXPECTED_HASH)\"
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
# Keep a new line here!! Because someone may append config
ccflags-y += -Wno-declaration-after-statement

View File

@@ -1,21 +1,21 @@
#include <linux/capability.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>
#include <linux/compiler_types.h>
#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 "klog.h" // IWYU pragma: keep
#include "selinux/selinux.h"
#include "kernel_compat.h"
#include "allowlist.h"
#include "manager.h"
#define FILE_MAGIC 0x7f4b5355 // ' KSU', u32
#define FILE_FORMAT_VERSION 3 // u32
@@ -63,14 +63,12 @@ static void remove_uid_from_arr(uid_t uid)
static void init_default_profiles()
{
kernel_cap_t full_cap = CAP_FULL_SET;
default_root_profile.uid = 0;
default_root_profile.gid = 0;
default_root_profile.groups_count = 1;
default_root_profile.groups[0] = 0;
memcpy(&default_root_profile.capabilities.effective, &full_cap,
sizeof(default_root_profile.capabilities.effective));
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);
@@ -111,7 +109,6 @@ void ksu_show_allow_list(void)
static void ksu_grant_root_to_shell()
{
struct app_profile profile = {
.version = KSU_APP_PROFILE_VER,
.allow_su = true,
.current_uid = 2000,
};
@@ -154,6 +151,11 @@ static bool profile_valid(struct app_profile *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;
@@ -272,11 +274,6 @@ bool __ksu_is_allow_uid(uid_t uid)
return false;
}
if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) {
// manager is always allowed!
return true;
}
if (likely(uid <= BITMAP_UID_MAX)) {
return !!(allow_list_bitmap[uid / BITS_PER_BYTE] & (1 << (uid % BITS_PER_BYTE)));
} else {
@@ -292,10 +289,6 @@ bool __ksu_is_allow_uid(uid_t uid)
bool ksu_uid_should_umount(uid_t uid)
{
struct app_profile profile = { .current_uid = uid };
if (likely(ksu_is_manager_uid_valid()) && unlikely(ksu_get_manager_uid() == uid)) {
// we should not umount on manager!
return false;
}
bool found = ksu_get_app_profile(&profile);
if (!found) {
// no app profile found, it must be non root app
@@ -358,7 +351,7 @@ void do_save_allow_list(struct work_struct *work)
loff_t off = 0;
struct file *fp =
ksu_filp_open_compat(KERNEL_SU_ALLOWLIST, O_WRONLY | O_CREAT | O_TRUNC, 0644);
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;
@@ -465,9 +458,7 @@ void ksu_prune_allowlist(bool (*is_uid_valid)(uid_t, char *, void *), void *data
modified = true;
pr_info("prune uid: %d, package: %s\n", uid, package);
list_del(&np->list);
if (likely(uid <= BITMAP_UID_MAX)) {
allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE));
}
allow_list_bitmap[uid / BITS_PER_BYTE] &= ~(1 << (uid % BITS_PER_BYTE));
remove_uid_from_arr(uid);
smp_mb();
kfree(np);

View File

@@ -1,7 +1,7 @@
#ifndef __KSU_H_ALLOWLIST
#define __KSU_H_ALLOWLIST
#include <linux/types.h>
#include "linux/types.h"
#include "ksu.h"
void ksu_allowlist_init(void);

View File

@@ -1,23 +1,21 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/version.h>
#ifdef CONFIG_KSU_DEBUG
#include <linux/moduleparam.h>
#endif
#include <crypto/hash.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
#include <crypto/sha2.h>
#else
#include <crypto/sha.h>
#endif
#include "linux/err.h"
#include "linux/fs.h"
#include "linux/gfp.h"
#include "linux/kernel.h"
#include "linux/moduleparam.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"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
#include "crypto/sha2.h"
#else
#include "crypto/sha.h"
#endif
struct sdesc {
struct shash_desc shash;
@@ -190,7 +188,7 @@ static __always_inline bool check_v2_signature(char *path,
struct file *fp = ksu_filp_open_compat(path, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("open %s error.\n", path);
return false;
return PTR_ERR(fp);
}
// disable inotify for this file
@@ -231,8 +229,7 @@ static __always_inline bool check_v2_signature(char *path,
goto clean;
}
int loop_count = 0;
while (loop_count++ < 10) {
for (;;) {
uint32_t id;
uint32_t offset;
ksu_kernel_read_compat(fp, &size8, 0x8,
@@ -242,6 +239,7 @@ static __always_inline bool check_v2_signature(char *path,
}
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 =
@@ -253,19 +251,13 @@ static __always_inline bool check_v2_signature(char *path,
} else if (id == 0x1b93ad61u) {
// http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java#74
v3_1_signing_exist = true;
} else {
#ifdef CONFIG_KSU_DEBUG
pr_info("Unknown id: 0x%08x\n", id);
#endif
}
pos += (size8 - offset);
}
if (v2_signing_blocks != 1) {
#ifdef CONFIG_KSU_DEBUG
pr_err("Unexpected v2 signature count: %d\n",
v2_signing_blocks);
#endif
v2_signing_valid = false;
}
@@ -281,9 +273,7 @@ clean:
filp_close(fp, 0);
if (v3_signing_exist || v3_1_signing_exist) {
#ifdef CONFIG_KSU_DEBUG
pr_err("Unexpected v3 signature scheme found!\n");
#endif
return false;
}
@@ -292,15 +282,25 @@ clean:
#ifdef CONFIG_KSU_DEBUG
int ksu_debug_manager_uid = -1;
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_set_manager_uid(ksu_debug_manager_uid);
pr_info("ksu_manager_uid set to %d\n", ksu_debug_manager_uid);
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;
}
@@ -309,12 +309,27 @@ static struct kernel_param_ops expected_size_ops = {
.get = param_get_uint,
};
module_param_cb(ksu_debug_manager_uid, &expected_size_ops,
&ksu_debug_manager_uid, S_IRUSR | S_IWUSR);
static struct kernel_param_ops expected_hash_ops = {
.set = set_expected_hash,
.get = param_get_charp,
.free = param_free_charp,
};
#endif
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

View File

@@ -1,7 +1,7 @@
#ifndef __KSU_H_APK_V2_SIGN
#define __KSU_H_APK_V2_SIGN
#include <linux/types.h>
#include "linux/types.h"
bool is_manager_apk(char *path);

View File

@@ -1,7 +1,7 @@
#ifndef __KSU_H_ARCH
#define __KSU_H_ARCH
#include <linux/version.h>
#include "linux/version.h"
#if defined(__aarch64__)
@@ -18,11 +18,11 @@
#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"
#define SYS_READ_SYMBOL "__arm64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__arm64_sys_faccessat"
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
#else
#define PRCTL_SYMBOL "sys_prctl"
#endif
#elif defined(__x86_64__)
@@ -39,11 +39,11 @@
#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"
#define SYS_READ_SYMBOL "__x64_sys_read"
#define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat"
#define SYS_FACCESSAT_SYMBOL "__x64_sys_faccessat"
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
#else
#define PRCTL_SYMBOL "sys_prctl"
#endif
#else
#error "Unsupported arch"
@@ -67,6 +67,4 @@
#define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG)
#define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG)
#define PT_REAL_REGS(regs) ((struct pt_regs *)PT_REGS_PARM1(regs))
#endif

View File

@@ -1,37 +1,23 @@
#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/kallsyms.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/lsm_hooks.h>
#include <linux/mm.h>
#include <linux/nsproxy.h>
#include <linux/path.h>
#include <linux/printk.h>
#include <linux/sched.h>
#include <linux/security.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/uidgid.h>
#include <linux/version.h>
#include <linux/mount.h>
#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>
#ifdef MODULE
#include <linux/list.h>
#include <linux/irqflags.h>
#include <linux/mm_types.h>
#include <linux/rcupdate.h>
#include <linux/vmalloc.h>
#endif
#include "linux/fs.h"
#include "linux/namei.h"
#include "linux/rcupdate.h"
#include "allowlist.h"
#include "arch.h"
@@ -41,18 +27,11 @@
#include "ksud.h"
#include "manager.h"
#include "selinux/selinux.h"
#include "throne_tracker.h"
#include "throne_tracker.h"
#include "uid_observer.h"
#include "kernel_compat.h"
static bool ksu_module_mounted = false;
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
static bool ksu_su_compat_enabled = true;
extern void ksu_sucompat_init();
extern void ksu_sucompat_exit();
static inline bool is_allow_su()
{
if (is_manager()) {
@@ -62,11 +41,16 @@ static inline bool is_allow_su()
return ksu_is_allow_uid(current_uid().val);
}
static inline bool is_unsupported_uid(uid_t uid)
static inline bool is_isolated_uid(uid_t uid)
{
#define LAST_APPLICATION_UID 19999
#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 > LAST_APPLICATION_UID;
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) };
@@ -103,17 +87,57 @@ static void setup_groups(struct root_profile *profile, struct cred *cred)
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);
put_group_info(group_info);
}
static void disable_seccomp()
void escape_to_root(void)
{
assert_spin_locked(&current->sighand->siglock);
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)
@@ -127,62 +151,9 @@ static void disable_seccomp()
current->seccomp.filter = NULL;
#else
#endif
}
void escape_to_root(void)
{
struct cred *cred;
cred = prepare_creds();
if (!cred) {
pr_warn("prepare_creds failed!\n");
return;
}
if (cred->euid.val == 0) {
pr_warn("Already root, don't escape!\n");
abort_creds(cred);
return;
}
struct root_profile *profile = ksu_get_root_profile(cred->uid.val);
cred->uid.val = profile->uid;
cred->suid.val = profile->uid;
cred->euid.val = profile->uid;
cred->fsuid.val = profile->uid;
cred->gid.val = profile->gid;
cred->fsgid.val = profile->gid;
cred->sgid.val = profile->gid;
cred->egid.val = profile->gid;
cred->securebits = 0;
BUILD_BUG_ON(sizeof(profile->capabilities.effective) !=
sizeof(kernel_cap_t));
// setup capabilities
// we need CAP_DAC_READ_SEARCH becuase `/data/adb/ksud` is not accessible for non root process
// we add it here but don't add it to cap_inhertiable, it would be dropped automaticly after exec!
u64 cap_for_ksud =
profile->capabilities.effective | CAP_DAC_READ_SEARCH;
memcpy(&cred->cap_effective, &cap_for_ksud,
sizeof(cred->cap_effective));
memcpy(&cred->cap_permitted, &profile->capabilities.effective,
sizeof(cred->cap_permitted));
memcpy(&cred->cap_bset, &profile->capabilities.effective,
sizeof(cred->cap_bset));
setup_groups(profile, cred);
commit_creds(cred);
// Refer to kernel/seccomp.c: seccomp_set_mode_strict
// When disabling Seccomp, ensure that current->sighand->siglock is held during the operation.
spin_lock_irq(&current->sighand->siglock);
disable_seccomp();
spin_unlock_irq(&current->sighand->siglock);
setup_selinux(profile->selinux_domain);
}
@@ -214,37 +185,17 @@ int ksu_handle_rename(struct dentry *old_dentry, struct dentry *new_dentry)
return 0;
}
if (!strstr(buf, "/system/packages.list")) {
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);
track_throne();
update_uid();
return 0;
}
static void nuke_ext4_sysfs() {
struct path path;
int err = kern_path("/data/adb/modules", 0, &path);
if (err) {
pr_err("nuke path err: %d\n", err);
return;
}
struct super_block* sb = path.dentry->d_inode->i_sb;
const char* name = sb->s_type->name;
if (strcmp(name, "ext4") != 0) {
pr_info("nuke but module aren't mounted\n");
path_put(&path);
return;
}
ext4_unregister_sysfs(sb);
path_put(&path);
}
int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
@@ -256,33 +207,83 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
// TODO: find it in throne tracker!
uid_t current_uid_val = current_uid().val;
uid_t manager_uid = ksu_get_manager_uid();
if (current_uid_val != manager_uid &&
current_uid_val % 100000 == manager_uid) {
ksu_set_manager_uid(current_uid_val);
}
bool from_root = 0 == current_uid().val;
bool from_manager = is_manager();
if (!from_root && !from_manager) {
// only root or manager can access this interface
// always ignore isolated app uid
if (is_isolated_uid(current_uid().val)) {
return 0;
}
#ifdef CONFIG_KSU_DEBUG
pr_info("option: 0x%x, cmd: %ld\n", option, arg2);
#endif
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) {
if (from_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;
}
@@ -299,23 +300,17 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
// Both root manager and root processes should be allowed to get version
if (arg2 == CMD_GET_VERSION) {
u32 version = KERNEL_SU_VERSION;
if (copy_to_user(arg3, &version, sizeof(version))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
u32 version_flags = 0;
#ifdef MODULE
version_flags |= 0x1;
#endif
if (arg4 &&
copy_to_user(arg4, &version_flags, sizeof(version_flags))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
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 (!from_root) {
if (0 != current_uid().val) {
return 0;
}
switch (arg3) {
@@ -336,12 +331,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
break;
}
case EVENT_MODULE_MOUNTED: {
ksu_module_mounted = true;
pr_info("module mounted!\n");
nuke_ext4_sysfs();
break;
}
default:
break;
}
@@ -349,7 +338,7 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
if (arg2 == CMD_SET_SEPOLICY) {
if (!from_root) {
if (0 != current_uid().val) {
return 0;
}
if (!handle_sepolicy(arg3, arg4)) {
@@ -362,6 +351,9 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
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))) {
@@ -372,60 +364,57 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
}
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: %lu\n",
arg2);
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");
}
} else {
pr_err("prctl copy allowlist error\n");
}
}
return 0;
}
if (arg2 == CMD_UID_GRANTED_ROOT || arg2 == CMD_UID_SHOULD_UMOUNT) {
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);
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);
}
} else {
pr_err("prctl copy err, cmd: %lu\n", arg2);
}
return 0;
}
if (arg2 == CMD_GET_MANAGER_UID) {
uid_t manager_uid = ksu_get_manager_uid();
if (copy_to_user(arg3, &manager_uid, sizeof(manager_uid))) {
pr_err("get manager uid failed\n");
}
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}
// all other cmds are for 'root manager'
if (!from_manager) {
if (!is_manager()) {
last_failed_uid = current_uid().val;
return 0;
}
@@ -466,42 +455,6 @@ int ksu_handle_prctl(int option, unsigned long arg2, unsigned long arg3,
return 0;
}
if (arg2 == CMD_IS_SU_ENABLED) {
if (copy_to_user(arg3, &ksu_su_compat_enabled,
sizeof(ksu_su_compat_enabled))) {
pr_err("copy su compat 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_ENABLE_SU) {
bool enabled = (arg3 != 0);
if (enabled == ksu_su_compat_enabled) {
pr_info("cmd enable su but no need to change.\n");
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {// return the reply_ok directly
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}
if (enabled) {
ksu_sucompat_init();
} else {
ksu_sucompat_exit();
}
ksu_su_compat_enabled = enabled;
if (copy_to_user(result, &reply_ok, sizeof(reply_ok))) {
pr_err("prctl reply error, cmd: %lu\n", arg2);
}
return 0;
}
return 0;
}
@@ -536,10 +489,14 @@ static bool should_umount(struct path *path)
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)
@@ -552,13 +509,11 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
if (path.dentry != path.mnt->mnt_root) {
// it is not root mountpoint, maybe umounted by others already.
path_put(&path);
return;
}
// we are only interest in some specific mounts
if (check_mnt && !should_umount(&path)) {
path_put(&path);
return;
}
@@ -567,11 +522,6 @@ static void try_umount(const char *mnt, bool check_mnt, int flags)
int ksu_handle_setuid(struct cred *new, const struct cred *old)
{
// this hook is used for umounting overlayfs for some uid, if there isn't any module mounted, just ignore it!
if (!ksu_module_mounted) {
return 0;
}
if (!new || !old) {
return 0;
}
@@ -584,7 +534,7 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
return 0;
}
if (!is_appuid(new_uid) || is_unsupported_uid(new_uid.val)) {
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;
}
@@ -607,28 +557,19 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
// 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);
pr_info("handle umount ignore non zygote child: %d\n", current->pid);
return 0;
}
#ifdef CONFIG_KSU_DEBUG
// umount the target mnt
pr_info("handle umount for uid: %d, pid: %d\n", new_uid.val,
current->pid);
#endif
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("/odm", true, 0);
try_umount("/system", true, 0);
try_umount("/vendor", true, 0);
try_umount("/product", true, 0);
try_umount("/system_ext", true, 0);
try_umount("/data/adb/modules", false, MNT_DETACH);
// try umount ksu temp path
try_umount("/debug_ramdisk", false, MNT_DETACH);
return 0;
}
@@ -636,12 +577,22 @@ int ksu_handle_setuid(struct cred *new, const struct cred *old)
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_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);
@@ -701,7 +652,23 @@ static int ksu_task_prctl(int option, unsigned long arg2, unsigned long arg3,
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)
{
@@ -714,196 +681,40 @@ static int ksu_task_fix_setuid(struct cred *new, const struct cred *old,
return ksu_handle_setuid(new, old);
}
#ifndef MODULE
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
static int override_security_head(void *head, const void *new_head, size_t len)
{
unsigned long base = (unsigned long)head & PAGE_MASK;
unsigned long offset = offset_in_page(head);
// this is impossible for our case because the page alignment
// but be careful for other cases!
BUG_ON(offset + len > PAGE_SIZE);
struct page *page = phys_to_page(__pa(base));
if (!page) {
return -EFAULT;
}
void *addr = vmap(&page, 1, VM_MAP, PAGE_KERNEL);
if (!addr) {
return -ENOMEM;
}
local_irq_disable();
memcpy(addr + offset, new_head, len);
local_irq_enable();
vunmap(addr);
return 0;
}
static void free_security_hook_list(struct hlist_head *head)
{
struct hlist_node *temp;
struct security_hook_list *entry;
if (!head)
return;
hlist_for_each_entry_safe (entry, temp, head, list) {
hlist_del(&entry->list);
kfree(entry);
}
kfree(head);
}
struct hlist_head *copy_security_hlist(struct hlist_head *orig)
{
struct hlist_head *new_head = kmalloc(sizeof(*new_head), GFP_KERNEL);
if (!new_head)
return NULL;
INIT_HLIST_HEAD(new_head);
struct security_hook_list *entry;
struct security_hook_list *new_entry;
hlist_for_each_entry (entry, orig, list) {
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
if (!new_entry) {
free_security_hook_list(new_head);
return NULL;
}
*new_entry = *entry;
hlist_add_tail_rcu(&new_entry->list, new_head);
}
return new_head;
}
#define LSM_SEARCH_MAX 180 // This should be enough to iterate
static void *find_head_addr(void *security_ptr, int *index)
{
if (!security_ptr) {
return NULL;
}
struct hlist_head *head_start =
(struct hlist_head *)&security_hook_heads;
for (int i = 0; i < LSM_SEARCH_MAX; i++) {
struct hlist_head *head = head_start + i;
struct security_hook_list *pos;
hlist_for_each_entry (pos, head, list) {
if (pos->hook.capget == security_ptr) {
if (index) {
*index = i;
}
return head;
}
}
}
return NULL;
}
#define GET_SYMBOL_ADDR(sym) \
({ \
void *addr = kallsyms_lookup_name(#sym ".cfi_jt"); \
if (!addr) { \
addr = kallsyms_lookup_name(#sym); \
} \
addr; \
})
#define KSU_LSM_HOOK_HACK_INIT(head_ptr, name, func) \
do { \
static struct security_hook_list hook = { \
.hook = { .name = func } \
}; \
hook.head = head_ptr; \
hook.lsm = "ksu"; \
struct hlist_head *new_head = copy_security_hlist(hook.head); \
if (!new_head) { \
pr_err("Failed to copy security list: %s\n", #name); \
break; \
} \
hlist_add_tail_rcu(&hook.list, new_head); \
if (override_security_head(hook.head, new_head, \
sizeof(*new_head))) { \
free_security_hook_list(new_head); \
pr_err("Failed to hack lsm for: %s\n", #name); \
} \
} while (0)
void __init ksu_lsm_hook_init(void)
{
void *cap_prctl = GET_SYMBOL_ADDR(cap_task_prctl);
void *prctl_head = find_head_addr(cap_prctl, NULL);
if (prctl_head) {
if (prctl_head != &security_hook_heads.task_prctl) {
pr_warn("prctl's address has shifted!\n");
}
KSU_LSM_HOOK_HACK_INIT(prctl_head, task_prctl, ksu_task_prctl);
} else {
pr_warn("Failed to find task_prctl!\n");
}
int inode_killpriv_index = -1;
void *cap_killpriv = GET_SYMBOL_ADDR(cap_inode_killpriv);
find_head_addr(cap_killpriv, &inode_killpriv_index);
if (inode_killpriv_index < 0) {
pr_warn("Failed to find inode_rename, use kprobe instead!\n");
register_kprobe(&renameat_kp);
} else {
int inode_rename_index = inode_killpriv_index +
&security_hook_heads.inode_rename -
&security_hook_heads.inode_killpriv;
struct hlist_head *head_start =
(struct hlist_head *)&security_hook_heads;
void *inode_rename_head = head_start + inode_rename_index;
if (inode_rename_head != &security_hook_heads.inode_rename) {
pr_warn("inode_rename's address has shifted!\n");
}
KSU_LSM_HOOK_HACK_INIT(inode_rename_head, inode_rename,
ksu_inode_rename);
}
void *cap_setuid = GET_SYMBOL_ADDR(cap_task_fix_setuid);
void *setuid_head = find_head_addr(cap_setuid, NULL);
if (setuid_head) {
if (setuid_head != &security_hook_heads.task_fix_setuid) {
pr_warn("setuid's address has shifted!\n");
}
KSU_LSM_HOOK_HACK_INIT(setuid_head, task_fix_setuid,
ksu_task_fix_setuid);
} else {
pr_warn("Failed to find task_fix_setuid!\n");
}
smp_mb();
}
// 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)
{
#ifdef CONFIG_KPROBES
pr_info("ksu_core_kprobe_exit\n");
// we dont use this now
// ksu_kprobe_exit();
#ifndef MODULE
pr_info("ksu_kprobe_exit\n");
ksu_kprobe_exit();
#endif
}

View File

@@ -1,7 +1,7 @@
#ifndef __KSU_H_KSU_CORE
#define __KSU_H_KSU_CORE
#include <linux/init.h>
#include "linux/init.h"
void __init ksu_core_init(void);
void ksu_core_exit(void);

View File

@@ -1,8 +1,8 @@
#ifndef __KSU_H_KSHOOK
#define __KSU_H_KSHOOK
#include <linux/fs.h>
#include <linux/types.h>
#include "linux/fs.h"
#include "linux/types.h"
// For sucompat

View File

@@ -1,10 +1,41 @@
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/nsproxy.h>
#include <linux/sched/task.h>
#include <linux/uaccess.h>
#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
#include "kernel_compat.h"
#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;
@@ -50,6 +81,13 @@ void ksu_android_ns_fs_check()
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) {
@@ -72,17 +110,69 @@ struct file *ksu_filp_open_compat(const char *filename, int flags, umode_t mode)
ssize_t ksu_kernel_read_compat(struct file *p, void *buf, size_t count,
loff_t *pos)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_read(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_read(p, offset, (char *)buf, count);
if (pos && result > 0) {
*pos = offset + result;
}
return result;
#endif
}
ssize_t ksu_kernel_write_compat(struct file *p, const void *buf, size_t count,
loff_t *pos)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
return kernel_write(p, buf, count, pos);
#else
loff_t offset = pos ? *pos : 0;
ssize_t result = kernel_write(p, buf, count, offset);
if (pos && result > 0) {
*pos = offset + result;
}
return result;
#endif
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count)
{
return strncpy_from_user_nofault(dst, unsafe_addr, count);
}
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count)
{
return strncpy_from_unsafe_user(dst, unsafe_addr, count);
}
#else
// Copied from: https://elixir.bootlin.com/linux/v4.9.337/source/mm/maccess.c#L201
long ksu_strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr,
long count)
{
mm_segment_t old_fs = get_fs();
long ret;
if (unlikely(count <= 0))
return 0;
set_fs(USER_DS);
pagefault_disable();
ret = strncpy_from_user(dst, unsafe_addr, count);
pagefault_enable();
set_fs(old_fs);
if (ret >= count) {
ret = count;
dst[ret - 1] = '\0';
} else if (ret > 0) {
ret++;
}
return ret;
}
#endif

View File

@@ -1,29 +1,18 @@
#ifndef __KSU_H_KERNEL_COMPAT
#define __KSU_H_KERNEL_COMPAT
#include <linux/fs.h>
#include <linux/version.h>
#include "ss/policydb.h"
#include "linux/fs.h"
#include "linux/key.h"
/*
* Adapt to Huawei HISI kernel without affecting other kernels ,
* Huawei Hisi Kernel EBITMAP Enable or Disable Flag ,
* From ss/ebitmap.h
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && \
(LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) && \
(LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0))
#ifdef HISI_SELINUX_EBITMAP_RO
#define CONFIG_IS_HW_HISI
#endif
#endif
#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);

View File

@@ -1,15 +1,13 @@
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include "linux/fs.h"
#include "linux/module.h"
#include "linux/workqueue.h"
#include "allowlist.h"
#include "arch.h"
#include "core_hook.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "throne_tracker.h"
#include "uid_observer.h"
static struct workqueue_struct *ksu_workqueue;
@@ -32,10 +30,8 @@ int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv,
flags);
}
extern void ksu_sucompat_init();
extern void ksu_sucompat_exit();
extern void ksu_ksud_init();
extern void ksu_ksud_exit();
extern void ksu_enable_sucompat();
extern void ksu_enable_ksud();
int __init kernelsu_init(void)
{
@@ -55,20 +51,15 @@ int __init kernelsu_init(void)
ksu_allowlist_init();
ksu_throne_tracker_init();
ksu_uid_observer_init();
#ifdef CONFIG_KPROBES
ksu_sucompat_init();
ksu_ksud_init();
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
#ifdef MODULE
#ifndef CONFIG_KSU_DEBUG
kobject_del(&THIS_MODULE->mkobj.kobj);
#endif
#endif
return 0;
}
@@ -76,15 +67,10 @@ void kernelsu_exit(void)
{
ksu_allowlist_exit();
ksu_throne_tracker_exit();
ksu_uid_observer_exit();
destroy_workqueue(ksu_workqueue);
#ifdef CONFIG_KPROBES
ksu_ksud_exit();
ksu_sucompat_exit();
#endif
ksu_core_exit();
}
@@ -94,4 +80,7 @@ module_exit(kernelsu_exit);
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

View File

@@ -1,8 +1,8 @@
#ifndef __KSU_H_KSU
#define __KSU_H_KSU
#include <linux/types.h>
#include <linux/workqueue.h>
#include "linux/types.h"
#include "linux/workqueue.h"
#define KERNEL_SU_VERSION KSU_VERSION
#define KERNEL_SU_OPTION 0xDEADBEEF
@@ -21,13 +21,9 @@
#define CMD_SET_APP_PROFILE 11
#define CMD_UID_GRANTED_ROOT 12
#define CMD_UID_SHOULD_UMOUNT 13
#define CMD_IS_SU_ENABLED 14
#define CMD_ENABLE_SU 15
#define CMD_GET_MANAGER_UID 16
#define EVENT_POST_FS_DATA 1
#define EVENT_BOOT_COMPLETED 2
#define EVENT_MODULE_MOUNTED 3
#define KSU_APP_PROFILE_VER 2
#define KSU_MAX_PACKAGE_NAME 256

View File

@@ -1,17 +1,15 @@
#include <asm/current.h>
#include <linux/compat.h>
#include <linux/cred.h>
#include <linux/dcache.h>
#include <linux/err.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/version.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/workqueue.h>
#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"
@@ -57,8 +55,6 @@ bool ksu_execveat_hook __read_mostly = true;
bool ksu_input_hook __read_mostly = true;
#endif
u32 ksu_devpts_sid;
void on_post_fs_data(void)
{
static bool done = false;
@@ -71,9 +67,6 @@ void on_post_fs_data(void)
ksu_load_allow_list();
// sanity check, this may influence the performance
stop_input_hook();
ksu_devpts_sid = ksu_get_devpts_sid();
pr_info("devpts sid: %d\n", ksu_devpts_sid);
}
#define MAX_ARG_STRINGS 0x7FFFFFFF
@@ -114,7 +107,7 @@ static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
* 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.
*/
@@ -147,8 +140,7 @@ static int __maybe_unused count(struct user_arg_ptr argv, int max)
// 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)
struct user_arg_ptr *argv, struct user_arg_ptr *envp, int *flags)
{
#ifndef CONFIG_KPROBES
if (!ksu_execveat_hook) {
@@ -174,9 +166,8 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
return 0;
}
if (unlikely(!memcmp(filename->name, system_bin_init,
sizeof(system_bin_init) - 1) &&
argv)) {
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);
@@ -184,10 +175,8 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
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);
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();
@@ -199,8 +188,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
}
}
} else if (unlikely(!memcmp(filename->name, old_system_init,
sizeof(old_system_init) - 1) &&
argv)) {
sizeof(old_system_init) - 1) && argv)) {
// /init executed
int argc = count(*argv, MAX_ARG_STRINGS);
pr_info("/init argc: %d\n", argc);
@@ -209,8 +197,7 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
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));
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");
@@ -227,15 +214,13 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
if (envc > 0) {
int n;
for (n = 1; n <= envc; n++) {
const char __user *p =
get_user_arg_ptr(*envp, 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)
if (ksu_strncpy_from_user_nofault(env, p, sizeof(env)) < 0)
continue;
// Parsing environment variable names and values
char *env_name = env;
@@ -246,14 +231,10 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
*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"))) {
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;
init_second_stage_executed = true;
ksu_android_ns_fs_check();
}
}
@@ -261,11 +242,10 @@ int ksu_handle_execveat_ksud(int *fd, struct filename **filename_ptr,
}
}
if (unlikely(first_app_process && !memcmp(filename->name, app_process,
sizeof(app_process) - 1))) {
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);
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();
}
@@ -284,8 +264,7 @@ static ssize_t read_proxy(struct file *file, char __user *buf, size_t count,
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);
pr_info("read_proxy append %ld + %ld\n", ret, read_count_append);
ret += read_count_append;
}
return ret;
@@ -397,18 +376,6 @@ int ksu_handle_vfs_read(struct file **file_ptr, char __user **buf_ptr,
return 0;
}
int ksu_handle_sys_read(unsigned int fd, char __user **buf_ptr,
size_t *count_ptr)
{
struct file *file = fget(fd);
if (!file) {
return 0;
}
int result = ksu_handle_vfs_read(&file, buf_ptr, count_ptr, NULL);
fput(file);
return result;
}
static unsigned int volumedown_pressed_count = 0;
static bool is_volumedown_enough(unsigned int count)
@@ -463,37 +430,35 @@ bool ksu_is_safe_mode()
#ifdef CONFIG_KPROBES
static int sys_execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
// 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)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
const char __user **filename_user =
(const char **)&PT_REGS_PARM1(real_regs);
const char __user *const __user *__argv =
(const char __user *const __user *)PT_REGS_PARM2(real_regs);
struct user_arg_ptr argv = { .ptr.native = __argv };
struct filename filename_in, *filename_p;
char path[32];
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
if (!filename_user)
return 0;
memset(path, 0, sizeof(path));
ksu_strncpy_from_user_nofault(path, *filename_user, 32);
filename_in.name = path;
filename_p = &filename_in;
return ksu_handle_execveat_ksud(AT_FDCWD, &filename_p, &argv, NULL,
NULL);
return ksu_handle_execveat_ksud(fd, filename_ptr, &argv, NULL, NULL);
}
static int sys_read_handler_pre(struct kprobe *p, struct pt_regs *regs)
static int read_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
unsigned int fd = PT_REGS_PARM1(real_regs);
char __user **buf_ptr = (char __user **)&PT_REGS_PARM2(real_regs);
size_t count_ptr = (size_t *)&PT_REGS_PARM3(real_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_sys_read(fd, buf_ptr, count_ptr);
return ksu_handle_vfs_read(file_ptr, buf_ptr, count_ptr, pos_ptr);
}
static int input_handle_event_handler_pre(struct kprobe *p,
@@ -506,18 +471,23 @@ static int input_handle_event_handler_pre(struct kprobe *p,
}
static struct kprobe execve_kp = {
.symbol_name = SYS_EXECVE_SYMBOL,
.pre_handler = sys_execve_handler_pre,
#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 = SYS_READ_SYMBOL,
.pre_handler = sys_read_handler_pre,
.symbol_name = "vfs_read",
.pre_handler = read_handler_pre,
};
static struct kprobe input_event_kp = {
.symbol_name = "input_event",
static struct kprobe input_handle_event_kp = {
.symbol_name = "input_handle_event",
.pre_handler = input_handle_event_handler_pre,
};
@@ -533,7 +503,7 @@ static void do_stop_execve_hook(struct work_struct *work)
static void do_stop_input_hook(struct work_struct *work)
{
unregister_kprobe(&input_event_kp);
unregister_kprobe(&input_handle_event_kp);
}
#endif
@@ -576,7 +546,7 @@ static void stop_input_hook()
}
// ksud: module support
void ksu_ksud_init()
void ksu_enable_ksud()
{
#ifdef CONFIG_KPROBES
int ret;
@@ -587,21 +557,11 @@ void ksu_ksud_init()
ret = register_kprobe(&vfs_read_kp);
pr_info("ksud: vfs_read_kp: %d\n", ret);
ret = register_kprobe(&input_event_kp);
pr_info("ksud: input_event_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
}
void ksu_ksud_exit()
{
#ifdef CONFIG_KPROBES
unregister_kprobe(&execve_kp);
// this should be done before unregister vfs_read_kp
// unregister_kprobe(&vfs_read_kp);
unregister_kprobe(&input_event_kp);
#endif
}

View File

@@ -1,14 +1,10 @@
#ifndef __KSU_H_KSUD
#define __KSU_H_KSUD
#include <linux/types.h>
#define KSUD_PATH "/data/adb/ksud"
void on_post_fs_data(void);
bool ksu_is_safe_mode(void);
extern u32 ksu_devpts_sid;
#endif

126
kernel/ksufs/5.10/Kconfig Normal file
View File

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

View File

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

1010
kernel/ksufs/5.10/copy_up.c Normal file

File diff suppressed because it is too large Load Diff

1325
kernel/ksufs/5.10/dir.c Normal file

File diff suppressed because it is too large Load Diff

870
kernel/ksufs/5.10/export.c Normal file
View File

@@ -0,0 +1,870 @@
// 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,
};

809
kernel/ksufs/5.10/file.c Normal file
View File

@@ -0,0 +1,809 @@
// 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);
}

1049
kernel/ksufs/5.10/inode.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,145 @@
/* 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);
}

1184
kernel/ksufs/5.10/namei.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,551 @@
/* 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;

1232
kernel/ksufs/5.10/readdir.c Normal file

File diff suppressed because it is too large Load Diff

2139
kernel/ksufs/5.10/super.c Normal file

File diff suppressed because it is too large Load Diff

974
kernel/ksufs/5.10/util.c Normal file
View File

@@ -0,0 +1,974 @@
// 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
kernel/ksufs/Makefile Normal file
View File

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

60
kernel/ksufs/README.md Normal file
View File

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

101
kernel/manager.c Normal file
View File

@@ -0,0 +1,101 @@
#include "linux/cred.h"
#include "linux/gfp.h"
#include "linux/slab.h"
#include "linux/uidgid.h"
#include "linux/version.h"
#include "linux/fdtable.h"
#include "linux/fs.h"
#include "linux/rcupdate.h"
#include "apk_sign.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "manager.h"
uid_t ksu_manager_uid = KSU_INVALID_UID;
bool become_manager(char *pkg)
{
struct fdtable *files_table;
int i = 0;
struct path files_path;
char *cwd;
char *buf;
bool result = false;
#ifdef KSU_MANAGER_PACKAGE
// pkg is `/<real package>`
if (strncmp(pkg + 1, KSU_MANAGER_PACKAGE,
sizeof(KSU_MANAGER_PACKAGE)) != 0) {
pr_info("manager package is inconsistent with kernel build: %s\n",
KSU_MANAGER_PACKAGE);
return false;
}
#endif
// must be zygote's direct child, otherwise any app can fork a new process and
// open manager's apk
if (task_uid(current->real_parent).val != 0) {
pr_info("parent is not zygote!\n");
return false;
}
buf = (char *)kmalloc(PATH_MAX, GFP_ATOMIC);
if (!buf) {
pr_err("kalloc path failed.\n");
return false;
}
files_table = files_fdtable(current->files);
int pkg_len = strlen(pkg);
// todo: use iterate_fd
for (i = 0; files_table->fd[i] != NULL; i++) {
files_path = files_table->fd[i]->f_path;
if (!d_is_reg(files_path.dentry)) {
continue;
}
cwd = d_path(&files_path, buf, PATH_MAX);
if (startswith(cwd, "/data/app/") != 0 ||
endswith(cwd, "/base.apk") != 0) {
continue;
}
// we have found the apk!
pr_info("found apk: %s\n", cwd);
char *pkg_index = strstr(cwd, pkg);
if (!pkg_index) {
pr_info("apk path not match package name!\n");
continue;
}
char *next_char = pkg_index + pkg_len;
// because we ensure the cwd must startswith `/data/app` and endswith `base.apk`
// we don't need to check if the pointer is out of bounds
if (*next_char != '-') {
// from android 8.1: http://aospxref.com/android-8.1.0_r81/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java#17612
// to android 13: http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java#1208
// /data/app/~~[randomStringA]/[packageName]-[randomStringB]
// the previous char must be `/` and the next char must be `-`
// because we use strstr instead of equals, this is a strong verfication.
pr_info("invalid pkg: %s\n", pkg);
continue;
}
if (is_manager_apk(cwd)) {
// check passed
uid_t uid = current_uid().val;
pr_info("manager uid: %d\n", uid);
ksu_set_manager_uid(uid);
result = true;
goto clean;
} else {
pr_info("manager signature invalid!\n");
}
break;
}
clean:
kfree(buf);
return result;
}

View File

@@ -1,8 +1,8 @@
#ifndef __KSU_H_KSU_MANAGER
#define __KSU_H_KSU_MANAGER
#include <linux/cred.h>
#include <linux/types.h>
#include "linux/cred.h"
#include "linux/types.h"
#define KSU_INVALID_UID -1
@@ -33,4 +33,6 @@ static inline void ksu_invalidate_manager_uid()
ksu_manager_uid = KSU_INVALID_UID;
}
bool become_manager(char *pkg);
#endif

33
kernel/module_api.c Normal file
View File

@@ -0,0 +1,33 @@
#include "linux/kallsyms.h"
#define RE_EXPORT_SYMBOL1(ret, func, t1, v1) \
ret ksu_##func(t1 v1) \
{ \
return func(v1); \
} \
EXPORT_SYMBOL(ksu_##func);
#define RE_EXPORT_SYMBOL2(ret, func, t1, v1, t2, v2) \
ret ksu_##func(t1 v1, t2 v2) \
{ \
return func(v1, v2); \
} \
EXPORT_SYMBOL(ksu_##func);
RE_EXPORT_SYMBOL1(unsigned long, kallsyms_lookup_name, const char *, name)
// RE_EXPORT_SYMBOL2(int, register_kprobe, struct kprobe *, p)
// RE_EXPORT_SYMBOL2(void, unregister_kprobe, struct kprobe *, p)
// RE_EXPORT_SYMBOL2(int, register_kprobe, struct kprobe *, p)
// RE_EXPORT_SYMBOL2(void, unregister_kprobe, struct kprobe *, p)
// int ksu_register_kprobe(struct kprobe *p);
// void ksu_unregister_kprobe(struct kprobe *p);
// int ksu_register_kprobes(struct kprobe **kps, int num);
// void ksu_unregister_kprobes(struct kprobe **kps, int num);
// int ksu_register_kretprobe(struct kretprobe *rp);
// void unregister_kretprobe(struct kretprobe *rp);
// int register_kretprobes(struct kretprobe **rps, int num);
// void unregister_kretprobes(struct kretprobe **rps, int num);

View File

@@ -1,6 +1,6 @@
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/version.h>
#include "linux/uaccess.h"
#include "linux/types.h"
#include "linux/version.h"
#include "../klog.h" // IWYU pragma: keep
#include "selinux.h"
@@ -9,7 +9,9 @@
#include "linux/lsm_audit.h"
#include "xfrm.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
#define SELINUX_POLICY_INSTEAD_SELINUX_SS
#endif
#define KERNEL_SU_DOMAIN "su"
#define KERNEL_SU_FILE "ksu_file"
@@ -19,24 +21,29 @@
static struct policydb *get_policydb(void)
{
struct policydb *db;
struct selinux_policy *policy = selinux_state.policy;
// selinux_state does not exists before 4.19
#ifdef KSU_COMPAT_USE_SELINUX_STATE
#ifdef SELINUX_POLICY_INSTEAD_SELINUX_SS
struct selinux_policy *policy = rcu_dereference(selinux_state.policy);
db = &policy->policydb;
#else
struct selinux_ss *ss = rcu_dereference(selinux_state.ss);
db = &ss->policydb;
#endif
#else
db = &policydb;
#endif
return db;
}
static DEFINE_MUTEX(ksu_rules);
void apply_kernelsu_rules()
{
struct policydb *db;
if (!getenforce()) {
pr_info("SELinux permissive or disabled, apply rules!\n");
}
mutex_lock(&ksu_rules);
db = get_policydb();
rcu_read_lock();
struct policydb *db = get_policydb();
ksu_permissive(db, KERNEL_SU_DOMAIN);
ksu_typeattribute(db, KERNEL_SU_DOMAIN, "mlstrustedsubject");
@@ -62,11 +69,6 @@ void apply_kernelsu_rules()
// we need to save allowlist in /data/adb/ksu
ksu_allow(db, "kernel", "adb_data_file", "dir", ALL);
ksu_allow(db, "kernel", "adb_data_file", "file", ALL);
// we need to search /data/app
ksu_allow(db, "kernel", "apk_data_file", "file", "open");
ksu_allow(db, "kernel", "apk_data_file", "dir", "open");
ksu_allow(db, "kernel", "apk_data_file", "dir", "read");
ksu_allow(db, "kernel", "apk_data_file", "dir", "search");
// we may need to do mount on shell
ksu_allow(db, "kernel", "shell_data_file", "file", ALL);
// we need to read /data/system/packages.list
@@ -82,7 +84,6 @@ void apply_kernelsu_rules()
ksu_allow(db, "kernel", "system_data_file", "dir", ALL);
// our ksud triggered by init
ksu_allow(db, "init", "adb_data_file", "file", ALL);
ksu_allow(db, "init", "adb_data_file", "dir", ALL); // #1289
ksu_allow(db, "init", KERNEL_SU_DOMAIN, ALL, ALL);
// we need to umount modules in zygote
ksu_allow(db, "zygote", "adb_data_file", "dir", "search");
@@ -123,11 +124,13 @@ void apply_kernelsu_rules()
// Allow all binder transactions
ksu_allow(db, ALL, KERNEL_SU_DOMAIN, "binder", ALL);
// Allow system server kill su process
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "getpgid");
ksu_allow(db, "system_server", KERNEL_SU_DOMAIN, "process", "sigkill");
// Allow system server devpts
ksu_allow(db, "system_server", "untrusted_app_all_devpts", "chr_file",
"read");
ksu_allow(db, "system_server", "untrusted_app_all_devpts", "chr_file",
"write");
mutex_unlock(&ksu_rules);
rcu_read_unlock();
}
#define MAX_SEPOL_LEN 128
@@ -174,7 +177,7 @@ static int get_object(char *buf, char __user *user_object, size_t buf_sz,
// reset avc cache table, otherwise the new rules will not take effect if already denied
static void reset_avc_cache()
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0))
#ifndef KSU_COMPAT_USE_SELINUX_STATE
avc_ss_reset(0);
selnl_notify_policyload(0);
selinux_status_update_policyload(0);
@@ -189,8 +192,6 @@ static void reset_avc_cache()
int handle_sepolicy(unsigned long arg3, void __user *arg4)
{
struct policydb *db;
if (!arg4) {
return -1;
}
@@ -208,9 +209,9 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
u32 cmd = data.cmd;
u32 subcmd = data.subcmd;
mutex_lock(&ksu_rules);
rcu_read_lock();
db = get_policydb();
struct policydb *db = get_policydb();
int ret = -1;
if (cmd == CMD_NORMAL_PERM) {
@@ -460,7 +461,7 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
}
exit:
mutex_unlock(&ksu_rules);
rcu_read_unlock();
// only allow and xallow needs to reset avc cache, but we cannot do that because
// we are in atomic context. so we just reset it every time.

View File

@@ -2,9 +2,14 @@
#include "objsec.h"
#include "linux/version.h"
#include "../klog.h" // IWYU pragma: keep
#ifndef KSU_COMPAT_USE_SELINUX_STATE
#include "avc.h"
#endif
#define KERNEL_SU_DOMAIN "u:r:su:s0"
static u32 ksu_sid;
static int transive_to_domain(const char *domain)
{
struct cred *cred;
@@ -26,6 +31,9 @@ static int transive_to_domain(const char *domain)
domain, sid, error);
}
if (!error) {
if (!ksu_sid)
ksu_sid = sid;
tsec->sid = sid;
tsec->create_sid = 0;
tsec->keycreate_sid = 0;
@@ -52,20 +60,32 @@ if (!is_domain_permissive) {
void setenforce(bool enforce)
{
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
#ifdef KSU_COMPAT_USE_SELINUX_STATE
selinux_state.enforcing = enforce;
#else
selinux_enforcing = enforce;
#endif
#endif
}
bool getenforce()
{
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
#ifdef KSU_COMPAT_USE_SELINUX_STATE
if (selinux_state.disabled) {
#else
if (selinux_disabled) {
#endif
return false;
}
#endif
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
#ifdef KSU_COMPAT_USE_SELINUX_STATE
return selinux_state.enforcing;
#else
return selinux_enforcing;
#endif
#else
return true;
#endif
@@ -86,16 +106,7 @@ static inline u32 current_sid(void)
bool is_ksu_domain()
{
char *domain;
u32 seclen;
bool result;
int err = security_secid_to_secctx(current_sid(), &domain, &seclen);
if (err) {
return false;
}
result = strncmp(KERNEL_SU_DOMAIN, domain, seclen) == 0;
security_release_secctx(domain, seclen);
return result;
return ksu_sid && current_sid() == ksu_sid;
}
bool is_zygote(void *sec)
@@ -106,25 +117,9 @@ bool is_zygote(void *sec)
}
char *domain;
u32 seclen;
bool result;
int err = security_secid_to_secctx(tsec->sid, &domain, &seclen);
if (err) {
return false;
}
result = strncmp("u:r:zygote:s0", domain, seclen) == 0;
security_release_secctx(domain, seclen);
return result;
}
#define DEVPTS_DOMAIN "u:object_r:ksu_file:s0"
u32 ksu_get_devpts_sid()
{
u32 devpts_sid = 0;
int err = security_secctx_to_secid(DEVPTS_DOMAIN, strlen(DEVPTS_DOMAIN),
&devpts_sid);
if (err) {
pr_info("get devpts sid err %d\n", err);
}
return devpts_sid;
}
return strncmp("u:r:zygote:s0", domain, seclen) == 0;
}

View File

@@ -4,6 +4,10 @@
#include "linux/types.h"
#include "linux/version.h"
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) || defined(KSU_COMPAT_HAS_SELINUX_STATE)
#define KSU_COMPAT_USE_SELINUX_STATE
#endif
void setup_selinux(const char *);
void setenforce(bool);
@@ -16,6 +20,4 @@ bool is_zygote(void *cred);
void apply_kernelsu_rules();
u32 ksu_get_devpts_sid();
#endif

View File

@@ -1,15 +1,26 @@
#include <linux/gfp.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/version.h>
#include "sepolicy.h"
#include "linux/gfp.h"
#include "linux/printk.h"
#include "linux/slab.h"
#include "linux/version.h"
#include "../klog.h" // IWYU pragma: keep
#include "ss/symtab.h"
#include "../kernel_compat.h" // Add check Huawei Device
#define KSU_SUPPORT_ADD_TYPE
/*
* Adapt to Huawei HISI kernel without affecting other kernels ,
* Huawei Hisi Kernel EBITMAP Enable or Disable Flag ,
* From ss/ebitmap.h
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#ifdef HISI_SELINUX_EBITMAP_RO
#define CONFIG_IS_HW_HISI
#endif
#endif
//////////////////////////////////////////////////////
// Declaration
//////////////////////////////////////////////////////
@@ -524,6 +535,7 @@ static bool add_filename_trans(struct policydb *db, const char *s,
return false;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
struct filename_trans_key key;
key.ttype = tgt->value;
key.tclass = cls->value;
@@ -531,8 +543,13 @@ static bool add_filename_trans(struct policydb *db, const char *s,
struct filename_trans_datum *last = NULL;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
struct filename_trans_datum *trans =
policydb_filenametr_search(db, &key);
#else
struct filename_trans_datum *trans =
hashtab_search(&db->filename_trans, &key);
#endif
while (trans) {
if (ebitmap_get_bit(&trans->stypes, src->value - 1)) {
// Duplicate, overwrite existing data and return
@@ -561,6 +578,39 @@ static bool add_filename_trans(struct policydb *db, const char *s,
db->compat_filename_trans_count++;
return ebitmap_set_bit(&trans->stypes, src->value - 1, 1) == 0;
#else // < 5.7.0, has no filename_trans_key, but struct filename_trans
struct filename_trans key;
key.ttype = tgt->value;
key.tclass = cls->value;
key.name = (char *)o;
struct filename_trans_datum *trans =
hashtab_search(db->filename_trans, &key);
if (trans == NULL) {
trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans),
1, GFP_ATOMIC);
if (!trans) {
pr_err("add_filename_trans: Failed to alloc datum\n");
return false;
}
struct filename_trans *new_key =
(struct filename_trans *)kmalloc(sizeof(*new_key),
GFP_ATOMIC);
if (!new_key) {
pr_err("add_filename_trans: Failed to alloc new_key\n");
return false;
}
*new_key = key;
new_key->name = kstrdup(key.name, GFP_ATOMIC);
trans->otype = def->value;
hashtab_insert(db->filename_trans, new_key, trans);
}
return ebitmap_set_bit(&db->filename_trans_ttypes, src->value - 1, 1) ==
0;
#endif
}
static bool add_genfscon(struct policydb *db, const char *fs_name,
@@ -569,24 +619,9 @@ static bool add_genfscon(struct policydb *db, const char *fs_name,
return false;
}
static void *ksu_realloc(void *old, size_t new_size, size_t old_size)
{
// we can't use krealloc, because it may be read-only
void *new = kzalloc(new_size, GFP_ATOMIC);
if (!new) {
return NULL;
}
if (old_size) {
memcpy(new, old, old_size);
}
// we can't use kfree, because it may be read-only
// there maybe some leaks, maybe we can check ptr_write, but it's not a big deal
// kfree(old);
return new;
}
static bool add_type(struct policydb *db, const char *type_name, bool attr)
{
#ifdef KSU_SUPPORT_ADD_TYPE
struct type_datum *type = symtab_search(&db->p_types, type_name);
if (type) {
pr_warn("Type %s already exists\n", type_name);
@@ -616,30 +651,30 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
return false;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim;
struct ebitmap *new_type_attr_map_array =
ksu_realloc(db->type_attr_map_array,
value * sizeof(struct ebitmap),
(value - 1) * sizeof(struct ebitmap));
(krealloc(db->type_attr_map_array, new_size, GFP_ATOMIC));
struct type_datum **new_type_val_to_struct =
krealloc(db->type_val_to_struct,
sizeof(*db->type_val_to_struct) * db->p_types.nprim,
GFP_ATOMIC);
if (!new_type_attr_map_array) {
pr_err("add_type: alloc type_attr_map_array failed\n");
return false;
}
struct type_datum **new_type_val_to_struct =
ksu_realloc(db->type_val_to_struct,
sizeof(*db->type_val_to_struct) * value,
sizeof(*db->type_val_to_struct) * (value - 1));
if (!new_type_val_to_struct) {
pr_err("add_type: alloc type_val_to_struct failed\n");
return false;
}
char **new_val_to_name_types =
ksu_realloc(db->sym_val_to_name[SYM_TYPES],
sizeof(char *) * value,
sizeof(char *) * (value - 1));
krealloc(db->sym_val_to_name[SYM_TYPES],
sizeof(char *) * db->symtab[SYM_TYPES].nprim,
GFP_KERNEL);
if (!new_val_to_name_types) {
pr_err("add_type: alloc val_to_name failed\n");
return false;
@@ -662,6 +697,171 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
}
return true;
#elif defined(CONFIG_IS_HW_HISI)
/*
* Huawei use type_attr_map and type_val_to_struct.
* And use ebitmap not flex_array.
*/
size_t new_size = sizeof(struct ebitmap) * db->p_types.nprim;
struct ebitmap *new_type_attr_map =
(krealloc(db->type_attr_map, new_size, GFP_ATOMIC));
struct type_datum **new_type_val_to_struct =
krealloc(db->type_val_to_struct,
sizeof(*db->type_val_to_struct) * db->p_types.nprim,
GFP_ATOMIC);
if (!new_type_attr_map) {
pr_err("add_type: alloc type_attr_map failed\n");
return false;
}
if (!new_type_val_to_struct) {
pr_err("add_type: alloc type_val_to_struct failed\n");
return false;
}
char **new_val_to_name_types =
krealloc(db->sym_val_to_name[SYM_TYPES],
sizeof(char *) * db->symtab[SYM_TYPES].nprim,
GFP_KERNEL);
if (!new_val_to_name_types) {
pr_err("add_type: alloc val_to_name failed\n");
return false;
}
db->type_attr_map = new_type_attr_map;
ebitmap_init(&db->type_attr_map[value - 1], HISI_SELINUX_EBITMAP_RO);
ebitmap_set_bit(&db->type_attr_map[value - 1], value - 1, 1);
db->type_val_to_struct = new_type_val_to_struct;
db->type_val_to_struct[value - 1] = type;
db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types;
db->sym_val_to_name[SYM_TYPES][value - 1] = key;
int i;
for (i = 0; i < db->p_roles.nprim; ++i) {
ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1,
1);
}
return true;
#else
// flex_array is not extensible, we need to create a new bigger one instead
struct flex_array *new_type_attr_map_array =
flex_array_alloc(sizeof(struct ebitmap), db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO);
struct flex_array *new_type_val_to_struct =
flex_array_alloc(sizeof(struct type_datum *), db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO);
struct flex_array *new_val_to_name_types =
flex_array_alloc(sizeof(char *), db->symtab[SYM_TYPES].nprim,
GFP_ATOMIC | __GFP_ZERO);
if (!new_type_attr_map_array) {
pr_err("add_type: alloc type_attr_map_array failed\n");
return false;
}
if (!new_type_val_to_struct) {
pr_err("add_type: alloc type_val_to_struct failed\n");
return false;
}
if (!new_val_to_name_types) {
pr_err("add_type: alloc val_to_name failed\n");
return false;
}
// preallocate so we don't have to worry about the put ever failing
if (flex_array_prealloc(new_type_attr_map_array, 0, db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO)) {
pr_err("add_type: prealloc type_attr_map_array failed\n");
return false;
}
if (flex_array_prealloc(new_type_val_to_struct, 0, db->p_types.nprim,
GFP_ATOMIC | __GFP_ZERO)) {
pr_err("add_type: prealloc type_val_to_struct_array failed\n");
return false;
}
if (flex_array_prealloc(new_val_to_name_types, 0,
db->symtab[SYM_TYPES].nprim,
GFP_ATOMIC | __GFP_ZERO)) {
pr_err("add_type: prealloc val_to_name_types failed\n");
return false;
}
int j;
void *old_elem;
// copy the old data or pointers to new flex arrays
for (j = 0; j < db->type_attr_map_array->total_nr_elements; j++) {
old_elem = flex_array_get(db->type_attr_map_array, j);
if (old_elem)
flex_array_put(new_type_attr_map_array, j, old_elem,
GFP_ATOMIC | __GFP_ZERO);
}
for (j = 0; j < db->type_val_to_struct_array->total_nr_elements; j++) {
old_elem = flex_array_get_ptr(db->type_val_to_struct_array, j);
if (old_elem)
flex_array_put_ptr(new_type_val_to_struct, j, old_elem,
GFP_ATOMIC | __GFP_ZERO);
}
for (j = 0; j < db->symtab[SYM_TYPES].nprim; j++) {
old_elem =
flex_array_get_ptr(db->sym_val_to_name[SYM_TYPES], j);
if (old_elem)
flex_array_put_ptr(new_val_to_name_types, j, old_elem,
GFP_ATOMIC | __GFP_ZERO);
}
// store the pointer of old flex arrays first, when assigning new ones we
// should free it
struct flex_array *old_fa;
old_fa = db->type_attr_map_array;
db->type_attr_map_array = new_type_attr_map_array;
if (old_fa) {
flex_array_free(old_fa);
}
ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1));
ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1),
value - 1, 1);
old_fa = db->type_val_to_struct_array;
db->type_val_to_struct_array = new_type_val_to_struct;
if (old_fa) {
flex_array_free(old_fa);
}
flex_array_put_ptr(db->type_val_to_struct_array, value - 1, type,
GFP_ATOMIC | __GFP_ZERO);
old_fa = db->sym_val_to_name[SYM_TYPES];
db->sym_val_to_name[SYM_TYPES] = new_val_to_name_types;
if (old_fa) {
flex_array_free(old_fa);
}
flex_array_put_ptr(db->sym_val_to_name[SYM_TYPES], value - 1, key,
GFP_ATOMIC | __GFP_ZERO);
int i;
for (i = 0; i < db->p_roles.nprim; ++i) {
ebitmap_set_bit(&db->role_val_to_struct[i]->types, value - 1,
1);
}
return true;
#endif
#else
return false;
#endif
}
static bool set_type_state(struct policydb *db, const char *type_name,
@@ -696,7 +896,18 @@ static bool set_type_state(struct policydb *db, const char *type_name,
static void add_typeattribute_raw(struct policydb *db, struct type_datum *type,
struct type_datum *attr)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1];
#elif defined(CONFIG_IS_HW_HISI)
/*
* HISI_SELINUX_EBITMAP_RO is Huawei's unique features.
*/
struct ebitmap *sattr = &db->type_attr_map[type->value - 1],
HISI_SELINUX_EBITMAP_RO;
#else
struct ebitmap *sattr =
flex_array_get(db->type_attr_map_array, type->value - 1);
#endif
ebitmap_set_bit(sattr, attr->value - 1, 1);
struct hashtab_node *node;

View File

@@ -1,7 +1,7 @@
#ifndef __KSU_H_SEPOLICY
#define __KSU_H_SEPOLICY
#include <linux/types.h>
#include "linux/types.h"
#include "ss/policydb.h"

View File

@@ -1,75 +1,50 @@
#!/bin/sh
set -eu
set -eux
GKI_ROOT=$(pwd)
display_usage() {
echo "Usage: $0 [--cleanup | <commit-or-tag>]"
echo " --cleanup: Cleans up previous modifications made by the script."
echo " <commit-or-tag>: Sets up or updates the KernelSU to specified tag or commit."
echo " -h, --help: Displays this usage information."
echo " (no args): Sets up or updates the KernelSU environment to the latest tagged version."
}
echo "[+] GKI_ROOT: $GKI_ROOT"
initialize_variables() {
if test -d "$GKI_ROOT/common/drivers"; then
DRIVER_DIR="$GKI_ROOT/common/drivers"
elif test -d "$GKI_ROOT/drivers"; then
DRIVER_DIR="$GKI_ROOT/drivers"
else
echo '[ERROR] "drivers/" directory not found.'
exit 127
fi
DRIVER_MAKEFILE=$DRIVER_DIR/Makefile
DRIVER_KCONFIG=$DRIVER_DIR/Kconfig
}
# Reverts modifications made by this script
perform_cleanup() {
echo "[+] Cleaning up..."
[ -L "$DRIVER_DIR/kernelsu" ] && rm "$DRIVER_DIR/kernelsu" && echo "[-] Symlink removed."
grep -q "kernelsu" "$DRIVER_MAKEFILE" && sed -i '/kernelsu/d' "$DRIVER_MAKEFILE" && echo "[-] Makefile reverted."
grep -q "drivers/kernelsu/Kconfig" "$DRIVER_KCONFIG" && sed -i '/drivers\/kernelsu\/Kconfig/d' "$DRIVER_KCONFIG" && echo "[-] Kconfig reverted."
if [ -d "$GKI_ROOT/KernelSU" ]; then
rm -rf "$GKI_ROOT/KernelSU" && echo "[-] KernelSU directory deleted."
fi
}
# Sets up or update KernelSU environment
setup_kernelsu() {
echo "[+] Setting up KernelSU..."
test -d "$GKI_ROOT/KernelSU" || git clone https://github.com/tiann/KernelSU && echo "[+] Repository cloned."
cd "$GKI_ROOT/KernelSU"
git stash && echo "[-] Stashed current changes."
if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then
git checkout main && echo "[-] Switched to main branch."
fi
git pull && echo "[+] Repository updated."
if [ -z "${1-}" ]; then
git checkout "$(git describe --abbrev=0 --tags)" && echo "[-] Checked out latest tag."
else
git checkout "$1" && echo "[-] Checked out $1." || echo "[-] Checkout default branch"
fi
cd "$DRIVER_DIR"
ln -sf "$(realpath --relative-to="$DRIVER_DIR" "$GKI_ROOT/KernelSU/kernel")" "kernelsu" && echo "[+] Symlink created."
# Add entries in Makefile and Kconfig if not already existing
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "\nobj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE" && echo "[+] Modified Makefile."
grep -q "source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG" && echo "[+] Modified Kconfig."
echo '[+] Done.'
}
# Process command-line arguments
if [ "$#" -eq 0 ]; then
initialize_variables
setup_kernelsu
elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
display_usage
elif [ "$1" = "--cleanup" ]; then
initialize_variables
perform_cleanup
if test -d "$GKI_ROOT/common/drivers"; then
DRIVER_DIR="$GKI_ROOT/common/drivers"
elif test -d "$GKI_ROOT/drivers"; then
DRIVER_DIR="$GKI_ROOT/drivers"
else
initialize_variables
setup_kernelsu "$@"
echo '[ERROR] "drivers/" directory is not found.'
echo '[+] You should modify this script by yourself.'
exit 127
fi
test -d "$GKI_ROOT/KernelSU" || git clone https://github.com/tiann/KernelSU
cd "$GKI_ROOT/KernelSU"
git stash
if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then
git checkout main
fi
git pull
if [ -z "${1-}" ]; then
git checkout "$(git describe --abbrev=0 --tags)"
else
git checkout "$1"
fi
cd "$GKI_ROOT"
echo "[+] GKI_ROOT: $GKI_ROOT"
echo "[+] Copy kernel su driver to $DRIVER_DIR"
cd "$DRIVER_DIR"
if test -d "$GKI_ROOT/common/drivers"; then
ln -sf "../../KernelSU/kernel" "kernelsu"
elif test -d "$GKI_ROOT/drivers"; then
ln -sf "../KernelSU/kernel" "kernelsu"
fi
cd "$GKI_ROOT"
echo '[+] Add kernel su driver to Makefile'
DRIVER_MAKEFILE=$DRIVER_DIR/Makefile
DRIVER_KCONFIG=$DRIVER_DIR/Kconfig
grep -q "kernelsu" "$DRIVER_MAKEFILE" || printf "obj-\$(CONFIG_KSU) += kernelsu/\n" >> "$DRIVER_MAKEFILE"
grep -q "kernelsu" "$DRIVER_KCONFIG" || sed -i "/endmenu/i\\source \"drivers/kernelsu/Kconfig\"" "$DRIVER_KCONFIG"
echo '[+] Done.'

View File

@@ -1,16 +1,17 @@
#include <linux/dcache.h>
#include <linux/security.h>
#include <asm/current.h>
#include <linux/cred.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/kprobes.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/sched/task_stack.h>
#include "asm/current.h"
#include "linux/cred.h"
#include "linux/err.h"
#include "linux/fs.h"
#include "linux/kprobes.h"
#include "linux/types.h"
#include "linux/uaccess.h"
#include "linux/version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#include "linux/sched/task_stack.h"
#else
#include "linux/sched.h"
#endif
#include "objsec.h"
#include "allowlist.h"
#include "arch.h"
#include "klog.h" // IWYU pragma: keep
@@ -38,15 +39,8 @@ static char __user *sh_user_path(void)
return userspace_stack_buffer(sh_path, sizeof(sh_path));
}
static char __user *ksud_user_path(void)
{
static const char ksud_path[] = KSUD_PATH;
return userspace_stack_buffer(ksud_path, sizeof(ksud_path));
}
int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode,
int *__unused_flags)
int *flags)
{
const char su[] = SU_PATH;
@@ -81,12 +75,11 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
char path[sizeof(su) + 1];
memset(path, 0, sizeof(path));
// Remove this later!! we use syscall hook, so this will never happen!!!!!
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0) && 0
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
// it becomes a `struct filename *` after 5.18
// https://elixir.bootlin.com/linux/v5.18/source/fs/stat.c#L216
const char sh[] = SH_PATH;
struct filename *filename = *((struct filename **)filename_user);
struct filename *filename = * ((struct filename **) filename_user);
if (IS_ERR(filename)) {
return 0;
}
@@ -108,8 +101,7 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
// the call from execve_handler_pre won't provided correct value for __never_use_argument, use them after fix execve_handler_pre, keeping them for consistence for manually patched code
int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
void *__never_use_argv, void *__never_use_envp,
int *__never_use_flags)
void *__never_use_argv, void *__never_use_envp, int *__never_use_flags)
{
struct filename *filename;
const char sh[] = KSUD_PATH;
@@ -137,150 +129,85 @@ int ksu_handle_execveat_sucompat(int *fd, struct filename **filename_ptr,
return 0;
}
int ksu_handle_execve_sucompat(int *fd, const char __user **filename_user,
void *__never_use_argv, void *__never_use_envp,
int *__never_use_flags)
{
const char su[] = SU_PATH;
char path[sizeof(su) + 1];
if (unlikely(!filename_user))
return 0;
memset(path, 0, sizeof(path));
ksu_strncpy_from_user_nofault(path, *filename_user, sizeof(path));
if (likely(memcmp(path, su, sizeof(su))))
return 0;
if (!ksu_is_allow_uid(current_uid().val))
return 0;
pr_info("sys_execve su found\n");
*filename_user = ksud_user_path();
escape_to_root();
return 0;
}
int ksu_handle_devpts(struct inode *inode)
{
if (!current->mm) {
return 0;
}
uid_t uid = current_uid().val;
if (uid % 100000 < 10000) {
// not untrusted_app, ignore it
return 0;
}
if (!ksu_is_allow_uid(uid))
return 0;
if (ksu_devpts_sid) {
struct inode_security_struct *sec = selinux_inode(inode);
if (sec) {
sec->sid = ksu_devpts_sid;
}
}
return 0;
}
#ifdef CONFIG_KPROBES
static int faccessat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
const char __user **filename_user =
(const char **)&PT_REGS_PARM2(real_regs);
int *mode = (int *)&PT_REGS_PARM3(real_regs);
int *dfd = (int *)PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
int *mode = (int *)&PT_REGS_PARM3(regs);
// Both sys_ and do_ is C function
int *flags = (int *)&PT_REGS_CCALL_PARM4(regs);
return ksu_handle_faccessat(dfd, filename_user, mode, NULL);
return ksu_handle_faccessat(dfd, filename_user, mode, flags);
}
static int newfstatat_handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
int *dfd = (int *)&PT_REGS_PARM1(real_regs);
const char __user **filename_user =
(const char **)&PT_REGS_PARM2(real_regs);
int *flags = (int *)&PT_REGS_SYSCALL_PARM4(real_regs);
int *dfd = (int *)&PT_REGS_PARM1(regs);
const char __user **filename_user = (const char **)&PT_REGS_PARM2(regs);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
// static int vfs_statx(int dfd, const char __user *filename, int flags, struct kstat *stat, u32 request_mask)
int *flags = (int *)&PT_REGS_PARM3(regs);
#else
// int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,int flag)
int *flags = (int *)&PT_REGS_CCALL_PARM4(regs);
#endif
return ksu_handle_stat(dfd, filename_user, flags);
}
// 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)
{
struct pt_regs *real_regs = PT_REAL_REGS(regs);
const char __user **filename_user =
(const char **)&PT_REGS_PARM1(real_regs);
int *fd = (int *)&PT_REGS_PARM1(regs);
struct filename **filename_ptr =
(struct filename **)&PT_REGS_PARM2(regs);
return ksu_handle_execve_sucompat(AT_FDCWD, filename_user, NULL, NULL,
NULL);
return ksu_handle_execveat_sucompat(fd, filename_ptr, NULL, NULL, NULL);
}
static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
{
struct inode *inode;
struct file *file = (struct file *)PT_REGS_PARM2(regs);
inode = file->f_path.dentry->d_inode;
static struct kprobe faccessat_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
.symbol_name = "do_faccessat",
#else
.symbol_name = "sys_faccessat",
#endif
.pre_handler = faccessat_handler_pre,
};
return ksu_handle_devpts(inode);
}
static struct kprobe newfstatat_kp = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
.symbol_name = "vfs_statx",
#else
.symbol_name = "vfs_fstatat",
#endif
.pre_handler = newfstatat_handler_pre,
};
static struct kprobe *init_kprobe(const char *name,
kprobe_pre_handler_t handler)
{
struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
if (!kp)
return NULL;
kp->symbol_name = name;
kp->pre_handler = handler;
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,
};
int ret = register_kprobe(kp);
pr_info("sucompat: register_%s kprobe: %d\n", name, ret);
if (ret) {
kfree(kp);
return NULL;
}
return kp;
}
static void destroy_kprobe(struct kprobe **kp_ptr)
{
struct kprobe *kp = *kp_ptr;
if (!kp)
return;
unregister_kprobe(kp);
synchronize_rcu();
kfree(kp);
*kp_ptr = NULL;
}
static struct kprobe *su_kps[4];
#endif
// sucompat: permited process can execute 'su' to gain root access.
void ksu_sucompat_init()
void ksu_enable_sucompat()
{
#ifdef CONFIG_KPROBES
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre);
su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre);
su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre);
#endif
}
void ksu_sucompat_exit()
{
#ifdef CONFIG_KPROBES
for (int i = 0; i < ARRAY_SIZE(su_kps); i++) {
destroy_kprobe(&su_kps[i]);
}
int ret;
ret = register_kprobe(&execve_kp);
pr_info("sucompat: execve_kp: %d\n", ret);
ret = register_kprobe(&newfstatat_kp);
pr_info("sucompat: newfstatat_kp: %d\n", ret);
ret = register_kprobe(&faccessat_kp);
pr_info("sucompat: faccessat_kp: %d\n", ret);
#endif
}

View File

@@ -1,405 +0,0 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/version.h>
#include "allowlist.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "manager.h"
#include "throne_tracker.h"
#include "kernel_compat.h"
uid_t ksu_manager_uid = KSU_INVALID_UID;
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list.tmp"
struct uid_data {
struct list_head list;
u32 uid;
char package[KSU_MAX_PACKAGE_NAME];
};
static int get_pkg_from_apk_path(char *pkg, const char *path)
{
int len = strlen(path);
if (len >= KSU_MAX_PACKAGE_NAME || len < 1)
return -1;
const char *last_slash = NULL;
const char *second_last_slash = NULL;
int i;
for (i = len - 1; i >= 0; i--) {
if (path[i] == '/') {
if (!last_slash) {
last_slash = &path[i];
} else {
second_last_slash = &path[i];
break;
}
}
}
if (!last_slash || !second_last_slash)
return -1;
const char *last_hyphen = strchr(second_last_slash, '-');
if (!last_hyphen || last_hyphen > last_slash)
return -1;
int pkg_len = last_hyphen - second_last_slash - 1;
if (pkg_len >= KSU_MAX_PACKAGE_NAME || pkg_len <= 0)
return -1;
// Copying the package name
strncpy(pkg, second_last_slash + 1, pkg_len);
pkg[pkg_len] = '\0';
return 0;
}
static void crown_manager(const char *apk, struct list_head *uid_data)
{
char pkg[KSU_MAX_PACKAGE_NAME];
if (get_pkg_from_apk_path(pkg, apk) < 0) {
pr_err("Failed to get package name from apk path: %s\n", apk);
return;
}
pr_info("manager pkg: %s\n", pkg);
#ifdef KSU_MANAGER_PACKAGE
// pkg is `/<real package>`
if (strncmp(pkg, KSU_MANAGER_PACKAGE, sizeof(KSU_MANAGER_PACKAGE))) {
pr_info("manager package is inconsistent with kernel build: %s\n",
KSU_MANAGER_PACKAGE);
return;
}
#endif
struct list_head *list = (struct list_head *)uid_data;
struct uid_data *np;
list_for_each_entry (np, list, list) {
if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) {
pr_info("Crowning manager: %s(uid=%d)\n", pkg, np->uid);
ksu_set_manager_uid(np->uid);
break;
}
}
}
#define DATA_PATH_LEN 384 // 384 is enough for /data/app/<package>/base.apk
struct data_path {
char dirpath[DATA_PATH_LEN];
int depth;
struct list_head list;
};
struct apk_path_hash {
unsigned int hash;
bool exists;
struct list_head list;
};
static struct list_head apk_path_hash_list = LIST_HEAD_INIT(apk_path_hash_list);
struct my_dir_context {
struct dir_context ctx;
struct list_head *data_path_list;
char *parent_dir;
void *private_data;
int depth;
int *stop;
};
// https://docs.kernel.org/filesystems/porting.html
// filldir_t (readdir callbacks) calling conventions have changed. Instead of returning 0 or -E... it returns bool now. false means "no more" (as -E... used to) and true - "keep going" (as 0 in old calling conventions). Rationale: callers never looked at specific -E... values anyway. -> iterate_shared() instances require no changes at all, all filldir_t ones in the tree converted.
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
#define FILLDIR_RETURN_TYPE bool
#define FILLDIR_ACTOR_CONTINUE true
#define FILLDIR_ACTOR_STOP false
#else
#define FILLDIR_RETURN_TYPE int
#define FILLDIR_ACTOR_CONTINUE 0
#define FILLDIR_ACTOR_STOP -EINVAL
#endif
FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
int namelen, loff_t off, u64 ino,
unsigned int d_type)
{
struct my_dir_context *my_ctx =
container_of(ctx, struct my_dir_context, ctx);
char dirpath[DATA_PATH_LEN];
if (!my_ctx) {
pr_err("Invalid context\n");
return FILLDIR_ACTOR_STOP;
}
if (my_ctx->stop && *my_ctx->stop) {
pr_info("Stop searching\n");
return FILLDIR_ACTOR_STOP;
}
if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen))
return FILLDIR_ACTOR_CONTINUE; // Skip "." and ".."
if (d_type == DT_DIR && namelen >= 8 && !strncmp(name, "vmdl", 4) &&
!strncmp(name + namelen - 4, ".tmp", 4)) {
pr_info("Skipping directory: %.*s\n", namelen, name);
return FILLDIR_ACTOR_CONTINUE; // Skip staging package
}
if (snprintf(dirpath, DATA_PATH_LEN, "%s/%.*s", my_ctx->parent_dir,
namelen, name) >= DATA_PATH_LEN) {
pr_err("Path too long: %s/%.*s\n", my_ctx->parent_dir, namelen,
name);
return FILLDIR_ACTOR_CONTINUE;
}
if (d_type == DT_DIR && my_ctx->depth > 0 &&
(my_ctx->stop && !*my_ctx->stop)) {
struct data_path *data = kmalloc(sizeof(struct data_path), GFP_ATOMIC);
if (!data) {
pr_err("Failed to allocate memory for %s\n", dirpath);
return FILLDIR_ACTOR_CONTINUE;
}
strscpy(data->dirpath, dirpath, DATA_PATH_LEN);
data->depth = my_ctx->depth - 1;
list_add_tail(&data->list, my_ctx->data_path_list);
} else {
if ((namelen == 8) && (strncmp(name, "base.apk", namelen) == 0)) {
struct apk_path_hash *pos, *n;
unsigned int hash = full_name_hash(NULL, dirpath, strlen(dirpath));
list_for_each_entry(pos, &apk_path_hash_list, list) {
if (hash == pos->hash) {
pos->exists = true;
return FILLDIR_ACTOR_CONTINUE;
}
}
bool is_manager = is_manager_apk(dirpath);
pr_info("Found new base.apk at path: %s, is_manager: %d\n",
dirpath, is_manager);
if (is_manager) {
crown_manager(dirpath, my_ctx->private_data);
*my_ctx->stop = 1;
// Manager found, clear APK cache list
list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) {
list_del(&pos->list);
kfree(pos);
}
} else {
struct apk_path_hash *apk_data = kmalloc(sizeof(struct apk_path_hash), GFP_ATOMIC);
apk_data->hash = hash;
apk_data->exists = true;
list_add_tail(&apk_data->list, &apk_path_hash_list);
}
}
}
return FILLDIR_ACTOR_CONTINUE;
}
void search_manager(const char *path, int depth, struct list_head *uid_data)
{
int i, stop = 0;
struct list_head data_path_list;
INIT_LIST_HEAD(&data_path_list);
unsigned long data_app_magic = 0;
// Initialize APK cache list
struct apk_path_hash *pos, *n;
list_for_each_entry(pos, &apk_path_hash_list, list) {
pos->exists = false;
}
// First depth
struct data_path data;
strscpy(data.dirpath, path, DATA_PATH_LEN);
data.depth = depth;
list_add_tail(&data.list, &data_path_list);
for (i = depth; i >= 0; i--) {
struct data_path *pos, *n;
list_for_each_entry_safe(pos, n, &data_path_list, list) {
struct my_dir_context ctx = { .ctx.actor = my_actor,
.data_path_list = &data_path_list,
.parent_dir = pos->dirpath,
.private_data = uid_data,
.depth = pos->depth,
.stop = &stop };
struct file *file;
if (!stop) {
file = ksu_filp_open_compat(pos->dirpath, O_RDONLY | O_NOFOLLOW, 0);
if (IS_ERR(file)) {
pr_err("Failed to open directory: %s, err: %ld\n", pos->dirpath, PTR_ERR(file));
goto skip_iterate;
}
// grab magic on first folder, which is /data/app
if (!data_app_magic) {
if (file->f_inode->i_sb->s_magic) {
data_app_magic = file->f_inode->i_sb->s_magic;
pr_info("%s: dir: %s got magic! 0x%lx\n", __func__, pos->dirpath, data_app_magic);
} else {
filp_close(file, NULL);
goto skip_iterate;
}
}
if (file->f_inode->i_sb->s_magic != data_app_magic) {
pr_info("%s: skip: %s magic: 0x%lx expected: 0x%lx\n", __func__, pos->dirpath,
file->f_inode->i_sb->s_magic, data_app_magic);
filp_close(file, NULL);
goto skip_iterate;
}
iterate_dir(file, &ctx.ctx);
filp_close(file, NULL);
}
skip_iterate:
list_del(&pos->list);
if (pos != &data)
kfree(pos);
}
}
// Remove stale cached APK entries
list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) {
if (!pos->exists) {
list_del(&pos->list);
kfree(pos);
}
}
}
static bool is_uid_exist(uid_t uid, char *package, void *data)
{
struct list_head *list = (struct list_head *)data;
struct uid_data *np;
bool exist = false;
list_for_each_entry (np, list, list) {
if (np->uid == uid % 100000 &&
strncmp(np->package, package, KSU_MAX_PACKAGE_NAME) == 0) {
exist = true;
break;
}
}
return exist;
}
void track_throne()
{
struct file *fp =
ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n",
__func__, PTR_ERR(fp));
return;
}
struct list_head uid_list;
INIT_LIST_HEAD(&uid_list);
char chr = 0;
loff_t pos = 0;
loff_t line_start = 0;
char buf[KSU_MAX_PACKAGE_NAME];
for (;;) {
ssize_t count =
ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos);
if (count != sizeof(chr))
break;
if (chr != '\n')
continue;
count = ksu_kernel_read_compat(fp, buf, sizeof(buf),
&line_start);
struct uid_data *data =
kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
if (!data) {
filp_close(fp, 0);
goto out;
}
char *tmp = buf;
const char *delim = " ";
char *package = strsep(&tmp, delim);
char *uid = strsep(&tmp, delim);
if (!uid || !package) {
pr_err("update_uid: package or uid is NULL!\n");
break;
}
u32 res;
if (kstrtou32(uid, 10, &res)) {
pr_err("update_uid: uid parse err\n");
break;
}
data->uid = res;
strncpy(data->package, package, KSU_MAX_PACKAGE_NAME);
list_add_tail(&data->list, &uid_list);
// reset line start
line_start = pos;
}
filp_close(fp, 0);
// now update uid list
struct uid_data *np;
struct uid_data *n;
// first, check if manager_uid exist!
bool manager_exist = false;
list_for_each_entry (np, &uid_list, list) {
// if manager is installed in work profile, the uid in packages.list is still equals main profile
// don't delete it in this case!
int manager_uid = ksu_get_manager_uid() % 100000;
if (np->uid == manager_uid) {
manager_exist = true;
break;
}
}
if (!manager_exist) {
if (ksu_is_manager_uid_valid()) {
pr_info("manager is uninstalled, invalidate it!\n");
ksu_invalidate_manager_uid();
goto prune;
}
pr_info("Searching manager...\n");
search_manager("/data/app", 2, &uid_list);
pr_info("Search manager finished\n");
}
prune:
// then prune the allowlist
ksu_prune_allowlist(is_uid_exist, &uid_list);
out:
// free uid_list
list_for_each_entry_safe (np, n, &uid_list, list) {
list_del(&np->list);
kfree(np);
}
}
void ksu_throne_tracker_init()
{
// nothing to do
}
void ksu_throne_tracker_exit()
{
// nothing to do
}

View File

@@ -1,10 +0,0 @@
#ifndef __KSU_H_UID_OBSERVER
#define __KSU_H_UID_OBSERVER
void ksu_throne_tracker_init();
void ksu_throne_tracker_exit();
void track_throne();
#endif

144
kernel/uid_observer.c Normal file
View File

@@ -0,0 +1,144 @@
#include "linux/err.h"
#include "linux/fs.h"
#include "linux/list.h"
#include "linux/slab.h"
#include "linux/string.h"
#include "linux/types.h"
#include "linux/version.h"
#include "linux/workqueue.h"
#include "allowlist.h"
#include "klog.h" // IWYU pragma: keep
#include "ksu.h"
#include "manager.h"
#include "uid_observer.h"
#include "kernel_compat.h"
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
static struct work_struct ksu_update_uid_work;
struct uid_data {
struct list_head list;
u32 uid;
char package[KSU_MAX_PACKAGE_NAME];
};
static bool is_uid_exist(uid_t uid, char *package, void *data)
{
struct list_head *list = (struct list_head *)data;
struct uid_data *np;
bool exist = false;
list_for_each_entry (np, list, list) {
if (np->uid == uid % 100000 &&
strncmp(np->package, package, KSU_MAX_PACKAGE_NAME) == 0) {
exist = true;
break;
}
}
return exist;
}
static void do_update_uid(struct work_struct *work)
{
struct file *fp =
ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
if (IS_ERR(fp)) {
pr_err("do_update_uid, open " SYSTEM_PACKAGES_LIST_PATH
" failed: %ld\n",
PTR_ERR(fp));
return;
}
struct list_head uid_list;
INIT_LIST_HEAD(&uid_list);
char chr = 0;
loff_t pos = 0;
loff_t line_start = 0;
char buf[128];
for (;;) {
ssize_t count =
ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos);
if (count != sizeof(chr))
break;
if (chr != '\n')
continue;
count = ksu_kernel_read_compat(fp, buf, sizeof(buf),
&line_start);
struct uid_data *data =
kmalloc(sizeof(struct uid_data), GFP_ATOMIC);
if (!data) {
goto out;
}
char *tmp = buf;
const char *delim = " ";
char *package = strsep(&tmp, delim);
char *uid = strsep(&tmp, delim);
if (!uid || !package) {
pr_err("update_uid: package or uid is NULL!\n");
continue;
}
u32 res;
if (kstrtou32(uid, 10, &res)) {
pr_err("update_uid: uid parse err\n");
continue;
}
data->uid = res;
strncpy(data->package, package, KSU_MAX_PACKAGE_NAME);
list_add_tail(&data->list, &uid_list);
// reset line start
line_start = pos;
}
// now update uid list
struct uid_data *np;
struct uid_data *n;
// first, check if manager_uid exist!
bool manager_exist = false;
list_for_each_entry (np, &uid_list, list) {
// if manager is installed in work profile, the uid in packages.list is still equals main profile
// don't delete it in this case!
int manager_uid = ksu_get_manager_uid() % 100000;
if (np->uid == manager_uid) {
manager_exist = true;
break;
}
}
if (!manager_exist && ksu_is_manager_uid_valid()) {
pr_info("manager is uninstalled, invalidate it!\n");
ksu_invalidate_manager_uid();
}
// then prune the allowlist
ksu_prune_allowlist(is_uid_exist, &uid_list);
out:
// free uid_list
list_for_each_entry_safe (np, n, &uid_list, list) {
list_del(&np->list);
kfree(np);
}
filp_close(fp, 0);
}
void update_uid()
{
ksu_queue_work(&ksu_update_uid_work);
}
int ksu_uid_observer_init()
{
INIT_WORK(&ksu_update_uid_work, do_update_uid);
return 0;
}
int ksu_uid_observer_exit()
{
return 0;
}

10
kernel/uid_observer.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef __KSU_H_UID_OBSERVER
#define __KSU_H_UID_OBSERVER
int ksu_uid_observer_init();
int ksu_uid_observer_exit();
void update_uid();
#endif

3
manager/.gitignore vendored
View File

@@ -1,10 +1,9 @@
*.iml
.gradle
local.properties
.idea
.kotlin
.DS_Store
build
captures
.cxx
local.properties
key.jks

View File

@@ -1,12 +1,8 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
import com.android.build.gradle.tasks.PackageAndroidArtifact
plugins {
alias(libs.plugins.agp.app)
alias(libs.plugins.kotlin)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.ksp)
alias(libs.plugins.lsplugin.apksign)
id("kotlin-parcelize")
@@ -37,11 +33,14 @@ android {
aidl = true
buildConfig = true
compose = true
prefab = true
}
kotlinOptions {
jvmTarget = "21"
jvmTarget = "17"
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
@@ -49,13 +48,7 @@ android {
useLegacyPackaging = true
}
resources {
// https://stackoverflow.com/a/58956288
// It will break Layout Inspector, but it's unused for release build.
excludes += "META-INF/*.version"
// https://github.com/Kotlin/kotlinx.coroutines?tab=readme-ov-file#avoiding-including-the-debug-infrastructure-in-the-resulting-apk
excludes += "DebugProbesKt.bin"
// https://issueantenna.com/repo/kotlin/kotlinx.coroutines/issues/3158
excludes += "kotlin-tooling-metadata.json"
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
@@ -70,30 +63,13 @@ android {
val output = it as BaseVariantOutputImpl
output.outputFileName = "KernelSU_${managerVersionName}_${managerVersionCode}-$name.apk"
}
kotlin.sourceSets {
getByName(name) {
kotlin.srcDir("build/generated/ksp/$name/kotlin")
}
}
}
// https://stackoverflow.com/a/77745844
tasks.withType<PackageAndroidArtifact> {
doFirst { appMetadata.asFile.orNull?.writeText("") }
}
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
androidResources {
generateLocaleConfig = true
}
}
ksp {
arg("compose-destinations.defaultTransitions", "none")
}
dependencies {
@@ -114,12 +90,15 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.compose.destinations.core)
implementation(libs.com.google.accompanist.drawablepainter)
implementation(libs.com.google.accompanist.navigation.animation)
implementation(libs.com.google.accompanist.systemuicontroller)
implementation(libs.compose.destinations.animations.core)
ksp(libs.compose.destinations.ksp)
implementation(libs.com.github.topjohnwu.libsu.core)
implementation(libs.com.github.topjohnwu.libsu.service)
implementation(libs.com.github.topjohnwu.libsu.io)
implementation(libs.dev.rikka.rikkax.parcelablelist)
@@ -134,7 +113,4 @@ dependencies {
implementation(libs.sheet.compose.dialogs.input)
implementation(libs.markdown)
implementation(libs.androidx.webkit)
implementation(libs.lsposed.cxx)
}
}

View File

@@ -0,0 +1,9 @@
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt$Version
-dontwarn org.conscrypt.Conscrypt
-dontwarn org.conscrypt.ConscryptHostnameVerifier
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE

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