Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions manager/app/src/main/cpp/jni.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <jni.h>

#include <sys/prctl.h>
#include <linux/capability.h>

#include <android/log.h>
#include <cstring>
Expand Down Expand Up @@ -170,7 +171,7 @@ Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg,
env->SetBooleanField(obj, rootUseDefaultField, (jboolean) profile.rp_config.use_default);
if (strlen(profile.rp_config.template_name) > 0) {
env->SetObjectField(obj, rootTemplateField,
env->NewStringUTF(profile.rp_config.template_name));
env->NewStringUTF(profile.rp_config.template_name));
}

env->SetIntField(obj, uidField, profile.rp_config.profile.uid);
Expand All @@ -192,12 +193,12 @@ Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg,
}

env->SetObjectField(obj, domainField,
env->NewStringUTF(profile.rp_config.profile.selinux_domain));
env->NewStringUTF(profile.rp_config.profile.selinux_domain));
env->SetIntField(obj, namespacesField, profile.rp_config.profile.namespaces);
env->SetBooleanField(obj, allowSuField, profile.allow_su);
} else {
env->SetBooleanField(obj, nonRootUseDefaultField,
(jboolean) profile.nrp_config.use_default);
(jboolean) profile.nrp_config.use_default);
env->SetBooleanField(obj, umountModulesField, profile.nrp_config.profile.umount_modules);
}

Expand Down Expand Up @@ -305,3 +306,15 @@ JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_setSuEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
return set_su_enabled(enabled);
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_isKernelUmountEnabled(JNIEnv *env, jobject thiz) {
return is_kernel_umount_enabled();
}

extern "C"
JNIEXPORT jboolean JNICALL
Java_me_weishu_kernelsu_Natives_setKernelUmountEnabled(JNIEnv *env, jobject thiz, jboolean enabled) {
return set_kernel_umount_enabled(enabled);
}
52 changes: 48 additions & 4 deletions manager/app/src/main/cpp/ksu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <stdlib.h>

#include <unistd.h>
#include <limits.h>
#include <sys/syscall.h>
#include "ksu.h"

Expand Down Expand Up @@ -128,11 +129,54 @@ int get_app_profile(app_profile *profile) {
}

bool set_su_enabled(bool enabled) {
struct ksu_enable_su_cmd cmd = {.enable = enabled};
return ksuctl(KSU_IOCTL_ENABLE_SU, &cmd) == 0;
struct ksu_set_feature_cmd cmd = {};
cmd.feature_id = KSU_FEATURE_SU_COMPAT;
cmd.value = enabled ? 1 : 0;
return ksuctl(KSU_IOCTL_SET_FEATURE, &cmd) == 0;
}

bool is_su_enabled() {
struct ksu_is_su_enabled_cmd cmd = {};
return ksuctl(KSU_IOCTL_IS_SU_ENABLED, &cmd) == 0 && cmd.enabled;
struct ksu_get_feature_cmd cmd = {};
cmd.feature_id = KSU_FEATURE_SU_COMPAT;
if (ksuctl(KSU_IOCTL_GET_FEATURE, &cmd) != 0) {
return false;
}
if (!cmd.supported) {
return false;
}
return cmd.value != 0;
}

static inline bool get_feature(uint32_t feature_id, uint64_t *out_value, bool *out_supported) {
struct ksu_get_feature_cmd cmd = {};
cmd.feature_id = feature_id;
if (ksuctl(KSU_IOCTL_GET_FEATURE, &cmd) != 0) {
return false;
}
if (out_value) *out_value = cmd.value;
if (out_supported) *out_supported = cmd.supported;
return true;
}

static inline bool set_feature(uint32_t feature_id, uint64_t value) {
struct ksu_set_feature_cmd cmd = {};
cmd.feature_id = feature_id;
cmd.value = value;
return ksuctl(KSU_IOCTL_SET_FEATURE, &cmd) == 0;
}

bool set_kernel_umount_enabled(bool enabled) {
return set_feature(KSU_FEATURE_KERNEL_UMOUNT, enabled ? 1 : 0);
}

