diff --git a/.github/workflows/build-manager.yml b/.github/workflows/build-manager.yml
index 10953eff..9b1afb4a 100644
--- a/.github/workflows/build-manager.yml
+++ b/.github/workflows/build-manager.yml
@@ -9,6 +9,7 @@ on:
- 'kernel/**'
- 'userspace/ksud_overlayfs**'
- 'userspace/ksud_magic/**'
+ - 'userspace/susfsd/**'
pull_request:
branches: [ "next" ]
paths:
@@ -21,8 +22,20 @@ jobs:
uses: ./.github/workflows/build-lkm.yml
secrets: inherit
- build-ksud_overlayfs:
+ build-susfsd:
needs: build-lkm
+ strategy:
+ matrix:
+ include:
+ - target: aarch64-linux-android
+ os: ubuntu-latest
+ uses: ./.github/workflows/susfsd.yml
+ with:
+ target: ${{ matrix.target }}
+ os: ${{ matrix.os }}
+
+ build-ksud_overlayfs:
+ needs: build-susfsd
strategy:
matrix:
include:
diff --git a/.github/workflows/ksud_magic.yml b/.github/workflows/ksud_magic.yml
index 9196e16f..7c76fadf 100644
--- a/.github/workflows/ksud_magic.yml
+++ b/.github/workflows/ksud_magic.yml
@@ -32,6 +32,10 @@ jobs:
if: ${{ inputs.pack_lkm }}
run: |
cp android*-lkm/*_kernelsu.ko ./userspace/ksud_magic/bin/aarch64/
+
+ - name: Import susfsd lib
+ run: |
+ cp susfsd-aarch64-linux-android/arm64-v8a/susfsd ./userspace/ksud_magic/bin/aarch64/
- name: Setup rustup
run: |
diff --git a/.github/workflows/ksud_overlayfs.yml b/.github/workflows/ksud_overlayfs.yml
index b3879e4f..2b24d907 100644
--- a/.github/workflows/ksud_overlayfs.yml
+++ b/.github/workflows/ksud_overlayfs.yml
@@ -32,6 +32,10 @@ jobs:
if: ${{ inputs.pack_lkm }}
run: |
cp android*-lkm/*_kernelsu.ko ./userspace/ksud_overlayfs/bin/aarch64/
+
+ - name: Import susfsd lib
+ run: |
+ cp susfsd-aarch64-linux-android/arm64-v8a/susfsd ./userspace/ksud_overlayfs/bin/aarch64/
- name: Setup rustup
run: |
diff --git a/.github/workflows/susfsd.yml b/.github/workflows/susfsd.yml
new file mode 100644
index 00000000..d63699a9
--- /dev/null
+++ b/.github/workflows/susfsd.yml
@@ -0,0 +1,34 @@
+name: Build susfsd
+on:
+ push:
+ branches: [ "next" ]
+ paths:
+ - '.github/workflows/susfsd.yml'
+ - 'userspace/susfsd/**'
+ workflow_dispatch:
+ workflow_call:
+ inputs:
+ target:
+ required: true
+ type: string
+ os:
+ required: false
+ type: string
+ default: ubuntu-latest
+jobs:
+ build-susfs:
+ name: Build userspace susfsd
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Build susfsd
+ working-directory: ./userspace/susfsd
+ run: $ANDROID_NDK/ndk-build
+ - name: Upload a Build Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: susfsd-aarch64-linux-android
+ path: ./userspace/susfsd/libs
+
diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Home.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Home.kt
index fe028ad4..af89e47c 100644
--- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Home.kt
+++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Home.kt
@@ -289,6 +289,14 @@ private fun StatusCard(
text = stringResource(R.string.home_module_count, getModuleCount()),
style = MaterialTheme.typography.bodyMedium
)
+ Spacer(Modifier.height(4.dp))
+ val suSFS = getSuSFS()
+ if (suSFS == "Supported") {
+ Text(
+ text = stringResource(R.string.home_susfs, getSuSFS()),
+ style = MaterialTheme.typography.bodyMedium
+ )
+ }
}
}
@@ -446,6 +454,18 @@ private fun InfoCard() {
},
icon = Icons.Filled.SettingsSuggest,
)
+ Spacer(Modifier.height(16.dp))
+ val isSUS_SU = getSuSFSFeatures() == "CONFIG_KSU_SUSFS_SUS_SU"
+ val suSFS = getSuSFS()
+
+ if (suSFS == "Supported") {
+ val susSUMode = if (isSUS_SU) "| SuS SU mode: ${susfsSUS_SU_Mode()}" else ""
+ InfoCardItem(
+ label = stringResource(R.string.home_susfs_version),
+ content = "${getSuSFSVersion()} (${getSuSFSVariant()}) $susSUMode",
+ icon = painterResource(R.drawable.ic_sus),
+ )
+ }
}
}
}
diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt
index 0a4dab4e..8c06eb8c 100644
--- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt
+++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/screen/Settings.kt
@@ -172,6 +172,32 @@ fun SettingScreen(navigator: DestinationsNavigator) {
val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
+ val isSUS_SU = getSuSFSFeatures()
+ if (isSUS_SU == "CONFIG_KSU_SUSFS_SUS_SU") {
+ var isEnabled by rememberSaveable {
+ mutableStateOf(susfsSUS_SU_Mode() == "2")
+ }
+
+ LaunchedEffect(Unit) {
+ isEnabled = susfsSUS_SU_Mode() == "2"
+ }
+
+ SwitchItem(
+ icon = Icons.Filled.VisibilityOff,
+ title = stringResource(id = R.string.settings_susfs_toggle),
+ summary = stringResource(id = R.string.settings_susfs_toggle_summary),
+ checked = isEnabled
+ ) {
+ if (it) {
+ susfsSUS_SU_2()
+ } else {
+ susfsSUS_SU_0()
+ }
+ prefs.edit().putBoolean("enable_sus_su", it).apply()
+ isEnabled = it
+ }
+ }
+
val hasShownWarning = rememberSaveable { mutableStateOf(prefs.getBoolean("has_shown_warning", false)) }
var useOverlayFs by rememberSaveable {
diff --git a/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt b/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt
index 737f09b0..a701c720 100644
--- a/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt
+++ b/manager/app/src/main/java/com/rifsxd/ksunext/ui/util/KsuCli.kt
@@ -503,6 +503,51 @@ fun moduleRestore(): Boolean {
return result.isEmpty()
}
+private fun getSuSFSDaemonPath(): String {
+ return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libsusfsd.so"
+}
+
+fun getSuSFS(): String {
+ val shell = getRootShell()
+ val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} support")
+ return result
+}
+
+fun getSuSFSVersion(): String {
+ val shell = getRootShell()
+ val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} version")
+ return result
+}
+
+fun getSuSFSVariant(): String {
+ val shell = getRootShell()
+ val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} variant")
+ return result
+}
+fun getSuSFSFeatures(): String {
+ val shell = getRootShell()
+ val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} features")
+ return result
+}
+
+fun susfsSUS_SU_0(): String {
+ val shell = getRootShell()
+ val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su 0")
+ return result
+}
+
+fun susfsSUS_SU_2(): String {
+ val shell = getRootShell()
+ val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su 2")
+ return result
+}
+
+fun susfsSUS_SU_Mode(): String {
+ val shell = getRootShell()
+ val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su mode")
+ return result
+}
+
fun setAppProfileTemplate(id: String, template: String): Boolean {
val shell = getRootShell()
val escapedTemplate = template.replace("\"", "\\\"")
diff --git a/manager/app/src/main/jniLibs/.gitignore b/manager/app/src/main/jniLibs/.gitignore
index a7a71352..27356efb 100644
--- a/manager/app/src/main/jniLibs/.gitignore
+++ b/manager/app/src/main/jniLibs/.gitignore
@@ -1,2 +1,3 @@
libksud_overlayfs.so
libksud_magic.so
+libsusfsd.so
\ No newline at end of file
diff --git a/manager/app/src/main/res/drawable/ic_sus.xml b/manager/app/src/main/res/drawable/ic_sus.xml
new file mode 100644
index 00000000..ea794670
--- /dev/null
+++ b/manager/app/src/main/res/drawable/ic_sus.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-in/strings.xml b/manager/app/src/main/res/values-in/strings.xml
index 25e8a06b..e534bb6e 100644
--- a/manager/app/src/main/res/values-in/strings.xml
+++ b/manager/app/src/main/res/values-in/strings.xml
@@ -92,6 +92,8 @@
Versi KernelSU-Next %d terlalu rendah agar manajer berfungsi normal. Harap membarui ke versi %d atau di atasnya!
Melepas Modul secara bawaan
Menggunakan \"Umount Modul\" secara universal pada Profil Aplikasi. Jika diaktifkan, akan menghapus semua modifikasi sistem untuk aplikasi yang tidak memiliki set profil.
+ Sembunyikan hook kprobe
+ Ini menonaktifkan hook kprobe yang dibuat oleh ksu, dan sebagai gantinya, hook inline non-kprobe akan diaktifkan, sama seperti implementasi untuk kernel non-gki yang tidak mendukung kprobe.
Aktifkan opsi ini agar KernelSU dapat memulihkan kembali berkas termodifikasi oleh modul pada aplikasi ini.
Domain
Aturan
diff --git a/manager/app/src/main/res/values-ko/strings.xml b/manager/app/src/main/res/values-ko/strings.xml
index 93722b74..fb3bf61b 100644
--- a/manager/app/src/main/res/values-ko/strings.xml
+++ b/manager/app/src/main/res/values-ko/strings.xml
@@ -101,6 +101,8 @@
현재 KernelSU Next 버전 %d이 너무 낮아 매니저가 올바르게 작동하기 어렵습니다. 버전 %d이상으로 업데이트해 주세요!
기본적으로 모듈 마운트 해제
앱 프로파일의 \"모듈 마운트 해제\" 옵션에 대한 전역 기본값입니다. 이 옵션이 활성화되면, 프로파일이 설정되어 있지 않은 앱들에 대한 모듈의 모든 수정사항을 복구합니다.
+ kprobe 훅 숨기기
+ 이 설정은 ksu가 만든 kprobe 훅을 비활성화하고 대신 비-kprobe 인라인 훅을 활성화합니다. 이는 kprobe가 지원되지 않는 non-gki 커널과 동일한 구현입니다.
이 옵션이 활성화되면, 이 앱에 대한 모듈의 모든 수정사항을 복구합니다.
도메인
규칙
diff --git a/manager/app/src/main/res/values-pt-rBR/strings.xml b/manager/app/src/main/res/values-pt-rBR/strings.xml
index 5803e3f3..73e33e03 100644
--- a/manager/app/src/main/res/values-pt-rBR/strings.xml
+++ b/manager/app/src/main/res/values-pt-rBR/strings.xml
@@ -106,6 +106,8 @@
A versão atual do KernelSU Next %d é muito baixa para o gerenciador funcionar corretamente. Por favor, atualize para a versão %d ou superior!
Desmontar módulos por padrão
O valor padrão global para \"Desmontar módulos\" em Perfil do Aplicativo. Se ativado, ele removerá todas as modificações do módulo no sistema para apps que não possuem um perfil definido.
+ Ocultar ganchos kprobe
+ Desativa os ganchos kprobe feitos pelo ksu e, em vez disso, os ganchos inline não-kprobe serão ativados, da mesma forma que em um kernel não-gki sem suporte a kprobe.
Ativar esta opção permitirá que o KernelSU Next restaure quaisquer arquivos modificados pelos módulos para este app.
Domínio
Regras
diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml
index 69be5686..9994f875 100644
--- a/manager/app/src/main/res/values-zh-rCN/strings.xml
+++ b/manager/app/src/main/res/values-zh-rCN/strings.xml
@@ -106,6 +106,8 @@
当前 KernelSU Next 版本 %d 过低,管理器无法正常工作,请升级内核 KernelSU Next 版本至 %d 或以上!
默认卸载模块
App Profile 中“卸载模块”的全局默认值,如果启用,将会为没有设置 Profile 的应用移除所有模块针对系统的修改。
+ 隐藏kprobe钩子
+ 它禁用由ksu创建的kprobe钩子,取而代之的是启用非kprobe内联钩子,类似于不支持kprobe的non-gki内核的实现。
启用后将允许 KernelSU Next 为本应用还原被模块修改过的文件。
域
规则
diff --git a/manager/app/src/main/res/values-zh-rTW/strings.xml b/manager/app/src/main/res/values-zh-rTW/strings.xml
index a864ee0e..c116ea30 100644
--- a/manager/app/src/main/res/values-zh-rTW/strings.xml
+++ b/manager/app/src/main/res/values-zh-rTW/strings.xml
@@ -106,6 +106,8 @@
當前 KernelSU-Next 版本 %d 過低,管理器無法正常工作,請升級內核 KernelSU-Next 版本至 %d 或以上!
預設卸載模組
App Profile 中"卸載模組"的全域預設值,如果啟用,將會為沒有設定 Profile 的應用移除所有模組針對系統的修改。
+ 隱藏kprobe鉤子
+ 它禁用由ksu所建立的kprobe鉤子,並啟用非kprobe內聯鉤子,就如同無法支援kprobe的non-gki核心的實現方式。
啟用後將允許 KernelSU-Next 為本應用還原被模組修改過的檔案。
域
規則
diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml
index 402a5c3b..fb727d62 100644
--- a/manager/app/src/main/res/values/strings.xml
+++ b/manager/app/src/main/res/values/strings.xml
@@ -19,6 +19,9 @@
KernelSU Next v2 signature not found in kernel! [ !KSU_NEXT || != size/hash ]
Ask your kernel developer to integrate KernelSU Next!
Kernel version
+ SuSFS: %s
+ SuSFS
+ SuS SU
Android version
Manager version
SELinux status
@@ -106,6 +109,8 @@
The current KernelSU Next version %d is too low for the manager to work properly. Please upgrade to version %d or higher!
Umount modules by default
The global default value for \"Umount modules\" in App Profile. If enabled, it will remove all module modifications to the system for apps that don\'t have a profile set.
+ Hide kprobe hooks
+ It disables kprobe hooks made by ksu, and instead the non-kprobe inline hooks will be enabled, just the same implementation for non-gki kernel without kprobe supported.
Enabling this option will allow KernelSU Next to restore any modified files by the modules for this app.
Domain
Rules
diff --git a/userspace/ksud_magic/bin/.gitignore b/userspace/ksud_magic/bin/.gitignore
index 1464b7ed..c8b95e0e 100644
--- a/userspace/ksud_magic/bin/.gitignore
+++ b/userspace/ksud_magic/bin/.gitignore
@@ -1 +1,2 @@
-**/*.ko
\ No newline at end of file
+**/*.ko
+susfsd
\ No newline at end of file
diff --git a/userspace/ksud_magic/src/assets.rs b/userspace/ksud_magic/src/assets.rs
index e8255c82..f7623bbe 100644
--- a/userspace/ksud_magic/src/assets.rs
+++ b/userspace/ksud_magic/src/assets.rs
@@ -8,6 +8,7 @@ use crate::{defs::BINARY_DIR, utils};
pub const RESETPROP_PATH: &str = concatcp!(BINARY_DIR, "resetprop");
pub const BUSYBOX_PATH: &str = concatcp!(BINARY_DIR, "busybox");
pub const BOOTCTL_PATH: &str = concatcp!(BINARY_DIR, "bootctl");
+pub const SUSFSD_PATH: &str = concatcp!(BINARY_DIR, "susfsd");
#[cfg(all(target_arch = "x86_64", target_os = "android"))]
#[derive(RustEmbed)]
diff --git a/userspace/ksud_overlayfs/bin/.gitignore b/userspace/ksud_overlayfs/bin/.gitignore
index 1464b7ed..c8b95e0e 100644
--- a/userspace/ksud_overlayfs/bin/.gitignore
+++ b/userspace/ksud_overlayfs/bin/.gitignore
@@ -1 +1,2 @@
-**/*.ko
\ No newline at end of file
+**/*.ko
+susfsd
\ No newline at end of file
diff --git a/userspace/ksud_overlayfs/bin/aarch64/busybox b/userspace/ksud_overlayfs/bin/aarch64/busybox
index 1ddf3f73..2fd8bcfa 100755
Binary files a/userspace/ksud_overlayfs/bin/aarch64/busybox and b/userspace/ksud_overlayfs/bin/aarch64/busybox differ
diff --git a/userspace/ksud_overlayfs/src/assets.rs b/userspace/ksud_overlayfs/src/assets.rs
index e8255c82..f7623bbe 100644
--- a/userspace/ksud_overlayfs/src/assets.rs
+++ b/userspace/ksud_overlayfs/src/assets.rs
@@ -8,6 +8,7 @@ use crate::{defs::BINARY_DIR, utils};
pub const RESETPROP_PATH: &str = concatcp!(BINARY_DIR, "resetprop");
pub const BUSYBOX_PATH: &str = concatcp!(BINARY_DIR, "busybox");
pub const BOOTCTL_PATH: &str = concatcp!(BINARY_DIR, "bootctl");
+pub const SUSFSD_PATH: &str = concatcp!(BINARY_DIR, "susfsd");
#[cfg(all(target_arch = "x86_64", target_os = "android"))]
#[derive(RustEmbed)]
diff --git a/userspace/susfsd/.gitignore b/userspace/susfsd/.gitignore
new file mode 100644
index 00000000..720289cc
--- /dev/null
+++ b/userspace/susfsd/.gitignore
@@ -0,0 +1,2 @@
+/obj
+/libs
diff --git a/userspace/susfsd/jni/Android.mk b/userspace/susfsd/jni/Android.mk
new file mode 100644
index 00000000..e805f0b4
--- /dev/null
+++ b/userspace/susfsd/jni/Android.mk
@@ -0,0 +1,6 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := susfsd
+LOCAL_SRC_FILES := susfsd.c
+include $(BUILD_EXECUTABLE)
diff --git a/userspace/susfsd/jni/Application.mk b/userspace/susfsd/jni/Application.mk
new file mode 100644
index 00000000..61d31236
--- /dev/null
+++ b/userspace/susfsd/jni/Application.mk
@@ -0,0 +1,3 @@
+APP_ABI := arm64-v8a
+APP_PLATFORM := android-24
+APP_STL := none
diff --git a/userspace/susfsd/jni/susfsd.c b/userspace/susfsd/jni/susfsd.c
new file mode 100644
index 00000000..61111f46
--- /dev/null
+++ b/userspace/susfsd/jni/susfsd.c
@@ -0,0 +1,239 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define KERNEL_SU_OPTION 0xDEADBEEF
+
+#define CMD_SUSFS_SHOW_VERSION 0x555e1
+#define CMD_SUSFS_SHOW_ENABLED_FEATURES 0x555e2
+#define CMD_SUSFS_SHOW_VARIANT 0x555e3
+#define CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE 0x555e4
+#define CMD_SUSFS_IS_SUS_SU_READY 0x555f0
+#define CMD_SUSFS_SUS_SU 0x60000
+
+#define SUS_SU_DISABLED 0
+#define SUS_SU_WITH_HOOKS 2
+
+struct st_sus_su {
+ int mode;
+};
+
+int enable_sus_su(int last_working_mode, int target_working_mode) {
+ struct st_sus_su info;
+ int error = -1;
+
+ if (target_working_mode == SUS_SU_WITH_HOOKS) {
+ info.mode = SUS_SU_WITH_HOOKS;
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_SUS_SU, &info, NULL, &error);
+ if (error) {
+ if (error == 1) {
+ } else if (error == 2) {
+ }
+ return error;
+ }
+ printf("[+] sus_su mode 2 is enabled\n");
+ } else if (target_working_mode == SUS_SU_DISABLED) {
+ info.mode = SUS_SU_DISABLED;
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_SUS_SU, &info, NULL, &error);
+ if (error) {
+ if (error == 1) {
+ }
+ return error;
+ }
+ printf("[+] sus_su mode 0 is enabled\n");
+ } else {
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ int error = -1;
+ char support[16];
+ char version[16];
+ char variant[16];
+
+
+
+ // Check for arguments
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s |>\n", argv[0]);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "version") == 0) {
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_SHOW_VERSION, version, NULL, &error);
+ if (!error) {
+ printf("%s\n", version);
+ } else {
+ printf("Invalid\n");
+ }
+ } else if (strcmp(argv[1], "variant") == 0) {
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_SHOW_VARIANT, variant, NULL, &error);
+ if (!error) {
+ printf("%s\n", variant);
+ } else {
+ printf("Invalid\n");
+ }
+ } else if (strcmp(argv[1], "features") == 0) {
+ char *enabled_features_buf = malloc(getpagesize() * 2);
+ char *ptr_buf;
+ unsigned long enabled_features;
+ int str_len;
+
+ if (!enabled_features_buf) {
+ perror("malloc");
+ return -ENOMEM;
+ }
+ ptr_buf = enabled_features_buf;
+
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_SHOW_ENABLED_FEATURES, &enabled_features, NULL, &error);
+ if (!error) {
+ if (enabled_features & (1 << 0)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_SUS_PATH\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SUS_PATH\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 1)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_SUS_MOUNT\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SUS_MOUNT\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 2)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_AUTO_ADD_SUS_KSU_DEFAULT_MOUNT\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 3)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_AUTO_ADD_SUS_BIND_MOUNT\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 4)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_SUS_KSTAT\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SUS_KSTAT\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 5)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_SUS_OVERLAYFS\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SUS_OVERLAYFS\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 6)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_TRY_UMOUNT\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_TRY_UMOUNT\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 7)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_AUTO_ADD_TRY_UMOUNT_FOR_BIND_MOUNT\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 8)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_SPOOF_UNAME\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SPOOF_UNAME\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 9)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_ENABLE_LOG\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_ENABLE_LOG\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 10)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_HIDE_KSU_SUSFS_SYMBOLS\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 11)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_SPOOF_BOOTCONFIG\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SPOOF_BOOTCONFIG\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 12)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_OPEN_REDIRECT\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_OPEN_REDIRECT\n", str_len);
+ ptr_buf += str_len;
+ }
+ if (enabled_features & (1 << 13)) {
+ str_len = strlen("CONFIG_KSU_SUSFS_SUS_SU\n");
+ strncpy(ptr_buf, "CONFIG_KSU_SUSFS_SUS_SU\n", str_len);
+ ptr_buf += str_len;
+ }
+ printf("%s", enabled_features_buf);
+ free(enabled_features_buf);
+ } else {
+ printf("Invalid\n");
+ }
+ } else if (strcmp(argv[1], "support") == 0) {
+ unsigned long enabled_features;
+ int any_feature_enabled = 0;
+
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_SHOW_ENABLED_FEATURES, &enabled_features, NULL, &error);
+ if (!error) {
+ if (enabled_features & ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) |
+ (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) |
+ (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) |
+ (1 << 12) | (1 << 13))) {
+ any_feature_enabled = 1;
+ }
+ if (any_feature_enabled) {
+ printf("Supported\n");
+ } else {
+ printf("Unsupported\n");
+ }
+ } else {
+ printf("Unsupported\n");
+ }
+ } else if (argc == 3 && !strcmp(argv[1], "sus_su")) {
+ int last_working_mode = 0;
+ int target_working_mode;
+ char* endptr;
+
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_SHOW_SUS_SU_WORKING_MODE, &last_working_mode, NULL, &error);
+ if (error)
+ return error;
+ if (!strcmp(argv[2], "mode")) {
+ printf("%d\n", last_working_mode);
+ return 0;
+ }
+ target_working_mode = strtol(argv[2], &endptr, 10);
+ if (*endptr != '\0') {
+ return 1;
+ }
+ if (target_working_mode == SUS_SU_WITH_HOOKS) {
+ bool is_sus_su_ready;
+ prctl(KERNEL_SU_OPTION, CMD_SUSFS_IS_SUS_SU_READY, &is_sus_su_ready, NULL, &error);
+ if (error)
+ return error;
+ if (!is_sus_su_ready) {
+ printf("[-] sus_su mode %d has to be run during or after service stage\n", SUS_SU_WITH_HOOKS);
+ return 1;
+ }
+ if (last_working_mode == SUS_SU_DISABLED) {
+ error = enable_sus_su(last_working_mode, SUS_SU_WITH_HOOKS);
+ } else if (last_working_mode == SUS_SU_WITH_HOOKS) {
+ printf("[-] sus_su is already in mode %d\n", last_working_mode);
+ return 1;
+ } else {
+ error = enable_sus_su(last_working_mode, SUS_SU_DISABLED);
+ if (!error)
+ error = enable_sus_su(last_working_mode, SUS_SU_WITH_HOOKS);
+ }
+ } else if (target_working_mode == SUS_SU_DISABLED) {
+ if (last_working_mode == SUS_SU_DISABLED) {
+ printf("[-] sus_su is already in mode %d\n", last_working_mode);
+ return 1;
+ }
+ error = enable_sus_su(last_working_mode, SUS_SU_DISABLED);
+ }
+ } else {
+ fprintf(stderr, "Invalid argument: %s\n", argv[1]);
+ return 1;
+ }
+
+ return 0;
+}