manager: fix capabilities and namespace save/load
This commit is contained in:
@@ -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) {
|
static int getListSize(JNIEnv *env, jobject list) {
|
||||||
auto cls = env->GetObjectClass(list);
|
auto cls = env->GetObjectClass(list);
|
||||||
auto size = env->GetMethodID(cls, "size", "()I");
|
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 groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
|
||||||
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
||||||
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
|
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 nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
|
||||||
auto umountModulesField = env->GetFieldID(cls, "umountModules", "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);
|
env->SetIntField(obj, gidField, profile.root_profile.gid);
|
||||||
|
|
||||||
jobject groupList = env->GetObjectField(obj, groupsField);
|
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);
|
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->SetObjectField(obj, domainField,
|
||||||
env->NewStringUTF(profile.root_profile.selinux_domain));
|
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);
|
env->SetBooleanField(obj, allowSuField, profile.allow_su);
|
||||||
} else {
|
} else {
|
||||||
env->SetBooleanField(obj, nonRootUseDefaultField,
|
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 groupsField = env->GetFieldID(cls, "groups", "Ljava/util/List;");
|
||||||
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
auto capabilitiesField = env->GetFieldID(cls, "capabilities", "Ljava/util/List;");
|
||||||
auto domainField = env->GetFieldID(cls, "context", "Ljava/lang/String;");
|
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 nonRootUseDefaultField = env->GetFieldID(cls, "nonRootUseDefault", "Z");
|
||||||
auto umountModulesField = env->GetFieldID(cls, "umountModules", "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;
|
p.root_profile.groups_count = groups_count;
|
||||||
fillArrayWithList(env, groups, p.root_profile.groups, 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);
|
auto cdomain = env->GetStringUTFChars((jstring) domain, nullptr);
|
||||||
strcpy(p.root_profile.selinux_domain, cdomain);
|
strcpy(p.root_profile.selinux_domain, cdomain);
|
||||||
env->ReleaseStringUTFChars((jstring) domain, cdomain);
|
env->ReleaseStringUTFChars((jstring) domain, cdomain);
|
||||||
|
|
||||||
// p.root_profile.namespaces = env->GetIntField(profile, namespacesField);
|
p.root_profile.namespaces = env->GetIntField(profile, namespacesField);
|
||||||
} else {
|
} else {
|
||||||
p.non_root_profile.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
|
p.non_root_profile.use_default = env->GetBooleanField(profile, nonRootUseDefaultField);
|
||||||
p.non_root_profile.umount_modules = umountModules;
|
p.non_root_profile.umount_modules = umountModules;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#ifndef KERNELSU_KSU_H
|
#ifndef KERNELSU_KSU_H
|
||||||
#define KERNELSU_KSU_H
|
#define KERNELSU_KSU_H
|
||||||
|
|
||||||
|
#include <linux/capability.h>
|
||||||
|
|
||||||
bool become_manager(const char *);
|
bool become_manager(const char *);
|
||||||
|
|
||||||
int get_version();
|
int get_version();
|
||||||
@@ -42,8 +44,12 @@ struct app_profile {
|
|||||||
int32_t groups[KSU_MAX_GROUPS];
|
int32_t groups[KSU_MAX_GROUPS];
|
||||||
int32_t groups_count;
|
int32_t groups_count;
|
||||||
|
|
||||||
// kernel_cap_t is u32[2]
|
struct {
|
||||||
int32_t capabilities[2];
|
// 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];
|
char selinux_domain[KSU_SELINUX_DOMAIN];
|
||||||
|
|
||||||
int32_t namespaces;
|
int32_t namespaces;
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ object Natives {
|
|||||||
// minimal supported kernel version
|
// minimal supported kernel version
|
||||||
// 10915: allowlist breaking change, add app profile
|
// 10915: allowlist breaking change, add app profile
|
||||||
// 10931: app profile struct add 'version' field
|
// 10931: app profile struct add 'version' field
|
||||||
const val MINIMAL_SUPPORTED_KERNEL = 10931
|
// 10946: add capabilities
|
||||||
|
const val MINIMAL_SUPPORTED_KERNEL = 10946
|
||||||
|
|
||||||
init {
|
init {
|
||||||
System.loadLibrary("kernelsu")
|
System.loadLibrary("kernelsu")
|
||||||
@@ -87,7 +88,7 @@ object Natives {
|
|||||||
val groups: List<Int> = mutableListOf(),
|
val groups: List<Int> = mutableListOf(),
|
||||||
val capabilities: List<Int> = mutableListOf(),
|
val capabilities: List<Int> = mutableListOf(),
|
||||||
val context: String = "su",
|
val context: String = "su",
|
||||||
val namespace: Namespace = Namespace.Inherited,
|
val namespace: Int = Namespace.Inherited.ordinal,
|
||||||
|
|
||||||
val nonRootUseDefault: Boolean = true,
|
val nonRootUseDefault: Boolean = true,
|
||||||
val umountModules: Boolean = true,
|
val umountModules: Boolean = true,
|
||||||
|
|||||||
@@ -62,9 +62,10 @@ fun RootProfileConfig(
|
|||||||
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
val currentNamespace = when (profile.namespace) {
|
val currentNamespace = when (profile.namespace) {
|
||||||
Natives.Profile.Namespace.Inherited -> stringResource(R.string.profile_namespace_inherited)
|
Natives.Profile.Namespace.Inherited.ordinal -> stringResource(R.string.profile_namespace_inherited)
|
||||||
Natives.Profile.Namespace.Global -> stringResource(R.string.profile_namespace_global)
|
Natives.Profile.Namespace.Global.ordinal -> stringResource(R.string.profile_namespace_global)
|
||||||
Natives.Profile.Namespace.Individual -> stringResource(R.string.profile_namespace_individual)
|
Natives.Profile.Namespace.Individual.ordinal -> stringResource(R.string.profile_namespace_individual)
|
||||||
|
else -> stringResource(R.string.profile_namespace_inherited)
|
||||||
}
|
}
|
||||||
ListItem(headlineContent = {
|
ListItem(headlineContent = {
|
||||||
ExposedDropdownMenuBox(
|
ExposedDropdownMenuBox(
|
||||||
@@ -91,21 +92,21 @@ fun RootProfileConfig(
|
|||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(R.string.profile_namespace_inherited)) },
|
text = { Text(stringResource(R.string.profile_namespace_inherited)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Inherited))
|
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Inherited.ordinal))
|
||||||
expanded = false
|
expanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(R.string.profile_namespace_global)) },
|
text = { Text(stringResource(R.string.profile_namespace_global)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Global))
|
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Global.ordinal))
|
||||||
expanded = false
|
expanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(stringResource(R.string.profile_namespace_individual)) },
|
text = { Text(stringResource(R.string.profile_namespace_individual)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Individual))
|
onProfileChange(profile.copy(namespace = Natives.Profile.Namespace.Individual.ordinal))
|
||||||
expanded = false
|
expanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -164,9 +165,9 @@ fun RootProfileConfig(
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let {
|
val selectedGroups = profile.groups.ifEmpty { listOf(0) }.let { e ->
|
||||||
it.mapNotNull { id ->
|
e.mapNotNull { g ->
|
||||||
Groups.values().find { it.gid == id }
|
Groups.values().find { it.gid == g }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GroupsPanel(selectedGroups) {
|
GroupsPanel(selectedGroups) {
|
||||||
@@ -178,8 +179,12 @@ fun RootProfileConfig(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectedCaps = profile.capabilities.mapNotNull { id ->
|
val selectedCaps = profile.capabilities.ifEmpty {
|
||||||
Capabilities.values().find { it.cap == id }
|
Capabilities.values().toList()
|
||||||
|
}.let { e ->
|
||||||
|
e.mapNotNull { cap ->
|
||||||
|
Capabilities.values().find { it.cap == cap }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CapsPanel(selectedCaps) {
|
CapsPanel(selectedCaps) {
|
||||||
onProfileChange(
|
onProfileChange(
|
||||||
|
|||||||
Reference in New Issue
Block a user