bool is_kernel_umount_enabled() {
uint64_t value = 0;
bool supported = false;
if (!get_feature(KSU_FEATURE_KERNEL_UMOUNT, &value, &supported)) {
return false;
}
if (!supported) {
return false;
}
return value != 0;
}
69 changes: 42 additions & 27 deletions manager/app/src/main/cpp/ksu.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#ifndef KERNELSU_KSU_H
#define KERNELSU_KSU_H

#include <linux/capability.h>
#include <stdint.h>
#include <sys/ioctl.h>

uint32_t get_version();
Expand Down Expand Up @@ -78,54 +78,69 @@ bool set_app_profile(const app_profile *profile);

int get_app_profile(app_profile *profile);

bool set_su_enabled(bool enabled);
// Feature IDs
enum ksu_feature_id {
KSU_FEATURE_SU_COMPAT = 0,
KSU_FEATURE_KERNEL_UMOUNT = 1,
};

bool is_su_enabled();
// Generic feature API
struct ksu_get_feature_cmd {
uint32_t feature_id; // Input: feature ID
uint64_t value; // Output: feature value/state
uint8_t supported; // Output: whether the feature is supported
};

struct ksu_set_feature_cmd {
uint32_t feature_id; // Input: feature ID
uint64_t value; // Input: feature value/state to set
};

struct ksu_become_daemon_cmd {
__u8 token[65]; // Input: daemon token (null-terminated)
uint8_t token[65]; // Input: daemon token (null-terminated)
};

struct ksu_get_info_cmd {
__u32 version; // Output: KERNEL_SU_VERSION
__u32 flags; // Output: flags (bit 0: MODULE mode)
uint32_t version; // Output: KERNEL_SU_VERSION
uint32_t flags; // Output: flags (bit 0: MODULE mode)
uint32_t features; // Output: max feature ID supported (KSU_FEATURE_MAX)
};

struct ksu_report_event_cmd {
__u32 event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc.
uint32_t event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc.
};

struct ksu_set_sepolicy_cmd {
__u64 cmd; // Input: sepolicy command
__aligned_u64 arg; // Input: sepolicy argument pointer
uint64_t cmd; // Input: sepolicy command
uint64_t arg; // Input: sepolicy argument pointer
};

struct ksu_check_safemode_cmd {
__u8 in_safe_mode; // Output: true if in safe mode, false otherwise
uint8_t in_safe_mode; // Output: true if in safe mode, false otherwise
};

struct ksu_get_allow_list_cmd {
__u32 uids[128]; // Output: array of allowed/denied UIDs
__u32 count; // Output: number of UIDs in array
__u8 allow; // Input: true for allow list, false for deny list
uint32_t uids[128]; // Output: array of allowed/denied UIDs
uint32_t count; // Output: number of UIDs in array
uint8_t allow; // Input: true for allow list, false for deny list
};

struct ksu_uid_granted_root_cmd {
__u32 uid; // Input: target UID to check
__u8 granted; // Output: true if granted, false otherwise
uint32_t uid; // Input: target UID to check
uint8_t granted; // Output: true if granted, false otherwise
};

struct ksu_uid_should_umount_cmd {
__u32 uid; // Input: target UID to check
__u8 should_umount; // Output: true if should umount, false otherwise
uint32_t uid; // Input: target UID to check
uint8_t should_umount; // Output: true if should umount, false otherwise
};

struct ksu_get_manager_uid_cmd {
__u32 uid; // Output: manager UID
uint32_t uid; // Output: manager UID
};

struct ksu_set_manager_uid_cmd {
__u32 uid; // Input: new manager UID
uint32_t uid; // Input: new manager UID
};

