manager: fix capabilities and namespace save/load

This commit is contained in:
weishu
2023-06-04 16:11:41 +08:00
parent 908fbadaf5
commit c9608af0c8
4 changed files with 70 additions and 24 deletions

View File

@@ -57,6 +57,35 @@ static void fillIntArray(JNIEnv* env, jobject list, int *data, int count) {
}
}
static void addIntToList(JNIEnv *env, jobject list, int ele) {
auto cls = env->GetObjectClass(list);
auto add = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
auto integerCls = env->FindClass("java/lang/Integer");
auto constructor = env->GetMethodID(integerCls, "<init>", "(I)V");
auto integer = env->NewObject(integerCls, constructor, ele);
env->CallBooleanMethod(list, add, integer);
}
static uint64_t capListToBits(JNIEnv *env, jobject list) {
auto cls = env->GetObjectClass(list);
auto get = env->GetMethodID(cls, "get", "(I)Ljava/lang/Object;");
auto size = env->GetMethodID(cls, "size", "()I");
auto listSize = env->CallIntMethod(list, size);
auto integerCls = env->FindClass("java/lang/Integer");
auto intValue = env->GetMethodID(integerCls, "intValue", "()I");
uint64_t result = 0;
for (int i = 0; i < listSize; ++i) {
auto integer = env->CallObjectMethod(list, get, i);
int data = env->CallIntMethod(integer, intValue);
if (cap_valid(data)) {
result |= (1ULL << data);
}
}
return result;
}
static int getListSize(JNIEnv *env, jobject list) {
auto cls = env->GetObjectClass(list);
auto size = env->GetMethodID(cls, "size", "()I");
@@ -115,7 +144,7 @@ Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg,
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
// auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
@@ -136,14 +165,19 @@ Java_me_weishu_kernelsu_Natives_getAppProfile(JNIEnv *env, jobject, jstring pkg,
env->SetIntField(obj, gidField, profile.root_profile.gid);
jobject groupList = env->GetObjectField(obj, groupsField);
fillIntArray(env, groupList, profile.root_profile.groups, profile.root_profile.groups_count);
fillIntArray(env, groupList, profile.root_profile.groups,
profile.root_profile.groups_count);
jobject capList = env->GetObjectField(obj, capabilitiesField);
// fillIntArray(env, capList, profile.root_profile.capabilities, 2);
for (int i = 0; i <= CAP_LAST_CAP; i++) {
if (profile.root_profile.caps.effective & (1ULL << i)) {
addIntToList(env, capList, i);
}
}
env->SetObjectField(obj, domainField,
env->NewStringUTF(profile.root_profile.selinux_domain));
// env->SetIntField(obj, namespacesField, profile.root_profile.namespaces);
env->SetIntField(obj, namespacesField, profile.root_profile.namespaces);
env->SetBooleanField(obj, allowSuField, profile.allow_su);
} else {
env->SetBooleanField(obj, nonRootUseDefaultField,
@@ -173,7 +207,7 @@ Java_me_weishu_kernelsu_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobjec
auto groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
// auto namespacesField = env->GetFieldID(cls, "namespaces", "I");
auto namespacesField = env->GetFieldID(cls, "namespace", "I");
auto nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
auto umountModulesField = env->GetFieldID(cls, "umountModules", "Z");
@@ -224,13 +258,13 @@ Java_me_weishu_kernelsu_Natives_setAppProfile(JNIEnv *env, jobject clazz, jobjec
p.root_profile.groups_count = groups_count;
fillArrayWithList(env, groups, p.root_profile.groups, groups_count);
// fillArrayWithList(env, capabilities, p.root_profile.capabilities, 2);
p.root_profile.caps.effective = capListToBits(env, capabilities);
auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr);
strcpy(p.root_profile.selinux_domain, cdomain);
env->ReleaseStringUTFChars((jstring) domain, cdomain);
// p.root_profile.namespaces = env->GetIntField(profile, namespacesField);
p.root_profile.namespaces = env->GetIntField(profile, namespacesField);
} else {
p.non_root_profile.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
p.non_root_profile.umount_modules = umountModules;

View File

@@ -5,6 +5,8 @@
#ifndef KERNELSU_KSU_H
#define KERNELSU_KSU_H
#include <linux/capability.h>
bool become_manager(const char *);
int get_version();
@@ -42,8 +44,12 @@ struct app_profile {
int32_t groups[KSU_MAX_GROUPS];
int32_t groups_count;
// kernel_cap_t is u32[2]
int32_t capabilities[2];
struct {
// kernel_cap_t is u32[2], we use u64 here to avoid alignment issues.
uint64_t effective;
uint64_t permitted;
uint64_t inheritable;
} caps;
char selinux_domain[KSU_SELINUX_DOMAIN];
int32_t namespaces;

View File

@@ -13,7 +13,8 @@ object Natives {
// minimal supported kernel version
// 10915: allowlist breaking change, add app profile
// 10931: app profile struct add 'version' field
const val MINIMAL_SUPPORTED_KERNEL = 10931
// 10946: add capabilities
const val MINIMAL_SUPPORTED_KERNEL = 10946
init {
System.loadLibrary("kernelsu")
@@ -87,7 +88,7 @@ object Natives {
val groups: List<Int> = mutableListOf(),
val capabilities: List<Int> = mutableListOf(),
val context: String = "su",
val namespace: Namespace = Namespace.Inherited,
val namespace: Int = Namespace.Inherited.ordinal,
val nonRootUseDefault: Boolean = true,
val umountModules: Boolean = true,

View File

@@ -62,9 +62,10 @@ fun RootProfileConfig(
var expanded by remember { mutableStateOf(false) }
val currentNamespace = when (profile.namespace) {
Natives.Profile.Namespace.Inherited -> stringResource(R.string.profile_namespace_inherited)
Natives.Profile.Namespace.Global -> stringResource(R.string.profile_namespace_global)
Natives.Profile.Namespace.Individual -> stringResource(R.string.profile_namespace_individual)
Natives.Profile.Namespace.Inherited.ordinal -> stringResource(R.string.profile_namespace_inherited)
Natives.Profile.Namespace.Global.ordinal -> stringResource(R.string.profile_namespace_global)
Natives.Profile.Namespace.Individual.ordinal -> stringResource(R.string.profile_namespace_individual)
else -> stringResource(R.string.profile_namespace_inherited)
}
ListItem(headlineContent = {
ExposedDropdownMenuBox(
@@ -91,21 +92,21 @@ fun RootProfileConfig(
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_inherited)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Inherited))
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Inherited.ordinal))
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_global)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Global))
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Global.ordinal))
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.profile_namespace_individual)) },
onClick = {
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Individual))
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Individual.ordinal))
expanded = false
},
)
@@ -164,9 +165,9 @@ fun RootProfileConfig(
)
})
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let {
it.mapNotNull { id ->
Groups.values().find { it.gid == id }
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e ->
e.mapNotNull { g ->
Groups.values().find { it.gid == g }
}
}
GroupsPanel(selectedGroups) {
@@ -178,8 +179,12 @@ fun RootProfileConfig(
)
}
val selectedCaps = profile.capabilities.mapNotNull { id ->
Capabilities.values().find { it.cap == id }
val selectedCaps = profile.capabilities.ifEmpty {
Capabilities.values().toList()
}.let { e ->
e.mapNotNull { cap ->
Capabilities.values().find { it.cap == cap }
}
}
CapsPanel(selectedCaps) {
onProfileChange(