manager: support setting selinux rules profile

This commit is contained in:
weishu
2023-07-01 18:44:56 +08:00
parent 827a2f2901
commit 70f2df11d1
5 changed files with 43 additions and 9 deletions

View File

@@ -93,6 +93,7 @@ object Natives {
val nonRootUseDefault: Boolean = true, val nonRootUseDefault: Boolean = true,
val umountModules: Boolean = true, val umountModules: Boolean = true,
var rules: String = "", // this field is save in ksud!!
) : Parcelable { ) : Parcelable {
enum class Namespace { enum class Namespace {
Inherited, Inherited,

View File

@@ -175,6 +175,7 @@ fun RootProfileConfig(
onProfileChange( onProfileChange(
profile.copy( profile.copy(
context = domain, context = domain,
rules = rules,
rootUseDefault = false rootUseDefault = false
) )
) )
@@ -357,11 +358,14 @@ private fun UidPanel(uid: Int, label: String, onUidChange: (Int) -> Unit) {
} }
@Composable @Composable
private fun SELinuxPanel(profile: Natives.Profile, onSELinuxChange: (domain: String, rules: String) -> Unit) { private fun SELinuxPanel(
profile: Natives.Profile,
onSELinuxChange: (domain: String, rules: String) -> Unit
) {
var showDialog by remember { mutableStateOf(false) } var showDialog by remember { mutableStateOf(false) }
if (showDialog) { if (showDialog) {
var domain by remember { mutableStateOf(profile.context) } var domain by remember { mutableStateOf(profile.context) }
var rules by remember { mutableStateOf("") } var rules by remember { mutableStateOf(profile.rules) }
val inputOptions = listOf( val inputOptions = listOf(
InputTextField( InputTextField(
@@ -382,7 +386,7 @@ private fun SELinuxPanel(profile: Natives.Profile, onSELinuxChange: (domain: Str
// value can be a-zA-Z0-9_ // value can be a-zA-Z0-9_
val regex = Regex("^[a-z_]+:[a-z0-9_]+:[a-z0-9_]+(:[a-z0-9_]+)?$") val regex = Regex("^[a-z_]+:[a-z0-9_]+:[a-z0-9_]+(:[a-z0-9_]+)?$")
if (value?.matches(regex) == true) ValidationResult.Valid if (value?.matches(regex) == true) ValidationResult.Valid
else ValidationResult.Invalid("Domain must be valid sepolicy") else ValidationResult.Invalid("Domain must be in the format of \"user:role:type:level\"")
} }
), ),
InputTextField( InputTextField(
@@ -393,7 +397,6 @@ private fun SELinuxPanel(profile: Natives.Profile, onSELinuxChange: (domain: Str
type = InputTextFieldType.OUTLINED, type = InputTextFieldType.OUTLINED,
keyboardOptions = KeyboardOptions( keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Ascii, keyboardType = KeyboardType.Ascii,
imeAction = ImeAction.Done
), ),
singleLine = false, singleLine = false,
resultListener = { resultListener = {
@@ -401,8 +404,8 @@ private fun SELinuxPanel(profile: Natives.Profile, onSELinuxChange: (domain: Str
}, },
validationListener = { value -> validationListener = { value ->
if (isSepolicyValid(value)) ValidationResult.Valid if (isSepolicyValid(value)) ValidationResult.Valid
else ValidationResult.Invalid("Rules must be valid sepolicy") else ValidationResult.Invalid("SELinux rules is invalid!")
}, }
) )
) )

View File

@@ -1,6 +1,5 @@
package me.weishu.kernelsu.ui.screen package me.weishu.kernelsu.ui.screen
import android.util.Log
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectTapGestures
@@ -64,8 +63,10 @@ import me.weishu.kernelsu.ui.component.profile.AppProfileConfig
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
import me.weishu.kernelsu.ui.util.LocalSnackbarHost import me.weishu.kernelsu.ui.util.LocalSnackbarHost
import me.weishu.kernelsu.ui.util.forceStopApp import me.weishu.kernelsu.ui.util.forceStopApp
import me.weishu.kernelsu.ui.util.getSepolicy
import me.weishu.kernelsu.ui.util.launchApp import me.weishu.kernelsu.ui.util.launchApp
import me.weishu.kernelsu.ui.util.restartApp import me.weishu.kernelsu.ui.util.restartApp
import me.weishu.kernelsu.ui.util.setSepolicy
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
/** /**
@@ -83,10 +84,16 @@ fun AppProfileScreen(
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val failToUpdateAppProfile = val failToUpdateAppProfile =
stringResource(R.string.failed_to_update_app_profile).format(appInfo.label) stringResource(R.string.failed_to_update_app_profile).format(appInfo.label)
val failToUpdateSepolicy =
stringResource(R.string.failed_to_update_sepolicy).format(appInfo.label)
val packageName = appInfo.packageName val packageName = appInfo.packageName
val initialProfile = Natives.getAppProfile(packageName, appInfo.uid)
if (initialProfile.allowSu) {
initialProfile.rules = getSepolicy(packageName)
}
var profile by rememberSaveable { var profile by rememberSaveable {
mutableStateOf(Natives.getAppProfile(packageName, appInfo.uid)) mutableStateOf(initialProfile)
} }
Scaffold( Scaffold(
@@ -114,6 +121,12 @@ fun AppProfileScreen(
profile = profile, profile = profile,
onProfileChange = { onProfileChange = {
scope.launch { scope.launch {
if (it.allowSu && !it.rootUseDefault && it.rules.isNotEmpty()) {
if (!setSepolicy(profile.name, it.rules)) {
snackbarHost.showSnackbar(failToUpdateSepolicy)
return@launch
}
}
if (!Natives.setAppProfile(it)) { if (!Natives.setAppProfile(it)) {
snackbarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid)) snackbarHost.showSnackbar(failToUpdateAppProfile.format(appInfo.uid))
} else { } else {

View File

@@ -147,7 +147,23 @@ fun isSepolicyValid(rules: String?): Boolean {
} }
val shell = getRootShell() val shell = getRootShell()
val result = val result =
shell.newJob().add("ksud sepolicy check '$rules'").to(ArrayList(), null).exec() shell.newJob().add("${getKsuDaemonPath()} sepolicy check '$rules'").to(ArrayList(), null).exec()
return result.isSuccess
}
fun getSepolicy(pkg: String): String {
val shell = getRootShell()
val result =
shell.newJob().add("${getKsuDaemonPath()} profile get-sepolicy $pkg").to(ArrayList(), null).exec()
Log.i(TAG, "code: ${result.code}, out: ${result.out}, err: ${result.err}")
return result.out.joinToString("\n")
}
fun setSepolicy(pkg: String, rules: String): Boolean {
val shell = getRootShell()
val result =
shell.newJob().add("${getKsuDaemonPath()} profile set-sepolicy $pkg '$rules'").to(ArrayList(), null).exec()
Log.i(TAG, "set sepolicy result: ${result.code}")
return result.isSuccess return result.isSuccess
} }

View File

@@ -83,4 +83,5 @@
<string name="launch_app">Launch</string> <string name="launch_app">Launch</string>
<string name="force_stop_app">Force Stop</string> <string name="force_stop_app">Force Stop</string>
<string name="restart_app">Restart</string> <string name="restart_app">Restart</string>
<string name="failed_to_update_sepolicy">Failed to update SELinux rules for: %s</string>
</resources> </resources>