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; +}