struct ksu_get_app_profile_cmd {
Expand All @@ -136,13 +151,13 @@ struct ksu_set_app_profile_cmd {
struct app_profile profile; // Input: app profile structure
};

struct ksu_is_su_enabled_cmd {
__u8 enabled; // Output: true if su compat enabled
};
// Su compat
bool set_su_enabled(bool enabled);
bool is_su_enabled();

struct ksu_enable_su_cmd {
__u8 enable; // Input: true to enable, false to disable
};
// Kernel umount
bool set_kernel_umount_enabled(bool enabled);
bool is_kernel_umount_enabled();

// IOCTL command definitions
#define KSU_IOCTL_GRANT_ROOT _IO('K', 1)
Expand All @@ -157,8 +172,8 @@ struct ksu_enable_su_cmd {
#define KSU_IOCTL_GET_MANAGER_UID _IOR('K', 10, struct ksu_get_manager_uid_cmd)
#define KSU_IOCTL_GET_APP_PROFILE _IOWR('K', 11, struct ksu_get_app_profile_cmd)
#define KSU_IOCTL_SET_APP_PROFILE _IOW('K', 12, struct ksu_set_app_profile_cmd)
#define KSU_IOCTL_IS_SU_ENABLED _IOR('K', 13, struct ksu_is_su_enabled_cmd)
#define KSU_IOCTL_ENABLE_SU _IOW('K', 14, struct ksu_enable_su_cmd)
#define KSU_IOCTL_GET_FEATURE _IOWR('K', 13, struct ksu_get_feature_cmd)
#define KSU_IOCTL_SET_FEATURE _IOW('K', 14, struct ksu_set_feature_cmd)

bool get_allow_list(struct ksu_get_allow_list_cmd*);

Expand Down
9 changes: 9 additions & 0 deletions manager/app/src/main/java/me/weishu/kernelsu/Natives.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ object Natives {
external fun isSuEnabled(): Boolean
external fun setSuEnabled(enabled: Boolean): Boolean

/**
* Kernel module umount can be disabled temporarily.
* 0: disabled
* 1: enabled
* negative : error
*/
external fun isKernelUmountEnabled(): Boolean
external fun setKernelUmountEnabled(enabled: Boolean): Boolean

private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
private const val NOBODY_UID = 9999

Expand Down
23 changes: 23 additions & 0 deletions manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,29 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
}
)

var isKernelUmountDisabled by rememberSaveable {
mutableStateOf(!Natives.isKernelUmountEnabled())
}
SuperSwitch(
title = stringResource(id = R.string.settings_disable_kernel_umount),
summary = stringResource(id = R.string.settings_disable_kernel_umount_summary),
leftAction = {
Icon(
Icons.Rounded.FolderDelete,
modifier = Modifier.padding(end = 16.dp),
contentDescription = stringResource(id = R.string.settings_disable_kernel_umount),
tint = colorScheme.onBackground
)
},
checked = isKernelUmountDisabled,
onCheckedChange = { checked: Boolean ->
val shouldEnable = !checked
if (Natives.setKernelUmountEnabled(shouldEnable)) {
isKernelUmountDisabled = !shouldEnable
}
}
)
}


Expand Down
2 changes: 2 additions & 0 deletions manager/app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@
<string name="log_saved">日志已保存</string>
<string name="settings_disable_su">关闭 su 兼容</string>
<string name="settings_disable_su_summary">临时禁止任何应用通过 su 命令获取 root 权限(已运行的 root 进程不受影响)</string>
<string name="settings_disable_kernel_umount">关闭内核 umount</string>
<string name="settings_disable_kernel_umount_summary">临时关闭 KernelSU 控制的内核级 umount 行为。</string>
<string name="module_install_prompt_with_name">将安装以下模块:%1$s</string>
<string name="confirm">确认</string>
<string name="processing">处理中…</string>
Expand Down
2 changes: 2 additions & 0 deletions manager/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@
<string name="log_saved">Logs saved</string>
<string name="settings_disable_su">Disable su compatibility</string>
<string name="settings_disable_su_summary">Temporarily disable the ability of any app to gain root privileges via the ⁠su command (existing root processes won\'t be affected).</string>
<string name="settings_disable_kernel_umount">Disable kernel umount</string>
<string name="settings_disable_kernel_umount_summary">Temporarily disable kernel-level umount behavior controlled by KernelSU.</string>
<string name="processing">Processing…</string>
<string name="refresh_pulling">Pull down to refresh</string>
<string name="refresh_release">Release to refresh</string>
Expand Down