mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 21:37:26 +00:00
Compare commits
66 Commits
manager-v8
...
manager-v8
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a27e30cf54 | ||
![]() |
79140c7636 | ||
![]() |
1f4c595cd3 | ||
![]() |
b5b62e03af | ||
![]() |
67e2a4720e | ||
![]() |
f5c2d72429 | ||
![]() |
2f5331ab48 | ||
![]() |
7f8257152f | ||
![]() |
0cd80f2556 | ||
![]() |
1717387876 | ||
![]() |
109363ebf6 | ||
![]() |
716c4fa386 | ||
![]() |
9a09b4eb20 | ||
![]() |
95a5b57265 | ||
![]() |
13fbf397d1 | ||
![]() |
20be99ec8a | ||
![]() |
04c53c3578 | ||
![]() |
51bc27a869 | ||
![]() |
71b083794c | ||
![]() |
b100d0c503 | ||
![]() |
76061296c9 | ||
![]() |
bb303d2da1 | ||
![]() |
c91c070343 | ||
![]() |
aec06a6f61 | ||
![]() |
e8ba671fc2 | ||
![]() |
1860e5d133 | ||
![]() |
f2cb3c38fe | ||
![]() |
9a28dd4f6e | ||
![]() |
d2acd59ea8 | ||
![]() |
79dfdb29e7 | ||
![]() |
eb21c8b42e | ||
![]() |
541bb53553 | ||
![]() |
fe8997efae | ||
![]() |
23455c722c | ||
![]() |
5ce29c30d2 | ||
![]() |
70d67728fd | ||
![]() |
e546884b08 | ||
![]() |
b36e6d987d | ||
![]() |
53c3dd5e8b | ||
![]() |
da723b207a | ||
![]() |
e050f77198 | ||
![]() |
540b4b7ea9 | ||
![]() |
bbef22daf7 | ||
![]() |
9ed110c91b | ||
![]() |
a30d510eb1 | ||
![]() |
ef98eaed8f | ||
![]() |
2a257f327c | ||
![]() |
4060c2107c | ||
![]() |
cd23d27048 | ||
![]() |
18b86e4fd2 | ||
![]() |
5f2e22a259 | ||
![]() |
4e97b18977 | ||
![]() |
f9bde347bc | ||
![]() |
947a7d6a2f | ||
![]() |
872ab2e99b | ||
![]() |
90b8813bb7 | ||
![]() |
88d0f63294 | ||
![]() |
79fa0d3a90 | ||
![]() |
8e61080a4a | ||
![]() |
3f9a64417b | ||
![]() |
eb959379e8 | ||
![]() |
41a644afb9 | ||
![]() |
6b42db943d | ||
![]() |
1c325459eb | ||
![]() |
6d88d8ad95 | ||
![]() |
246997f273 |
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## READ BEFORE OPENING ISSUES
|
||||||
|
|
||||||
|
All bug reports require you to **USE CANARY BUILDS**. Please include the version name and version code in the bug report.
|
||||||
|
|
||||||
|
If you experience a bootloop, attach a `dmesg` (kernel logs) when the device refuse to boot. This may very likely require a custom kernel on some devices as `last_kmsg` or `pstore ramoops` are usually not enabled by default. In addition, please also upload the result of `cat /proc/mounts` when your device is working correctly **WITHOUT ROOT**.
|
||||||
|
|
||||||
|
If you experience issues during installation, in recovery, upload the recovery logs, or in Magisk Manager, upload the install logs. Please also upload the `boot.img` or `recovery.img` that you are using for patching.
|
||||||
|
|
||||||
|
If you experience a crash of Magisk Manager, dump the full `logcat` **when the crash happens**. **DO NOT** upload `magisk.log`.
|
||||||
|
|
||||||
|
If you experience other issues related to Magisk, upload `magisk.log`, and preferably also include a boot `logcat` (start dumping `logcat` when the device boots up)
|
||||||
|
|
||||||
|
**DO NOT** open issues regarding root detection.
|
||||||
|
|
||||||
|
**DO NOT** ask for instructions.
|
||||||
|
|
||||||
|
**DO NOT** report issues if you have any modules installed.
|
||||||
|
|
||||||
|
Without following the rules above, your issue will be closed without explanation.
|
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@@ -3,6 +3,13 @@ name: Magisk Build
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
paths:
|
||||||
|
- 'app/**'
|
||||||
|
- 'native/**'
|
||||||
|
- 'stub/**'
|
||||||
|
- 'buildSrc/**'
|
||||||
|
- 'build.py'
|
||||||
|
- 'gradle.properties'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -43,6 +50,7 @@ jobs:
|
|||||||
echo "ANDROID_SDK_ROOT=$sdk_root" >> $env:GITHUB_ENV
|
echo "ANDROID_SDK_ROOT=$sdk_root" >> $env:GITHUB_ENV
|
||||||
echo "ANDROID_HOME=$sdk_root" >> $env:GITHUB_ENV
|
echo "ANDROID_HOME=$sdk_root" >> $env:GITHUB_ENV
|
||||||
echo "MAGISK_NDK_VERSION=$ndk_ver" >> $env:GITHUB_ENV
|
echo "MAGISK_NDK_VERSION=$ndk_ver" >> $env:GITHUB_ENV
|
||||||
|
echo "GRADLE_OPTS=-Dorg.gradle.daemon=false" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
- name: Set up GitHub env (Unix)
|
- name: Set up GitHub env (Unix)
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
@@ -57,7 +65,6 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
~/.gradle/wrapper
|
~/.gradle/wrapper
|
||||||
!~/.gradle/caches/**/*.lock
|
|
||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||||
restore-keys: ${{ runner.os }}-gradle-
|
restore-keys: ${{ runner.os }}-gradle-
|
||||||
|
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -25,6 +25,9 @@
|
|||||||
[submodule "pcre"]
|
[submodule "pcre"]
|
||||||
path = native/jni/external/pcre
|
path = native/jni/external/pcre
|
||||||
url = https://android.googlesource.com/platform/external/pcre
|
url = https://android.googlesource.com/platform/external/pcre
|
||||||
|
[submodule "xhook"]
|
||||||
|
path = native/jni/external/xhook
|
||||||
|
url = https://github.com/iqiyi/xHook.git
|
||||||
[submodule "termux-elf-cleaner"]
|
[submodule "termux-elf-cleaner"]
|
||||||
path = tools/termux-elf-cleaner
|
path = tools/termux-elf-cleaner
|
||||||
url = https://github.com/termux/termux-elf-cleaner.git
|
url = https://github.com/termux/termux-elf-cleaner.git
|
||||||
|
@@ -15,11 +15,11 @@ Here are some feature highlights:
|
|||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
|
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.3/MagiskManager-v8.0.3.apk)
|
[](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.6/MagiskManager-v8.0.6.apk)
|
||||||
[](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
|
[](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
|
||||||
<br>
|
<br>
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v20.4)
|
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.3)
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.1)
|
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.3)
|
||||||
|
|
||||||
## Useful Links
|
## Useful Links
|
||||||
|
|
||||||
|
@@ -41,6 +41,11 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
activity.supportActionBar?.subtitle = null
|
||||||
|
}
|
||||||
|
|
||||||
override fun onEventDispatched(event: ViewEvent) = when(event) {
|
override fun onEventDispatched(event: ViewEvent) = when(event) {
|
||||||
is ContextExecutor -> event(requireContext())
|
is ContextExecutor -> event(requireContext())
|
||||||
is ActivityExecutor -> event(activity)
|
is ActivityExecutor -> event(activity)
|
||||||
|
@@ -25,6 +25,7 @@ object Const {
|
|||||||
fun atLeast_20_2() = Info.env.magiskVersionCode >= 20200 || isCanary()
|
fun atLeast_20_2() = Info.env.magiskVersionCode >= 20200 || isCanary()
|
||||||
fun atLeast_20_4() = Info.env.magiskVersionCode >= 20400 || isCanary()
|
fun atLeast_20_4() = Info.env.magiskVersionCode >= 20400 || isCanary()
|
||||||
fun atLeast_21_0() = Info.env.magiskVersionCode >= 21000 || isCanary()
|
fun atLeast_21_0() = Info.env.magiskVersionCode >= 21000 || isCanary()
|
||||||
|
fun atLeast_21_2() = Info.env.magiskVersionCode >= 21200 || isCanary()
|
||||||
fun isCanary() = Info.env.magiskVersionCode % 100 != 0
|
fun isCanary() = Info.env.magiskVersionCode % 100 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,6 @@ object Const {
|
|||||||
// notifications
|
// notifications
|
||||||
const val MAGISK_UPDATE_NOTIFICATION_ID = 4
|
const val MAGISK_UPDATE_NOTIFICATION_ID = 4
|
||||||
const val APK_UPDATE_NOTIFICATION_ID = 5
|
const val APK_UPDATE_NOTIFICATION_ID = 5
|
||||||
const val HIDE_MANAGER_NOTIFICATION_ID = 8
|
|
||||||
const val UPDATE_NOTIFICATION_CHANNEL = "update"
|
const val UPDATE_NOTIFICATION_CHANNEL = "update"
|
||||||
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
|
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
|
||||||
const val CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update"
|
const val CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update"
|
||||||
|
@@ -27,13 +27,13 @@ class LocalModule(path: String) : Module() {
|
|||||||
val dir = "$PERSIST/$id"
|
val dir = "$PERSIST/$id"
|
||||||
if (enable) {
|
if (enable) {
|
||||||
disableFile.delete()
|
disableFile.delete()
|
||||||
if (Const.Version.isCanary())
|
if (Const.Version.atLeast_21_2())
|
||||||
Shell.su("copy_sepolicy_rules").submit()
|
Shell.su("copy_sepolicy_rules").submit()
|
||||||
else
|
else
|
||||||
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
|
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
|
||||||
} else {
|
} else {
|
||||||
!disableFile.createNewFile()
|
!disableFile.createNewFile()
|
||||||
if (Const.Version.isCanary())
|
if (Const.Version.atLeast_21_2())
|
||||||
Shell.su("copy_sepolicy_rules").submit()
|
Shell.su("copy_sepolicy_rules").submit()
|
||||||
else
|
else
|
||||||
Shell.su("rm -rf $dir").submit()
|
Shell.su("rm -rf $dir").submit()
|
||||||
@@ -45,13 +45,13 @@ class LocalModule(path: String) : Module() {
|
|||||||
set(remove) {
|
set(remove) {
|
||||||
if (remove) {
|
if (remove) {
|
||||||
removeFile.createNewFile()
|
removeFile.createNewFile()
|
||||||
if (Const.Version.isCanary())
|
if (Const.Version.atLeast_21_2())
|
||||||
Shell.su("copy_sepolicy_rules").submit()
|
Shell.su("copy_sepolicy_rules").submit()
|
||||||
else
|
else
|
||||||
Shell.su("rm -rf $PERSIST/$id").submit()
|
Shell.su("rm -rf $PERSIST/$id").submit()
|
||||||
} else {
|
} else {
|
||||||
!removeFile.delete()
|
!removeFile.delete()
|
||||||
if (Const.Version.isCanary())
|
if (Const.Version.atLeast_21_2())
|
||||||
Shell.su("copy_sepolicy_rules").submit()
|
Shell.su("copy_sepolicy_rules").submit()
|
||||||
else
|
else
|
||||||
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
|
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
|
||||||
|
@@ -191,9 +191,10 @@ abstract class MagiskInstallImpl : KoinComponent {
|
|||||||
if (rawData.size < 256)
|
if (rawData.size < 256)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
// Patch flags to AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED
|
// Patch flags to AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED |
|
||||||
|
// AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED
|
||||||
console.add("-- Patching: vbmeta.img")
|
console.add("-- Patching: vbmeta.img")
|
||||||
ByteBuffer.wrap(rawData).putInt(120, 2)
|
ByteBuffer.wrap(rawData).putInt(120, 3)
|
||||||
tarOut.putNextEntry(newEntry("vbmeta.img", rawData.size.toLong()))
|
tarOut.putNextEntry(newEntry("vbmeta.img", rawData.size.toLong()))
|
||||||
tarOut.write(rawData)
|
tarOut.write(rawData)
|
||||||
} else {
|
} else {
|
||||||
@@ -204,7 +205,7 @@ abstract class MagiskInstallImpl : KoinComponent {
|
|||||||
}
|
}
|
||||||
val boot = SuFile.open(installDir, "boot.img")
|
val boot = SuFile.open(installDir, "boot.img")
|
||||||
val recovery = SuFile.open(installDir, "recovery.img")
|
val recovery = SuFile.open(installDir, "recovery.img")
|
||||||
if (recovery.exists() && boot.exists()) {
|
if (Config.recovery && recovery.exists() && boot.exists()) {
|
||||||
// Install Magisk to recovery
|
// Install Magisk to recovery
|
||||||
srcBoot = recovery.path
|
srcBoot = recovery.path
|
||||||
// Repack boot image to prevent restore
|
// Repack boot image to prevent restore
|
||||||
@@ -360,9 +361,10 @@ abstract class MagiskInstallImpl : KoinComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun copySepolicyRules(): Boolean {
|
private fun copySepolicyRules(): Boolean {
|
||||||
if (Info.remote.magisk.versionCode >= 21100) return true
|
if (Info.remote.magisk.versionCode >= 21100) {
|
||||||
// Copy existing rules for migration
|
// Copy existing rules for migration
|
||||||
"copy_sepolicy_rules".sh()
|
"copy_sepolicy_rules".sh()
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,6 +29,6 @@ val viewModelModules = module {
|
|||||||
viewModel { MainViewModel() }
|
viewModel { MainViewModel() }
|
||||||
|
|
||||||
// Legacy
|
// Legacy
|
||||||
viewModel { (args: FlashFragmentArgs) -> FlashViewModel(args, get()) }
|
viewModel { (args: FlashFragmentArgs) -> FlashViewModel(args) }
|
||||||
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
|
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
|
||||||
}
|
}
|
||||||
|
@@ -7,9 +7,11 @@ import android.content.Context
|
|||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.ComponentInfo
|
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.pm.PackageManager.*
|
import android.content.pm.PackageManager.*
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS
|
||||||
|
import android.content.pm.ServiceInfo.FLAG_USE_APP_ZYGOTE
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
@@ -57,32 +59,10 @@ import java.lang.reflect.Array as JArray
|
|||||||
|
|
||||||
val packageName: String get() = get<Context>().packageName
|
val packageName: String get() = get<Context>().packageName
|
||||||
|
|
||||||
val ApplicationInfo.processes: List<String> @SuppressLint("InlinedApi") get() {
|
val ServiceInfo.isIsolated get() = (flags and FLAG_ISOLATED_PROCESS) != 0
|
||||||
val pm = get<PackageManager>()
|
|
||||||
val appProcessName = processName ?: packageName
|
@get:SuppressLint("InlinedApi")
|
||||||
val baseFlag = MATCH_DISABLED_COMPONENTS or MATCH_UNINSTALLED_PACKAGES
|
val ServiceInfo.useAppZygote get() = (flags and FLAG_USE_APP_ZYGOTE) != 0
|
||||||
val packageInfo = try {
|
|
||||||
val request = GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS
|
|
||||||
pm.getPackageInfo(packageName, baseFlag or request)
|
|
||||||
} catch (e: NameNotFoundException) { // EdXposed hooked, issue#3276
|
|
||||||
return listOf(appProcessName)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Exceed binder data transfer limit, fetch each component type separately
|
|
||||||
pm.getPackageInfo(packageName, baseFlag).apply {
|
|
||||||
runCatching { activities = pm.getPackageInfo(packageName, GET_ACTIVITIES).activities }
|
|
||||||
runCatching { services = pm.getPackageInfo(packageName, GET_SERVICES).services }
|
|
||||||
runCatching { receivers = pm.getPackageInfo(packageName, GET_RECEIVERS).receivers }
|
|
||||||
runCatching { providers = pm.getPackageInfo(packageName, GET_PROVIDERS).providers }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fun Array<out ComponentInfo>.processNames() = map { it.processName ?: appProcessName }
|
|
||||||
return with(packageInfo) {
|
|
||||||
activities?.processNames().orEmpty() +
|
|
||||||
services?.processNames().orEmpty() +
|
|
||||||
receivers?.processNames().orEmpty() +
|
|
||||||
providers?.processNames().orEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Context.rawResource(id: Int) = resources.openRawResource(id)
|
fun Context.rawResource(id: Int) = resources.openRawResource(id)
|
||||||
|
|
||||||
|
@@ -32,6 +32,10 @@ class FlashFragment : BaseUIFragment<FlashViewModel, FragmentFlashMd2Binding>()
|
|||||||
super.onStart()
|
super.onStart()
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
activity.setTitle(R.string.flash_screen_title)
|
activity.setTitle(R.string.flash_screen_title)
|
||||||
|
|
||||||
|
viewModel.subtitle.observe(this) {
|
||||||
|
activity.supportActionBar?.setSubtitle(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
package com.topjohnwu.magisk.ui.flash
|
package com.topjohnwu.magisk.ui.flash
|
||||||
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
@@ -26,17 +27,15 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class FlashViewModel(
|
class FlashViewModel(
|
||||||
args: FlashFragmentArgs,
|
args: FlashFragmentArgs
|
||||||
private val resources: Resources
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var showReboot = Shell.rootAccess()
|
var showReboot = Shell.rootAccess()
|
||||||
set(value) = set(value, field, { field = it }, BR.showReboot)
|
set(value) = set(value, field, { field = it }, BR.showReboot)
|
||||||
|
|
||||||
@get:Bindable
|
private val _subtitle = MutableLiveData(R.string.flashing)
|
||||||
var behaviorText = resources.getString(R.string.flashing)
|
val subtitle get() = _subtitle as LiveData<Int>
|
||||||
set(value) = set(value, field, { field = it }, BR.behaviorText)
|
|
||||||
|
|
||||||
val adapter = RvBindingAdapter<ConsoleItem>()
|
val adapter = RvBindingAdapter<ConsoleItem>()
|
||||||
val items = diffListOf<ConsoleItem>()
|
val items = diffListOf<ConsoleItem>()
|
||||||
@@ -91,9 +90,9 @@ class FlashViewModel(
|
|||||||
|
|
||||||
private fun onResult(success: Boolean) {
|
private fun onResult(success: Boolean) {
|
||||||
state = if (success) State.LOADED else State.LOADING_FAILED
|
state = if (success) State.LOADED else State.LOADING_FAILED
|
||||||
behaviorText = when {
|
when {
|
||||||
success -> resources.getString(R.string.done)
|
success -> _subtitle.postValue(R.string.done)
|
||||||
else -> resources.getString(R.string.failure)
|
else -> _subtitle.postValue(R.string.failure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,47 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.ui.hide
|
|
||||||
|
|
||||||
import android.content.pm.ApplicationInfo
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
|
||||||
import com.topjohnwu.magisk.ktx.getLabel
|
|
||||||
|
|
||||||
class HideTarget(line: String) {
|
|
||||||
val packageName: String
|
|
||||||
val process: String
|
|
||||||
|
|
||||||
init {
|
|
||||||
val split = line.split(Regex("\\|"), 2)
|
|
||||||
packageName = split[0]
|
|
||||||
process = split.getOrElse(1) { packageName }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HideAppInfo(info: ApplicationInfo, pm: PackageManager)
|
|
||||||
: ApplicationInfo(info), Comparable<HideAppInfo> {
|
|
||||||
|
|
||||||
val label = info.getLabel(pm)
|
|
||||||
val iconImage: Drawable = info.loadIcon(pm)
|
|
||||||
|
|
||||||
override fun compareTo(other: HideAppInfo) = comparator.compare(this, other)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val comparator = compareBy<HideAppInfo>(
|
|
||||||
{ it.label.toLowerCase(currentLocale) },
|
|
||||||
{ it.packageName }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class HideProcessInfo(
|
|
||||||
val name: String,
|
|
||||||
val packageName: String,
|
|
||||||
val isHidden: Boolean
|
|
||||||
)
|
|
||||||
|
|
||||||
class HideAppTarget(
|
|
||||||
val info: HideAppInfo,
|
|
||||||
val processes: List<HideProcessInfo>
|
|
||||||
) : Comparable<HideAppTarget> {
|
|
||||||
override fun compareTo(other: HideAppTarget) = compareValuesBy(this, other) { it.info }
|
|
||||||
}
|
|
105
app/src/main/java/com/topjohnwu/magisk/ui/hide/HideInfo.kt
Normal file
105
app/src/main/java/com/topjohnwu/magisk/ui/hide/HideInfo.kt
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package com.topjohnwu.magisk.ui.hide
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.ComponentInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.PackageManager.*
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||||
|
import com.topjohnwu.magisk.ktx.getLabel
|
||||||
|
import com.topjohnwu.magisk.ktx.isIsolated
|
||||||
|
import com.topjohnwu.magisk.ktx.useAppZygote
|
||||||
|
|
||||||
|
class CmdlineHiddenItem(line: String) {
|
||||||
|
val packageName: String
|
||||||
|
val process: String
|
||||||
|
|
||||||
|
init {
|
||||||
|
val split = line.split(Regex("\\|"), 2)
|
||||||
|
packageName = split[0]
|
||||||
|
process = split.getOrElse(1) { packageName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const val ISOLATED_MAGIC = "isolated"
|
||||||
|
|
||||||
|
@SuppressLint("InlinedApi")
|
||||||
|
class HideAppInfo(info: ApplicationInfo, pm: PackageManager, hideList: List<CmdlineHiddenItem>)
|
||||||
|
: ApplicationInfo(info), Comparable<HideAppInfo> {
|
||||||
|
|
||||||
|
val label = info.getLabel(pm)
|
||||||
|
val iconImage: Drawable = info.loadIcon(pm)
|
||||||
|
val processes = fetchProcesses(pm, hideList)
|
||||||
|
|
||||||
|
override fun compareTo(other: HideAppInfo) = comparator.compare(this, other)
|
||||||
|
|
||||||
|
private fun fetchProcesses(
|
||||||
|
pm: PackageManager,
|
||||||
|
hideList: List<CmdlineHiddenItem>
|
||||||
|
): List<HideProcessInfo> {
|
||||||
|
// Fetch full PackageInfo
|
||||||
|
val baseFlag = MATCH_DISABLED_COMPONENTS or MATCH_UNINSTALLED_PACKAGES
|
||||||
|
val packageInfo = try {
|
||||||
|
val request = GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS
|
||||||
|
pm.getPackageInfo(packageName, baseFlag or request)
|
||||||
|
} catch (e: NameNotFoundException) {
|
||||||
|
// EdXposed hooked, issue#3276
|
||||||
|
return emptyList()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Exceed binder data transfer limit, fetch each component type separately
|
||||||
|
pm.getPackageInfo(packageName, baseFlag).apply {
|
||||||
|
runCatching { activities = pm.getPackageInfo(packageName, baseFlag or GET_ACTIVITIES).activities }
|
||||||
|
runCatching { services = pm.getPackageInfo(packageName, baseFlag or GET_SERVICES).services }
|
||||||
|
runCatching { receivers = pm.getPackageInfo(packageName, baseFlag or GET_RECEIVERS).receivers }
|
||||||
|
runCatching { providers = pm.getPackageInfo(packageName, baseFlag or GET_PROVIDERS).providers }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hidden = hideList.filter { it.packageName == packageName || it.packageName == ISOLATED_MAGIC }
|
||||||
|
fun createProcess(name: String, pkg: String = packageName): HideProcessInfo {
|
||||||
|
return HideProcessInfo(name, pkg, hidden.any { it.process == name })
|
||||||
|
}
|
||||||
|
|
||||||
|
var haveAppZygote = false
|
||||||
|
fun Array<out ComponentInfo>.processes() = map { createProcess(it.processName) }
|
||||||
|
fun Array<ServiceInfo>.processes() = map {
|
||||||
|
if (it.isIsolated) {
|
||||||
|
if (it.useAppZygote) {
|
||||||
|
haveAppZygote = true
|
||||||
|
// Using app zygote, don't need to track the process
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
createProcess("${it.processName}:${it.name}", ISOLATED_MAGIC)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
createProcess(it.processName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return with(packageInfo) {
|
||||||
|
activities?.processes().orEmpty() +
|
||||||
|
services?.processes().orEmpty() +
|
||||||
|
receivers?.processes().orEmpty() +
|
||||||
|
providers?.processes().orEmpty() +
|
||||||
|
listOf(if (haveAppZygote) createProcess("${processName}_zygote") else null)
|
||||||
|
}.filterNotNull().distinctBy { it.name }.sortedBy { it.name }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val comparator = compareBy<HideAppInfo>(
|
||||||
|
{ it.label.toLowerCase(currentLocale) },
|
||||||
|
{ it.packageName }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class HideProcessInfo(
|
||||||
|
val name: String,
|
||||||
|
val packageName: String,
|
||||||
|
var isHidden: Boolean
|
||||||
|
) {
|
||||||
|
val isIsolated get() = name == ISOLATED_MAGIC
|
||||||
|
val isAppZygote get() = name.endsWith("_zygote")
|
||||||
|
}
|
@@ -12,14 +12,13 @@ import com.topjohnwu.magisk.utils.set
|
|||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class HideItem(
|
class HideRvItem(
|
||||||
app: HideAppTarget
|
val info: HideAppInfo
|
||||||
) : ObservableItem<HideItem>(), Comparable<HideItem> {
|
) : ObservableItem<HideRvItem>(), Comparable<HideRvItem> {
|
||||||
|
|
||||||
override val layoutRes = R.layout.item_hide_md2
|
override val layoutRes get() = R.layout.item_hide_md2
|
||||||
|
|
||||||
val info = app.info
|
val processes = info.processes.map { HideProcessRvItem(it) }
|
||||||
val processes = app.processes.map { HideProcessItem(it) }
|
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var isExpanded = false
|
var isExpanded = false
|
||||||
@@ -41,11 +40,10 @@ class HideItem(
|
|||||||
if (value == true) {
|
if (value == true) {
|
||||||
processes
|
processes
|
||||||
.filterNot { it.isHidden }
|
.filterNot { it.isHidden }
|
||||||
.filter { isExpanded || it.process.name == it.process.packageName }
|
.filter { isExpanded || it.defaultSelection }
|
||||||
} else {
|
} else {
|
||||||
processes
|
processes
|
||||||
.filter { it.isHidden }
|
.filter { it.isHidden }
|
||||||
.filter { isExpanded || it.process.name == it.process.packageName }
|
|
||||||
}.forEach { it.toggle() }
|
}.forEach { it.toggle() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,14 +67,19 @@ class HideItem(
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
processes.find { it.isHidden && it.process.name == it.process.packageName } != null
|
val defaultProcesses = processes.filter { it.defaultSelection }
|
||||||
|
when (defaultProcesses.count { it.isHidden }) {
|
||||||
|
0 -> false
|
||||||
|
defaultProcesses.size -> true
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun compareTo(other: HideItem) = comparator.compare(this, other)
|
override fun compareTo(other: HideRvItem) = comparator.compare(this, other)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val comparator = compareBy<HideItem>(
|
private val comparator = compareBy<HideRvItem>(
|
||||||
{ it.itemsChecked == 0 },
|
{ it.itemsChecked == 0 },
|
||||||
{ it.info }
|
{ it.info }
|
||||||
)
|
)
|
||||||
@@ -84,16 +87,17 @@ class HideItem(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class HideProcessItem(
|
class HideProcessRvItem(
|
||||||
val process: HideProcessInfo
|
val process: HideProcessInfo
|
||||||
) : ObservableItem<HideProcessItem>() {
|
) : ObservableItem<HideProcessRvItem>() {
|
||||||
|
|
||||||
override val layoutRes = R.layout.item_hide_process_md2
|
override val layoutRes get() = R.layout.item_hide_process_md2
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var isHidden = process.isHidden
|
var isHidden
|
||||||
set(value) = set(value, field, { field = it }, BR.hidden) {
|
get() = process.isHidden
|
||||||
val arg = if (isHidden) "add" else "rm"
|
set(value) = set(value, process.isHidden, { process.isHidden = it }, BR.hidden) {
|
||||||
|
val arg = if (it) "add" else "rm"
|
||||||
val (name, pkg) = process
|
val (name, pkg) = process
|
||||||
Shell.su("magiskhide --$arg $pkg $name").submit()
|
Shell.su("magiskhide --$arg $pkg $name").submit()
|
||||||
}
|
}
|
||||||
@@ -102,7 +106,10 @@ class HideProcessItem(
|
|||||||
isHidden = !isHidden
|
isHidden = !isHidden
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun contentSameAs(other: HideProcessItem) = process == other.process
|
val defaultSelection get() =
|
||||||
override fun itemSameAs(other: HideProcessItem) = process.name == other.process.name
|
process.isIsolated || process.isAppZygote || process.name == process.packageName
|
||||||
|
|
||||||
|
override fun contentSameAs(other: HideProcessRvItem) = process == other.process
|
||||||
|
override fun itemSameAs(other: HideProcessRvItem) = process.name == other.process.name
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.hide
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
@@ -14,7 +15,6 @@ import com.topjohnwu.magisk.arch.itemBindingOf
|
|||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.ktx.get
|
import com.topjohnwu.magisk.ktx.get
|
||||||
import com.topjohnwu.magisk.ktx.packageName
|
import com.topjohnwu.magisk.ktx.packageName
|
||||||
import com.topjohnwu.magisk.ktx.processes
|
|
||||||
import com.topjohnwu.magisk.utils.Utils
|
import com.topjohnwu.magisk.utils.Utils
|
||||||
import com.topjohnwu.magisk.utils.set
|
import com.topjohnwu.magisk.utils.set
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
@@ -45,11 +45,11 @@ class HideViewModel : BaseViewModel(), Queryable {
|
|||||||
submitQuery()
|
submitQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
val items = filterableListOf<HideItem>()
|
val items = filterableListOf<HideRvItem>()
|
||||||
val itemBinding = itemBindingOf<HideItem> {
|
val itemBinding = itemBindingOf<HideRvItem> {
|
||||||
it.bindExtra(BR.viewModel, this)
|
it.bindExtra(BR.viewModel, this)
|
||||||
}
|
}
|
||||||
val itemInternalBinding = itemBindingOf<HideProcessItem> {
|
val itemInternalBinding = itemBindingOf<HideProcessRvItem> {
|
||||||
it.bindExtra(BR.viewModel, this)
|
it.bindExtra(BR.viewModel, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,14 +62,13 @@ class HideViewModel : BaseViewModel(), Queryable {
|
|||||||
state = State.LOADING
|
state = State.LOADING
|
||||||
val (apps, diff) = withContext(Dispatchers.Default) {
|
val (apps, diff) = withContext(Dispatchers.Default) {
|
||||||
val pm = get<PackageManager>()
|
val pm = get<PackageManager>()
|
||||||
val hides = Shell.su("magiskhide --ls").exec().out.map { HideTarget(it) }
|
val hideList = Shell.su("magiskhide --ls").exec().out.map { CmdlineHiddenItem(it) }
|
||||||
val apps = pm.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES)
|
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.enabled && !blacklist.contains(it.packageName) }
|
.filter { it.enabled && !blacklist.contains(it.packageName) }
|
||||||
.map { HideAppInfo(it, pm) }
|
.map { HideAppInfo(it, pm, hideList) }
|
||||||
.map { createTarget(it, hides) }
|
|
||||||
.filter { it.processes.isNotEmpty() }
|
.filter { it.processes.isNotEmpty() }
|
||||||
.map { HideItem(it) }
|
.map { HideRvItem(it) }
|
||||||
.toList()
|
.toList()
|
||||||
.sorted()
|
.sorted()
|
||||||
apps to items.calculateDiff(apps)
|
apps to items.calculateDiff(apps)
|
||||||
@@ -80,18 +79,6 @@ class HideViewModel : BaseViewModel(), Queryable {
|
|||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
private fun createTarget(info: HideAppInfo, hideList: List<HideTarget>): HideAppTarget {
|
|
||||||
val pkg = info.packageName
|
|
||||||
val hidden = hideList.filter { it.packageName == pkg }
|
|
||||||
val processNames = info.processes.distinct()
|
|
||||||
val processes = processNames.map { name ->
|
|
||||||
HideProcessInfo(name, pkg, hidden.any { name == it.process })
|
|
||||||
}
|
|
||||||
return HideAppTarget(info, processes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---
|
|
||||||
|
|
||||||
override fun query() {
|
override fun query() {
|
||||||
items.filter {
|
items.filter {
|
||||||
fun showHidden() = it.itemsChecked != 0
|
fun showHidden() = it.itemsChecked != 0
|
||||||
|
@@ -312,7 +312,7 @@ object RequestTimeout : BaseSettingsItem.Selector() {
|
|||||||
|
|
||||||
override var value = selected
|
override var value = selected
|
||||||
set(value) = setV(value, field, { field = it }) {
|
set(value) = setV(value, field, { field = it }) {
|
||||||
Config.suDefaultTimeout = it
|
Config.suDefaultTimeout = entryValues[it].toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val selected: Int
|
private val selected: Int
|
||||||
|
@@ -56,29 +56,6 @@
|
|||||||
app:icon="@drawable/ic_restart"
|
app:icon="@drawable/ic_restart"
|
||||||
app:iconTint="?colorOnPrimary" />
|
app:iconTint="?colorOnPrimary" />
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
style="@style/WidgetFoundation.Card.Elevated"
|
|
||||||
goneUnless="@{viewModel.loading}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
app:contentPadding="@dimen/l1">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
movieBehavior="@{viewModel.loading}"
|
|
||||||
movieBehaviorText="@{viewModel.behaviorText}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Body"
|
|
||||||
android:textColor="?colorOnSurface"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:text="Flashing..." />
|
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="item"
|
name="item"
|
||||||
type="com.topjohnwu.magisk.ui.hide.HideItem" />
|
type="com.topjohnwu.magisk.ui.hide.HideRvItem" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="viewModel"
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="item"
|
name="item"
|
||||||
type="com.topjohnwu.magisk.ui.hide.HideProcessItem" />
|
type="com.topjohnwu.magisk.ui.hide.HideProcessRvItem" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="viewModel"
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
## v8.0.4
|
## v8.0.7
|
||||||
|
|
||||||
- A lot of stability changes and minor bug fixes
|
- Fix sepolicy rule migration when upgrading
|
||||||
- Collect device properties, app logcat, and Magisk logs when saving logs in the logs menu
|
|
||||||
|
|
||||||
## v8.0.3
|
## v8.0.6
|
||||||
|
|
||||||
- Switch to the new Magisk Module Repo setup in preparation to allow 3rd party repos
|
- Minor UI changes
|
||||||
- Add tapjacking protection on Superuser request dialog
|
- Update internal scripts
|
||||||
- Stability changes and bug fixes
|
|
||||||
|
@@ -1,169 +1,247 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!--Welcome Activity-->
|
<!--Sections-->
|
||||||
<string name="modules">Moduly</string>
|
<string name="modules">Správce modulů</string>
|
||||||
<string name="superuser">Superuser</string>
|
<string name="superuser">SuperUser</string>
|
||||||
<string name="logs">Log</string>
|
<string name="logs">Protokol</string>
|
||||||
<string name="settings">Nastavení</string>
|
<string name="settings">Nastavení</string>
|
||||||
|
<string name="refresh">Obnovit lokální data</string>
|
||||||
<string name="install">Instalovat</string>
|
<string name="install">Instalovat</string>
|
||||||
<string name="unsupport_magisk_title">Nepodporovaná verze Magisk</string>
|
<string name="section_home">Domů</string>
|
||||||
|
<string name="section_theme">Téma</string>
|
||||||
|
<string name="safetynet">SafetyNet</string>
|
||||||
|
|
||||||
<!--Status Fragment-->
|
<!--Home-->
|
||||||
<string name="invalid_update_channel">Neplatný kanál aktualizace</string>
|
<string name="no_connection">Žádné připojení</string>
|
||||||
<string name="safetynet_api_error">Chyba SafetyNet API</string>
|
|
||||||
<string name="safetynet_res_invalid">Odpověď je neplatná.</string>
|
|
||||||
<string name="keep_force_encryption">Udržet "force encryption"</string>
|
|
||||||
<string name="keep_dm_verity">Udržet "AVB 2.0/dm-verity"</string>
|
|
||||||
<string name="uninstall_magisk_title">Odinstalovat Magisk</string>
|
|
||||||
<string name="uninstall_magisk_msg">Všechny moduly budou zakázány/odstraněny. Root bude odstraněn a pokud jsou data dešifrována, můžou být zašifrována.</string>
|
|
||||||
<string name="update">Aktualizovat</string>
|
|
||||||
|
|
||||||
<!--Module Fragment-->
|
|
||||||
<string name="no_info_provided">(Žádné informace)</string>
|
|
||||||
<string name="reboot_recovery">Restartovat do Recovery</string>
|
|
||||||
<string name="reboot_bootloader">Restartovat do Bootloaderu</string>
|
|
||||||
<string name="reboot_download">Restartovat do Download</string>
|
|
||||||
|
|
||||||
<!--Repo Fragment-->
|
|
||||||
<string name="update_available">Dostupná aktualizace</string>
|
|
||||||
<string name="home_installed_version">Nainstalováno</string>
|
|
||||||
<string name="sorting_order">Pořadí řazení</string>
|
|
||||||
|
|
||||||
<!--Log Fragment-->
|
|
||||||
<string name="menuSaveLog">Uložit log</string>
|
|
||||||
<string name="menuClearLog">Smazat log</string>
|
|
||||||
<string name="logs_cleared">Log byl smazán.</string>
|
|
||||||
|
|
||||||
<!--About Activity-->
|
|
||||||
<string name="app_changelog">Seznam změn</string>
|
<string name="app_changelog">Seznam změn</string>
|
||||||
|
<string name="manager">Správce</string>
|
||||||
|
<string name="loading">Načítání…</string>
|
||||||
|
<string name="update">Aktualizovat</string>
|
||||||
|
<string name="not_available">N/A</string>
|
||||||
|
<string name="hide">Skrýt</string>
|
||||||
|
<string name="status">Stav</string>
|
||||||
|
<string name="home_package">Balíček</string>
|
||||||
|
|
||||||
<!-- System Components, Notifications -->
|
<string name="home_notice_content">Zkontrolujte, zda používáte Magisk Manager s otevřeným kódem. Správce z neznámého zdroje může provádět nebezpečné akce!</string>
|
||||||
<string name="update_channel">Aktualizace Magisk</string>
|
<string name="home_support_title">Podpořte nás</string>
|
||||||
<string name="progress_channel">Oznámení o průběhu</string>
|
<string name="home_item_source">Zdroj</string>
|
||||||
<string name="download_complete">Stahování dokončeno</string>
|
<string name="home_support_content">Magisk je a vždy bude svobodný s otevřeným kódem. Můžete nám však zaslat malý dar jako poděkování.</string>
|
||||||
<string name="download_file_error">Chyba při stahování souboru</string>
|
<string name="home_status_normal">Normální</string>
|
||||||
<string name="magisk_update_title">Aktualizace Magisk je dostupná!</string>
|
<string name="home_status_stub">Testovací</string>
|
||||||
<string name="manager_update_title">Aktualizace Magisk Manager je dostupná!</string>
|
<string name="home_installed_version">Nainstalovaná</string>
|
||||||
|
<string name="home_latest_version">Poslední</string>
|
||||||
|
<string name="invalid_update_channel">Neplatný kanál aktualizace</string>
|
||||||
|
<string name="uninstall_magisk_title">Odinstalovat Magisk</string>
|
||||||
|
<string name="uninstall_magisk_msg">Všechny moduly budou zakázány/odstraněny!\nROOT bude odstraněn!\nPokud jsou data dešifrována, můžou být zašifrována!</string>
|
||||||
|
<string name="home_check_safetynet">Zkontrolovat SafetyNet</string>
|
||||||
|
|
||||||
<!-- Installation -->
|
<!--Install-->
|
||||||
<string name="manager_download_install">Stiskněte pro stažení a instalaci.</string>
|
<string name="keep_force_encryption">Ponechat Force Encryption</string>
|
||||||
<string name="download_zip_only">Stáhnout pouze zip</string>
|
<string name="keep_dm_verity">Ponechat AVB 2.0/DM-Verity</string>
|
||||||
|
<string name="recovery_mode">Režim Recovery</string>
|
||||||
|
<string name="install_options_title">Možnosti</string>
|
||||||
|
<string name="install_method_title">Způsob</string>
|
||||||
|
<string name="install_next">Další</string>
|
||||||
|
<string name="install_start">Spustit</string>
|
||||||
|
<string name="manager_download_install">Stiskněte pro stažení a instalaci</string>
|
||||||
|
<string name="download_zip_only">Stáhnout pouze soubor ZIP</string>
|
||||||
<string name="direct_install">Přímá instalace (doporučeno)</string>
|
<string name="direct_install">Přímá instalace (doporučeno)</string>
|
||||||
<string name="install_inactive_slot">Instalace do druhého slotu (po OTA)</string>
|
<string name="install_inactive_slot">Instalace do druhého slotu (po OTA)</string>
|
||||||
<string name="install_inactive_slot_msg">Vaše zařízení bude po restartu VYNUCENĚ spuštěno do aktuálního neaktivního slotu!\nTuto možnost použijte pouze po dokončení OTA.\nPokračovat?</string>
|
<string name="install_inactive_slot_msg">Vaše zařízení bude po restartu VYNUCENĚ spuštěno do aktuálního neaktivního slotu!\nTuto možnost použijte pouze po dokončení OTA.\nChcete pokračovat?</string>
|
||||||
<string name="setup_title">Další nastavení</string>
|
<string name="setup_title">Další nastavení</string>
|
||||||
<string name="select_patch_file">Vybrat a opravit soubor</string>
|
<string name="select_patch_file">Vybrat a opravit soubor</string>
|
||||||
<string name="patch_file_msg">Vyberte obraz raw (*.img) nebo soubor tar pro ODIN (*.tar)</string>
|
<string name="patch_file_msg">Vyberte soubor RAW (*.img) nebo soubor TAR pro ODIN (*.tar)</string>
|
||||||
<string name="reboot_delay_toast">Restartování za 5 sekund…</string>
|
<string name="reboot_delay_toast">Restartování za 5 sekund…</string>
|
||||||
|
<string name="flash_screen_title">Instalace</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Superuser-->
|
||||||
<string name="repo_install_title">Instalovat %1$s</string>
|
<string name="su_request_title">Požadavek SuperUser</string>
|
||||||
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
|
<string name="touch_filtered_warning">Protože aplikace zavírá požadavek SuperUser, Magisk nemůže ověřit Vaši odpověď</string>
|
||||||
<string name="download">Stáhnout</string>
|
<string name="deny">Zakázat</string>
|
||||||
<string name="reboot">Restartovat</string>
|
<string name="prompt">Zeptat se</string>
|
||||||
<string name="release_notes">Poznámky k vydání</string>
|
<string name="grant">Povolit</string>
|
||||||
<string name="repo_cache_cleared">Mezipaměť smazána</string>
|
<string name="su_warning">Povolí plný přístup k Vašemu zařízení.\nZakažte, pokud si nejste jisti!</string>
|
||||||
|
<string name="forever">Trvale</string>
|
||||||
|
<string name="once">Jednou</string>
|
||||||
|
<string name="tenmin">10 minut</string>
|
||||||
|
<string name="twentymin">20 minut</string>
|
||||||
|
<string name="thirtymin">30 minut</string>
|
||||||
|
<string name="sixtymin">60 minut</string>
|
||||||
|
<string name="su_allow_toast">Pro %1$s bylo oprávnění SuperUser povoleno</string>
|
||||||
|
<string name="su_deny_toast">Pro %1$s bylo oprávnění SuperUser zakázáno</string>
|
||||||
|
<string name="su_snack_grant">SuperUser oprávnění pro %1$s je povoleno</string>
|
||||||
|
<string name="su_snack_deny">SuperUser oprávnění pro %1$s je zakázáno</string>
|
||||||
|
<string name="su_snack_notif_on">Oznámení pro %1$s jsou povolena</string>
|
||||||
|
<string name="su_snack_notif_off">Oznámení pro %1$s jsou zakázána</string>
|
||||||
|
<string name="su_snack_log_on">Protokolování %1$s je povoleno</string>
|
||||||
|
<string name="su_snack_log_off">Protokolování %1$s je zakázáno</string>
|
||||||
|
<string name="su_revoke_title">Smazat?</string>
|
||||||
|
<string name="su_revoke_msg">Chcete smazat protokol k oprávnění pro %1$s?</string>
|
||||||
|
<string name="toast">Text</string>
|
||||||
|
<string name="none">Žádné</string>
|
||||||
|
|
||||||
<string name="flashing">Instalování</string>
|
<string name="superuser_toggle_notification">Oznámení</string>
|
||||||
<string name="hide_manager_title">Skrytí Magisk Manageru…</string>
|
<string name="superuser_toggle_revoke">Smazat</string>
|
||||||
<string name="hide_manager_fail_toast">Skrytí Magisk Manageru selhalo.</string>
|
<string name="superuser_policy_none">Žádná aplikace nepožádala o oprávnění SuperUser.</string>
|
||||||
<string name="open_link_failed_toast">Nebyla nalezena žádná aplikace pro otevření odkazu.</string>
|
|
||||||
<string name="complete_uninstall">Dokončete odinstalaci</string>
|
|
||||||
<string name="restore_img">Obnovit obrazy</string>
|
|
||||||
<string name="restore_img_msg">Obnovování…</string>
|
|
||||||
<string name="restore_done">Obnovení bylo provedeno!</string>
|
|
||||||
<string name="restore_fail">Výchozí záloha neexistuje!</string>
|
|
||||||
<string name="proprietary_title">Stáhnout proprietární kód</string>
|
|
||||||
<string name="proprietary_notice">Magisk Manager je FOSS a neobsahuje proprietární kód SafetyNet API společnosti Google.\n\nChcete povolit aplikaci Magisk Manager stažení rozšíření (obsahuje GoogleApiClient) pro kontrolu SafetyNet?</string>
|
|
||||||
<string name="setup_fail">Nastavení selhalo.</string>
|
|
||||||
<string name="env_fix_title">Vyžaduje se další nastavení</string>
|
|
||||||
<string name="env_fix_msg">Vaše zařízení potřebuje další nastavení, aby Magisk fungoval správně. Stáhne se instalační zip Magisk, chcete pokračovat?</string>
|
|
||||||
<string name="setup_msg">Nastavení je spuštěno…</string>
|
|
||||||
|
|
||||||
<!--Settings Activity -->
|
<!--Logs-->
|
||||||
<string name="settings_clear_cache_title">Smazat uchovanou mezipaměť</string>
|
<string name="log_data_none">Žádné protokoly. Vyzkoušejte nějakou aplikaci vyžadující oprávnění SuperUser.</string>
|
||||||
<string name="settings_clear_cache_summary">Smaže informace online použití v mezipaměti, donutí aplikaci obnovit informace online.</string>
|
<string name="log_data_magisk_none">Protokoly Magisk jsou prázdné. To je zvláštní!</string>
|
||||||
|
<string name="menuSaveLog">Uložit protokol</string>
|
||||||
|
<string name="menuClearLog">Smazat protokol</string>
|
||||||
|
<string name="logs_cleared">Protokol byl smazán</string>
|
||||||
|
<string name="pid">PID:%1$d</string>
|
||||||
|
<string name="target_uid">Cílové UID: %1$d</string>
|
||||||
|
|
||||||
|
<!--SafetyNet-->
|
||||||
|
<string name="safetynet_api_error">Chyba SafetyNet API</string>
|
||||||
|
<string name="safetynet_res_invalid">Odpověď je neplatná</string>
|
||||||
|
<string name="safetynet_attest_success">Úspěšné!</string>
|
||||||
|
<string name="safetynet_attest_failure">Chyba ověření!</string>
|
||||||
|
<string name="safetynet_attest_loading">Čekejte…</string>
|
||||||
|
<string name="safetynet_attest_restart">Zkusit znovu</string>
|
||||||
|
|
||||||
|
<!--MagiskHide-->
|
||||||
|
<string name="show_system_app">Zobrazit systémové aplikace</string>
|
||||||
|
<string name="show_os_app">Zobrazit OS aplikace</string>
|
||||||
|
<string name="hide_filter_hint">Filtrovat podle názvu</string>
|
||||||
|
<string name="hide_scroll_up">Posunout nahoru</string>
|
||||||
|
<string name="hide_filters">Filtry</string>
|
||||||
|
<string name="hide_search">Vyhledávání</string>
|
||||||
|
|
||||||
|
<!--Module-->
|
||||||
|
<string name="no_info_provided">(žádné informace)</string>
|
||||||
|
<string name="reboot_userspace">Restartovat do UserSpace</string>
|
||||||
|
<string name="reboot_recovery">Restartovat do Recovery</string>
|
||||||
|
<string name="reboot_bootloader">Restartovat do Bootloader</string>
|
||||||
|
<string name="reboot_download">Restartovat do Download</string>
|
||||||
|
<string name="reboot_edl">Restartovat do EDL</string>
|
||||||
|
<string name="module_version_author">%1$s z %2$s</string>
|
||||||
|
<string name="module_section_pending">Aktualizace</string>
|
||||||
|
<string name="module_section_pending_action">Aktualizovat vše</string>
|
||||||
|
<string name="module_state_remove">Odstranit</string>
|
||||||
|
<string name="module_state_restore">Obnovit</string>
|
||||||
|
<string name="module_action_install_external">Instalace z úložiště</string>
|
||||||
|
<string name="update_available">Dostupná aktualizace</string>
|
||||||
|
<string name="module_installed">@string/home_installed_version</string>
|
||||||
|
<string name="module_section_online">Online</string>
|
||||||
|
<string name="sorting_order">Seřadit</string>
|
||||||
|
|
||||||
|
<!--Settings-->
|
||||||
|
<string name="settings_dark_mode_title">Režim motivu</string>
|
||||||
|
<string name="settings_dark_mode_message">Vyberte režim, který nejlépe vyhovuje Vašemu stylu!</string>
|
||||||
|
<string name="settings_dark_mode_light">Světlý</string>
|
||||||
|
<string name="settings_dark_mode_system">Podle systému</string>
|
||||||
|
<string name="settings_dark_mode_dark">Tmavý</string>
|
||||||
|
<string name="settings_download_path_title">Složka pro stahování</string>
|
||||||
|
<string name="settings_download_path_message">Soubory budou uloženy do %1$s.</string>
|
||||||
|
<string name="settings_clear_cache_title">Smazat mezipaměť</string>
|
||||||
|
<string name="settings_clear_cache_summary">Smažete online informace o použití z mezipaměti, a tím na aplikaci vynutíte obnovení online informací.</string>
|
||||||
<string name="settings_hide_manager_title">Skrýt Magisk Manager</string>
|
<string name="settings_hide_manager_title">Skrýt Magisk Manager</string>
|
||||||
<string name="settings_hide_manager_summary">Nahradí Magisk Manager náhodným názvem balíčku.</string>
|
<string name="settings_hide_manager_summary">Nahradíte Magisk Manager náhodným názvem balíčku.</string>
|
||||||
<string name="settings_restore_manager_title">Obnovit Magisk Manager</string>
|
<string name="settings_restore_manager_title">Obnovit Magisk Manager</string>
|
||||||
<string name="settings_restore_manager_summary">Obnoví Magisk Manager na původní název balíčku.</string>
|
<string name="settings_restore_manager_summary">Obnovíte Magisk Manager na původní název balíčku.</string>
|
||||||
<string name="language">Jazyk</string>
|
<string name="language">Jazyk</string>
|
||||||
<string name="system_default">(Výchozí systémový)</string>
|
<string name="system_default">(výchozí podle systému)</string>
|
||||||
<string name="settings_check_update_title">Zkontrolovat aktualizace</string>
|
<string name="settings_check_update_title">Automatické aktualizace</string>
|
||||||
<string name="settings_check_update_summary">Pravidelně kontrolujte aktualizace na pozadí.</string>
|
<string name="settings_check_update_summary">Povolíte pravidelnou kontrolu aktualizace na pozadí.</string>
|
||||||
<string name="settings_update_channel_title">Kanál aktualizace</string>
|
<string name="settings_update_channel_title">Kanál aktualizace</string>
|
||||||
<string name="settings_update_stable">Stabilní</string>
|
<string name="settings_update_stable">Stabilní</string>
|
||||||
<string name="settings_update_beta">Beta</string>
|
<string name="settings_update_beta">Beta</string>
|
||||||
<string name="settings_update_custom">Vlastní</string>
|
<string name="settings_update_custom">Vlastní</string>
|
||||||
<string name="settings_update_custom_msg">Vložte vlastní URL</string>
|
<string name="settings_update_custom_msg">Vložte vlastní URL</string>
|
||||||
<string name="settings_magiskhide_summary">Skrýt Magisk z různých detekcí.</string>
|
<string name="settings_magiskhide_summary">Skryjete Magisk před různými detekcemi.</string>
|
||||||
<string name="settings_hosts_title">Nesystémoví hostitelé</string>
|
<string name="settings_hosts_title">Nesystémový hostitel</string>
|
||||||
<string name="settings_hosts_summary">Podpora nesystémových hostitelů pro aplikace Adblock.</string>
|
<string name="settings_hosts_summary">Přidáte modul pro podporu nesystémových hostitelů v aplikaci AdBlock.</string>
|
||||||
<string name="settings_hosts_toast">Přidán systémový modul hostitelů</string>
|
<string name="settings_hosts_toast">Přidán systémový modul hostitelů</string>
|
||||||
|
<string name="settings_app_name_hint">Nový název</string>
|
||||||
|
<string name="settings_app_name_helper">Název aplikace bude nahrazen tímto názvem.</string>
|
||||||
|
<string name="settings_app_name_error">Neplatný formát</string>
|
||||||
<string name="settings_su_app_adb">Aplikace a ADB</string>
|
<string name="settings_su_app_adb">Aplikace a ADB</string>
|
||||||
<string name="settings_su_app">Pouze aplikace</string>
|
<string name="settings_su_app">Pouze aplikace</string>
|
||||||
<string name="settings_su_adb">Pouze ADB</string>
|
<string name="settings_su_adb">Pouze ADB</string>
|
||||||
<string name="settings_su_disable">Zakázáno</string>
|
<string name="settings_su_disable">Zakázat</string>
|
||||||
<string name="settings_su_request_10">10 sekund</string>
|
<string name="settings_su_request_10">10 sekund</string>
|
||||||
<string name="settings_su_request_15">15 sekund</string>
|
<string name="settings_su_request_15">15 sekund</string>
|
||||||
<string name="settings_su_request_20">20 sekund</string>
|
<string name="settings_su_request_20">20 sekund</string>
|
||||||
<string name="settings_su_request_30">30 sekund</string>
|
<string name="settings_su_request_30">30 sekund</string>
|
||||||
<string name="settings_su_request_45">45 sekund</string>
|
<string name="settings_su_request_45">45 sekund</string>
|
||||||
<string name="settings_su_request_60">60 sekund</string>
|
<string name="settings_su_request_60">60 sekund</string>
|
||||||
<string name="superuser_access">Přístup Superuser</string>
|
<string name="superuser_access">Přístup SuperUser</string>
|
||||||
<string name="auto_response">Automatická odezva</string>
|
<string name="auto_response">Automatická odezva</string>
|
||||||
<string name="request_timeout">Časový limit požadavku</string>
|
<string name="request_timeout">Časový limit požadavku</string>
|
||||||
<string name="superuser_notification">Oznámení Superuser</string>
|
<string name="superuser_notification">Oznámení SuperUser</string>
|
||||||
<string name="settings_su_reauth_title">Opětovné ověření po aktualizaci</string>
|
<string name="settings_su_reauth_title">Opětovné ověření po aktualizaci</string>
|
||||||
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění Superuser po aktualizaci aplikace</string>
|
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění SuperUser po aktualizaci aplikace.</string>
|
||||||
|
<string name="settings_su_tapjack_title">Povolit ochranu před TapJack</string>
|
||||||
|
<string name="settings_su_tapjack_summary">Okno dialogu SuperUser nebude reagovat na kliknutí v případě, že je zavřené nebo překryté jiným oknem.</string>
|
||||||
|
<string name="settings_su_biometric_title">Povolit biometrické ověření</string>
|
||||||
|
<string name="settings_su_biometric_summary">Použijte biometrické ověření pro povolení požadavků SuperUser.</string>
|
||||||
|
<string name="no_biometric">Nepodporované zařízení nebo není biometrické ověření povolené</string>
|
||||||
|
<string name="settings_customization">Přizpůsobit</string>
|
||||||
|
<string name="setting_add_shortcut_summary">Přidejte odkaz na domovskou obrazovku v případě, že se po skrytí aplikace její název a ikona těžko rozpoznávají.</string>
|
||||||
|
<string name="settings_doh_title">DNS nebo HTTPS</string>
|
||||||
|
<string name="settings_doh_description">Řešení pro opravy DNS v některých zemích.</string>
|
||||||
|
|
||||||
<string name="multiuser_mode">Režim více uživatelů</string>
|
<string name="multiuser_mode">Režim více uživatelů</string>
|
||||||
<string name="settings_owner_only">Pouze vlastník zařízení</string>
|
<string name="settings_owner_only">Vlastník zařízení</string>
|
||||||
<string name="settings_owner_manage">Spravováno vlastníkem zařízení</string>
|
<string name="settings_owner_manage">Správce zařízení</string>
|
||||||
<string name="settings_user_independent">Nezávislý uživatel</string>
|
<string name="settings_user_independent">Všichni uživatelé</string>
|
||||||
<string name="owner_only_summary">Pouze vlastník má root přístup.</string>
|
<string name="owner_only_summary">Pouze vlastník má přístup ROOT.</string>
|
||||||
<string name="owner_manage_summary">Root přístup spravuje pouze vlastník a přijímá požadavky k přístupu.</string>
|
<string name="owner_manage_summary">Přístup ROOT má správce zařízení, který přijímá požadavky k přístupu.</string>
|
||||||
<string name="user_indepenent_summary">Každý uživatel má svá vlastní pravidla root.</string>
|
<string name="user_indepenent_summary">Každý uživatel má svá vlastní pravidla přístupu ROOT.</string>
|
||||||
|
|
||||||
<string name="mount_namespace_mode">Režim připojení jmenného prostoru</string>
|
<string name="mount_namespace_mode">Režim připojení jmenného prostoru</string>
|
||||||
<string name="settings_ns_global">Globální jmenný prostor</string>
|
<string name="settings_ns_global">Globální jmenný prostor</string>
|
||||||
<string name="settings_ns_requester">Zděděný jmenný prostor</string>
|
<string name="settings_ns_requester">Odvozený jmenný prostor</string>
|
||||||
<string name="settings_ns_isolate">Izolovaný jmenný prostor</string>
|
<string name="settings_ns_isolate">Izolovaný jmenný prostor</string>
|
||||||
<string name="global_summary">Všechny relace root používají globální připojení jmenného prostoru.</string>
|
<string name="global_summary">Všechny relace ROOT používají globální jmenný prostor.</string>
|
||||||
<string name="requester_summary">Kořenové relace dědí jmenný prostor žadatele.</string>
|
<string name="requester_summary">Relace ROOT je odvozena od jmenného prostoru žadatele.</string>
|
||||||
<string name="isolate_summary">Každá relace root bude mít svůj vlastní izolovaný jmenný prostor.</string>
|
<string name="isolate_summary">Každá relace ROOT má svůj vlastní izolovaný jmenný prostor.</string>
|
||||||
|
|
||||||
<!--Superuser-->
|
<!--Notifications-->
|
||||||
<string name="su_request_title">Požadavek Superuser</string>
|
<string name="update_channel">Aktualizace Magisk</string>
|
||||||
<string name="deny">Zamítnout</string>
|
<string name="progress_channel">Oznámení o průběhu</string>
|
||||||
<string name="prompt">Dotaz</string>
|
<string name="download_complete">Stahování dokončeno</string>
|
||||||
<string name="grant">Povolit</string>
|
<string name="download_file_error">Chyba při stahování souboru</string>
|
||||||
<string name="su_warning">Povolí plný přístup k vašemu zařízení.\nZamítněte, pokud si nejste jisti!</string>
|
<string name="download_open_parent">Zobrazit výchozí složku</string>
|
||||||
<string name="forever">Navždy</string>
|
<string name="download_open_self">Zobrazit soubor</string>
|
||||||
<string name="once">Jednou</string>
|
<string name="magisk_update_title">Aktualizace Magisk je dostupná!</string>
|
||||||
<string name="tenmin">10 minut</string>
|
<string name="manager_update_title">Aktualizace Magisk Manager je dostupná!</string>
|
||||||
<string name="twentymin">20 minut</string>
|
|
||||||
<string name="thirtymin">30 minut</string>
|
|
||||||
<string name="sixtymin">60 minut</string>
|
|
||||||
<string name="su_allow_toast">Pro %1$s bylo oprávnění Superuser povoleno</string>
|
|
||||||
<string name="su_deny_toast">Pro %1$s bylo oprávnění Superuser zamítnuto</string>
|
|
||||||
<string name="su_snack_grant">Superuser oprávnění pro %1$s je povoleno</string>
|
|
||||||
<string name="su_snack_deny">Superuser oprávnění pro %1$s je zamítnuto</string>
|
|
||||||
<string name="su_snack_notif_on">Oznámení pro %1$s jsou povolena</string>
|
|
||||||
<string name="su_snack_notif_off">Oznámení pro %1$s jsou zakázána</string>
|
|
||||||
<string name="su_snack_log_on">Logování %1$s je povoleno</string>
|
|
||||||
<string name="su_snack_log_off">Logování %1$s je zakázáno</string>
|
|
||||||
<string name="su_revoke_title">Smazat?</string>
|
|
||||||
<string name="su_revoke_msg">Smazat záznam ohledně oprávnění pro %1$s?</string>
|
|
||||||
<string name="toast">Informační text</string>
|
|
||||||
<string name="none">Žádný</string>
|
|
||||||
|
|
||||||
<!--Superuser logs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="pid">PID: %1$d</string>
|
<string name="yes">ANO</string>
|
||||||
<string name="target_uid">Cílové UID: %1$d</string>
|
<string name="no">NE</string>
|
||||||
|
<string name="repo_install_title">Instalovat %1$s</string>
|
||||||
<!-- MagiskHide -->
|
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
|
||||||
<string name="show_system_app">Zobrazit systémové aplikace</string>
|
<string name="download">Stáhnout</string>
|
||||||
|
<string name="reboot">Restartovat</string>
|
||||||
|
<string name="release_notes">Poznámky k vydání</string>
|
||||||
|
<string name="repo_cache_cleared">Mezipaměť smazána</string>
|
||||||
|
<string name="flashing">Instalování…</string>
|
||||||
|
<string name="done">Hotovo!</string>
|
||||||
|
<string name="failure">Selhalo!</string>
|
||||||
|
<string name="hide_manager_title">Skrývání Magisk Manager…</string>
|
||||||
|
<string name="hide_manager_fail_toast">Skrývání Magisk Manager selhalo.</string>
|
||||||
|
<string name="restore_manager_fail_toast">Obnovení Magisk Manager selhalo.</string>
|
||||||
|
<string name="open_link_failed_toast">Nebyla nalezena žádná aplikace pro otevření odkazu.</string>
|
||||||
|
<string name="complete_uninstall">Odinstalovat</string>
|
||||||
|
<string name="restore_img">Obnovit obrazy</string>
|
||||||
|
<string name="restore_img_msg">Obnovování…</string>
|
||||||
|
<string name="restore_done">Obnovení bylo provedeno!</string>
|
||||||
|
<string name="restore_fail">Výchozí záloha neexistuje!</string>
|
||||||
|
<string name="proprietary_title">Stáhnout kód</string>
|
||||||
|
<string name="proprietary_notice">Magisk Manager je FOSS a neobsahuje kód SafetyNet API společnosti Google.\n\nChcete povolit aplikaci Magisk Manager stažení rozšíření (obsahuje GoogleApiClient) pro kontrolu SafetyNet?</string>
|
||||||
|
<string name="setup_fail">Nastavení selhalo</string>
|
||||||
|
<string name="env_fix_title">Vyžaduje se další nastavení</string>
|
||||||
|
<string name="env_fix_msg">Vaše zařízení potřebuje další nastavení, aby Magisk fungoval správně. Stáhne se instalační soubor (.zip) Magisk. Chcete pokračovat?</string>
|
||||||
|
<string name="setup_msg">Nastavení je spuštěno…</string>
|
||||||
|
<string name="authenticate">Ověřit</string>
|
||||||
|
<string name="unsupport_magisk_title">Nepodporovaná verze Magisk</string>
|
||||||
|
<string name="unsupport_magisk_msg">Tato verze Magisk Manager nepodporuje verzi Magisk nižší než %1$s.\n\nMůžete buď ručně aktualizovat Magisk, nebo nainstalovat starší verzi aplikace.</string>
|
||||||
|
<string name="external_rw_permission_denied">Udělte oprávnění pro povolení této funkce.</string>
|
||||||
|
<string name="add_shortcut_title">Přidat odkaz na domovskou obrazovku</string>
|
||||||
|
<string name="add_shortcut_msg">Po skrytí Magisk Manager se může jeho název a ikona těžko rozpoznat. Chcete přidat odkaz na domovskou obrazovku?</string>
|
||||||
|
<string name="app_not_found">Nelze nalézt žádnou aplikaci, která dokáže provést tuto akci.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
<string name="no_connection">Keine Verbindung verfügbar</string>
|
<string name="no_connection">Keine Verbindung verfügbar</string>
|
||||||
<string name="app_changelog">Änderungen</string>
|
<string name="app_changelog">Änderungen</string>
|
||||||
<string name="manager">Manager</string>
|
<string name="manager">Manager</string>
|
||||||
<string name="loading">Lädt…</string>
|
<string name="loading">Laden…</string>
|
||||||
<string name="update">Update</string>
|
<string name="update">Update</string>
|
||||||
<string name="not_available">N/A</string>
|
<string name="not_available">N/A</string>
|
||||||
<string name="hide">Verstecken</string>
|
<string name="hide">Verstecken</string>
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
<string name="recovery_mode">Recovery Modus</string>
|
<string name="recovery_mode">Recovery Modus</string>
|
||||||
<string name="install_options_title">Optionen</string>
|
<string name="install_options_title">Optionen</string>
|
||||||
<string name="install_method_title">Methode</string>
|
<string name="install_method_title">Methode</string>
|
||||||
<string name="install_next">Nächste</string>
|
<string name="install_next">Nächster Schritt</string>
|
||||||
<string name="install_start">Los geht\'s</string>
|
<string name="install_start">Los geht\'s</string>
|
||||||
<string name="manager_download_install">Tippen zum Herunterladen und Installieren</string>
|
<string name="manager_download_install">Tippen zum Herunterladen und Installieren</string>
|
||||||
<string name="download_zip_only">Nur Zip herunterladen</string>
|
<string name="download_zip_only">Nur Zip herunterladen</string>
|
||||||
|
@@ -44,7 +44,7 @@
|
|||||||
<string name="install_next">Ďalej</string>
|
<string name="install_next">Ďalej</string>
|
||||||
<string name="install_start">Poďme na to</string>
|
<string name="install_start">Poďme na to</string>
|
||||||
<string name="manager_download_install">Stlačte pre stiahnutie a inštaláciu</string>
|
<string name="manager_download_install">Stlačte pre stiahnutie a inštaláciu</string>
|
||||||
<string name="download_zip_only">Len tiahnuť zip</string>
|
<string name="download_zip_only">Len stiahnuť zip</string>
|
||||||
<string name="direct_install">Priama inštalácia (Odporúča sa)</string>
|
<string name="direct_install">Priama inštalácia (Odporúča sa)</string>
|
||||||
<string name="install_inactive_slot">Inštalovať na neaktívny slot (Po OTA)</string>
|
<string name="install_inactive_slot">Inštalovať na neaktívny slot (Po OTA)</string>
|
||||||
<string name="install_inactive_slot_msg">Vaše zariadenie bude po reštarte PRINÚTENÉ nabootovať do aktuálne neaktívneho slotu!\nTúto voľbu použite iba po skončení OTA.\nPokračovať?</string>
|
<string name="install_inactive_slot_msg">Vaše zariadenie bude po reštarte PRINÚTENÉ nabootovať do aktuálne neaktívneho slotu!\nTúto voľbu použite iba po skončení OTA.\nPokračovať?</string>
|
||||||
|
@@ -28,11 +28,11 @@
|
|||||||
<string name="home_support_content">Magisk është, dhe gjithmonë do të jetë, falas dhe me burim të hapur. Megjithatë mund të na tregoni se ju interesoni duke dërguar një donacion të vogël.</string>
|
<string name="home_support_content">Magisk është, dhe gjithmonë do të jetë, falas dhe me burim të hapur. Megjithatë mund të na tregoni se ju interesoni duke dërguar një donacion të vogël.</string>
|
||||||
<string name="home_status_normal">Normale</string>
|
<string name="home_status_normal">Normale</string>
|
||||||
<string name="home_status_stub">Stub</string>
|
<string name="home_status_stub">Stub</string>
|
||||||
<string name="home_installed_version">Instaluar</string>
|
<string name="home_installed_version">E instaluar</string>
|
||||||
<string name="home_latest_version">Më të fundit</string>
|
<string name="home_latest_version">Më e fundit</string>
|
||||||
<string name="invalid_update_channel">Kanal i pavlefshëm i azhurnimit</string>
|
<string name="invalid_update_channel">Kanal i pavlefshëm i azhurnimit</string>
|
||||||
<string name="uninstall_magisk_title">Çinstalo Magisk</string>
|
<string name="uninstall_magisk_title">Çinstalo Magisk</string>
|
||||||
<string name="uninstall_magisk_msg">Të gjitha modulet do të çaktivizohen/hiqen! \n Rrënja do të hiqet! \n Të dhënat tuaja potencialisht të koduara nëse jo tashmë!</string>
|
<string name="uninstall_magisk_msg">Të gjitha modulet do të çaktivizohen/hiqen! \n Rrënja do të hiqet! \n\n Të dhënat tuaja potencialisht të koduara nëse jo tashmë!</string>
|
||||||
<string name="home_check_safetynet">Kontrolloni Rrjetin e Sigurisë</string>
|
<string name="home_check_safetynet">Kontrolloni Rrjetin e Sigurisë</string>
|
||||||
|
|
||||||
<!--Install-->
|
<!--Install-->
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
<string name="prompt">Pyet</string>
|
<string name="prompt">Pyet</string>
|
||||||
<string name="grant">Lejo</string>
|
<string name="grant">Lejo</string>
|
||||||
<string name="su_warning">Jep akses të plotë në pajisjen tuaj. \n Moho nëse nuk je i sigurt!</string>
|
<string name="su_warning">Jep akses të plotë në pajisjen tuaj. \n Moho nëse nuk je i sigurt!</string>
|
||||||
<string name="forever">Përgjithmonë</string>
|
<string name="forever">Gjithmonë</string>
|
||||||
<string name="once">Një herë</string>
|
<string name="once">Një herë</string>
|
||||||
<string name="tenmin">10 minuta</string>
|
<string name="tenmin">10 minuta</string>
|
||||||
<string name="twentymin">20 minuta</string>
|
<string name="twentymin">20 minuta</string>
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
<string name="su_revoke_title">Anulohet?</string>
|
<string name="su_revoke_title">Anulohet?</string>
|
||||||
<string name="su_revoke_msg">Konfirmo të heqësh të drejtat e %1$s?</string>
|
<string name="su_revoke_msg">Konfirmo të heqësh të drejtat e %1$s?</string>
|
||||||
<string name="toast">dolli</string>
|
<string name="toast">dolli</string>
|
||||||
|
<string name="none">Asnjë</string>
|
||||||
<string name="superuser_toggle_notification">Njoftimet</string>
|
<string name="superuser_toggle_notification">Njoftimet</string>
|
||||||
<string name="superuser_toggle_revoke">Anulo</string>
|
<string name="superuser_toggle_revoke">Anulo</string>
|
||||||
<string name="superuser_policy_none">Asnjë aplikacion nuk ka kërkuar ende leje për superpërdoruesin.</string>
|
<string name="superuser_policy_none">Asnjë aplikacion nuk ka kërkuar ende leje për superpërdoruesin.</string>
|
||||||
@@ -95,7 +96,7 @@
|
|||||||
<string name="safetynet_res_invalid">Përgjigjja është e pavlefshme </string>
|
<string name="safetynet_res_invalid">Përgjigjja është e pavlefshme </string>
|
||||||
<string name="safetynet_attest_success">Suksese!</string>
|
<string name="safetynet_attest_success">Suksese!</string>
|
||||||
<string name="safetynet_attest_failure">Vërtetimi dështoi!</string>
|
<string name="safetynet_attest_failure">Vërtetimi dështoi!</string>
|
||||||
<string name="safetynet_attest_loading">Thjesht një sekondë…</string>
|
<string name="safetynet_attest_loading">Prit një sekondë…</string>
|
||||||
<string name="safetynet_attest_restart">Provo përsëri</string>
|
<string name="safetynet_attest_restart">Provo përsëri</string>
|
||||||
|
|
||||||
<!--MagiskHide-->
|
<!--MagiskHide-->
|
||||||
@@ -111,7 +112,7 @@
|
|||||||
<string name="reboot_userspace">Ristartim normal</string>
|
<string name="reboot_userspace">Ristartim normal</string>
|
||||||
<string name="reboot_recovery">Ristartoni në recovery</string>
|
<string name="reboot_recovery">Ristartoni në recovery</string>
|
||||||
<string name="reboot_bootloader">Ristartoni në bootloader</string>
|
<string name="reboot_bootloader">Ristartoni në bootloader</string>
|
||||||
<string name="reboot_download">Ristartoni për në download</string>
|
<string name="reboot_download">Ristartoni në download</string>
|
||||||
<string name="reboot_edl">Ristartoni në EDL</string>
|
<string name="reboot_edl">Ristartoni në EDL</string>
|
||||||
<string name="module_version_author">%1$s nga %2$s</string>
|
<string name="module_version_author">%1$s nga %2$s</string>
|
||||||
<string name="module_state_remove">Hiq</string>
|
<string name="module_state_remove">Hiq</string>
|
||||||
@@ -156,6 +157,12 @@
|
|||||||
<string name="settings_su_app">Vetëm aplikacionet</string>
|
<string name="settings_su_app">Vetëm aplikacionet</string>
|
||||||
<string name="settings_su_adb">Vetëm ADB</string>
|
<string name="settings_su_adb">Vetëm ADB</string>
|
||||||
<string name="settings_su_disable">Çaktivizuar</string>
|
<string name="settings_su_disable">Çaktivizuar</string>
|
||||||
|
<string name="settings_su_request_10">10 Sekonda</string>
|
||||||
|
<string name="settings_su_request_15">15 Sekonda</string>
|
||||||
|
<string name="settings_su_request_20">20 Sekonda</string>
|
||||||
|
<string name="settings_su_request_30">30 Sekonda</string>
|
||||||
|
<string name="settings_su_request_45">45 Sekonda</string>
|
||||||
|
<string name="settings_su_request_60">60 Sekonda</string>
|
||||||
<string name="superuser_access">Hyrja në superpërdorues</string>
|
<string name="superuser_access">Hyrja në superpërdorues</string>
|
||||||
<string name="auto_response">Përgjigje Automatike</string>
|
<string name="auto_response">Përgjigje Automatike</string>
|
||||||
<string name="request_timeout">Koha e kërkesës</string>
|
<string name="request_timeout">Koha e kërkesës</string>
|
||||||
@@ -207,7 +214,7 @@
|
|||||||
<string name="failure">Dështoi!</string>
|
<string name="failure">Dështoi!</string>
|
||||||
<string name="hide_manager_title">Fshehja e Magisk manager…</string>
|
<string name="hide_manager_title">Fshehja e Magisk manager…</string>
|
||||||
<string name="hide_manager_fail_toast">Fsheh Menaxherin e Magisk dështoi</string>
|
<string name="hide_manager_fail_toast">Fsheh Menaxherin e Magisk dështoi</string>
|
||||||
<string name="restore_manager_fail_toast">Rikthe menaxherin e Magisk dështoi</string>
|
<string name="restore_manager_fail_toast">Rikthimi i menaxherin e Magisk dështoi</string>
|
||||||
<string name="open_link_failed_toast">Asnjë aplikacion nuk u gjet për të hapur lidhjen</string>
|
<string name="open_link_failed_toast">Asnjë aplikacion nuk u gjet për të hapur lidhjen</string>
|
||||||
<string name="complete_uninstall">Çinstalimi i plotë</string>
|
<string name="complete_uninstall">Çinstalimi i plotë</string>
|
||||||
<string name="restore_img">Rikthe Imazhet</string>
|
<string name="restore_img">Rikthe Imazhet</string>
|
||||||
|
@@ -132,7 +132,7 @@
|
|||||||
<string name="settings_dark_mode_message">Stilinize en iyi uyan modu seçin!</string>
|
<string name="settings_dark_mode_message">Stilinize en iyi uyan modu seçin!</string>
|
||||||
<string name="settings_dark_mode_light">Her Zaman Aydınlık</string>
|
<string name="settings_dark_mode_light">Her Zaman Aydınlık</string>
|
||||||
<string name="settings_dark_mode_system">Sistemi Takip Et</string>
|
<string name="settings_dark_mode_system">Sistemi Takip Et</string>
|
||||||
<string name="settings_dark_mode_dark">Her Zmana Karanlık</string>
|
<string name="settings_dark_mode_dark">Her Zaman Karanlık</string>
|
||||||
<string name="settings_download_path_title">İndirme dizini</string>
|
<string name="settings_download_path_title">İndirme dizini</string>
|
||||||
<string name="settings_download_path_message">Dosyalar %1$s konumuna kaydedilecek</string>
|
<string name="settings_download_path_message">Dosyalar %1$s konumuna kaydedilecek</string>
|
||||||
<string name="settings_clear_cache_title">Depo Önbelleğini Temizle</string>
|
<string name="settings_clear_cache_title">Depo Önbelleğini Temizle</string>
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
# Magisk Documentation
|
# Magisk Documentation
|
||||||
(Updated on 2020.11.13)
|
|
||||||
|
|
||||||
- [Installation Instructions](install.md)
|
- [Installation Instructions](install.md)
|
||||||
- [Frequently Asked Questions](faq.md)
|
- [Frequently Asked Questions](faq.md)
|
||||||
|
@@ -1,5 +1,18 @@
|
|||||||
# Magisk Manager Changelog
|
# Magisk Manager Changelog
|
||||||
|
|
||||||
|
### v8.0.7
|
||||||
|
|
||||||
|
- Fix sepolicy rule migration when upgrading
|
||||||
|
|
||||||
|
### v8.0.6
|
||||||
|
|
||||||
|
- Minor UI changes
|
||||||
|
- Update internal scripts
|
||||||
|
|
||||||
|
### v8.0.5
|
||||||
|
|
||||||
|
- Fix sepolicy rule copying
|
||||||
|
|
||||||
### v8.0.4
|
### v8.0.4
|
||||||
|
|
||||||
- A lot of stability changes and minor bug fixes
|
- A lot of stability changes and minor bug fixes
|
||||||
|
@@ -1,5 +1,16 @@
|
|||||||
# Magisk Changelog
|
# Magisk Changelog
|
||||||
|
|
||||||
|
### v21.4
|
||||||
|
|
||||||
|
- [MagiskSU] Fix `su -c` behavior that broke many root apps
|
||||||
|
- [General] Properly handle read/write over sockets (the `broken pipe` issue)
|
||||||
|
|
||||||
|
### v21.3
|
||||||
|
|
||||||
|
- [MagiskInit] Avoid mounting `f2fs` userdata as it may result in kernel crashes. This shall fix a lot of bootloops
|
||||||
|
- [MagiskBoot] Fix a minor header checksum bug for `DHTB` header and ASUS `blob` image formats
|
||||||
|
- [MagiskHide] Allowing hiding isolated processes if the mount namespace is separated
|
||||||
|
|
||||||
### v21.2
|
### v21.2
|
||||||
|
|
||||||
- [MagiskInit] Detect 2SI after mounting `system_root` on legacy SAR devices
|
- [MagiskInit] Detect 2SI after mounting `system_root` on legacy SAR devices
|
||||||
|
@@ -17,7 +17,7 @@ Download and install the latest Magisk Manager. We use the app to gather some in
|
|||||||
|
|
||||||
<p align="center"><img src="images/device_info.png" width="500"/></p>
|
<p align="center"><img src="images/device_info.png" width="500"/></p>
|
||||||
|
|
||||||
Pay special attention to the **Ramdisk** info. If the result is **Yes**, congratulations, your device is perfect for installing Magisk! However, if the result is **No**, this means your device's boot partition does **NOT** include ramdisk, and unfortunately you would have to go through some hoops to make Magisk work properly.
|
Pay special attention to the **Ramdisk** info. If the result is **Yes**, congratulations, your device is perfect for installing Magisk! However, if the result is **No** this means your device's boot partition does **NOT** include ramdisk. This means you will have to go through some extra steps to make Magisk work properly.
|
||||||
|
|
||||||
> **If your device does not have boot ramdisk, read the [Magisk in Recovery](#magisk-in-recovery) section after installing. The information in that section is VERY important!**
|
> **If your device does not have boot ramdisk, read the [Magisk in Recovery](#magisk-in-recovery) section after installing. The information in that section is VERY important!**
|
||||||
|
|
||||||
@@ -27,15 +27,15 @@ If you are using a Huawei device and the **SAR** result is **Yes**, please check
|
|||||||
|
|
||||||
Otherwise, continue to [Patching Images](#patching-images).
|
Otherwise, continue to [Patching Images](#patching-images).
|
||||||
|
|
||||||
(P.S.1 If your device have boot ramdisk, you can also install with [Custom Recovery](#custom-recovery))<br>
|
(P.S.1 If your device has boot ramdisk, you can also install with [Custom Recovery](#custom-recovery))<br>
|
||||||
(P.S.2 If you are interested in how Android boots and how it affects Magisk, check out [this document](boot.md))
|
(P.S.2 If you are interested in how Android boots and how it affects Magisk, check out [this document](boot.md))
|
||||||
|
|
||||||
## Patching Images
|
## Patching Images
|
||||||
|
|
||||||
If your device have boot ramdisk, you need a copy of the `boot.img`<br>
|
If your device has boot ramdisk, you need a copy of the `boot.img`<br>
|
||||||
If your device does **NOT** have boot ramdisk, you need a copy of the `recovery.img`
|
If your device does **NOT** have boot ramdisk, you need a copy of the `recovery.img`
|
||||||
|
|
||||||
You should be able to extract either of them from official firmware packages, your custom ROM zip (if using one), or go to [XDA-Developers](https://forum.xda-developers.com/) and seek for resources, guides, discussions, or ask for help in your device's forum.
|
You should be able to extract the file you need from official firmware packages or your custom ROM zip (if using one). If you are still having trouble, go to [XDA-Developers](https://forum.xda-developers.com/) and look for resources, guides, discussions, or ask for help in your device's forum.
|
||||||
|
|
||||||
- Copy the boot/recovery image to your device
|
- Copy the boot/recovery image to your device
|
||||||
- Press the **Install** button in the Magisk card
|
- Press the **Install** button in the Magisk card
|
||||||
@@ -52,7 +52,7 @@ For most devices, reboot into fastboot mode and flash with command:<br>
|
|||||||
|
|
||||||
## Custom Recovery
|
## Custom Recovery
|
||||||
|
|
||||||
In some custom recoveries of modern devices, the installer scripts either cannot properly detect the correct device info, or the recovery environment does not meet its expectation, causing the installation to fail (or looks like success but actually bootloops). If you face any issues, use the [Patch Image](#patching-images) method as it is guaranteed to work 100% of the time. Due to this reason, we no longer recommend installing Magisk through custom recoveries on modern devices. The custom recovery installation method exists mostly for legacy support.
|
In some custom recoveries the installation may fail (this may look like success but actually bootloops). This is because the installer scripts cannot properly detect the correct device info or the recovery environment does not meet its expectation. If you face any issues, use the [Patch Image](#patching-images) method as it is guaranteed to work 100% of the time. Due to this reason, we no longer recommend installing Magisk through custom recoveries on modern devices. The custom recovery installation method exists mostly for legacy support.
|
||||||
|
|
||||||
- Download the Magisk installer zip
|
- Download the Magisk installer zip
|
||||||
- Reboot to custom recovery
|
- Reboot to custom recovery
|
||||||
@@ -65,7 +65,7 @@ If your device does not have ramdisk in boot images, Magisk has no choice but to
|
|||||||
|
|
||||||
When Magisk is installed in your recovery, **you CANNOT use custom recoveries to install/upgrade Magisk!** The only way to install/upgrade Magisk is through Magisk Manager. The app will be aware of your device state and install to the correct partition and reboot into the correct mode.
|
When Magisk is installed in your recovery, **you CANNOT use custom recoveries to install/upgrade Magisk!** The only way to install/upgrade Magisk is through Magisk Manager. The app will be aware of your device state and install to the correct partition and reboot into the correct mode.
|
||||||
|
|
||||||
Since Magisk now hijacks the recovery of the device, there is a mechanism to let you *actually* boot into recovery mode when needed: it is determined by **how long you press volume up**.
|
Since Magisk now hijacks the recovery of the device, there is a mechanism to let you *actually* boot into recovery mode when needed: it is determined by **how long you press the recovery key combo**.
|
||||||
|
|
||||||
Each device has its own key combo to boot into recovery, as an example for Galaxy S10 it is (Power + Bixby + Volume Up). A quick Google search should easily get you this info of your device. As soon as you press the combo and the device vibrates with a splash screen, release all buttons to boot into Magisk. If you decide to boot into actual recovery mode, continue to press volume up until you see the recovery screen.
|
Each device has its own key combo to boot into recovery, as an example for Galaxy S10 it is (Power + Bixby + Volume Up). A quick Google search should easily get you this info of your device. As soon as you press the combo and the device vibrates with a splash screen, release all buttons to boot into Magisk. If you decide to boot into actual recovery mode, continue to press volume up until you see the recovery screen.
|
||||||
|
|
||||||
|
18
docs/releases/21400.md
Normal file
18
docs/releases/21400.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
## 2021.1.17 Magisk v21.4
|
||||||
|
|
||||||
|
**Update**: v21.4 adds more regression hot fixes.
|
||||||
|
|
||||||
|
Happy 2021! v21.3 adds a workaround for devices with buggy F2FS Linux kernel drivers. This F2FS bug may cause bootloops on many devices. Checkout the full [v21.0 release notes](https://topjohnwu.github.io/Magisk/releases/21000.html) if coming from older releases.
|
||||||
|
|
||||||
|
### v21.4
|
||||||
|
|
||||||
|
- [MagiskSU] Fix `su -c` behavior that broke many root apps
|
||||||
|
- [General] Properly handle read/write over sockets (the `broken pipe` issue)
|
||||||
|
|
||||||
|
### v21.3
|
||||||
|
|
||||||
|
- [MagiskInit] Avoid mounting `f2fs` userdata as it may result in kernel crashes. This shall fix a lot of bootloops
|
||||||
|
- [MagiskBoot] Fix a minor header checksum bug for `DHTB` header and ASUS `blob` image formats
|
||||||
|
- [MagiskHide] Allowing hiding isolated processes if the mount namespace is separated
|
||||||
|
|
||||||
|
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)
|
@@ -1,5 +1,7 @@
|
|||||||
# Release Notes
|
# Release Notes
|
||||||
|
|
||||||
|
- [v21.3](21300.md)
|
||||||
|
- [v21.2](21200.md)
|
||||||
- [v21.1](21100.md)
|
- [v21.1](21100.md)
|
||||||
- [v21.0](21000.md)
|
- [v21.0](21000.md)
|
||||||
- [v20.4](20400.md)
|
- [v20.4](20400.md)
|
||||||
|
@@ -27,6 +27,6 @@ android.injected.testOnly=false
|
|||||||
kapt.incremental.apt=true
|
kapt.incremental.apt=true
|
||||||
|
|
||||||
# Magisk
|
# Magisk
|
||||||
magisk.versionCode=21200
|
magisk.versionCode=21400
|
||||||
magisk.ndkVersion=21d
|
magisk.ndkVersion=21d
|
||||||
magisk.fullNdkVersion=21.3.6528147
|
magisk.fullNdkVersion=21.3.6528147
|
||||||
|
@@ -4,6 +4,9 @@ LOCAL_PATH := $(call my-dir)
|
|||||||
# Binaries
|
# Binaries
|
||||||
########################
|
########################
|
||||||
|
|
||||||
|
# Global toggle for the WIP zygote injection features
|
||||||
|
ENABLE_INJECT := 0
|
||||||
|
|
||||||
ifdef B_MAGISK
|
ifdef B_MAGISK
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
@@ -12,27 +15,38 @@ LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils
|
|||||||
LOCAL_C_INCLUDES := jni/include
|
LOCAL_C_INCLUDES := jni/include
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
core/applets.cpp \
|
core/applets.cpp \
|
||||||
core/magisk.cpp \
|
core/magisk.cpp \
|
||||||
core/daemon.cpp \
|
core/daemon.cpp \
|
||||||
core/bootstages.cpp \
|
core/bootstages.cpp \
|
||||||
core/socket.cpp \
|
core/socket.cpp \
|
||||||
core/db.cpp \
|
core/db.cpp \
|
||||||
core/scripting.cpp \
|
core/scripting.cpp \
|
||||||
core/restorecon.cpp \
|
core/restorecon.cpp \
|
||||||
core/module.cpp \
|
core/module.cpp \
|
||||||
magiskhide/magiskhide.cpp \
|
magiskhide/magiskhide.cpp \
|
||||||
magiskhide/proc_monitor.cpp \
|
magiskhide/hide_utils.cpp \
|
||||||
magiskhide/hide_utils.cpp \
|
magiskhide/hide_policy.cpp \
|
||||||
magiskhide/hide_policy.cpp \
|
resetprop/persist_properties.cpp \
|
||||||
resetprop/persist_properties.cpp \
|
resetprop/resetprop.cpp \
|
||||||
resetprop/resetprop.cpp \
|
su/su.cpp \
|
||||||
su/su.cpp \
|
su/connect.cpp \
|
||||||
su/connect.cpp \
|
su/pts.cpp \
|
||||||
su/pts.cpp \
|
su/su_daemon.cpp
|
||||||
su/su_daemon.cpp
|
|
||||||
|
|
||||||
LOCAL_LDLIBS := -llog
|
LOCAL_LDLIBS := -llog
|
||||||
|
LOCAL_CPPFLAGS := -DENABLE_INJECT=$(ENABLE_INJECT)
|
||||||
|
|
||||||
|
ifeq ($(ENABLE_INJECT),1)
|
||||||
|
LOCAL_STATIC_LIBRARIES += libxhook
|
||||||
|
LOCAL_SRC_FILES += \
|
||||||
|
inject/entry.cpp \
|
||||||
|
inject/utils.cpp \
|
||||||
|
inject/hook.cpp
|
||||||
|
else
|
||||||
|
LOCAL_SRC_FILES += magiskhide/proc_monitor.cpp
|
||||||
|
endif
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
endif
|
endif
|
||||||
@@ -52,24 +66,24 @@ ifdef BB_INIT
|
|||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := libsepol libxz libutils
|
LOCAL_STATIC_LIBRARIES := libsepol libxz libutils
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
jni/include \
|
jni/include \
|
||||||
out \
|
out \
|
||||||
out/$(TARGET_ARCH_ABI)
|
out/$(TARGET_ARCH_ABI)
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
init/init.cpp \
|
init/init.cpp \
|
||||||
init/mount.cpp \
|
init/mount.cpp \
|
||||||
init/rootdir.cpp \
|
init/rootdir.cpp \
|
||||||
init/getinfo.cpp \
|
init/getinfo.cpp \
|
||||||
init/twostage.cpp \
|
init/twostage.cpp \
|
||||||
init/raw_data.cpp \
|
init/raw_data.cpp \
|
||||||
core/socket.cpp \
|
core/socket.cpp \
|
||||||
magiskpolicy/sepolicy.cpp \
|
magiskpolicy/sepolicy.cpp \
|
||||||
magiskpolicy/magiskpolicy.cpp \
|
magiskpolicy/magiskpolicy.cpp \
|
||||||
magiskpolicy/rules.cpp \
|
magiskpolicy/rules.cpp \
|
||||||
magiskpolicy/policydb.cpp \
|
magiskpolicy/policydb.cpp \
|
||||||
magiskpolicy/statement.cpp \
|
magiskpolicy/statement.cpp \
|
||||||
magiskboot/pattern.cpp
|
magiskboot/pattern.cpp
|
||||||
|
|
||||||
LOCAL_LDFLAGS := -static
|
LOCAL_LDFLAGS := -static
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
@@ -84,15 +98,15 @@ LOCAL_STATIC_LIBRARIES := libmincrypt liblzma liblz4 libbz2 libfdt libutils
|
|||||||
LOCAL_C_INCLUDES := jni/include
|
LOCAL_C_INCLUDES := jni/include
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
magiskboot/main.cpp \
|
magiskboot/main.cpp \
|
||||||
magiskboot/bootimg.cpp \
|
magiskboot/bootimg.cpp \
|
||||||
magiskboot/hexpatch.cpp \
|
magiskboot/hexpatch.cpp \
|
||||||
magiskboot/compress.cpp \
|
magiskboot/compress.cpp \
|
||||||
magiskboot/format.cpp \
|
magiskboot/format.cpp \
|
||||||
magiskboot/dtb.cpp \
|
magiskboot/dtb.cpp \
|
||||||
magiskboot/ramdisk.cpp \
|
magiskboot/ramdisk.cpp \
|
||||||
magiskboot/pattern.cpp \
|
magiskboot/pattern.cpp \
|
||||||
utils/cpio.cpp
|
utils/cpio.cpp
|
||||||
|
|
||||||
LOCAL_LDLIBS := -lz
|
LOCAL_LDLIBS := -lz
|
||||||
LOCAL_LDFLAGS := -static
|
LOCAL_LDFLAGS := -static
|
||||||
@@ -108,12 +122,12 @@ LOCAL_STATIC_LIBRARIES := libsepol libutils
|
|||||||
LOCAL_C_INCLUDES := jni/include
|
LOCAL_C_INCLUDES := jni/include
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
core/applet_stub.cpp \
|
core/applet_stub.cpp \
|
||||||
magiskpolicy/sepolicy.cpp \
|
magiskpolicy/sepolicy.cpp \
|
||||||
magiskpolicy/magiskpolicy.cpp \
|
magiskpolicy/magiskpolicy.cpp \
|
||||||
magiskpolicy/rules.cpp \
|
magiskpolicy/rules.cpp \
|
||||||
magiskpolicy/policydb.cpp \
|
magiskpolicy/policydb.cpp \
|
||||||
magiskpolicy/statement.cpp
|
magiskpolicy/statement.cpp
|
||||||
|
|
||||||
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=magiskpolicy_main
|
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=magiskpolicy_main
|
||||||
LOCAL_LDFLAGS := -static
|
LOCAL_LDFLAGS := -static
|
||||||
@@ -129,9 +143,9 @@ LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils
|
|||||||
LOCAL_C_INCLUDES := jni/include
|
LOCAL_C_INCLUDES := jni/include
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
core/applet_stub.cpp \
|
core/applet_stub.cpp \
|
||||||
resetprop/persist_properties.cpp \
|
resetprop/persist_properties.cpp \
|
||||||
resetprop/resetprop.cpp \
|
resetprop/resetprop.cpp \
|
||||||
|
|
||||||
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=resetprop_main
|
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=resetprop_main
|
||||||
LOCAL_LDFLAGS := -static
|
LOCAL_LDFLAGS := -static
|
||||||
@@ -140,15 +154,16 @@ include $(BUILD_EXECUTABLE)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef B_TEST
|
ifdef B_TEST
|
||||||
|
ifneq (,$(wildcard jni/test.cpp))
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := test
|
LOCAL_MODULE := test
|
||||||
LOCAL_STATIC_LIBRARIES := libutils
|
LOCAL_STATIC_LIBRARIES := libutils
|
||||||
LOCAL_C_INCLUDES := jni/include
|
LOCAL_C_INCLUDES := jni/include
|
||||||
LOCAL_SRC_FILES := test.cpp
|
LOCAL_SRC_FILES := test.cpp
|
||||||
LOCAL_LDFLAGS := -static
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef B_BB
|
ifdef B_BB
|
||||||
@@ -161,5 +176,4 @@ endif
|
|||||||
# Libraries
|
# Libraries
|
||||||
########################
|
########################
|
||||||
include jni/utils/Android.mk
|
include jni/utils/Android.mk
|
||||||
include jni/systemproperties/Android.mk
|
|
||||||
include jni/external/Android.mk
|
include jni/external/Android.mk
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
umask(0);
|
umask(0);
|
||||||
cmdline_logging();
|
cmdline_logging();
|
||||||
return APPLET_STUB_MAIN(argc, argv);
|
return APPLET_STUB_MAIN(argc, argv);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
@@ -8,39 +6,45 @@
|
|||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std;
|
||||||
|
|
||||||
using main_fun = int (*)(int, char *[]);
|
using main_fun = int (*)(int, char *[]);
|
||||||
|
|
||||||
static main_fun applet_main[] = { su_client_main, resetprop_main, magiskhide_main, nullptr };
|
static main_fun applet_main[] = { su_client_main, resetprop_main, magiskhide_main, nullptr };
|
||||||
|
|
||||||
[[noreturn]] static void call_applet(int argc, char **argv) {
|
static int call_applet(int argc, char *argv[]) {
|
||||||
// Applets
|
// Applets
|
||||||
for (int i = 0; applet_names[i]; ++i) {
|
string_view base = basename(argv[0]);
|
||||||
if (strcmp(basename(argv[0]), applet_names[i]) == 0) {
|
for (int i = 0; applet_names[i]; ++i) {
|
||||||
exit((*applet_main[i])(argc, argv));
|
if (base == applet_names[i]) {
|
||||||
}
|
return (*applet_main[i])(argc, argv);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
|
}
|
||||||
exit(1);
|
#if ENABLE_INJECT
|
||||||
|
if (str_starts(base, "app_process")) {
|
||||||
|
return app_process_main(argc, argv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
fprintf(stderr, "%s: applet not found\n", base.data());
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
umask(0);
|
umask(0);
|
||||||
dload_selinux();
|
dload_selinux();
|
||||||
cmdline_logging();
|
cmdline_logging();
|
||||||
init_argv0(argc, argv);
|
init_argv0(argc, argv);
|
||||||
|
|
||||||
if (basename(argv[0]) == "magisk"sv) {
|
if (basename(argv[0]) == "magisk"sv) {
|
||||||
if (argc > 1 && argv[1][0] != '-') {
|
if (argc > 1 && argv[1][0] != '-') {
|
||||||
// Calling applet via magisk [applet] args
|
// Calling applet via magisk [applet] args
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
} else {
|
} else {
|
||||||
return magisk_main(argc, argv);
|
return magisk_main(argc, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
call_applet(argc, argv);
|
return call_applet(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,6 +13,8 @@
|
|||||||
#include <resetprop.hpp>
|
#include <resetprop.hpp>
|
||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
|
|
||||||
|
#include "core.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static bool safe_mode = false;
|
static bool safe_mode = false;
|
||||||
@@ -37,64 +39,64 @@ static bool safe_mode = false;
|
|||||||
|
|
||||||
#define mount_mirror(part, flag) \
|
#define mount_mirror(part, flag) \
|
||||||
else if (MNT_DIR_IS("/" #part) && me->mnt_type != "tmpfs"sv && lstat(me->mnt_dir, &st) == 0) \
|
else if (MNT_DIR_IS("/" #part) && me->mnt_type != "tmpfs"sv && lstat(me->mnt_dir, &st) == 0) \
|
||||||
do_mount_mirror(part, flag)
|
do_mount_mirror(part, flag)
|
||||||
|
|
||||||
#define link_mirror(part) \
|
#define link_mirror(part) \
|
||||||
SETMIR(buf1, part); \
|
SETMIR(buf1, part); \
|
||||||
if (access("/system/" #part, F_OK) == 0 && access(buf1, F_OK) != 0) { \
|
if (access("/system/" #part, F_OK) == 0 && access(buf1, F_OK) != 0) { \
|
||||||
xsymlink("./system/" #part, buf1); \
|
xsymlink("./system/" #part, buf1); \
|
||||||
LOGI("link: %s\n", buf1); \
|
LOGI("link: %s\n", buf1); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define link_orig_dir(dir, part) \
|
#define link_orig_dir(dir, part) \
|
||||||
else if (MNT_DIR_IS(dir) && me->mnt_type != "tmpfs"sv) { \
|
else if (MNT_DIR_IS(dir) && me->mnt_type != "tmpfs"sv) { \
|
||||||
SETMIR(buf1, part); \
|
SETMIR(buf1, part); \
|
||||||
rmdir(buf1); \
|
rmdir(buf1); \
|
||||||
xsymlink(dir, buf1); \
|
xsymlink(dir, buf1); \
|
||||||
LOGI("link: %s\n", buf1); \
|
LOGI("link: %s\n", buf1); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define link_orig(part) link_orig_dir("/" #part, part)
|
#define link_orig(part) link_orig_dir("/" #part, part)
|
||||||
|
|
||||||
static void mount_mirrors() {
|
static void mount_mirrors() {
|
||||||
char buf1[4096];
|
char buf1[4096];
|
||||||
char buf2[4096];
|
char buf2[4096];
|
||||||
|
|
||||||
LOGI("* Mounting mirrors\n");
|
LOGI("* Mounting mirrors\n");
|
||||||
|
|
||||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (0) {}
|
if (0) {}
|
||||||
mount_mirror(system, MS_RDONLY)
|
mount_mirror(system, MS_RDONLY)
|
||||||
mount_mirror(vendor, MS_RDONLY)
|
mount_mirror(vendor, MS_RDONLY)
|
||||||
mount_mirror(product, MS_RDONLY)
|
mount_mirror(product, MS_RDONLY)
|
||||||
mount_mirror(system_ext, MS_RDONLY)
|
mount_mirror(system_ext, MS_RDONLY)
|
||||||
mount_mirror(data, 0)
|
mount_mirror(data, 0)
|
||||||
link_orig(cache)
|
link_orig(cache)
|
||||||
link_orig(metadata)
|
link_orig(metadata)
|
||||||
link_orig(persist)
|
link_orig(persist)
|
||||||
link_orig_dir("/mnt/vendor/persist", persist)
|
link_orig_dir("/mnt/vendor/persist", persist)
|
||||||
else if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) {
|
else if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) {
|
||||||
xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009");
|
xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
SETMIR(buf1, system);
|
SETMIR(buf1, system);
|
||||||
if (access(buf1, F_OK) != 0) {
|
if (access(buf1, F_OK) != 0) {
|
||||||
xsymlink("./system_root/system", buf1);
|
xsymlink("./system_root/system", buf1);
|
||||||
LOGI("link: %s\n", buf1);
|
LOGI("link: %s\n", buf1);
|
||||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
|
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
|
||||||
do_mount_mirror(system_root, MS_RDONLY)
|
do_mount_mirror(system_root, MS_RDONLY)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
link_mirror(vendor)
|
link_mirror(vendor)
|
||||||
link_mirror(product)
|
link_mirror(product)
|
||||||
link_mirror(system_ext)
|
link_mirror(system_ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr char bb_script[] = R"EOF(
|
constexpr char bb_script[] = R"EOF(
|
||||||
@@ -105,167 +107,167 @@ exec /data/adb/magisk/busybox.bin "$@"
|
|||||||
)EOF";
|
)EOF";
|
||||||
|
|
||||||
static bool magisk_env() {
|
static bool magisk_env() {
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
|
||||||
LOGI("* Initializing Magisk environment\n");
|
LOGI("* Initializing Magisk environment\n");
|
||||||
|
|
||||||
string pkg;
|
string pkg;
|
||||||
check_manager(&pkg);
|
check_manager(&pkg);
|
||||||
|
|
||||||
sprintf(buf, "%s/0/%s/install", APP_DATA_DIR, pkg.data());
|
sprintf(buf, "%s/0/%s/install", APP_DATA_DIR, pkg.data());
|
||||||
|
|
||||||
// Alternative binaries paths
|
// Alternative binaries paths
|
||||||
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
|
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
|
||||||
for (auto alt : alt_bin) {
|
for (auto alt : alt_bin) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(alt, &st) == 0) {
|
if (lstat(alt, &st) == 0) {
|
||||||
if (S_ISLNK(st.st_mode)) {
|
if (S_ISLNK(st.st_mode)) {
|
||||||
unlink(alt);
|
unlink(alt);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rm_rf(DATABIN);
|
rm_rf(DATABIN);
|
||||||
cp_afc(alt, DATABIN);
|
cp_afc(alt, DATABIN);
|
||||||
rm_rf(alt);
|
rm_rf(alt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove stuffs
|
// Remove stuffs
|
||||||
rm_rf("/cache/data_adb");
|
rm_rf("/cache/data_adb");
|
||||||
rm_rf("/data/adb/modules/.core");
|
rm_rf("/data/adb/modules/.core");
|
||||||
unlink("/data/adb/magisk.img");
|
unlink("/data/adb/magisk.img");
|
||||||
unlink("/data/adb/magisk_merge.img");
|
unlink("/data/adb/magisk_merge.img");
|
||||||
unlink("/data/magisk.img");
|
unlink("/data/magisk.img");
|
||||||
unlink("/data/magisk_merge.img");
|
unlink("/data/magisk_merge.img");
|
||||||
unlink("/data/magisk_debug.log");
|
unlink("/data/magisk_debug.log");
|
||||||
|
|
||||||
// Directories in /data/adb
|
// Directories in /data/adb
|
||||||
xmkdir(DATABIN, 0755);
|
xmkdir(DATABIN, 0755);
|
||||||
xmkdir(MODULEROOT, 0755);
|
xmkdir(MODULEROOT, 0755);
|
||||||
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
|
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
|
||||||
xmkdir(SECURE_DIR "/service.d", 0755);
|
xmkdir(SECURE_DIR "/service.d", 0755);
|
||||||
|
|
||||||
// Disable/remove magiskhide, resetprop
|
// Disable/remove magiskhide, resetprop
|
||||||
if (SDK_INT < 19) {
|
if (SDK_INT < 19) {
|
||||||
unlink("/sbin/resetprop");
|
unlink("/sbin/resetprop");
|
||||||
unlink("/sbin/magiskhide");
|
unlink("/sbin/magiskhide");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (access(DATABIN "/busybox.bin", X_OK)) {
|
if (access(DATABIN "/busybox.bin", X_OK)) {
|
||||||
if (access(DATABIN "/busybox", X_OK))
|
if (access(DATABIN "/busybox", X_OK))
|
||||||
return false;
|
return false;
|
||||||
rename(DATABIN "/busybox", DATABIN "/busybox.bin");
|
rename(DATABIN "/busybox", DATABIN "/busybox.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buf, "%s/" BBPATH "/busybox", MAGISKTMP.data());
|
sprintf(buf, "%s/" BBPATH "/busybox", MAGISKTMP.data());
|
||||||
{
|
{
|
||||||
auto fp = open_file(DATABIN "/busybox", "we");
|
auto fp = open_file(DATABIN "/busybox", "we");
|
||||||
fprintf(fp.get(), bb_script, buf);
|
fprintf(fp.get(), bb_script, buf);
|
||||||
}
|
}
|
||||||
chmod(DATABIN "/busybox", 0755);
|
chmod(DATABIN "/busybox", 0755);
|
||||||
mkdir(dirname(buf), 0755);
|
mkdir(dirname(buf), 0755);
|
||||||
cp_afc(DATABIN "/busybox.bin", buf);
|
cp_afc(DATABIN "/busybox.bin", buf);
|
||||||
exec_command_async(buf, "--install", "-s", dirname(buf));
|
exec_command_async(buf, "--install", "-s", dirname(buf));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reboot() {
|
void reboot() {
|
||||||
if (RECOVERY_MODE)
|
if (RECOVERY_MODE)
|
||||||
exec_command_sync("/system/bin/reboot", "recovery");
|
exec_command_sync("/system/bin/reboot", "recovery");
|
||||||
else
|
else
|
||||||
exec_command_sync("/system/bin/reboot");
|
exec_command_sync("/system/bin/reboot");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_data() {
|
static bool check_data() {
|
||||||
bool mnt = false;
|
bool mnt = false;
|
||||||
file_readline("/proc/mounts", [&](string_view s) {
|
file_readline("/proc/mounts", [&](string_view s) {
|
||||||
if (str_contains(s, " /data ") && !str_contains(s, "tmpfs")) {
|
if (str_contains(s, " /data ") && !str_contains(s, "tmpfs")) {
|
||||||
mnt = true;
|
mnt = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (!mnt)
|
if (!mnt)
|
||||||
return false;
|
return false;
|
||||||
auto crypto = getprop("ro.crypto.state");
|
auto crypto = getprop("ro.crypto.state");
|
||||||
if (!crypto.empty()) {
|
if (!crypto.empty()) {
|
||||||
if (crypto == "unencrypted") {
|
if (crypto == "unencrypted") {
|
||||||
// Unencrypted, we can directly access data
|
// Unencrypted, we can directly access data
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Encrypted, check whether vold is started
|
// Encrypted, check whether vold is started
|
||||||
return !getprop("init.svc.vold").empty();
|
return !getprop("init.svc.vold").empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ro.crypto.state is not set, assume it's unencrypted
|
// ro.crypto.state is not set, assume it's unencrypted
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock_blocks() {
|
void unlock_blocks() {
|
||||||
int fd, dev, OFF = 0;
|
int fd, dev, OFF = 0;
|
||||||
|
|
||||||
auto dir = xopen_dir("/dev/block");
|
auto dir = xopen_dir("/dev/block");
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return;
|
return;
|
||||||
dev = dirfd(dir.get());
|
dev = dirfd(dir.get());
|
||||||
|
|
||||||
for (dirent *entry; (entry = readdir(dir.get()));) {
|
for (dirent *entry; (entry = readdir(dir.get()));) {
|
||||||
if (entry->d_type == DT_BLK) {
|
if (entry->d_type == DT_BLK) {
|
||||||
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
|
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
|
||||||
continue;
|
continue;
|
||||||
if (ioctl(fd, BLKROSET, &OFF) < 0)
|
if (ioctl(fd, BLKROSET, &OFF) < 0)
|
||||||
PLOGE("unlock %s", entry->d_name);
|
PLOGE("unlock %s", entry->d_name);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
||||||
|
|
||||||
static bool check_key_combo() {
|
static bool check_key_combo() {
|
||||||
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
||||||
vector<int> events;
|
vector<int> events;
|
||||||
constexpr char name[] = "/dev/.ev";
|
constexpr char name[] = "/dev/.ev";
|
||||||
|
|
||||||
// First collect candidate events that accepts volume down
|
// First collect candidate events that accepts volume down
|
||||||
for (int minor = 64; minor < 96; ++minor) {
|
for (int minor = 64; minor < 96; ++minor) {
|
||||||
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
||||||
continue;
|
continue;
|
||||||
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
||||||
unlink(name);
|
unlink(name);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
continue;
|
continue;
|
||||||
memset(bitmask, 0, sizeof(bitmask));
|
memset(bitmask, 0, sizeof(bitmask));
|
||||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
||||||
if (test_bit(KEY_VOLUMEDOWN, bitmask))
|
if (test_bit(KEY_VOLUMEDOWN, bitmask))
|
||||||
events.push_back(fd);
|
events.push_back(fd);
|
||||||
else
|
else
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
if (events.empty())
|
if (events.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
|
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
|
||||||
|
|
||||||
// Check if volume down key is held continuously for more than 3 seconds
|
// Check if volume down key is held continuously for more than 3 seconds
|
||||||
for (int i = 0; i < 300; ++i) {
|
for (int i = 0; i < 300; ++i) {
|
||||||
bool pressed = false;
|
bool pressed = false;
|
||||||
for (const int &fd : events) {
|
for (const int &fd : events) {
|
||||||
memset(bitmask, 0, sizeof(bitmask));
|
memset(bitmask, 0, sizeof(bitmask));
|
||||||
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
||||||
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
|
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
|
||||||
pressed = true;
|
pressed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pressed)
|
if (!pressed)
|
||||||
return false;
|
return false;
|
||||||
// Check every 10ms
|
// Check every 10ms
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
|
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************
|
/***********************
|
||||||
@@ -275,114 +277,114 @@ static bool check_key_combo() {
|
|||||||
static pthread_mutex_t stage_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t stage_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
void post_fs_data(int client) {
|
void post_fs_data(int client) {
|
||||||
// ack
|
// ack
|
||||||
write_int(client, 0);
|
write_int(client, 0);
|
||||||
close(client);
|
close(client);
|
||||||
|
|
||||||
mutex_guard lock(stage_lock);
|
mutex_guard lock(stage_lock);
|
||||||
|
|
||||||
if (getenv("REMOUNT_ROOT"))
|
if (getenv("REMOUNT_ROOT"))
|
||||||
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
|
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
|
||||||
|
|
||||||
if (!check_data())
|
if (!check_data())
|
||||||
goto unblock_init;
|
goto unblock_init;
|
||||||
|
|
||||||
DAEMON_STATE = STATE_POST_FS_DATA;
|
DAEMON_STATE = STATE_POST_FS_DATA;
|
||||||
setup_logfile(true);
|
setup_logfile(true);
|
||||||
|
|
||||||
LOGI("** post-fs-data mode running\n");
|
LOGI("** post-fs-data mode running\n");
|
||||||
|
|
||||||
unlock_blocks();
|
unlock_blocks();
|
||||||
mount_mirrors();
|
mount_mirrors();
|
||||||
|
|
||||||
if (access(SECURE_DIR, F_OK) != 0) {
|
if (access(SECURE_DIR, F_OK) != 0) {
|
||||||
if (SDK_INT < 24) {
|
if (SDK_INT < 24) {
|
||||||
// There is no FBE pre 7.0, we can directly create the folder without issues
|
// There is no FBE pre 7.0, we can directly create the folder without issues
|
||||||
xmkdir(SECURE_DIR, 0700);
|
xmkdir(SECURE_DIR, 0700);
|
||||||
} else {
|
} else {
|
||||||
// If the folder is not automatically created by Android,
|
// If the folder is not automatically created by Android,
|
||||||
// do NOT proceed further. Manual creation of the folder
|
// do NOT proceed further. Manual creation of the folder
|
||||||
// will cause bootloops on FBE devices.
|
// will cause bootloops on FBE devices.
|
||||||
LOGE(SECURE_DIR " is not present, abort\n");
|
LOGE(SECURE_DIR " is not present, abort\n");
|
||||||
goto early_abort;
|
goto early_abort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!magisk_env()) {
|
if (!magisk_env()) {
|
||||||
LOGE("* Magisk environment incomplete, abort\n");
|
LOGE("* Magisk environment incomplete, abort\n");
|
||||||
goto early_abort;
|
goto early_abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
|
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
|
||||||
safe_mode = true;
|
safe_mode = true;
|
||||||
// Disable all modules and magiskhide so next boot will be clean
|
// Disable all modules and magiskhide so next boot will be clean
|
||||||
disable_modules();
|
disable_modules();
|
||||||
stop_magiskhide();
|
stop_magiskhide();
|
||||||
} else {
|
} else {
|
||||||
exec_common_scripts("post-fs-data");
|
exec_common_scripts("post-fs-data");
|
||||||
auto_start_magiskhide();
|
auto_start_magiskhide(false);
|
||||||
handle_modules();
|
handle_modules();
|
||||||
}
|
}
|
||||||
|
|
||||||
early_abort:
|
early_abort:
|
||||||
// We still do magic mount because root itself might need it
|
// We still do magic mount because root itself might need it
|
||||||
magic_mount();
|
magic_mount();
|
||||||
DAEMON_STATE = STATE_POST_FS_DATA_DONE;
|
DAEMON_STATE = STATE_POST_FS_DATA_DONE;
|
||||||
|
|
||||||
unblock_init:
|
unblock_init:
|
||||||
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
|
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void late_start(int client) {
|
void late_start(int client) {
|
||||||
// ack
|
// ack
|
||||||
write_int(client, 0);
|
write_int(client, 0);
|
||||||
close(client);
|
close(client);
|
||||||
|
|
||||||
mutex_guard lock(stage_lock);
|
mutex_guard lock(stage_lock);
|
||||||
run_finally fin([]{ DAEMON_STATE = STATE_LATE_START_DONE; });
|
run_finally fin([]{ DAEMON_STATE = STATE_LATE_START_DONE; });
|
||||||
setup_logfile(false);
|
setup_logfile(false);
|
||||||
|
|
||||||
LOGI("** late_start service mode running\n");
|
LOGI("** late_start service mode running\n");
|
||||||
|
|
||||||
if (DAEMON_STATE < STATE_POST_FS_DATA_DONE || safe_mode)
|
if (DAEMON_STATE < STATE_POST_FS_DATA_DONE || safe_mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
exec_common_scripts("service");
|
exec_common_scripts("service");
|
||||||
exec_module_scripts("service");
|
exec_module_scripts("service");
|
||||||
}
|
}
|
||||||
|
|
||||||
void boot_complete(int client) {
|
void boot_complete(int client) {
|
||||||
// ack
|
// ack
|
||||||
write_int(client, 0);
|
write_int(client, 0);
|
||||||
close(client);
|
close(client);
|
||||||
|
|
||||||
mutex_guard lock(stage_lock);
|
mutex_guard lock(stage_lock);
|
||||||
DAEMON_STATE = STATE_BOOT_COMPLETE;
|
DAEMON_STATE = STATE_BOOT_COMPLETE;
|
||||||
setup_logfile(false);
|
setup_logfile(false);
|
||||||
|
|
||||||
LOGI("** boot_complete triggered\n");
|
LOGI("** boot_complete triggered\n");
|
||||||
|
|
||||||
if (safe_mode)
|
if (safe_mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// At this point it's safe to create the folder
|
// At this point it's safe to create the folder
|
||||||
if (access(SECURE_DIR, F_OK) != 0)
|
if (access(SECURE_DIR, F_OK) != 0)
|
||||||
xmkdir(SECURE_DIR, 0700);
|
xmkdir(SECURE_DIR, 0700);
|
||||||
|
|
||||||
auto_start_magiskhide();
|
auto_start_magiskhide(true);
|
||||||
|
|
||||||
if (!check_manager()) {
|
if (!check_manager()) {
|
||||||
if (access(MANAGERAPK, F_OK) == 0) {
|
if (access(MANAGERAPK, F_OK) == 0) {
|
||||||
// Only try to install APK when no manager is installed
|
// Only try to install APK when no manager is installed
|
||||||
// Magisk Manager should be upgraded by itself, not through recovery installs
|
// Magisk Manager should be upgraded by itself, not through recovery installs
|
||||||
rename(MANAGERAPK, "/data/magisk.apk");
|
rename(MANAGERAPK, "/data/magisk.apk");
|
||||||
install_apk("/data/magisk.apk");
|
install_apk("/data/magisk.apk");
|
||||||
} else {
|
} else {
|
||||||
// Install stub
|
// Install stub
|
||||||
auto init = MAGISKTMP + "/magiskinit";
|
auto init = MAGISKTMP + "/magiskinit";
|
||||||
exec_command_sync(init.data(), "-x", "manager", "/data/magisk.apk");
|
exec_command_sync(init.data(), "-x", "manager", "/data/magisk.apk");
|
||||||
install_apk("/data/magisk.apk");
|
install_apk("/data/magisk.apk");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlink(MANAGERAPK);
|
unlink(MANAGERAPK);
|
||||||
}
|
}
|
||||||
|
26
native/jni/core/core.hpp
Normal file
26
native/jni/core/core.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
extern bool RECOVERY_MODE;
|
||||||
|
extern int DAEMON_STATE;
|
||||||
|
|
||||||
|
void unlock_blocks();
|
||||||
|
void reboot();
|
||||||
|
void setup_logfile(bool reset);
|
||||||
|
|
||||||
|
// Module stuffs
|
||||||
|
void handle_modules();
|
||||||
|
void magic_mount();
|
||||||
|
void disable_modules();
|
||||||
|
void remove_modules();
|
||||||
|
void exec_module_scripts(const char *stage);
|
||||||
|
|
||||||
|
// Scripting
|
||||||
|
void exec_script(const char *script);
|
||||||
|
void exec_common_scripts(const char *stage);
|
||||||
|
void exec_module_scripts(const char *stage, const std::vector<std::string> &module_list);
|
||||||
|
void install_apk(const char *apk);
|
||||||
|
[[noreturn]] void install_module(const char *file);
|
||||||
|
|
@@ -1,6 +1,6 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <csignal>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@@ -16,111 +16,134 @@
|
|||||||
#include <flags.hpp>
|
#include <flags.hpp>
|
||||||
#include <stream.hpp>
|
#include <stream.hpp>
|
||||||
|
|
||||||
|
#include "core.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int SDK_INT = -1;
|
int SDK_INT = -1;
|
||||||
bool RECOVERY_MODE = false;
|
|
||||||
string MAGISKTMP;
|
string MAGISKTMP;
|
||||||
|
|
||||||
|
bool RECOVERY_MODE = false;
|
||||||
int DAEMON_STATE = STATE_NONE;
|
int DAEMON_STATE = STATE_NONE;
|
||||||
|
|
||||||
static struct stat self_st;
|
static struct stat self_st;
|
||||||
|
|
||||||
static bool verify_client(pid_t pid) {
|
static bool verify_client(pid_t pid) {
|
||||||
// Verify caller is the same as server
|
// Verify caller is the same as server
|
||||||
char path[32];
|
char path[32];
|
||||||
sprintf(path, "/proc/%d/exe", pid);
|
sprintf(path, "/proc/%d/exe", pid);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
|
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_zygote(pid_t pid) {
|
||||||
|
char buf[32];
|
||||||
|
sprintf(buf, "/proc/%d/attr/current", pid);
|
||||||
|
auto fp = open_file(buf, "r");
|
||||||
|
if (!fp)
|
||||||
|
return false;
|
||||||
|
fscanf(fp.get(), "%s", buf);
|
||||||
|
return buf == "u:r:zygote:s0"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void request_handler(int client, int req_code, ucred cred) {
|
static void request_handler(int client, int req_code, ucred cred) {
|
||||||
switch (req_code) {
|
switch (req_code) {
|
||||||
case MAGISKHIDE:
|
case MAGISKHIDE:
|
||||||
magiskhide_handler(client);
|
magiskhide_handler(client, &cred);
|
||||||
break;
|
break;
|
||||||
case SUPERUSER:
|
case SUPERUSER:
|
||||||
su_daemon_handler(client, &cred);
|
su_daemon_handler(client, &cred);
|
||||||
break;
|
break;
|
||||||
case POST_FS_DATA:
|
case POST_FS_DATA:
|
||||||
post_fs_data(client);
|
post_fs_data(client);
|
||||||
break;
|
break;
|
||||||
case LATE_START:
|
case LATE_START:
|
||||||
late_start(client);
|
late_start(client);
|
||||||
break;
|
break;
|
||||||
case BOOT_COMPLETE:
|
case BOOT_COMPLETE:
|
||||||
boot_complete(client);
|
boot_complete(client);
|
||||||
break;
|
break;
|
||||||
case SQLITE_CMD:
|
case SQLITE_CMD:
|
||||||
exec_sql(client);
|
exec_sql(client);
|
||||||
break;
|
break;
|
||||||
case REMOVE_MODULES:
|
case REMOVE_MODULES:
|
||||||
remove_modules();
|
remove_modules();
|
||||||
write_int(client, 0);
|
write_int(client, 0);
|
||||||
close(client);
|
close(client);
|
||||||
reboot();
|
reboot();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
close(client);
|
close(client);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_request(int client) {
|
static void handle_request(int client) {
|
||||||
int req_code;
|
int req_code;
|
||||||
|
|
||||||
// Verify client credentials
|
// Verify client credentials
|
||||||
ucred cred;
|
ucred cred;
|
||||||
get_client_cred(client, &cred);
|
get_client_cred(client, &cred);
|
||||||
if (cred.uid != 0 && !verify_client(cred.pid))
|
|
||||||
goto shortcut;
|
|
||||||
|
|
||||||
req_code = read_int(client);
|
bool is_root = cred.uid == 0;
|
||||||
if (req_code < 0 || req_code >= DAEMON_CODE_END)
|
bool is_zygote = check_zygote(cred.pid);
|
||||||
goto shortcut;
|
bool is_client = verify_client(cred.pid);
|
||||||
|
|
||||||
// Check client permissions
|
if (!is_root && !is_zygote && !is_client)
|
||||||
switch (req_code) {
|
goto shortcut;
|
||||||
case MAGISKHIDE:
|
|
||||||
case POST_FS_DATA:
|
|
||||||
case LATE_START:
|
|
||||||
case BOOT_COMPLETE:
|
|
||||||
case SQLITE_CMD:
|
|
||||||
case GET_PATH:
|
|
||||||
if (cred.uid != 0) {
|
|
||||||
write_int(client, ROOT_REQUIRED);
|
|
||||||
goto shortcut;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case REMOVE_MODULES:
|
|
||||||
if (cred.uid != UID_SHELL && cred.uid != UID_ROOT) {
|
|
||||||
write_int(client, 1);
|
|
||||||
goto shortcut;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple requests
|
req_code = read_int(client);
|
||||||
switch (req_code) {
|
if (req_code < 0 || req_code >= DAEMON_CODE_END)
|
||||||
case CHECK_VERSION:
|
goto shortcut;
|
||||||
write_string(client, MAGISK_VERSION ":MAGISK");
|
|
||||||
goto shortcut;
|
|
||||||
case CHECK_VERSION_CODE:
|
|
||||||
write_int(client, MAGISK_VER_CODE);
|
|
||||||
goto shortcut;
|
|
||||||
case GET_PATH:
|
|
||||||
write_string(client, MAGISKTMP.data());
|
|
||||||
goto shortcut;
|
|
||||||
case START_DAEMON:
|
|
||||||
setup_logfile(true);
|
|
||||||
goto shortcut;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new thread to handle complex requests
|
// Check client permissions
|
||||||
new_daemon_thread([=] { return request_handler(client, req_code, cred); });
|
switch (req_code) {
|
||||||
return;
|
case POST_FS_DATA:
|
||||||
|
case LATE_START:
|
||||||
|
case BOOT_COMPLETE:
|
||||||
|
case SQLITE_CMD:
|
||||||
|
case GET_PATH:
|
||||||
|
if (!is_root) {
|
||||||
|
write_int(client, ROOT_REQUIRED);
|
||||||
|
goto shortcut;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REMOVE_MODULES:
|
||||||
|
if (cred.uid != UID_SHELL && cred.uid != UID_ROOT) {
|
||||||
|
write_int(client, 1);
|
||||||
|
goto shortcut;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MAGISKHIDE: // accept hide request from zygote
|
||||||
|
if (!is_root && !is_zygote) {
|
||||||
|
write_int(client, ROOT_REQUIRED);
|
||||||
|
goto shortcut;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple requests
|
||||||
|
switch (req_code) {
|
||||||
|
case CHECK_VERSION:
|
||||||
|
write_string(client, MAGISK_VERSION ":MAGISK");
|
||||||
|
goto shortcut;
|
||||||
|
case CHECK_VERSION_CODE:
|
||||||
|
write_int(client, MAGISK_VER_CODE);
|
||||||
|
goto shortcut;
|
||||||
|
case GET_PATH:
|
||||||
|
write_string(client, MAGISKTMP.data());
|
||||||
|
goto shortcut;
|
||||||
|
case START_DAEMON:
|
||||||
|
setup_logfile(true);
|
||||||
|
goto shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new thread to handle complex requests
|
||||||
|
new_daemon_thread([=] { return request_handler(client, req_code, cred); });
|
||||||
|
return;
|
||||||
|
|
||||||
shortcut:
|
shortcut:
|
||||||
close(client);
|
close(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static shared_ptr<FILE> log_file;
|
static shared_ptr<FILE> log_file;
|
||||||
@@ -130,185 +153,186 @@ static char *log_buf;
|
|||||||
static size_t log_buf_len;
|
static size_t log_buf_len;
|
||||||
|
|
||||||
void setup_logfile(bool reset) {
|
void setup_logfile(bool reset) {
|
||||||
if (file_backed.test_and_set(memory_order_relaxed))
|
if (file_backed.test_and_set(memory_order_relaxed))
|
||||||
return;
|
return;
|
||||||
if (reset)
|
if (reset)
|
||||||
rename(LOGFILE, LOGFILE ".bak");
|
rename(LOGFILE, LOGFILE ".bak");
|
||||||
|
|
||||||
int fd = xopen(LOGFILE, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
|
int fd = xopen(LOGFILE, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
log_file.reset();
|
log_file.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump all logs in memory (if exists)
|
// Dump all logs in memory (if exists)
|
||||||
if (log_buf)
|
if (log_buf)
|
||||||
write(fd, log_buf, log_buf_len);
|
write(fd, log_buf, log_buf_len);
|
||||||
|
|
||||||
if (FILE *fp = fdopen(fd, "a")) {
|
if (FILE *fp = fdopen(fd, "a")) {
|
||||||
setbuf(fp, nullptr);
|
setbuf(fp, nullptr);
|
||||||
log_file.reset(fp, &fclose);
|
log_file.reset(fp, &fclose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int magisk_log(int prio, const char *fmt, va_list ap) {
|
static int magisk_log(int prio, const char *fmt, va_list ap) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_copy(args, ap);
|
va_copy(args, ap);
|
||||||
|
|
||||||
// Log to logcat
|
// Log to logcat
|
||||||
__android_log_vprint(prio, "Magisk", fmt, ap);
|
__android_log_vprint(prio, "Magisk", fmt, ap);
|
||||||
|
|
||||||
auto local_log_file = log_file;
|
auto local_log_file = log_file;
|
||||||
if (!local_log_file)
|
if (!local_log_file)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
timeval tv;
|
timeval tv;
|
||||||
tm tm;
|
tm tm;
|
||||||
char type;
|
char type;
|
||||||
switch (prio) {
|
switch (prio) {
|
||||||
case ANDROID_LOG_DEBUG:
|
case ANDROID_LOG_DEBUG:
|
||||||
type = 'D';
|
type = 'D';
|
||||||
break;
|
break;
|
||||||
case ANDROID_LOG_INFO:
|
case ANDROID_LOG_INFO:
|
||||||
type = 'I';
|
type = 'I';
|
||||||
break;
|
break;
|
||||||
case ANDROID_LOG_WARN:
|
case ANDROID_LOG_WARN:
|
||||||
type = 'W';
|
type = 'W';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
type = 'E';
|
type = 'E';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gettimeofday(&tv, nullptr);
|
gettimeofday(&tv, nullptr);
|
||||||
localtime_r(&tv.tv_sec, &tm);
|
localtime_r(&tv.tv_sec, &tm);
|
||||||
size_t len = strftime(buf, sizeof(buf), "%m-%d %T", &tm);
|
size_t len = strftime(buf, sizeof(buf), "%m-%d %T", &tm);
|
||||||
int ms = tv.tv_usec / 1000;
|
int ms = tv.tv_usec / 1000;
|
||||||
len += sprintf(buf + len, ".%03d %c : ", ms, type);
|
len += sprintf(buf + len, ".%03d %*d %*d %c : ", ms, 5, getpid(), 5, gettid(), type);
|
||||||
strcpy(buf + len, fmt);
|
strcpy(buf + len, fmt);
|
||||||
return vfprintf(local_log_file.get(), buf, args);
|
return vfprintf(local_log_file.get(), buf, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_logging() {
|
#define mlog(prio) [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_##prio, fmt, ap); }
|
||||||
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
|
static void magisk_logging() {
|
||||||
log_file.reset(in_mem_file.release(), [](FILE *) {
|
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
|
||||||
free(log_buf);
|
log_file.reset(in_mem_file.release(), [](FILE *) {
|
||||||
log_buf = nullptr;
|
free(log_buf);
|
||||||
});
|
log_buf = nullptr;
|
||||||
log_cb.d = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_DEBUG, fmt, ap); };
|
});
|
||||||
log_cb.i = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_INFO, fmt, ap); };
|
log_cb.d = mlog(DEBUG);
|
||||||
log_cb.w = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_WARN, fmt, ap); };
|
log_cb.i = mlog(INFO);
|
||||||
log_cb.e = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_ERROR, fmt, ap); };
|
log_cb.w = mlog(WARN);
|
||||||
log_cb.ex = nop_ex;
|
log_cb.e = mlog(ERROR);
|
||||||
|
log_cb.ex = nop_ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void daemon_entry(int ppid) {
|
static void daemon_entry(int ppid) {
|
||||||
android_logging();
|
magisk_logging();
|
||||||
|
|
||||||
int fd = xopen("/dev/null", O_WRONLY);
|
int fd = xopen("/dev/null", O_WRONLY);
|
||||||
xdup2(fd, STDOUT_FILENO);
|
xdup2(fd, STDOUT_FILENO);
|
||||||
xdup2(fd, STDERR_FILENO);
|
xdup2(fd, STDERR_FILENO);
|
||||||
if (fd > STDERR_FILENO)
|
if (fd > STDERR_FILENO)
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = xopen("/dev/zero", O_RDONLY);
|
fd = xopen("/dev/zero", O_RDONLY);
|
||||||
xdup2(fd, STDIN_FILENO);
|
xdup2(fd, STDIN_FILENO);
|
||||||
if (fd > STDERR_FILENO)
|
if (fd > STDERR_FILENO)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
setsid();
|
setsid();
|
||||||
setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
|
setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
|
||||||
|
|
||||||
LOGI(NAME_WITH_VER(Magisk) " daemon started\n");
|
LOGI(NAME_WITH_VER(Magisk) " daemon started\n");
|
||||||
|
|
||||||
// Make sure ppid is not in acct
|
// Make sure ppid is not in acct
|
||||||
char src[64], dest[64];
|
char src[64], dest[64];
|
||||||
sprintf(src, "/acct/uid_0/pid_%d", ppid);
|
sprintf(src, "/acct/uid_0/pid_%d", ppid);
|
||||||
sprintf(dest, "/acct/uid_0/pid_%d", getpid());
|
sprintf(dest, "/acct/uid_0/pid_%d", getpid());
|
||||||
rename(src, dest);
|
rename(src, dest);
|
||||||
|
|
||||||
// Get self stat
|
// Get self stat
|
||||||
xreadlink("/proc/self/exe", src, sizeof(src));
|
xreadlink("/proc/self/exe", src, sizeof(src));
|
||||||
MAGISKTMP = dirname(src);
|
MAGISKTMP = dirname(src);
|
||||||
xstat("/proc/self/exe", &self_st);
|
xstat("/proc/self/exe", &self_st);
|
||||||
|
|
||||||
// Get API level
|
// Get API level
|
||||||
parse_prop_file("/system/build.prop", [](auto key, auto val) -> bool {
|
parse_prop_file("/system/build.prop", [](auto key, auto val) -> bool {
|
||||||
if (key == "ro.build.version.sdk") {
|
if (key == "ro.build.version.sdk") {
|
||||||
SDK_INT = parse_int(val);
|
SDK_INT = parse_int(val);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (SDK_INT < 0) {
|
if (SDK_INT < 0) {
|
||||||
// In case some devices do not store this info in build.prop, fallback to getprop
|
// In case some devices do not store this info in build.prop, fallback to getprop
|
||||||
auto sdk = getprop("ro.build.version.sdk");
|
auto sdk = getprop("ro.build.version.sdk");
|
||||||
if (!sdk.empty()) {
|
if (!sdk.empty()) {
|
||||||
SDK_INT = parse_int(sdk);
|
SDK_INT = parse_int(sdk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOGI("* Device API level: %d\n", SDK_INT);
|
LOGI("* Device API level: %d\n", SDK_INT);
|
||||||
|
|
||||||
restore_tmpcon();
|
restore_tmpcon();
|
||||||
|
|
||||||
// SAR cleanups
|
// SAR cleanups
|
||||||
auto mount_list = MAGISKTMP + "/" ROOTMNT;
|
auto mount_list = MAGISKTMP + "/" ROOTMNT;
|
||||||
if (access(mount_list.data(), F_OK) == 0) {
|
if (access(mount_list.data(), F_OK) == 0) {
|
||||||
file_readline(true, mount_list.data(), [](string_view line) -> bool {
|
file_readline(true, mount_list.data(), [](string_view line) -> bool {
|
||||||
umount2(line.data(), MNT_DETACH);
|
umount2(line.data(), MNT_DETACH);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
unlink("/dev/.se");
|
unlink("/dev/.se");
|
||||||
|
|
||||||
// Load config status
|
// Load config status
|
||||||
auto config = MAGISKTMP + "/" INTLROOT "/config";
|
auto config = MAGISKTMP + "/" INTLROOT "/config";
|
||||||
parse_prop_file(config.data(), [](auto key, auto val) -> bool {
|
parse_prop_file(config.data(), [](auto key, auto val) -> bool {
|
||||||
if (key == "RECOVERYMODE" && val == "true")
|
if (key == "RECOVERYMODE" && val == "true")
|
||||||
RECOVERY_MODE = true;
|
RECOVERY_MODE = true;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sun;
|
||||||
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
||||||
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
if (xbind(fd, (struct sockaddr*) &sun, len))
|
if (xbind(fd, (struct sockaddr*) &sun, len))
|
||||||
exit(1);
|
exit(1);
|
||||||
xlisten(fd, 10);
|
xlisten(fd, 10);
|
||||||
|
|
||||||
// Change process name
|
// Change process name
|
||||||
set_nice_name("magiskd");
|
set_nice_name("magiskd");
|
||||||
|
|
||||||
// Block all signals
|
// Block all signals
|
||||||
sigset_t block_set;
|
sigset_t block_set;
|
||||||
sigfillset(&block_set);
|
sigfillset(&block_set);
|
||||||
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
|
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
|
||||||
|
|
||||||
// Loop forever to listen for requests
|
// Loop forever to listen for requests
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int client = xaccept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
|
int client = xaccept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||||
handle_request(client);
|
handle_request(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int connect_daemon(bool create) {
|
int connect_daemon(bool create) {
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sun;
|
||||||
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
||||||
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
if (connect(fd, (struct sockaddr*) &sun, len)) {
|
if (connect(fd, (struct sockaddr*) &sun, len)) {
|
||||||
if (!create || getuid() != UID_ROOT || getgid() != UID_ROOT) {
|
if (!create || getuid() != UID_ROOT || getgid() != UID_ROOT) {
|
||||||
LOGE("No daemon is currently running!\n");
|
LOGE("No daemon is currently running!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppid = getpid();
|
int ppid = getpid();
|
||||||
LOGD("client: launching new main daemon process\n");
|
LOGD("client: launching new main daemon process\n");
|
||||||
if (fork_dont_care() == 0) {
|
if (fork_dont_care() == 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
daemon_entry(ppid);
|
daemon_entry(ppid);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (connect(fd, (struct sockaddr*) &sun, len))
|
while (connect(fd, (struct sockaddr*) &sun, len))
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +1,10 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <magisk.hpp>
|
#include <magisk.hpp>
|
||||||
#include <db.hpp>
|
#include <db.hpp>
|
||||||
#include <daemon.hpp>
|
#include <socket.hpp>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
#define DB_VERSION 10
|
#define DB_VERSION 10
|
||||||
@@ -26,19 +22,19 @@ static sqlite3 *mDB = nullptr;
|
|||||||
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||||
|
|
||||||
static int (*sqlite3_open_v2)(
|
static int (*sqlite3_open_v2)(
|
||||||
const char *filename,
|
const char *filename,
|
||||||
sqlite3 **ppDb,
|
sqlite3 **ppDb,
|
||||||
int flags,
|
int flags,
|
||||||
const char *zVfs);
|
const char *zVfs);
|
||||||
static const char *(*sqlite3_errmsg)(sqlite3 *db);
|
static const char *(*sqlite3_errmsg)(sqlite3 *db);
|
||||||
static int (*sqlite3_close)(sqlite3 *db);
|
static int (*sqlite3_close)(sqlite3 *db);
|
||||||
static void (*sqlite3_free)(void *v);
|
static void (*sqlite3_free)(void *v);
|
||||||
static int (*sqlite3_exec)(
|
static int (*sqlite3_exec)(
|
||||||
sqlite3 *db,
|
sqlite3 *db,
|
||||||
const char *sql,
|
const char *sql,
|
||||||
int (*callback)(void*, int, char**, char**),
|
int (*callback)(void*, int, char**, char**),
|
||||||
void *v,
|
void *v,
|
||||||
char **errmsg);
|
char **errmsg);
|
||||||
|
|
||||||
// Internal Android linker APIs
|
// Internal Android linker APIs
|
||||||
|
|
||||||
@@ -46,14 +42,14 @@ static void (*android_get_LD_LIBRARY_PATH)(char *buffer, size_t buffer_size);
|
|||||||
static void (*android_update_LD_LIBRARY_PATH)(const char *ld_library_path);
|
static void (*android_update_LD_LIBRARY_PATH)(const char *ld_library_path);
|
||||||
|
|
||||||
#define DLERR(ptr) if (!(ptr)) { \
|
#define DLERR(ptr) if (!(ptr)) { \
|
||||||
LOGE("db: %s\n", dlerror()); \
|
LOGE("db: %s\n", dlerror()); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DLOAD(handle, arg) {\
|
#define DLOAD(handle, arg) {\
|
||||||
auto f = dlsym(handle, #arg); \
|
auto f = dlsym(handle, #arg); \
|
||||||
DLERR(f) \
|
DLERR(f) \
|
||||||
*(void **) &(arg) = f; \
|
*(void **) &(arg) = f; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __LP64__
|
#ifdef __LP64__
|
||||||
@@ -65,339 +61,337 @@ constexpr char apex_path[] = "/apex/com.android.runtime/lib:/apex/com.android.ar
|
|||||||
static int dl_init = 0;
|
static int dl_init = 0;
|
||||||
|
|
||||||
static bool dload_sqlite() {
|
static bool dload_sqlite() {
|
||||||
if (dl_init)
|
if (dl_init)
|
||||||
return dl_init > 0;
|
return dl_init > 0;
|
||||||
dl_init = -1;
|
dl_init = -1;
|
||||||
|
|
||||||
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||||
if (!sqlite) {
|
if (!sqlite) {
|
||||||
// Should only happen on Android 10+
|
// Should only happen on Android 10+
|
||||||
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
|
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
|
||||||
DLERR(dl);
|
DLERR(dl);
|
||||||
|
|
||||||
DLOAD(dl, android_get_LD_LIBRARY_PATH);
|
DLOAD(dl, android_get_LD_LIBRARY_PATH);
|
||||||
DLOAD(dl, android_update_LD_LIBRARY_PATH);
|
DLOAD(dl, android_update_LD_LIBRARY_PATH);
|
||||||
|
|
||||||
// Inject APEX into LD_LIBRARY_PATH
|
// Inject APEX into LD_LIBRARY_PATH
|
||||||
char ld_path[4096];
|
char ld_path[4096];
|
||||||
memcpy(ld_path, apex_path, sizeof(apex_path));
|
memcpy(ld_path, apex_path, sizeof(apex_path));
|
||||||
constexpr int len = sizeof(apex_path) - 1;
|
constexpr int len = sizeof(apex_path) - 1;
|
||||||
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
|
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
|
||||||
android_update_LD_LIBRARY_PATH(ld_path);
|
android_update_LD_LIBRARY_PATH(ld_path);
|
||||||
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||||
|
|
||||||
// Revert LD_LIBRARY_PATH just in case
|
// Revert LD_LIBRARY_PATH just in case
|
||||||
android_update_LD_LIBRARY_PATH(ld_path + len);
|
android_update_LD_LIBRARY_PATH(ld_path + len);
|
||||||
}
|
}
|
||||||
DLERR(sqlite);
|
DLERR(sqlite);
|
||||||
|
|
||||||
DLOAD(sqlite, sqlite3_open_v2);
|
DLOAD(sqlite, sqlite3_open_v2);
|
||||||
DLOAD(sqlite, sqlite3_errmsg);
|
DLOAD(sqlite, sqlite3_errmsg);
|
||||||
DLOAD(sqlite, sqlite3_close);
|
DLOAD(sqlite, sqlite3_close);
|
||||||
DLOAD(sqlite, sqlite3_exec);
|
DLOAD(sqlite, sqlite3_exec);
|
||||||
DLOAD(sqlite, sqlite3_free);
|
DLOAD(sqlite, sqlite3_free);
|
||||||
|
|
||||||
dl_init = 1;
|
dl_init = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int db_strings::getKeyIdx(string_view key) const {
|
int db_strings::getKeyIdx(string_view key) const {
|
||||||
int idx = DB_STRING_NUM;
|
int idx = DB_STRING_NUM;
|
||||||
for (int i = 0; i < DB_STRING_NUM; ++i) {
|
for (int i = 0; i < DB_STRING_NUM; ++i) {
|
||||||
if (key == DB_STRING_KEYS[i])
|
if (key == DB_STRING_KEYS[i])
|
||||||
idx = i;
|
idx = i;
|
||||||
}
|
}
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
db_settings::db_settings() {
|
db_settings::db_settings() {
|
||||||
// Default settings
|
// Default settings
|
||||||
data[ROOT_ACCESS] = ROOT_ACCESS_APPS_AND_ADB;
|
data[ROOT_ACCESS] = ROOT_ACCESS_APPS_AND_ADB;
|
||||||
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
|
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
|
||||||
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
|
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
|
||||||
data[HIDE_CONFIG] = false;
|
data[HIDE_CONFIG] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int db_settings::getKeyIdx(string_view key) const {
|
int db_settings::getKeyIdx(string_view key) const {
|
||||||
int idx = DB_SETTINGS_NUM;
|
int idx = DB_SETTINGS_NUM;
|
||||||
for (int i = 0; i < DB_SETTINGS_NUM; ++i) {
|
for (int i = 0; i < DB_SETTINGS_NUM; ++i) {
|
||||||
if (key == DB_SETTING_KEYS[i])
|
if (key == DB_SETTING_KEYS[i])
|
||||||
idx = i;
|
idx = i;
|
||||||
}
|
}
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ver_cb(void *ver, int, char **data, char **) {
|
static int ver_cb(void *ver, int, char **data, char **) {
|
||||||
*((int *) ver) = parse_int(data[0]);
|
*((int *) ver) = parse_int(data[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define err_ret(e) if (e) return e;
|
#define err_ret(e) if (e) return e;
|
||||||
|
|
||||||
static char *open_and_init_db(sqlite3 *&db) {
|
static char *open_and_init_db(sqlite3 *&db) {
|
||||||
if (!dload_sqlite())
|
if (!dload_sqlite())
|
||||||
return strdup("Cannot load libsqlite.so");
|
return strdup("Cannot load libsqlite.so");
|
||||||
|
|
||||||
int ret = sqlite3_open_v2(MAGISKDB, &db,
|
int ret = sqlite3_open_v2(MAGISKDB, &db,
|
||||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return strdup(sqlite3_errmsg(db));
|
return strdup(sqlite3_errmsg(db));
|
||||||
int ver;
|
int ver;
|
||||||
bool upgrade = false;
|
bool upgrade = false;
|
||||||
char *err;
|
char *err;
|
||||||
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
|
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
if (ver > DB_VERSION) {
|
if (ver > DB_VERSION) {
|
||||||
// Don't support downgrading database
|
// Don't support downgrading database
|
||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (ver < 3) {
|
if (ver < 3) {
|
||||||
// Policies
|
// Policies
|
||||||
sqlite3_exec(db,
|
sqlite3_exec(db,
|
||||||
"CREATE TABLE IF NOT EXISTS policies "
|
"CREATE TABLE IF NOT EXISTS policies "
|
||||||
"(uid INT, package_name TEXT, policy INT, until INT, "
|
"(uid INT, package_name TEXT, policy INT, until INT, "
|
||||||
"logging INT, notification INT, PRIMARY KEY(uid))",
|
"logging INT, notification INT, PRIMARY KEY(uid))",
|
||||||
nullptr, nullptr, &err);
|
nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
// Settings
|
// Settings
|
||||||
sqlite3_exec(db,
|
sqlite3_exec(db,
|
||||||
"CREATE TABLE IF NOT EXISTS settings "
|
"CREATE TABLE IF NOT EXISTS settings "
|
||||||
"(key TEXT, value INT, PRIMARY KEY(key))",
|
"(key TEXT, value INT, PRIMARY KEY(key))",
|
||||||
nullptr, nullptr, &err);
|
nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
ver = 3;
|
ver = 3;
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
if (ver < 4) {
|
if (ver < 4) {
|
||||||
// Strings
|
// Strings
|
||||||
sqlite3_exec(db,
|
sqlite3_exec(db,
|
||||||
"CREATE TABLE IF NOT EXISTS strings "
|
"CREATE TABLE IF NOT EXISTS strings "
|
||||||
"(key TEXT, value TEXT, PRIMARY KEY(key))",
|
"(key TEXT, value TEXT, PRIMARY KEY(key))",
|
||||||
nullptr, nullptr, &err);
|
nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
ver = 4;
|
ver = 4;
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
if (ver < 5) {
|
if (ver < 5) {
|
||||||
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
|
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
/* Directly jump to version 6 */
|
/* Directly jump to version 6 */
|
||||||
ver = 6;
|
ver = 6;
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
if (ver < 7) {
|
if (ver < 7) {
|
||||||
sqlite3_exec(db,
|
sqlite3_exec(db,
|
||||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));",
|
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));",
|
||||||
nullptr, nullptr, &err);
|
nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
/* Directly jump to version 9 */
|
/* Directly jump to version 9 */
|
||||||
ver = 9;
|
ver = 9;
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
if (ver < 8) {
|
if (ver < 8) {
|
||||||
sqlite3_exec(db,
|
sqlite3_exec(db,
|
||||||
"BEGIN TRANSACTION;"
|
"BEGIN TRANSACTION;"
|
||||||
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
||||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
||||||
"INSERT INTO hidelist SELECT process as package_name, process FROM hidelist_tmp;"
|
"INSERT INTO hidelist SELECT process as package_name, process FROM hidelist_tmp;"
|
||||||
"DROP TABLE hidelist_tmp;"
|
"DROP TABLE hidelist_tmp;"
|
||||||
"COMMIT;",
|
"COMMIT;",
|
||||||
nullptr, nullptr, &err);
|
nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
/* Directly jump to version 9 */
|
/* Directly jump to version 9 */
|
||||||
ver = 9;
|
ver = 9;
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
if (ver < 9) {
|
if (ver < 9) {
|
||||||
sqlite3_exec(db,
|
sqlite3_exec(db,
|
||||||
"BEGIN TRANSACTION;"
|
"BEGIN TRANSACTION;"
|
||||||
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
||||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
||||||
"INSERT INTO hidelist SELECT * FROM hidelist_tmp;"
|
"INSERT INTO hidelist SELECT * FROM hidelist_tmp;"
|
||||||
"DROP TABLE hidelist_tmp;"
|
"DROP TABLE hidelist_tmp;"
|
||||||
"COMMIT;",
|
"COMMIT;",
|
||||||
nullptr, nullptr, &err);
|
nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
ver = 9;
|
ver = 9;
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
if (ver < 10) {
|
if (ver < 10) {
|
||||||
sqlite3_exec(db, "DROP TABLE IF EXISTS logs", nullptr, nullptr, &err);
|
sqlite3_exec(db, "DROP TABLE IF EXISTS logs", nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
ver = 10;
|
ver = 10;
|
||||||
upgrade = true;
|
upgrade = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upgrade) {
|
if (upgrade) {
|
||||||
// Set version
|
// Set version
|
||||||
char query[32];
|
char query[32];
|
||||||
sprintf(query, "PRAGMA user_version=%d", ver);
|
sprintf(query, "PRAGMA user_version=%d", ver);
|
||||||
sqlite3_exec(db, query, nullptr, nullptr, &err);
|
sqlite3_exec(db, query, nullptr, nullptr, &err);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *db_exec(const char *sql) {
|
char *db_exec(const char *sql) {
|
||||||
char *err;
|
char *err;
|
||||||
if (mDB == nullptr) {
|
if (mDB == nullptr) {
|
||||||
err = open_and_init_db(mDB);
|
err = open_and_init_db(mDB);
|
||||||
db_err_cmd(err,
|
db_err_cmd(err,
|
||||||
// Open fails, remove and reconstruct
|
// Open fails, remove and reconstruct
|
||||||
unlink(MAGISKDB);
|
unlink(MAGISKDB);
|
||||||
err = open_and_init_db(mDB);
|
err = open_and_init_db(mDB);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (mDB) {
|
if (mDB) {
|
||||||
sqlite3_exec(mDB, sql, nullptr, nullptr, &err);
|
sqlite3_exec(mDB, sql, nullptr, nullptr, &err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *db_exec(const char *sql, const db_row_cb &fn) {
|
char *db_exec(const char *sql, const db_row_cb &fn) {
|
||||||
char *err;
|
char *err;
|
||||||
if (mDB == nullptr) {
|
if (mDB == nullptr) {
|
||||||
err = open_and_init_db(mDB);
|
err = open_and_init_db(mDB);
|
||||||
db_err_cmd(err,
|
db_err_cmd(err,
|
||||||
// Open fails, remove and reconstruct
|
// Open fails, remove and reconstruct
|
||||||
unlink(MAGISKDB);
|
unlink(MAGISKDB);
|
||||||
err = open_and_init_db(mDB);
|
err = open_and_init_db(mDB);
|
||||||
err_ret(err);
|
err_ret(err);
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (mDB) {
|
if (mDB) {
|
||||||
sqlite3_exec(mDB, sql, [](void *cb, int col_num, char **data, char **col_name) -> int {
|
sqlite3_exec(mDB, sql, [](void *cb, int col_num, char **data, char **col_name) -> int {
|
||||||
auto &func = *reinterpret_cast<const db_row_cb*>(cb);
|
auto &func = *reinterpret_cast<const db_row_cb*>(cb);
|
||||||
db_row row;
|
db_row row;
|
||||||
for (int i = 0; i < col_num; ++i)
|
for (int i = 0; i < col_num; ++i)
|
||||||
row[col_name[i]] = data[i];
|
row[col_name[i]] = data[i];
|
||||||
return func(row) ? 0 : 1;
|
return func(row) ? 0 : 1;
|
||||||
}, (void *) &fn, &err);
|
}, (void *) &fn, &err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_db_settings(db_settings &cfg, int key) {
|
int get_db_settings(db_settings &cfg, int key) {
|
||||||
char *err;
|
char *err;
|
||||||
auto settings_cb = [&](db_row &row) -> bool {
|
auto settings_cb = [&](db_row &row) -> bool {
|
||||||
cfg[row["key"]] = parse_int(row["value"]);
|
cfg[row["key"]] = parse_int(row["value"]);
|
||||||
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
|
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (key >= 0) {
|
if (key >= 0) {
|
||||||
char query[128];
|
char query[128];
|
||||||
sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]);
|
sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]);
|
||||||
err = db_exec(query, settings_cb);
|
err = db_exec(query, settings_cb);
|
||||||
} else {
|
} else {
|
||||||
err = db_exec("SELECT key, value FROM settings", settings_cb);
|
err = db_exec("SELECT key, value FROM settings", settings_cb);
|
||||||
}
|
}
|
||||||
db_err_cmd(err, return 1);
|
db_err_cmd(err, return 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_db_strings(db_strings &str, int key) {
|
int get_db_strings(db_strings &str, int key) {
|
||||||
char *err;
|
char *err;
|
||||||
auto string_cb = [&](db_row &row) -> bool {
|
auto string_cb = [&](db_row &row) -> bool {
|
||||||
str[row["key"]] = row["value"];
|
str[row["key"]] = row["value"];
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (key >= 0) {
|
if (key >= 0) {
|
||||||
char query[128];
|
char query[128];
|
||||||
sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]);
|
sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]);
|
||||||
err = db_exec(query, string_cb);
|
err = db_exec(query, string_cb);
|
||||||
} else {
|
} else {
|
||||||
err = db_exec("SELECT key, value FROM strings", string_cb);
|
err = db_exec("SELECT key, value FROM strings", string_cb);
|
||||||
}
|
}
|
||||||
db_err_cmd(err, return 1);
|
db_err_cmd(err, return 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_uid_policy(su_access &su, int uid) {
|
int get_uid_policy(su_access &su, int uid) {
|
||||||
char query[256], *err;
|
char query[256], *err;
|
||||||
sprintf(query, "SELECT policy, logging, notification FROM policies "
|
sprintf(query, "SELECT policy, logging, notification FROM policies "
|
||||||
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
||||||
err = db_exec(query, [&](db_row &row) -> bool {
|
err = db_exec(query, [&](db_row &row) -> bool {
|
||||||
su.policy = (policy_t) parse_int(row["policy"]);
|
su.policy = (policy_t) parse_int(row["policy"]);
|
||||||
su.log = parse_int(row["logging"]);
|
su.log = parse_int(row["logging"]);
|
||||||
su.notify = parse_int(row["notification"]);
|
su.notify = parse_int(row["notification"]);
|
||||||
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify);
|
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
db_err_cmd(err, return 1);
|
db_err_cmd(err, return 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_manager(string *pkg) {
|
bool check_manager(string *pkg) {
|
||||||
db_strings str;
|
db_strings str;
|
||||||
get_db_strings(str, SU_MANAGER);
|
get_db_strings(str, SU_MANAGER);
|
||||||
bool ret = validate_manager(str[SU_MANAGER], 0, nullptr);
|
bool ret = validate_manager(str[SU_MANAGER], 0, nullptr);
|
||||||
if (pkg) {
|
if (pkg) {
|
||||||
if (ret)
|
if (ret)
|
||||||
pkg->swap(str[SU_MANAGER]);
|
pkg->swap(str[SU_MANAGER]);
|
||||||
else
|
else
|
||||||
*pkg = "xxx"; /* Make sure the return pkg can never exist */
|
*pkg = "xxx"; /* Make sure the return pkg can never exist */
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate_manager(string &pkg, int userid, struct stat *st) {
|
bool validate_manager(string &pkg, int userid, struct stat *st) {
|
||||||
struct stat tmp_st;
|
struct stat tmp_st;
|
||||||
if (st == nullptr)
|
if (st == nullptr)
|
||||||
st = &tmp_st;
|
st = &tmp_st;
|
||||||
|
|
||||||
// Prefer DE storage
|
// Prefer DE storage
|
||||||
char app_path[128];
|
char app_path[128];
|
||||||
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, pkg.data());
|
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, pkg.data());
|
||||||
if (pkg.empty() || stat(app_path, st)) {
|
if (pkg.empty() || stat(app_path, st)) {
|
||||||
// Check the official package name
|
// Check the official package name
|
||||||
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid);
|
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid);
|
||||||
if (stat(app_path, st)) {
|
if (stat(app_path, st)) {
|
||||||
LOGE("su: cannot find manager\n");
|
LOGE("su: cannot find manager\n");
|
||||||
memset(st, 0, sizeof(*st));
|
memset(st, 0, sizeof(*st));
|
||||||
pkg.clear();
|
pkg.clear();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Switch to official package if exists
|
// Switch to official package if exists
|
||||||
pkg = JAVA_PACKAGE_NAME;
|
pkg = JAVA_PACKAGE_NAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_sql(int client) {
|
void exec_sql(int client) {
|
||||||
run_finally f([=]{ close(client); });
|
run_finally f([=]{ close(client); });
|
||||||
char *sql = read_string(client);
|
string sql = read_string(client);
|
||||||
char *err = db_exec(sql, [&](db_row &row) -> bool {
|
char *err = db_exec(sql.data(), [client](db_row &row) -> bool {
|
||||||
string out;
|
string out;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto it : row) {
|
for (auto it : row) {
|
||||||
if (first) first = false;
|
if (first) first = false;
|
||||||
else out += '|';
|
else out += '|';
|
||||||
out += it.first;
|
out += it.first;
|
||||||
out += '=';
|
out += '=';
|
||||||
out += it.second;
|
out += it.second;
|
||||||
}
|
}
|
||||||
write_int(client, out.length());
|
write_string(client, out);
|
||||||
xwrite(client, out.data(), out.length());
|
return true;
|
||||||
return true;
|
});
|
||||||
});
|
write_int(client, 0);
|
||||||
free(sql);
|
db_err_cmd(err, return; );
|
||||||
write_int(client, 0);
|
|
||||||
db_err_cmd(err, return; );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool db_err(char *e) {
|
bool db_err(char *e) {
|
||||||
if (e) {
|
if (e) {
|
||||||
LOGE("sqlite3_exec: %s\n", e);
|
LOGE("sqlite3_exec: %s\n", e);
|
||||||
sqlite3_free(e);
|
sqlite3_free(e);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -7,10 +7,12 @@
|
|||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
#include <flags.hpp>
|
#include <flags.hpp>
|
||||||
|
|
||||||
|
#include "core.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
[[noreturn]] static void usage() {
|
[[noreturn]] static void usage() {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
R"EOF(Magisk - Multi-purpose Utility
|
R"EOF(Magisk - Multi-purpose Utility
|
||||||
|
|
||||||
Usage: magisk [applet [arguments]...]
|
Usage: magisk [applet [arguments]...]
|
||||||
@@ -39,92 +41,90 @@ Advanced Options (Internal APIs):
|
|||||||
Available applets:
|
Available applets:
|
||||||
)EOF");
|
)EOF");
|
||||||
|
|
||||||
for (int i = 0; applet_names[i]; ++i)
|
for (int i = 0; applet_names[i]; ++i)
|
||||||
fprintf(stderr, i ? ", %s" : " %s", applet_names[i]);
|
fprintf(stderr, i ? ", %s" : " %s", applet_names[i]);
|
||||||
fprintf(stderr, "\n\n");
|
fprintf(stderr, "\n\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int magisk_main(int argc, char *argv[]) {
|
int magisk_main(int argc, char *argv[]) {
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
usage();
|
usage();
|
||||||
if (argv[1] == "-c"sv) {
|
if (argv[1] == "-c"sv) {
|
||||||
printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n");
|
printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n");
|
||||||
return 0;
|
return 0;
|
||||||
} else if (argv[1] == "-v"sv) {
|
} else if (argv[1] == "-v"sv) {
|
||||||
int fd = connect_daemon();
|
int fd = connect_daemon();
|
||||||
write_int(fd, CHECK_VERSION);
|
write_int(fd, CHECK_VERSION);
|
||||||
char *v = read_string(fd);
|
string v = read_string(fd);
|
||||||
printf("%s\n", v);
|
printf("%s\n", v.data());
|
||||||
free(v);
|
return 0;
|
||||||
return 0;
|
} else if (argv[1] == "-V"sv) {
|
||||||
} else if (argv[1] == "-V"sv) {
|
int fd = connect_daemon();
|
||||||
int fd = connect_daemon();
|
write_int(fd, CHECK_VERSION_CODE);
|
||||||
write_int(fd, CHECK_VERSION_CODE);
|
printf("%d\n", read_int(fd));
|
||||||
printf("%d\n", read_int(fd));
|
return 0;
|
||||||
return 0;
|
} else if (argv[1] == "--list"sv) {
|
||||||
} else if (argv[1] == "--list"sv) {
|
for (int i = 0; applet_names[i]; ++i)
|
||||||
for (int i = 0; applet_names[i]; ++i)
|
printf("%s\n", applet_names[i]);
|
||||||
printf("%s\n", applet_names[i]);
|
return 0;
|
||||||
return 0;
|
} else if (argv[1] == "--unlock-blocks"sv) {
|
||||||
} else if (argv[1] == "--unlock-blocks"sv) {
|
unlock_blocks();
|
||||||
unlock_blocks();
|
return 0;
|
||||||
return 0;
|
} else if (argv[1] == "--restorecon"sv) {
|
||||||
} else if (argv[1] == "--restorecon"sv) {
|
restorecon();
|
||||||
restorecon();
|
return 0;
|
||||||
return 0;
|
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
|
||||||
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
|
clone_attr(argv[2], argv[3]);
|
||||||
clone_attr(argv[2], argv[3]);
|
return 0;
|
||||||
return 0;
|
} else if (argc >= 4 && argv[1] == "--clone"sv) {
|
||||||
} else if (argc >= 4 && argv[1] == "--clone"sv) {
|
cp_afc(argv[2], argv[3]);
|
||||||
cp_afc(argv[2], argv[3]);
|
return 0;
|
||||||
return 0;
|
} else if (argv[1] == "--daemon"sv) {
|
||||||
} else if (argv[1] == "--daemon"sv) {
|
int fd = connect_daemon(true);
|
||||||
int fd = connect_daemon(true);
|
write_int(fd, START_DAEMON);
|
||||||
write_int(fd, START_DAEMON);
|
return 0;
|
||||||
return 0;
|
} else if (argv[1] == "--post-fs-data"sv) {
|
||||||
} else if (argv[1] == "--post-fs-data"sv) {
|
int fd = connect_daemon(true);
|
||||||
int fd = connect_daemon(true);
|
write_int(fd, POST_FS_DATA);
|
||||||
write_int(fd, POST_FS_DATA);
|
return read_int(fd);
|
||||||
return read_int(fd);
|
} else if (argv[1] == "--service"sv) {
|
||||||
} else if (argv[1] == "--service"sv) {
|
int fd = connect_daemon(true);
|
||||||
int fd = connect_daemon(true);
|
write_int(fd, LATE_START);
|
||||||
write_int(fd, LATE_START);
|
return read_int(fd);
|
||||||
return read_int(fd);
|
} else if (argv[1] == "--boot-complete"sv) {
|
||||||
} else if (argv[1] == "--boot-complete"sv) {
|
int fd = connect_daemon(true);
|
||||||
int fd = connect_daemon(true);
|
write_int(fd, BOOT_COMPLETE);
|
||||||
write_int(fd, BOOT_COMPLETE);
|
return read_int(fd);
|
||||||
return read_int(fd);
|
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
|
||||||
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
|
int fd = connect_daemon();
|
||||||
int fd = connect_daemon();
|
write_int(fd, SQLITE_CMD);
|
||||||
write_int(fd, SQLITE_CMD);
|
write_string(fd, argv[2]);
|
||||||
write_string(fd, argv[2]);
|
string res;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *res = read_string(fd);
|
read_string(fd, res);
|
||||||
if (res[0] == '\0') {
|
if (res.empty())
|
||||||
return 0;
|
return 0;
|
||||||
}
|
printf("%s\n", res.data());
|
||||||
printf("%s\n", res);
|
}
|
||||||
free(res);
|
} else if (argv[1] == "--remove-modules"sv) {
|
||||||
}
|
int fd = connect_daemon();
|
||||||
} else if (argv[1] == "--remove-modules"sv) {
|
write_int(fd, REMOVE_MODULES);
|
||||||
int fd = connect_daemon();
|
return read_int(fd);
|
||||||
write_int(fd, REMOVE_MODULES);
|
} else if (argv[1] == "--path"sv) {
|
||||||
return read_int(fd);
|
int fd = connect_daemon();
|
||||||
} else if (argv[1] == "--path"sv) {
|
write_int(fd, GET_PATH);
|
||||||
int fd = connect_daemon();
|
string path = read_string(fd);
|
||||||
write_int(fd, GET_PATH);
|
printf("%s\n", path.data());
|
||||||
char *path = read_string(fd);
|
return 0;
|
||||||
printf("%s\n", path);
|
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
|
||||||
return 0;
|
install_module(argv[2]);
|
||||||
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
|
}
|
||||||
install_module(argv[2]);
|
|
||||||
}
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Entry point for testing stuffs */
|
/* Entry point for testing stuffs */
|
||||||
else if (argv[1] == "--test"sv) {
|
else if (argv[1] == "--test"sv) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include <magisk.hpp>
|
#include <magisk.hpp>
|
||||||
#include <daemon.hpp>
|
|
||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
@@ -15,89 +14,89 @@ using namespace std;
|
|||||||
#define EXEC_CON "u:object_r:" SEPOL_EXEC_TYPE ":s0"
|
#define EXEC_CON "u:object_r:" SEPOL_EXEC_TYPE ":s0"
|
||||||
|
|
||||||
static void restore_syscon(int dirfd) {
|
static void restore_syscon(int dirfd) {
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
char *con;
|
char *con;
|
||||||
|
|
||||||
fgetfilecon(dirfd, &con);
|
fgetfilecon(dirfd, &con);
|
||||||
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
|
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
|
||||||
fsetfilecon(dirfd, SYSTEM_CON);
|
fsetfilecon(dirfd, SYSTEM_CON);
|
||||||
freecon(con);
|
freecon(con);
|
||||||
|
|
||||||
dir = xfdopendir(dirfd);
|
dir = xfdopendir(dirfd);
|
||||||
while ((entry = xreaddir(dir))) {
|
while ((entry = xreaddir(dir))) {
|
||||||
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||||
if (entry->d_type == DT_DIR) {
|
if (entry->d_type == DT_DIR) {
|
||||||
restore_syscon(fd);
|
restore_syscon(fd);
|
||||||
} else if (entry->d_type == DT_REG) {
|
} else if (entry->d_type == DT_REG) {
|
||||||
fgetfilecon(fd, &con);
|
fgetfilecon(fd, &con);
|
||||||
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
||||||
fsetfilecon(fd, SYSTEM_CON);
|
fsetfilecon(fd, SYSTEM_CON);
|
||||||
freecon(con);
|
freecon(con);
|
||||||
} else if (entry->d_type == DT_LNK) {
|
} else if (entry->d_type == DT_LNK) {
|
||||||
getfilecon_at(dirfd, entry->d_name, &con);
|
getfilecon_at(dirfd, entry->d_name, &con);
|
||||||
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
||||||
setfilecon_at(dirfd, entry->d_name, con);
|
setfilecon_at(dirfd, entry->d_name, con);
|
||||||
freecon(con);
|
freecon(con);
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore_magiskcon(int dirfd) {
|
static void restore_magiskcon(int dirfd) {
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
fsetfilecon(dirfd, MAGISK_CON);
|
fsetfilecon(dirfd, MAGISK_CON);
|
||||||
fchown(dirfd, 0, 0);
|
fchown(dirfd, 0, 0);
|
||||||
|
|
||||||
dir = xfdopendir(dirfd);
|
dir = xfdopendir(dirfd);
|
||||||
while ((entry = xreaddir(dir))) {
|
while ((entry = xreaddir(dir))) {
|
||||||
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||||
if (entry->d_type == DT_DIR) {
|
if (entry->d_type == DT_DIR) {
|
||||||
restore_magiskcon(fd);
|
restore_magiskcon(fd);
|
||||||
} else if (entry->d_type) {
|
} else if (entry->d_type) {
|
||||||
fsetfilecon(fd, MAGISK_CON);
|
fsetfilecon(fd, MAGISK_CON);
|
||||||
fchown(fd, 0, 0);
|
fchown(fd, 0, 0);
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void restorecon() {
|
void restorecon() {
|
||||||
int fd = xopen(SELINUX_CONTEXT, O_WRONLY | O_CLOEXEC);
|
int fd = xopen(SELINUX_CONTEXT, O_WRONLY | O_CLOEXEC);
|
||||||
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
|
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
|
||||||
lsetfilecon(SECURE_DIR, ADB_CON);
|
lsetfilecon(SECURE_DIR, ADB_CON);
|
||||||
close(fd);
|
close(fd);
|
||||||
lsetfilecon(MODULEROOT, SYSTEM_CON);
|
lsetfilecon(MODULEROOT, SYSTEM_CON);
|
||||||
fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
|
fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
|
||||||
restore_syscon(fd);
|
restore_syscon(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC);
|
fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC);
|
||||||
restore_magiskcon(fd);
|
restore_magiskcon(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore_tmpcon() {
|
void restore_tmpcon() {
|
||||||
if (MAGISKTMP == "/system/bin") {
|
if (MAGISKTMP == "/system/bin") {
|
||||||
// Running with emulator.sh
|
// Running with emulator.sh
|
||||||
if (SDK_INT >= 26)
|
if (SDK_INT >= 26)
|
||||||
lsetfilecon("/system/bin/magisk", EXEC_CON);
|
lsetfilecon("/system/bin/magisk", EXEC_CON);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MAGISKTMP == "/sbin")
|
if (MAGISKTMP == "/sbin")
|
||||||
setfilecon(MAGISKTMP.data(), ROOT_CON);
|
setfilecon(MAGISKTMP.data(), ROOT_CON);
|
||||||
else
|
else
|
||||||
chmod(MAGISKTMP.data(), 0700);
|
chmod(MAGISKTMP.data(), 0700);
|
||||||
|
|
||||||
auto dir = xopen_dir(MAGISKTMP.data());
|
auto dir = xopen_dir(MAGISKTMP.data());
|
||||||
int dfd = dirfd(dir.get());
|
int dfd = dirfd(dir.get());
|
||||||
|
|
||||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||||
if (SDK_INT >= 26 && entry->d_name == "magisk"sv)
|
if (SDK_INT >= 26 && entry->d_name == "magisk"sv)
|
||||||
setfilecon_at(dfd, entry->d_name, EXEC_CON);
|
setfilecon_at(dfd, entry->d_name, EXEC_CON);
|
||||||
else
|
else
|
||||||
setfilecon_at(dfd, entry->d_name, SYSTEM_CON);
|
setfilecon_at(dfd, entry->d_name, SYSTEM_CON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,144 +6,146 @@
|
|||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
|
|
||||||
|
#include "core.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define BBEXEC_CMD bbpath(), "sh"
|
#define BBEXEC_CMD bbpath(), "sh"
|
||||||
|
|
||||||
static const char *bbpath() {
|
static const char *bbpath() {
|
||||||
static string path;
|
static string path;
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
path = MAGISKTMP + "/" BBPATH "/busybox";
|
path = MAGISKTMP + "/" BBPATH "/busybox";
|
||||||
return path.data();
|
return path.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_script_env() {
|
static void set_script_env() {
|
||||||
setenv("ASH_STANDALONE", "1", 1);
|
setenv("ASH_STANDALONE", "1", 1);
|
||||||
char new_path[4096];
|
char new_path[4096];
|
||||||
sprintf(new_path, "%s:%s", getenv("PATH"), MAGISKTMP.data());
|
sprintf(new_path, "%s:%s", getenv("PATH"), MAGISKTMP.data());
|
||||||
setenv("PATH", new_path, 1);
|
setenv("PATH", new_path, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
void exec_script(const char *script) {
|
void exec_script(const char *script) {
|
||||||
exec_t exec {
|
exec_t exec {
|
||||||
.pre_exec = set_script_env,
|
.pre_exec = set_script_env,
|
||||||
.fork = fork_no_orphan
|
.fork = fork_no_orphan
|
||||||
};
|
};
|
||||||
exec_command_sync(exec, BBEXEC_CMD, script);
|
exec_command_sync(exec, BBEXEC_CMD, script);
|
||||||
}
|
}
|
||||||
|
|
||||||
static timespec pfs_timeout;
|
static timespec pfs_timeout;
|
||||||
|
|
||||||
#define PFS_SETUP() \
|
#define PFS_SETUP() \
|
||||||
if (pfs) { \
|
if (pfs) { \
|
||||||
if (int pid = xfork()) { \
|
if (int pid = xfork()) { \
|
||||||
if (pid < 0) \
|
if (pid < 0) \
|
||||||
return; \
|
return; \
|
||||||
/* In parent process, simply wait for child to finish */ \
|
/* In parent process, simply wait for child to finish */ \
|
||||||
waitpid(pid, nullptr, 0); \
|
waitpid(pid, nullptr, 0); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
timer_pid = xfork(); \
|
timer_pid = xfork(); \
|
||||||
if (timer_pid == 0) { \
|
if (timer_pid == 0) { \
|
||||||
/* In timer process, count down */ \
|
/* In timer process, count down */ \
|
||||||
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pfs_timeout, nullptr); \
|
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pfs_timeout, nullptr); \
|
||||||
exit(0); \
|
exit(0); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PFS_WAIT() \
|
#define PFS_WAIT() \
|
||||||
if (pfs) { \
|
if (pfs) { \
|
||||||
/* If we ran out of time, don't block */ \
|
/* If we ran out of time, don't block */ \
|
||||||
if (timer_pid < 0) \
|
if (timer_pid < 0) \
|
||||||
continue; \
|
continue; \
|
||||||
if (int pid = waitpid(-1, nullptr, 0); pid == timer_pid) { \
|
if (int pid = waitpid(-1, nullptr, 0); pid == timer_pid) { \
|
||||||
LOGW("* post-fs-data scripts blocking phase timeout\n"); \
|
LOGW("* post-fs-data scripts blocking phase timeout\n"); \
|
||||||
timer_pid = -1; \
|
timer_pid = -1; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PFS_DONE() \
|
#define PFS_DONE() \
|
||||||
if (pfs) { \
|
if (pfs) { \
|
||||||
if (timer_pid > 0) \
|
if (timer_pid > 0) \
|
||||||
kill(timer_pid, SIGKILL); \
|
kill(timer_pid, SIGKILL); \
|
||||||
exit(0); \
|
exit(0); \
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_common_scripts(const char *stage) {
|
void exec_common_scripts(const char *stage) {
|
||||||
LOGI("* Running %s.d scripts\n", stage);
|
LOGI("* Running %s.d scripts\n", stage);
|
||||||
char path[4096];
|
char path[4096];
|
||||||
char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage);
|
char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage);
|
||||||
auto dir = xopen_dir(path);
|
auto dir = xopen_dir(path);
|
||||||
if (!dir) return;
|
if (!dir) return;
|
||||||
|
|
||||||
bool pfs = stage == "post-fs-data"sv;
|
bool pfs = stage == "post-fs-data"sv;
|
||||||
int timer_pid = -1;
|
int timer_pid = -1;
|
||||||
if (pfs) {
|
if (pfs) {
|
||||||
// Setup timer
|
// Setup timer
|
||||||
clock_gettime(CLOCK_MONOTONIC, &pfs_timeout);
|
clock_gettime(CLOCK_MONOTONIC, &pfs_timeout);
|
||||||
pfs_timeout.tv_sec += POST_FS_DATA_SCRIPT_MAX_TIME;
|
pfs_timeout.tv_sec += POST_FS_DATA_SCRIPT_MAX_TIME;
|
||||||
}
|
}
|
||||||
PFS_SETUP()
|
PFS_SETUP()
|
||||||
|
|
||||||
*(name++) = '/';
|
*(name++) = '/';
|
||||||
int dfd = dirfd(dir.get());
|
int dfd = dirfd(dir.get());
|
||||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||||
if (entry->d_type == DT_REG) {
|
if (entry->d_type == DT_REG) {
|
||||||
if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
|
if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
|
||||||
continue;
|
continue;
|
||||||
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
|
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
|
||||||
strcpy(name, entry->d_name);
|
strcpy(name, entry->d_name);
|
||||||
exec_t exec {
|
exec_t exec {
|
||||||
.pre_exec = set_script_env,
|
.pre_exec = set_script_env,
|
||||||
.fork = pfs ? xfork : fork_dont_care
|
.fork = pfs ? xfork : fork_dont_care
|
||||||
};
|
};
|
||||||
exec_command(exec, BBEXEC_CMD, path);
|
exec_command(exec, BBEXEC_CMD, path);
|
||||||
PFS_WAIT()
|
PFS_WAIT()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PFS_DONE()
|
PFS_DONE()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return if a > b
|
// Return if a > b
|
||||||
static bool timespec_larger(timespec *a, timespec *b) {
|
static bool timespec_larger(timespec *a, timespec *b) {
|
||||||
if (a->tv_sec != b->tv_sec)
|
if (a->tv_sec != b->tv_sec)
|
||||||
return a->tv_sec > b->tv_sec;
|
return a->tv_sec > b->tv_sec;
|
||||||
return a->tv_nsec > b->tv_nsec;
|
return a->tv_nsec > b->tv_nsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_module_scripts(const char *stage, const vector<string> &module_list) {
|
void exec_module_scripts(const char *stage, const vector<string> &module_list) {
|
||||||
LOGI("* Running module %s scripts\n", stage);
|
LOGI("* Running module %s scripts\n", stage);
|
||||||
if (module_list.empty())
|
if (module_list.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool pfs = stage == "post-fs-data"sv;
|
bool pfs = stage == "post-fs-data"sv;
|
||||||
if (pfs) {
|
if (pfs) {
|
||||||
timespec now{};
|
timespec now{};
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
// If we had already timed out, treat it as service mode
|
// If we had already timed out, treat it as service mode
|
||||||
if (timespec_larger(&now, &pfs_timeout))
|
if (timespec_larger(&now, &pfs_timeout))
|
||||||
pfs = false;
|
pfs = false;
|
||||||
}
|
}
|
||||||
int timer_pid = -1;
|
int timer_pid = -1;
|
||||||
PFS_SETUP()
|
PFS_SETUP()
|
||||||
|
|
||||||
char path[4096];
|
char path[4096];
|
||||||
for (auto &m : module_list) {
|
for (auto &m : module_list) {
|
||||||
const char* module = m.data();
|
const char* module = m.data();
|
||||||
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
|
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
|
||||||
if (access(path, F_OK) == -1)
|
if (access(path, F_OK) == -1)
|
||||||
continue;
|
continue;
|
||||||
LOGI("%s: exec [%s.sh]\n", module, stage);
|
LOGI("%s: exec [%s.sh]\n", module, stage);
|
||||||
exec_t exec {
|
exec_t exec {
|
||||||
.pre_exec = set_script_env,
|
.pre_exec = set_script_env,
|
||||||
.fork = pfs ? xfork : fork_dont_care
|
.fork = pfs ? xfork : fork_dont_care
|
||||||
};
|
};
|
||||||
exec_command(exec, BBEXEC_CMD, path);
|
exec_command(exec, BBEXEC_CMD, path);
|
||||||
PFS_WAIT()
|
PFS_WAIT()
|
||||||
}
|
}
|
||||||
|
|
||||||
PFS_DONE()
|
PFS_DONE()
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr char install_script[] = R"EOF(
|
constexpr char install_script[] = R"EOF(
|
||||||
@@ -154,23 +156,23 @@ rm -f $APK
|
|||||||
)EOF";
|
)EOF";
|
||||||
|
|
||||||
void install_apk(const char *apk) {
|
void install_apk(const char *apk) {
|
||||||
setfilecon(apk, "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
setfilecon(apk, "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
||||||
exec_t exec {
|
exec_t exec {
|
||||||
.fork = fork_no_orphan
|
.fork = fork_no_orphan
|
||||||
};
|
};
|
||||||
char cmds[sizeof(install_script) + 4096];
|
char cmds[sizeof(install_script) + 4096];
|
||||||
sprintf(cmds, install_script, apk);
|
sprintf(cmds, install_script, apk);
|
||||||
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
|
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] __printflike(2, 3)
|
[[noreturn]] __printflike(2, 3)
|
||||||
static void abort(FILE *fp, const char *fmt, ...) {
|
static void abort(FILE *fp, const char *fmt, ...) {
|
||||||
va_list valist;
|
va_list valist;
|
||||||
va_start(valist, fmt);
|
va_start(valist, fmt);
|
||||||
vfprintf(fp, fmt, valist);
|
vfprintf(fp, fmt, valist);
|
||||||
fprintf(fp, "\n\n");
|
fprintf(fp, "\n\n");
|
||||||
va_end(valist);
|
va_end(valist);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr char install_module_script[] = R"EOF(
|
constexpr char install_module_script[] = R"EOF(
|
||||||
@@ -181,24 +183,24 @@ exit 0'
|
|||||||
)EOF";
|
)EOF";
|
||||||
|
|
||||||
void install_module(const char *file) {
|
void install_module(const char *file) {
|
||||||
if (getuid() != 0)
|
if (getuid() != 0)
|
||||||
abort(stderr, "Run this command with root");
|
abort(stderr, "Run this command with root");
|
||||||
if (access(DATABIN, F_OK) ||
|
if (access(DATABIN, F_OK) ||
|
||||||
access(DATABIN "/busybox", X_OK) ||
|
access(DATABIN "/busybox", X_OK) ||
|
||||||
access(DATABIN "/util_functions.sh", F_OK))
|
access(DATABIN "/util_functions.sh", F_OK))
|
||||||
abort(stderr, "Incomplete Magisk install");
|
abort(stderr, "Incomplete Magisk install");
|
||||||
if (access(file, F_OK))
|
if (access(file, F_OK))
|
||||||
abort(stderr, "'%s' does not exist", file);
|
abort(stderr, "'%s' does not exist", file);
|
||||||
|
|
||||||
setenv("OUTFD", "1", 1);
|
setenv("OUTFD", "1", 1);
|
||||||
setenv("ZIPFILE", file, 1);
|
setenv("ZIPFILE", file, 1);
|
||||||
setenv("ASH_STANDALONE", "1", 1);
|
setenv("ASH_STANDALONE", "1", 1);
|
||||||
|
|
||||||
int fd = xopen("/dev/null", O_RDONLY);
|
int fd = xopen("/dev/null", O_RDONLY);
|
||||||
xdup2(fd, STDERR_FILENO);
|
xdup2(fd, STDERR_FILENO);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
const char *argv[] = { "/system/bin/sh", "-c", install_module_script, nullptr };
|
const char *argv[] = { "/system/bin/sh", "-c", install_module_script, nullptr };
|
||||||
execve(argv[0], (char **) argv, environ);
|
execve(argv[0], (char **) argv, environ);
|
||||||
abort(stdout, "Failed to execute BusyBox shell");
|
abort(stdout, "Failed to execute BusyBox shell");
|
||||||
}
|
}
|
||||||
|
@@ -1,36 +1,36 @@
|
|||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
|
|
||||||
#include <socket.hpp>
|
#include <socket.hpp>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
static size_t socket_len(sockaddr_un *sun) {
|
static size_t socket_len(sockaddr_un *sun) {
|
||||||
if (sun->sun_path[0])
|
if (sun->sun_path[0])
|
||||||
return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
|
return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
|
||||||
else
|
else
|
||||||
return sizeof(sa_family_t) + strlen(sun->sun_path + 1) + 1;
|
return sizeof(sa_family_t) + strlen(sun->sun_path + 1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name) {
|
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name) {
|
||||||
memset(sun, 0, sizeof(*sun));
|
memset(sun, 0, sizeof(*sun));
|
||||||
sun->sun_family = AF_UNIX;
|
sun->sun_family = AF_UNIX;
|
||||||
strcpy(sun->sun_path + 1, name);
|
strcpy(sun->sun_path + 1, name);
|
||||||
return socket_len(sun);
|
return socket_len(sun);
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_accept(int sockfd, int timeout) {
|
int socket_accept(int sockfd, int timeout) {
|
||||||
struct pollfd pfd = {
|
struct pollfd pfd = {
|
||||||
.fd = sockfd,
|
.fd = sockfd,
|
||||||
.events = POLL_IN
|
.events = POLL_IN
|
||||||
};
|
};
|
||||||
return xpoll(&pfd, 1, timeout * 1000) <= 0 ? -1 : xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
return xpoll(&pfd, 1, timeout * 1000) <= 0 ? -1 : xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_client_cred(int fd, struct ucred *cred) {
|
void get_client_cred(int fd, struct ucred *cred) {
|
||||||
socklen_t ucred_length = sizeof(*cred);
|
socklen_t ucred_length = sizeof(*cred);
|
||||||
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length);
|
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -43,50 +43,50 @@ void get_client_cred(int fd, struct ucred *cred) {
|
|||||||
* On error the function terminates by calling exit(-1)
|
* On error the function terminates by calling exit(-1)
|
||||||
*/
|
*/
|
||||||
int recv_fd(int sockfd) {
|
int recv_fd(int sockfd) {
|
||||||
// Need to receive data from the message, otherwise don't care about it.
|
// Need to receive data from the message, otherwise don't care about it.
|
||||||
char iovbuf;
|
char iovbuf;
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
|
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
.iov_base = &iovbuf,
|
.iov_base = &iovbuf,
|
||||||
.iov_len = 1,
|
.iov_len = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||||
|
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
.msg_control = cmsgbuf,
|
.msg_control = cmsgbuf,
|
||||||
.msg_controllen = sizeof(cmsgbuf),
|
.msg_controllen = sizeof(cmsgbuf),
|
||||||
};
|
};
|
||||||
|
|
||||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||||
|
|
||||||
// Was a control message actually sent?
|
// Was a control message actually sent?
|
||||||
switch (msg.msg_controllen) {
|
switch (msg.msg_controllen) {
|
||||||
case 0:
|
case 0:
|
||||||
// No, so the file descriptor was closed and won't be used.
|
// No, so the file descriptor was closed and won't be used.
|
||||||
return -1;
|
return -1;
|
||||||
case sizeof(cmsgbuf):
|
case sizeof(cmsgbuf):
|
||||||
// Yes, grab the file descriptor from it.
|
// Yes, grab the file descriptor from it.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmsg = CMSG_FIRSTHDR(&msg);
|
cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
|
|
||||||
if (cmsg == nullptr ||
|
if (cmsg == nullptr ||
|
||||||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
||||||
cmsg->cmsg_level != SOL_SOCKET ||
|
cmsg->cmsg_level != SOL_SOCKET ||
|
||||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||||
error:
|
error:
|
||||||
LOGE("unable to read fd\n");
|
LOGE("unable to read fd\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *(int *)CMSG_DATA(cmsg);
|
return *(int *)CMSG_DATA(cmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -99,106 +99,84 @@ error:
|
|||||||
* but no control message with the FD is sent.
|
* but no control message with the FD is sent.
|
||||||
*/
|
*/
|
||||||
void send_fd(int sockfd, int fd) {
|
void send_fd(int sockfd, int fd) {
|
||||||
// Need to send some data in the message, this will do.
|
// Need to send some data in the message, this will do.
|
||||||
char junk[] = { '\0' };
|
char junk[] = { '\0' };
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
.iov_base = junk,
|
.iov_base = junk,
|
||||||
.iov_len = 1,
|
.iov_len = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
.msg_iovlen = 1,
|
.msg_iovlen = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||||
|
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
// Is the file descriptor actually open?
|
// Is the file descriptor actually open?
|
||||||
if (fcntl(fd, F_GETFD) == -1) {
|
if (fcntl(fd, F_GETFD) == -1) {
|
||||||
if (errno != EBADF) {
|
if (errno != EBADF) {
|
||||||
PLOGE("unable to send fd");
|
PLOGE("unable to send fd");
|
||||||
}
|
}
|
||||||
// It's closed, don't send a control message or sendmsg will EBADF.
|
// It's closed, don't send a control message or sendmsg will EBADF.
|
||||||
} else {
|
} else {
|
||||||
// It's open, send the file descriptor in a control message.
|
// It's open, send the file descriptor in a control message.
|
||||||
msg.msg_control = cmsgbuf;
|
msg.msg_control = cmsgbuf;
|
||||||
msg.msg_controllen = sizeof(cmsgbuf);
|
msg.msg_controllen = sizeof(cmsgbuf);
|
||||||
|
|
||||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
|
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||||
cmsg->cmsg_level = SOL_SOCKET;
|
cmsg->cmsg_level = SOL_SOCKET;
|
||||||
cmsg->cmsg_type = SCM_RIGHTS;
|
cmsg->cmsg_type = SCM_RIGHTS;
|
||||||
|
|
||||||
*(int *)CMSG_DATA(cmsg) = fd;
|
*(int *)CMSG_DATA(cmsg) = fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xsendmsg(sockfd, &msg, 0);
|
xsendmsg(sockfd, &msg, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_int(int fd) {
|
int read_int(int fd) {
|
||||||
int val;
|
int val;
|
||||||
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
||||||
return -1;
|
return -1;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_int_be(int fd) {
|
int read_int_be(int fd) {
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
||||||
return -1;
|
return -1;
|
||||||
return ntohl(val);
|
return ntohl(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_int(int fd, int val) {
|
void write_int(int fd, int val) {
|
||||||
if (fd < 0) return;
|
if (fd < 0) return;
|
||||||
xwrite(fd, &val, sizeof(val));
|
xwrite(fd, &val, sizeof(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_int_be(int fd, int val) {
|
void write_int_be(int fd, int val) {
|
||||||
uint32_t nl = htonl(val);
|
uint32_t nl = htonl(val);
|
||||||
xwrite(fd, &nl, sizeof(nl));
|
xwrite(fd, &nl, sizeof(nl));
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *rd_str(int fd, int len) {
|
void read_string(int fd, std::string &str) {
|
||||||
char *val = (char *) xmalloc(sizeof(char) * (len + 1));
|
int len = read_int(fd);
|
||||||
xxread(fd, val, len);
|
str.clear();
|
||||||
val[len] = '\0';
|
str.resize(len);
|
||||||
return val;
|
xxread(fd, str.data(), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* read_string(int fd) {
|
string read_string(int fd) {
|
||||||
int len = read_int(fd);
|
string str;
|
||||||
return rd_str(fd, len);
|
read_string(fd, str);
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* read_string_be(int fd) {
|
void write_string(int fd, string_view str) {
|
||||||
int len = read_int_be(fd);
|
if (fd < 0) return;
|
||||||
return rd_str(fd, len);
|
write_int(fd, str.size());
|
||||||
}
|
xwrite(fd, str.data(), str.size());
|
||||||
|
|
||||||
void write_string(int fd, const char *val) {
|
|
||||||
if (fd < 0) return;
|
|
||||||
int len = strlen(val);
|
|
||||||
write_int(fd, len);
|
|
||||||
xwrite(fd, val, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_string_be(int fd, const char *val) {
|
|
||||||
int len = strlen(val);
|
|
||||||
write_int_be(fd, len);
|
|
||||||
xwrite(fd, val, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_key_value(int fd, const char *key, const char *val) {
|
|
||||||
write_string_be(fd, key);
|
|
||||||
write_string_be(fd, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_key_token(int fd, const char *key, int tok) {
|
|
||||||
char val[16];
|
|
||||||
sprintf(val, "%d", tok);
|
|
||||||
write_key_value(fd, key, val);
|
|
||||||
}
|
}
|
||||||
|
563
native/jni/external/Android.mk
vendored
563
native/jni/external/Android.mk
vendored
@@ -6,9 +6,9 @@ LOCAL_MODULE:= libxz
|
|||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/xz-embedded
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/xz-embedded
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
xz-embedded/xz_crc32.c \
|
xz-embedded/xz_crc32.c \
|
||||||
xz-embedded/xz_dec_lzma2.c \
|
xz-embedded/xz_dec_lzma2.c \
|
||||||
xz-embedded/xz_dec_stream.c
|
xz-embedded/xz_dec_stream.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# libnanopb.a
|
# libnanopb.a
|
||||||
@@ -17,9 +17,9 @@ LOCAL_MODULE:= libnanopb
|
|||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/nanopb
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/nanopb
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
nanopb/pb_common.c \
|
nanopb/pb_common.c \
|
||||||
nanopb/pb_decode.c \
|
nanopb/pb_decode.c \
|
||||||
nanopb/pb_encode.c
|
nanopb/pb_encode.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# libfdt.a
|
# libfdt.a
|
||||||
@@ -28,15 +28,15 @@ LOCAL_MODULE:= libfdt
|
|||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/dtc/libfdt
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/dtc/libfdt
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
dtc/libfdt/fdt.c \
|
dtc/libfdt/fdt.c \
|
||||||
dtc/libfdt/fdt_addresses.c \
|
dtc/libfdt/fdt_addresses.c \
|
||||||
dtc/libfdt/fdt_empty_tree.c \
|
dtc/libfdt/fdt_empty_tree.c \
|
||||||
dtc/libfdt/fdt_overlay.c \
|
dtc/libfdt/fdt_overlay.c \
|
||||||
dtc/libfdt/fdt_ro.c \
|
dtc/libfdt/fdt_ro.c \
|
||||||
dtc/libfdt/fdt_rw.c \
|
dtc/libfdt/fdt_rw.c \
|
||||||
dtc/libfdt/fdt_strerror.c \
|
dtc/libfdt/fdt_strerror.c \
|
||||||
dtc/libfdt/fdt_sw.c \
|
dtc/libfdt/fdt_sw.c \
|
||||||
dtc/libfdt/fdt_wip.c
|
dtc/libfdt/fdt_wip.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# liblz4.a
|
# liblz4.a
|
||||||
@@ -45,10 +45,10 @@ LOCAL_MODULE := liblz4
|
|||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/lz4/lib
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/lz4/lib
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
lz4/lib/lz4.c \
|
lz4/lib/lz4.c \
|
||||||
lz4/lib/lz4frame.c \
|
lz4/lib/lz4frame.c \
|
||||||
lz4/lib/lz4hc.c \
|
lz4/lib/lz4hc.c \
|
||||||
lz4/lib/xxhash.c
|
lz4/lib/xxhash.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# libbz2.a
|
# libbz2.a
|
||||||
@@ -57,112 +57,112 @@ LOCAL_MODULE := libbz2
|
|||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/bzip2
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/bzip2
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
bzip2/blocksort.c \
|
bzip2/blocksort.c \
|
||||||
bzip2/huffman.c \
|
bzip2/huffman.c \
|
||||||
bzip2/crctable.c \
|
bzip2/crctable.c \
|
||||||
bzip2/randtable.c \
|
bzip2/randtable.c \
|
||||||
bzip2/compress.c \
|
bzip2/compress.c \
|
||||||
bzip2/decompress.c \
|
bzip2/decompress.c \
|
||||||
bzip2/bzlib.c
|
bzip2/bzlib.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# liblzma.a
|
# liblzma.a
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := liblzma
|
LOCAL_MODULE := liblzma
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
$(LOCAL_PATH)/xz_config \
|
$(LOCAL_PATH)/xz_config \
|
||||||
$(LOCAL_PATH)/xz/src/common \
|
$(LOCAL_PATH)/xz/src/common \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/api \
|
$(LOCAL_PATH)/xz/src/liblzma/api \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/check \
|
$(LOCAL_PATH)/xz/src/liblzma/check \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/common \
|
$(LOCAL_PATH)/xz/src/liblzma/common \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/delta \
|
$(LOCAL_PATH)/xz/src/liblzma/delta \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/lz \
|
$(LOCAL_PATH)/xz/src/liblzma/lz \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/lzma \
|
$(LOCAL_PATH)/xz/src/liblzma/lzma \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/rangecoder \
|
$(LOCAL_PATH)/xz/src/liblzma/rangecoder \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma/simple \
|
$(LOCAL_PATH)/xz/src/liblzma/simple \
|
||||||
$(LOCAL_PATH)/xz/src/liblzma
|
$(LOCAL_PATH)/xz/src/liblzma
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/xz/src/liblzma/api
|
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/xz/src/liblzma/api
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
xz/src/common/tuklib_cpucores.c \
|
xz/src/common/tuklib_cpucores.c \
|
||||||
xz/src/common/tuklib_exit.c \
|
xz/src/common/tuklib_exit.c \
|
||||||
xz/src/common/tuklib_mbstr_fw.c \
|
xz/src/common/tuklib_mbstr_fw.c \
|
||||||
xz/src/common/tuklib_mbstr_width.c \
|
xz/src/common/tuklib_mbstr_width.c \
|
||||||
xz/src/common/tuklib_open_stdxxx.c \
|
xz/src/common/tuklib_open_stdxxx.c \
|
||||||
xz/src/common/tuklib_physmem.c \
|
xz/src/common/tuklib_physmem.c \
|
||||||
xz/src/common/tuklib_progname.c \
|
xz/src/common/tuklib_progname.c \
|
||||||
xz/src/liblzma/check/check.c \
|
xz/src/liblzma/check/check.c \
|
||||||
xz/src/liblzma/check/crc32_fast.c \
|
xz/src/liblzma/check/crc32_fast.c \
|
||||||
xz/src/liblzma/check/crc32_table.c \
|
xz/src/liblzma/check/crc32_table.c \
|
||||||
xz/src/liblzma/check/crc64_fast.c \
|
xz/src/liblzma/check/crc64_fast.c \
|
||||||
xz/src/liblzma/check/crc64_table.c \
|
xz/src/liblzma/check/crc64_table.c \
|
||||||
xz/src/liblzma/check/sha256.c \
|
xz/src/liblzma/check/sha256.c \
|
||||||
xz/src/liblzma/common/alone_decoder.c \
|
xz/src/liblzma/common/alone_decoder.c \
|
||||||
xz/src/liblzma/common/alone_encoder.c \
|
xz/src/liblzma/common/alone_encoder.c \
|
||||||
xz/src/liblzma/common/auto_decoder.c \
|
xz/src/liblzma/common/auto_decoder.c \
|
||||||
xz/src/liblzma/common/block_buffer_decoder.c \
|
xz/src/liblzma/common/block_buffer_decoder.c \
|
||||||
xz/src/liblzma/common/block_buffer_encoder.c \
|
xz/src/liblzma/common/block_buffer_encoder.c \
|
||||||
xz/src/liblzma/common/block_decoder.c \
|
xz/src/liblzma/common/block_decoder.c \
|
||||||
xz/src/liblzma/common/block_encoder.c \
|
xz/src/liblzma/common/block_encoder.c \
|
||||||
xz/src/liblzma/common/block_header_decoder.c \
|
xz/src/liblzma/common/block_header_decoder.c \
|
||||||
xz/src/liblzma/common/block_header_encoder.c \
|
xz/src/liblzma/common/block_header_encoder.c \
|
||||||
xz/src/liblzma/common/block_util.c \
|
xz/src/liblzma/common/block_util.c \
|
||||||
xz/src/liblzma/common/common.c \
|
xz/src/liblzma/common/common.c \
|
||||||
xz/src/liblzma/common/easy_buffer_encoder.c \
|
xz/src/liblzma/common/easy_buffer_encoder.c \
|
||||||
xz/src/liblzma/common/easy_decoder_memusage.c \
|
xz/src/liblzma/common/easy_decoder_memusage.c \
|
||||||
xz/src/liblzma/common/easy_encoder.c \
|
xz/src/liblzma/common/easy_encoder.c \
|
||||||
xz/src/liblzma/common/easy_encoder_memusage.c \
|
xz/src/liblzma/common/easy_encoder_memusage.c \
|
||||||
xz/src/liblzma/common/easy_preset.c \
|
xz/src/liblzma/common/easy_preset.c \
|
||||||
xz/src/liblzma/common/filter_buffer_decoder.c \
|
xz/src/liblzma/common/filter_buffer_decoder.c \
|
||||||
xz/src/liblzma/common/filter_buffer_encoder.c \
|
xz/src/liblzma/common/filter_buffer_encoder.c \
|
||||||
xz/src/liblzma/common/filter_common.c \
|
xz/src/liblzma/common/filter_common.c \
|
||||||
xz/src/liblzma/common/filter_decoder.c \
|
xz/src/liblzma/common/filter_decoder.c \
|
||||||
xz/src/liblzma/common/filter_encoder.c \
|
xz/src/liblzma/common/filter_encoder.c \
|
||||||
xz/src/liblzma/common/filter_flags_decoder.c \
|
xz/src/liblzma/common/filter_flags_decoder.c \
|
||||||
xz/src/liblzma/common/filter_flags_encoder.c \
|
xz/src/liblzma/common/filter_flags_encoder.c \
|
||||||
xz/src/liblzma/common/hardware_cputhreads.c \
|
xz/src/liblzma/common/hardware_cputhreads.c \
|
||||||
xz/src/liblzma/common/hardware_physmem.c \
|
xz/src/liblzma/common/hardware_physmem.c \
|
||||||
xz/src/liblzma/common/index.c \
|
xz/src/liblzma/common/index.c \
|
||||||
xz/src/liblzma/common/index_decoder.c \
|
xz/src/liblzma/common/index_decoder.c \
|
||||||
xz/src/liblzma/common/index_encoder.c \
|
xz/src/liblzma/common/index_encoder.c \
|
||||||
xz/src/liblzma/common/index_hash.c \
|
xz/src/liblzma/common/index_hash.c \
|
||||||
xz/src/liblzma/common/outqueue.c \
|
xz/src/liblzma/common/outqueue.c \
|
||||||
xz/src/liblzma/common/stream_buffer_decoder.c \
|
xz/src/liblzma/common/stream_buffer_decoder.c \
|
||||||
xz/src/liblzma/common/stream_buffer_encoder.c \
|
xz/src/liblzma/common/stream_buffer_encoder.c \
|
||||||
xz/src/liblzma/common/stream_decoder.c \
|
xz/src/liblzma/common/stream_decoder.c \
|
||||||
xz/src/liblzma/common/stream_encoder.c \
|
xz/src/liblzma/common/stream_encoder.c \
|
||||||
xz/src/liblzma/common/stream_encoder_mt.c \
|
xz/src/liblzma/common/stream_encoder_mt.c \
|
||||||
xz/src/liblzma/common/stream_flags_common.c \
|
xz/src/liblzma/common/stream_flags_common.c \
|
||||||
xz/src/liblzma/common/stream_flags_decoder.c \
|
xz/src/liblzma/common/stream_flags_decoder.c \
|
||||||
xz/src/liblzma/common/stream_flags_encoder.c \
|
xz/src/liblzma/common/stream_flags_encoder.c \
|
||||||
xz/src/liblzma/common/vli_decoder.c \
|
xz/src/liblzma/common/vli_decoder.c \
|
||||||
xz/src/liblzma/common/vli_encoder.c \
|
xz/src/liblzma/common/vli_encoder.c \
|
||||||
xz/src/liblzma/common/vli_size.c \
|
xz/src/liblzma/common/vli_size.c \
|
||||||
xz/src/liblzma/delta/delta_common.c \
|
xz/src/liblzma/delta/delta_common.c \
|
||||||
xz/src/liblzma/delta/delta_decoder.c \
|
xz/src/liblzma/delta/delta_decoder.c \
|
||||||
xz/src/liblzma/delta/delta_encoder.c \
|
xz/src/liblzma/delta/delta_encoder.c \
|
||||||
xz/src/liblzma/lz/lz_decoder.c \
|
xz/src/liblzma/lz/lz_decoder.c \
|
||||||
xz/src/liblzma/lz/lz_encoder.c \
|
xz/src/liblzma/lz/lz_encoder.c \
|
||||||
xz/src/liblzma/lz/lz_encoder_mf.c \
|
xz/src/liblzma/lz/lz_encoder_mf.c \
|
||||||
xz/src/liblzma/lzma/fastpos_table.c \
|
xz/src/liblzma/lzma/fastpos_table.c \
|
||||||
xz/src/liblzma/lzma/fastpos_tablegen.c \
|
xz/src/liblzma/lzma/fastpos_tablegen.c \
|
||||||
xz/src/liblzma/lzma/lzma2_decoder.c \
|
xz/src/liblzma/lzma/lzma2_decoder.c \
|
||||||
xz/src/liblzma/lzma/lzma2_encoder.c \
|
xz/src/liblzma/lzma/lzma2_encoder.c \
|
||||||
xz/src/liblzma/lzma/lzma_decoder.c \
|
xz/src/liblzma/lzma/lzma_decoder.c \
|
||||||
xz/src/liblzma/lzma/lzma_encoder.c \
|
xz/src/liblzma/lzma/lzma_encoder.c \
|
||||||
xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c \
|
xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c \
|
||||||
xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c \
|
xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c \
|
||||||
xz/src/liblzma/lzma/lzma_encoder_presets.c \
|
xz/src/liblzma/lzma/lzma_encoder_presets.c \
|
||||||
xz/src/liblzma/rangecoder/price_table.c \
|
xz/src/liblzma/rangecoder/price_table.c \
|
||||||
xz/src/liblzma/rangecoder/price_tablegen.c \
|
xz/src/liblzma/rangecoder/price_tablegen.c \
|
||||||
xz/src/liblzma/simple/arm.c \
|
xz/src/liblzma/simple/arm.c \
|
||||||
xz/src/liblzma/simple/armthumb.c \
|
xz/src/liblzma/simple/armthumb.c \
|
||||||
xz/src/liblzma/simple/ia64.c \
|
xz/src/liblzma/simple/ia64.c \
|
||||||
xz/src/liblzma/simple/powerpc.c \
|
xz/src/liblzma/simple/powerpc.c \
|
||||||
xz/src/liblzma/simple/simple_coder.c \
|
xz/src/liblzma/simple/simple_coder.c \
|
||||||
xz/src/liblzma/simple/simple_decoder.c \
|
xz/src/liblzma/simple/simple_decoder.c \
|
||||||
xz/src/liblzma/simple/simple_encoder.c \
|
xz/src/liblzma/simple/simple_encoder.c \
|
||||||
xz/src/liblzma/simple/sparc.c \
|
xz/src/liblzma/simple/sparc.c \
|
||||||
xz/src/liblzma/simple/x86.c
|
xz/src/liblzma/simple/x86.c
|
||||||
LOCAL_CFLAGS := -DHAVE_CONFIG_H -Wno-implicit-function-declaration
|
LOCAL_CFLAGS := -DHAVE_CONFIG_H -Wno-implicit-function-declaration
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
@@ -175,72 +175,72 @@ LOCAL_MODULE := libsepol
|
|||||||
LOCAL_C_INCLUDES := $(LIBSEPOL) $(LOCAL_PATH)/selinux/libsepol/src
|
LOCAL_C_INCLUDES := $(LIBSEPOL) $(LOCAL_PATH)/selinux/libsepol/src
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LIBSEPOL)
|
LOCAL_EXPORT_C_INCLUDES := $(LIBSEPOL)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
selinux/libsepol/src/assertion.c \
|
selinux/libsepol/src/assertion.c \
|
||||||
selinux/libsepol/src/avrule_block.c \
|
selinux/libsepol/src/avrule_block.c \
|
||||||
selinux/libsepol/src/avtab.c \
|
selinux/libsepol/src/avtab.c \
|
||||||
selinux/libsepol/src/boolean_record.c \
|
selinux/libsepol/src/boolean_record.c \
|
||||||
selinux/libsepol/src/booleans.c \
|
selinux/libsepol/src/booleans.c \
|
||||||
selinux/libsepol/src/conditional.c \
|
selinux/libsepol/src/conditional.c \
|
||||||
selinux/libsepol/src/constraint.c \
|
selinux/libsepol/src/constraint.c \
|
||||||
selinux/libsepol/src/context.c \
|
selinux/libsepol/src/context.c \
|
||||||
selinux/libsepol/src/context_record.c \
|
selinux/libsepol/src/context_record.c \
|
||||||
selinux/libsepol/src/debug.c \
|
selinux/libsepol/src/debug.c \
|
||||||
selinux/libsepol/src/deprecated_funcs.c \
|
selinux/libsepol/src/deprecated_funcs.c \
|
||||||
selinux/libsepol/src/ebitmap.c \
|
selinux/libsepol/src/ebitmap.c \
|
||||||
selinux/libsepol/src/expand.c \
|
selinux/libsepol/src/expand.c \
|
||||||
selinux/libsepol/src/handle.c \
|
selinux/libsepol/src/handle.c \
|
||||||
selinux/libsepol/src/hashtab.c \
|
selinux/libsepol/src/hashtab.c \
|
||||||
selinux/libsepol/src/hierarchy.c \
|
selinux/libsepol/src/hierarchy.c \
|
||||||
selinux/libsepol/src/ibendport_record.c \
|
selinux/libsepol/src/ibendport_record.c \
|
||||||
selinux/libsepol/src/ibendports.c \
|
selinux/libsepol/src/ibendports.c \
|
||||||
selinux/libsepol/src/ibpkey_record.c \
|
selinux/libsepol/src/ibpkey_record.c \
|
||||||
selinux/libsepol/src/ibpkeys.c \
|
selinux/libsepol/src/ibpkeys.c \
|
||||||
selinux/libsepol/src/iface_record.c \
|
selinux/libsepol/src/iface_record.c \
|
||||||
selinux/libsepol/src/interfaces.c \
|
selinux/libsepol/src/interfaces.c \
|
||||||
selinux/libsepol/src/kernel_to_cil.c \
|
selinux/libsepol/src/kernel_to_cil.c \
|
||||||
selinux/libsepol/src/kernel_to_common.c \
|
selinux/libsepol/src/kernel_to_common.c \
|
||||||
selinux/libsepol/src/kernel_to_conf.c \
|
selinux/libsepol/src/kernel_to_conf.c \
|
||||||
selinux/libsepol/src/link.c \
|
selinux/libsepol/src/link.c \
|
||||||
selinux/libsepol/src/mls.c \
|
selinux/libsepol/src/mls.c \
|
||||||
selinux/libsepol/src/module.c \
|
selinux/libsepol/src/module.c \
|
||||||
selinux/libsepol/src/module_to_cil.c \
|
selinux/libsepol/src/module_to_cil.c \
|
||||||
selinux/libsepol/src/node_record.c \
|
selinux/libsepol/src/node_record.c \
|
||||||
selinux/libsepol/src/nodes.c \
|
selinux/libsepol/src/nodes.c \
|
||||||
selinux/libsepol/src/optimize.c \
|
selinux/libsepol/src/optimize.c \
|
||||||
selinux/libsepol/src/polcaps.c \
|
selinux/libsepol/src/polcaps.c \
|
||||||
selinux/libsepol/src/policydb.c \
|
selinux/libsepol/src/policydb.c \
|
||||||
selinux/libsepol/src/policydb_convert.c \
|
selinux/libsepol/src/policydb_convert.c \
|
||||||
selinux/libsepol/src/policydb_public.c \
|
selinux/libsepol/src/policydb_public.c \
|
||||||
selinux/libsepol/src/port_record.c \
|
selinux/libsepol/src/port_record.c \
|
||||||
selinux/libsepol/src/ports.c \
|
selinux/libsepol/src/ports.c \
|
||||||
selinux/libsepol/src/roles.c \
|
selinux/libsepol/src/roles.c \
|
||||||
selinux/libsepol/src/services.c \
|
selinux/libsepol/src/services.c \
|
||||||
selinux/libsepol/src/sidtab.c \
|
selinux/libsepol/src/sidtab.c \
|
||||||
selinux/libsepol/src/symtab.c \
|
selinux/libsepol/src/symtab.c \
|
||||||
selinux/libsepol/src/user_record.c \
|
selinux/libsepol/src/user_record.c \
|
||||||
selinux/libsepol/src/users.c \
|
selinux/libsepol/src/users.c \
|
||||||
selinux/libsepol/src/util.c \
|
selinux/libsepol/src/util.c \
|
||||||
selinux/libsepol/src/write.c \
|
selinux/libsepol/src/write.c \
|
||||||
selinux/libsepol/cil/src/cil.c \
|
selinux/libsepol/cil/src/cil.c \
|
||||||
selinux/libsepol/cil/src/cil_binary.c \
|
selinux/libsepol/cil/src/cil_binary.c \
|
||||||
selinux/libsepol/cil/src/cil_build_ast.c \
|
selinux/libsepol/cil/src/cil_build_ast.c \
|
||||||
selinux/libsepol/cil/src/cil_copy_ast.c \
|
selinux/libsepol/cil/src/cil_copy_ast.c \
|
||||||
selinux/libsepol/cil/src/cil_find.c \
|
selinux/libsepol/cil/src/cil_find.c \
|
||||||
selinux/libsepol/cil/src/cil_fqn.c \
|
selinux/libsepol/cil/src/cil_fqn.c \
|
||||||
selinux/libsepol/cil/src/cil_lexer.c \
|
selinux/libsepol/cil/src/cil_lexer.c \
|
||||||
selinux/libsepol/cil/src/cil_list.c \
|
selinux/libsepol/cil/src/cil_list.c \
|
||||||
selinux/libsepol/cil/src/cil_log.c \
|
selinux/libsepol/cil/src/cil_log.c \
|
||||||
selinux/libsepol/cil/src/cil_mem.c \
|
selinux/libsepol/cil/src/cil_mem.c \
|
||||||
selinux/libsepol/cil/src/cil_parser.c \
|
selinux/libsepol/cil/src/cil_parser.c \
|
||||||
selinux/libsepol/cil/src/cil_policy.c \
|
selinux/libsepol/cil/src/cil_policy.c \
|
||||||
selinux/libsepol/cil/src/cil_post.c \
|
selinux/libsepol/cil/src/cil_post.c \
|
||||||
selinux/libsepol/cil/src/cil_reset_ast.c \
|
selinux/libsepol/cil/src/cil_reset_ast.c \
|
||||||
selinux/libsepol/cil/src/cil_resolve_ast.c \
|
selinux/libsepol/cil/src/cil_resolve_ast.c \
|
||||||
selinux/libsepol/cil/src/cil_stack.c \
|
selinux/libsepol/cil/src/cil_stack.c \
|
||||||
selinux/libsepol/cil/src/cil_strpool.c \
|
selinux/libsepol/cil/src/cil_strpool.c \
|
||||||
selinux/libsepol/cil/src/cil_symtab.c \
|
selinux/libsepol/cil/src/cil_symtab.c \
|
||||||
selinux/libsepol/cil/src/cil_tree.c \
|
selinux/libsepol/cil/src/cil_tree.c \
|
||||||
selinux/libsepol/cil/src/cil_verify.c
|
selinux/libsepol/cil/src/cil_verify.c
|
||||||
LOCAL_CFLAGS := -Dgetline=__getline -Wno-implicit-function-declaration
|
LOCAL_CFLAGS := -Dgetline=__getline -Wno-implicit-function-declaration
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
@@ -252,67 +252,67 @@ LOCAL_C_INCLUDES := $(LIBSELINUX)
|
|||||||
LOCAL_EXPORT_C_INCLUDES := $(LIBSELINUX)
|
LOCAL_EXPORT_C_INCLUDES := $(LIBSELINUX)
|
||||||
LOCAL_STATIC_LIBRARIES := libpcre2
|
LOCAL_STATIC_LIBRARIES := libpcre2
|
||||||
LOCAL_CFLAGS := \
|
LOCAL_CFLAGS := \
|
||||||
-Wno-implicit-function-declaration -Wno-int-conversion -Wno-unused-function \
|
-Wno-implicit-function-declaration -Wno-int-conversion -Wno-unused-function \
|
||||||
-D_GNU_SOURCE -DUSE_PCRE2 \
|
-D_GNU_SOURCE -DUSE_PCRE2 \
|
||||||
-DNO_PERSISTENTLY_STORED_PATTERNS -DDISABLE_SETRANS -DDISABLE_BOOL \
|
-DNO_PERSISTENTLY_STORED_PATTERNS -DDISABLE_SETRANS -DDISABLE_BOOL \
|
||||||
-DNO_MEDIA_BACKEND -DNO_X_BACKEND -DNO_DB_BACKEND -DNO_ANDROID_BACKEND
|
-DNO_MEDIA_BACKEND -DNO_X_BACKEND -DNO_DB_BACKEND -DNO_ANDROID_BACKEND
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
selinux/libselinux/src/avc.c \
|
selinux/libselinux/src/avc.c \
|
||||||
selinux/libselinux/src/avc_internal.c \
|
selinux/libselinux/src/avc_internal.c \
|
||||||
selinux/libselinux/src/avc_sidtab.c \
|
selinux/libselinux/src/avc_sidtab.c \
|
||||||
selinux/libselinux/src/booleans.c \
|
selinux/libselinux/src/booleans.c \
|
||||||
selinux/libselinux/src/callbacks.c \
|
selinux/libselinux/src/callbacks.c \
|
||||||
selinux/libselinux/src/canonicalize_context.c \
|
selinux/libselinux/src/canonicalize_context.c \
|
||||||
selinux/libselinux/src/checkAccess.c \
|
selinux/libselinux/src/checkAccess.c \
|
||||||
selinux/libselinux/src/check_context.c \
|
selinux/libselinux/src/check_context.c \
|
||||||
selinux/libselinux/src/checkreqprot.c \
|
selinux/libselinux/src/checkreqprot.c \
|
||||||
selinux/libselinux/src/compute_av.c \
|
selinux/libselinux/src/compute_av.c \
|
||||||
selinux/libselinux/src/compute_create.c \
|
selinux/libselinux/src/compute_create.c \
|
||||||
selinux/libselinux/src/compute_member.c \
|
selinux/libselinux/src/compute_member.c \
|
||||||
selinux/libselinux/src/compute_relabel.c \
|
selinux/libselinux/src/compute_relabel.c \
|
||||||
selinux/libselinux/src/compute_user.c \
|
selinux/libselinux/src/compute_user.c \
|
||||||
selinux/libselinux/src/context.c \
|
selinux/libselinux/src/context.c \
|
||||||
selinux/libselinux/src/deny_unknown.c \
|
selinux/libselinux/src/deny_unknown.c \
|
||||||
selinux/libselinux/src/disable.c \
|
selinux/libselinux/src/disable.c \
|
||||||
selinux/libselinux/src/enabled.c \
|
selinux/libselinux/src/enabled.c \
|
||||||
selinux/libselinux/src/fgetfilecon.c \
|
selinux/libselinux/src/fgetfilecon.c \
|
||||||
selinux/libselinux/src/freecon.c \
|
selinux/libselinux/src/freecon.c \
|
||||||
selinux/libselinux/src/freeconary.c \
|
selinux/libselinux/src/freeconary.c \
|
||||||
selinux/libselinux/src/fsetfilecon.c \
|
selinux/libselinux/src/fsetfilecon.c \
|
||||||
selinux/libselinux/src/get_context_list.c \
|
selinux/libselinux/src/get_context_list.c \
|
||||||
selinux/libselinux/src/get_default_type.c \
|
selinux/libselinux/src/get_default_type.c \
|
||||||
selinux/libselinux/src/get_initial_context.c \
|
selinux/libselinux/src/get_initial_context.c \
|
||||||
selinux/libselinux/src/getenforce.c \
|
selinux/libselinux/src/getenforce.c \
|
||||||
selinux/libselinux/src/getfilecon.c \
|
selinux/libselinux/src/getfilecon.c \
|
||||||
selinux/libselinux/src/getpeercon.c \
|
selinux/libselinux/src/getpeercon.c \
|
||||||
selinux/libselinux/src/init.c \
|
selinux/libselinux/src/init.c \
|
||||||
selinux/libselinux/src/is_customizable_type.c \
|
selinux/libselinux/src/is_customizable_type.c \
|
||||||
selinux/libselinux/src/label.c \
|
selinux/libselinux/src/label.c \
|
||||||
selinux/libselinux/src/label_file.c \
|
selinux/libselinux/src/label_file.c \
|
||||||
selinux/libselinux/src/label_support.c \
|
selinux/libselinux/src/label_support.c \
|
||||||
selinux/libselinux/src/lgetfilecon.c \
|
selinux/libselinux/src/lgetfilecon.c \
|
||||||
selinux/libselinux/src/load_policy.c \
|
selinux/libselinux/src/load_policy.c \
|
||||||
selinux/libselinux/src/lsetfilecon.c \
|
selinux/libselinux/src/lsetfilecon.c \
|
||||||
selinux/libselinux/src/mapping.c \
|
selinux/libselinux/src/mapping.c \
|
||||||
selinux/libselinux/src/matchmediacon.c \
|
selinux/libselinux/src/matchmediacon.c \
|
||||||
selinux/libselinux/src/matchpathcon.c \
|
selinux/libselinux/src/matchpathcon.c \
|
||||||
selinux/libselinux/src/policyvers.c \
|
selinux/libselinux/src/policyvers.c \
|
||||||
selinux/libselinux/src/procattr.c \
|
selinux/libselinux/src/procattr.c \
|
||||||
selinux/libselinux/src/query_user_context.c \
|
selinux/libselinux/src/query_user_context.c \
|
||||||
selinux/libselinux/src/regex.c \
|
selinux/libselinux/src/regex.c \
|
||||||
selinux/libselinux/src/reject_unknown.c \
|
selinux/libselinux/src/reject_unknown.c \
|
||||||
selinux/libselinux/src/selinux_check_securetty_context.c \
|
selinux/libselinux/src/selinux_check_securetty_context.c \
|
||||||
selinux/libselinux/src/selinux_config.c \
|
selinux/libselinux/src/selinux_config.c \
|
||||||
selinux/libselinux/src/selinux_restorecon.c \
|
selinux/libselinux/src/selinux_restorecon.c \
|
||||||
selinux/libselinux/src/sestatus.c \
|
selinux/libselinux/src/sestatus.c \
|
||||||
selinux/libselinux/src/setenforce.c \
|
selinux/libselinux/src/setenforce.c \
|
||||||
selinux/libselinux/src/setexecfilecon.c \
|
selinux/libselinux/src/setexecfilecon.c \
|
||||||
selinux/libselinux/src/setfilecon.c \
|
selinux/libselinux/src/setfilecon.c \
|
||||||
selinux/libselinux/src/setrans_client.c \
|
selinux/libselinux/src/setrans_client.c \
|
||||||
selinux/libselinux/src/seusers.c \
|
selinux/libselinux/src/seusers.c \
|
||||||
selinux/libselinux/src/sha1.c \
|
selinux/libselinux/src/sha1.c \
|
||||||
selinux/libselinux/src/stringrep.c \
|
selinux/libselinux/src/stringrep.c \
|
||||||
selinux/libselinux/src/validatetrans.c
|
selinux/libselinux/src/validatetrans.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# libpcre2.a
|
# libpcre2.a
|
||||||
@@ -323,34 +323,53 @@ LOCAL_CFLAGS := -DHAVE_CONFIG_H
|
|||||||
LOCAL_C_INCLUDES := $(LIBPCRE2) $(LIBPCRE2)_internal
|
LOCAL_C_INCLUDES := $(LIBPCRE2) $(LIBPCRE2)_internal
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LIBPCRE2)
|
LOCAL_EXPORT_C_INCLUDES := $(LIBPCRE2)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
pcre/dist2/src/pcre2_auto_possess.c \
|
pcre/dist2/src/pcre2_auto_possess.c \
|
||||||
pcre/dist2/src/pcre2_chartables.c \
|
pcre/dist2/src/pcre2_chartables.c \
|
||||||
pcre/dist2/src/pcre2_compile.c \
|
pcre/dist2/src/pcre2_compile.c \
|
||||||
pcre/dist2/src/pcre2_config.c \
|
pcre/dist2/src/pcre2_config.c \
|
||||||
pcre/dist2/src/pcre2_context.c \
|
pcre/dist2/src/pcre2_context.c \
|
||||||
pcre/dist2/src/pcre2_convert.c \
|
pcre/dist2/src/pcre2_convert.c \
|
||||||
pcre/dist2/src/pcre2_dfa_match.c \
|
pcre/dist2/src/pcre2_dfa_match.c \
|
||||||
pcre/dist2/src/pcre2_error.c \
|
pcre/dist2/src/pcre2_error.c \
|
||||||
pcre/dist2/src/pcre2_extuni.c \
|
pcre/dist2/src/pcre2_extuni.c \
|
||||||
pcre/dist2/src/pcre2_find_bracket.c \
|
pcre/dist2/src/pcre2_find_bracket.c \
|
||||||
pcre/dist2/src/pcre2_fuzzsupport.c \
|
pcre/dist2/src/pcre2_fuzzsupport.c \
|
||||||
pcre/dist2/src/pcre2_jit_compile.c \
|
pcre/dist2/src/pcre2_jit_compile.c \
|
||||||
pcre/dist2/src/pcre2_maketables.c \
|
pcre/dist2/src/pcre2_maketables.c \
|
||||||
pcre/dist2/src/pcre2_match.c \
|
pcre/dist2/src/pcre2_match.c \
|
||||||
pcre/dist2/src/pcre2_match_data.c \
|
pcre/dist2/src/pcre2_match_data.c \
|
||||||
pcre/dist2/src/pcre2_newline.c \
|
pcre/dist2/src/pcre2_newline.c \
|
||||||
pcre/dist2/src/pcre2_ord2utf.c \
|
pcre/dist2/src/pcre2_ord2utf.c \
|
||||||
pcre/dist2/src/pcre2_pattern_info.c \
|
pcre/dist2/src/pcre2_pattern_info.c \
|
||||||
pcre/dist2/src/pcre2_script_run.c \
|
pcre/dist2/src/pcre2_script_run.c \
|
||||||
pcre/dist2/src/pcre2_serialize.c \
|
pcre/dist2/src/pcre2_serialize.c \
|
||||||
pcre/dist2/src/pcre2_string_utils.c \
|
pcre/dist2/src/pcre2_string_utils.c \
|
||||||
pcre/dist2/src/pcre2_study.c \
|
pcre/dist2/src/pcre2_study.c \
|
||||||
pcre/dist2/src/pcre2_substitute.c \
|
pcre/dist2/src/pcre2_substitute.c \
|
||||||
pcre/dist2/src/pcre2_substring.c \
|
pcre/dist2/src/pcre2_substring.c \
|
||||||
pcre/dist2/src/pcre2_tables.c \
|
pcre/dist2/src/pcre2_tables.c \
|
||||||
pcre/dist2/src/pcre2_ucd.c \
|
pcre/dist2/src/pcre2_ucd.c \
|
||||||
pcre/dist2/src/pcre2_valid_utf.c \
|
pcre/dist2/src/pcre2_valid_utf.c \
|
||||||
pcre/dist2/src/pcre2_xclass.c
|
pcre/dist2/src/pcre2_xclass.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
include $(LOCAL_PATH)/mincrypt/Android.mk
|
# libxhook.a
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE:= libxhook
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/xhook/libxhook/jni
|
||||||
|
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||||
|
LOCAL_CFLAGS := -Wall -Wextra -Werror -fvisibility=hidden
|
||||||
|
LOCAL_CONLYFLAGS := -std=c11
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
xhook/libxhook/jni/xh_log.c \
|
||||||
|
xhook/libxhook/jni/xh_version.c \
|
||||||
|
xhook/libxhook/jni/xh_jni.c \
|
||||||
|
xhook/libxhook/jni/xhook.c \
|
||||||
|
xhook/libxhook/jni/xh_core.c \
|
||||||
|
xhook/libxhook/jni/xh_util.c \
|
||||||
|
xhook/libxhook/jni/xh_elf.c
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
CWD := $(LOCAL_PATH)
|
||||||
|
include $(CWD)/systemproperties/Android.mk
|
||||||
|
include $(CWD)/mincrypt/Android.mk
|
||||||
|
1
native/jni/external/xhook
vendored
Submodule
1
native/jni/external/xhook
vendored
Submodule
Submodule native/jni/external/xhook added at 9180bd7409
36
native/jni/external/xz-embedded/xz.h
vendored
36
native/jni/external/xz-embedded/xz.h
vendored
@@ -54,9 +54,9 @@ extern "C" {
|
|||||||
* be built with fewer features to minimize code size.
|
* be built with fewer features to minimize code size.
|
||||||
*/
|
*/
|
||||||
enum xz_mode {
|
enum xz_mode {
|
||||||
XZ_SINGLE,
|
XZ_SINGLE,
|
||||||
XZ_PREALLOC,
|
XZ_PREALLOC,
|
||||||
XZ_DYNALLOC
|
XZ_DYNALLOC
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,15 +110,15 @@ enum xz_mode {
|
|||||||
* is used instead of XZ_BUF_ERROR.
|
* is used instead of XZ_BUF_ERROR.
|
||||||
*/
|
*/
|
||||||
enum xz_ret {
|
enum xz_ret {
|
||||||
XZ_OK,
|
XZ_OK,
|
||||||
XZ_STREAM_END,
|
XZ_STREAM_END,
|
||||||
XZ_UNSUPPORTED_CHECK,
|
XZ_UNSUPPORTED_CHECK,
|
||||||
XZ_MEM_ERROR,
|
XZ_MEM_ERROR,
|
||||||
XZ_MEMLIMIT_ERROR,
|
XZ_MEMLIMIT_ERROR,
|
||||||
XZ_FORMAT_ERROR,
|
XZ_FORMAT_ERROR,
|
||||||
XZ_OPTIONS_ERROR,
|
XZ_OPTIONS_ERROR,
|
||||||
XZ_DATA_ERROR,
|
XZ_DATA_ERROR,
|
||||||
XZ_BUF_ERROR
|
XZ_BUF_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,13 +138,13 @@ enum xz_ret {
|
|||||||
* the variables in_pos and out_pos are modified by the XZ code.
|
* the variables in_pos and out_pos are modified by the XZ code.
|
||||||
*/
|
*/
|
||||||
struct xz_buf {
|
struct xz_buf {
|
||||||
const uint8_t *in;
|
const uint8_t *in;
|
||||||
size_t in_pos;
|
size_t in_pos;
|
||||||
size_t in_size;
|
size_t in_size;
|
||||||
|
|
||||||
uint8_t *out;
|
uint8_t *out;
|
||||||
size_t out_pos;
|
size_t out_pos;
|
||||||
size_t out_size;
|
size_t out_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
34
native/jni/external/xz-embedded/xz_config.h
vendored
34
native/jni/external/xz-embedded/xz_config.h
vendored
@@ -65,7 +65,7 @@ typedef unsigned char bool;
|
|||||||
#ifndef __always_inline
|
#ifndef __always_inline
|
||||||
# ifdef __GNUC__
|
# ifdef __GNUC__
|
||||||
# define __always_inline \
|
# define __always_inline \
|
||||||
inline __attribute__((__always_inline__))
|
inline __attribute__((__always_inline__))
|
||||||
# else
|
# else
|
||||||
# define __always_inline inline
|
# define __always_inline inline
|
||||||
# endif
|
# endif
|
||||||
@@ -75,40 +75,40 @@ typedef unsigned char bool;
|
|||||||
#ifndef get_unaligned_le32
|
#ifndef get_unaligned_le32
|
||||||
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
|
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
|
||||||
{
|
{
|
||||||
return (uint32_t)buf[0]
|
return (uint32_t)buf[0]
|
||||||
| ((uint32_t)buf[1] << 8)
|
| ((uint32_t)buf[1] << 8)
|
||||||
| ((uint32_t)buf[2] << 16)
|
| ((uint32_t)buf[2] << 16)
|
||||||
| ((uint32_t)buf[3] << 24);
|
| ((uint32_t)buf[3] << 24);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef get_unaligned_be32
|
#ifndef get_unaligned_be32
|
||||||
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
|
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
|
||||||
{
|
{
|
||||||
return (uint32_t)(buf[0] << 24)
|
return (uint32_t)(buf[0] << 24)
|
||||||
| ((uint32_t)buf[1] << 16)
|
| ((uint32_t)buf[1] << 16)
|
||||||
| ((uint32_t)buf[2] << 8)
|
| ((uint32_t)buf[2] << 8)
|
||||||
| (uint32_t)buf[3];
|
| (uint32_t)buf[3];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef put_unaligned_le32
|
#ifndef put_unaligned_le32
|
||||||
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
|
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t)val;
|
buf[0] = (uint8_t)val;
|
||||||
buf[1] = (uint8_t)(val >> 8);
|
buf[1] = (uint8_t)(val >> 8);
|
||||||
buf[2] = (uint8_t)(val >> 16);
|
buf[2] = (uint8_t)(val >> 16);
|
||||||
buf[3] = (uint8_t)(val >> 24);
|
buf[3] = (uint8_t)(val >> 24);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef put_unaligned_be32
|
#ifndef put_unaligned_be32
|
||||||
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
|
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t)(val >> 24);
|
buf[0] = (uint8_t)(val >> 24);
|
||||||
buf[1] = (uint8_t)(val >> 16);
|
buf[1] = (uint8_t)(val >> 16);
|
||||||
buf[2] = (uint8_t)(val >> 8);
|
buf[2] = (uint8_t)(val >> 8);
|
||||||
buf[3] = (uint8_t)val;
|
buf[3] = (uint8_t)val;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
34
native/jni/external/xz-embedded/xz_crc32.c
vendored
34
native/jni/external/xz-embedded/xz_crc32.c
vendored
@@ -29,31 +29,31 @@ STATIC_RW_DATA uint32_t xz_crc32_table[256];
|
|||||||
|
|
||||||
XZ_EXTERN void xz_crc32_init(void)
|
XZ_EXTERN void xz_crc32_init(void)
|
||||||
{
|
{
|
||||||
const uint32_t poly = 0xEDB88320;
|
const uint32_t poly = 0xEDB88320;
|
||||||
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
uint32_t r;
|
uint32_t r;
|
||||||
|
|
||||||
for (i = 0; i < 256; ++i) {
|
for (i = 0; i < 256; ++i) {
|
||||||
r = i;
|
r = i;
|
||||||
for (j = 0; j < 8; ++j)
|
for (j = 0; j < 8; ++j)
|
||||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||||
|
|
||||||
xz_crc32_table[i] = r;
|
xz_crc32_table[i] = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
||||||
{
|
{
|
||||||
crc = ~crc;
|
crc = ~crc;
|
||||||
|
|
||||||
while (size != 0) {
|
while (size != 0) {
|
||||||
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||||
--size;
|
--size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ~crc;
|
return ~crc;
|
||||||
}
|
}
|
||||||
|
1468
native/jni/external/xz-embedded/xz_dec_lzma2.c
vendored
1468
native/jni/external/xz-embedded/xz_dec_lzma2.c
vendored
File diff suppressed because it is too large
Load Diff
1062
native/jni/external/xz-embedded/xz_dec_stream.c
vendored
1062
native/jni/external/xz-embedded/xz_dec_stream.c
vendored
File diff suppressed because it is too large
Load Diff
48
native/jni/external/xz-embedded/xz_lzma2.h
vendored
48
native/jni/external/xz-embedded/xz_lzma2.h
vendored
@@ -40,18 +40,18 @@
|
|||||||
* either short or long repeated match, and NONLIT means any non-literal.
|
* either short or long repeated match, and NONLIT means any non-literal.
|
||||||
*/
|
*/
|
||||||
enum lzma_state {
|
enum lzma_state {
|
||||||
STATE_LIT_LIT,
|
STATE_LIT_LIT,
|
||||||
STATE_MATCH_LIT_LIT,
|
STATE_MATCH_LIT_LIT,
|
||||||
STATE_REP_LIT_LIT,
|
STATE_REP_LIT_LIT,
|
||||||
STATE_SHORTREP_LIT_LIT,
|
STATE_SHORTREP_LIT_LIT,
|
||||||
STATE_MATCH_LIT,
|
STATE_MATCH_LIT,
|
||||||
STATE_REP_LIT,
|
STATE_REP_LIT,
|
||||||
STATE_SHORTREP_LIT,
|
STATE_SHORTREP_LIT,
|
||||||
STATE_LIT_MATCH,
|
STATE_LIT_MATCH,
|
||||||
STATE_LIT_LONGREP,
|
STATE_LIT_LONGREP,
|
||||||
STATE_LIT_SHORTREP,
|
STATE_LIT_SHORTREP,
|
||||||
STATE_NONLIT_MATCH,
|
STATE_NONLIT_MATCH,
|
||||||
STATE_NONLIT_REP
|
STATE_NONLIT_REP
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Total number of states */
|
/* Total number of states */
|
||||||
@@ -63,36 +63,36 @@ enum lzma_state {
|
|||||||
/* Indicate that the latest symbol was a literal. */
|
/* Indicate that the latest symbol was a literal. */
|
||||||
static inline void lzma_state_literal(enum lzma_state *state)
|
static inline void lzma_state_literal(enum lzma_state *state)
|
||||||
{
|
{
|
||||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||||
*state = STATE_LIT_LIT;
|
*state = STATE_LIT_LIT;
|
||||||
else if (*state <= STATE_LIT_SHORTREP)
|
else if (*state <= STATE_LIT_SHORTREP)
|
||||||
*state -= 3;
|
*state -= 3;
|
||||||
else
|
else
|
||||||
*state -= 6;
|
*state -= 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indicate that the latest symbol was a match. */
|
/* Indicate that the latest symbol was a match. */
|
||||||
static inline void lzma_state_match(enum lzma_state *state)
|
static inline void lzma_state_match(enum lzma_state *state)
|
||||||
{
|
{
|
||||||
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
|
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indicate that the latest state was a long repeated match. */
|
/* Indicate that the latest state was a long repeated match. */
|
||||||
static inline void lzma_state_long_rep(enum lzma_state *state)
|
static inline void lzma_state_long_rep(enum lzma_state *state)
|
||||||
{
|
{
|
||||||
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
|
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indicate that the latest symbol was a short match. */
|
/* Indicate that the latest symbol was a short match. */
|
||||||
static inline void lzma_state_short_rep(enum lzma_state *state)
|
static inline void lzma_state_short_rep(enum lzma_state *state)
|
||||||
{
|
{
|
||||||
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
|
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test if the previous symbol was a literal. */
|
/* Test if the previous symbol was a literal. */
|
||||||
static inline bool lzma_state_is_literal(enum lzma_state state)
|
static inline bool lzma_state_is_literal(enum lzma_state state)
|
||||||
{
|
{
|
||||||
return state < LIT_STATES;
|
return state < LIT_STATES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Each literal coder is divided in three sections:
|
/* Each literal coder is divided in three sections:
|
||||||
@@ -146,8 +146,8 @@ static inline bool lzma_state_is_literal(enum lzma_state state)
|
|||||||
*/
|
*/
|
||||||
static inline uint32_t lzma_get_dist_state(uint32_t len)
|
static inline uint32_t lzma_get_dist_state(uint32_t len)
|
||||||
{
|
{
|
||||||
return len < DIST_STATES + MATCH_LEN_MIN
|
return len < DIST_STATES + MATCH_LEN_MIN
|
||||||
? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
30
native/jni/external/xz-embedded/xz_private.h
vendored
30
native/jni/external/xz-embedded/xz_private.h
vendored
@@ -14,7 +14,7 @@
|
|||||||
# include <linux/xz.h>
|
# include <linux/xz.h>
|
||||||
# include <linux/kernel.h>
|
# include <linux/kernel.h>
|
||||||
# include <asm/unaligned.h>
|
# include <asm/unaligned.h>
|
||||||
/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
|
/* XZ_PREBOOT may be defined only via decompress_unxz.c. */
|
||||||
# ifndef XZ_PREBOOT
|
# ifndef XZ_PREBOOT
|
||||||
# include <linux/slab.h>
|
# include <linux/slab.h>
|
||||||
# include <linux/vmalloc.h>
|
# include <linux/vmalloc.h>
|
||||||
@@ -42,17 +42,17 @@
|
|||||||
# endif
|
# endif
|
||||||
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
|
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* For userspace builds, use a separate header to define the required
|
* For userspace builds, use a separate header to define the required
|
||||||
* macros and functions. This makes it easier to adapt the code into
|
* macros and functions. This makes it easier to adapt the code into
|
||||||
* different environments and avoids clutter in the Linux kernel tree.
|
* different environments and avoids clutter in the Linux kernel tree.
|
||||||
*/
|
*/
|
||||||
# include "xz_config.h"
|
# include "xz_config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If no specific decoding mode is requested, enable support for all modes. */
|
/* If no specific decoding mode is requested, enable support for all modes. */
|
||||||
#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
|
#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
|
||||||
&& !defined(XZ_DEC_DYNALLOC)
|
&& !defined(XZ_DEC_DYNALLOC)
|
||||||
# define XZ_DEC_SINGLE
|
# define XZ_DEC_SINGLE
|
||||||
# define XZ_DEC_PREALLOC
|
# define XZ_DEC_PREALLOC
|
||||||
# define XZ_DEC_DYNALLOC
|
# define XZ_DEC_DYNALLOC
|
||||||
@@ -95,9 +95,9 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef XZ_DEC_BCJ
|
#ifndef XZ_DEC_BCJ
|
||||||
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|
||||||
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|
||||||
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|
||||||
|| defined(XZ_DEC_SPARC)
|
|| defined(XZ_DEC_SPARC)
|
||||||
# define XZ_DEC_BCJ
|
# define XZ_DEC_BCJ
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
* before calling xz_dec_lzma2_run().
|
* before calling xz_dec_lzma2_run().
|
||||||
*/
|
*/
|
||||||
XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
|
XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
|
||||||
uint32_t dict_max);
|
uint32_t dict_max);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
|
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
|
||||||
@@ -116,11 +116,11 @@ XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
|
|||||||
* decoder doesn't support.
|
* decoder doesn't support.
|
||||||
*/
|
*/
|
||||||
XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
|
XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
|
||||||
uint8_t props);
|
uint8_t props);
|
||||||
|
|
||||||
/* Decode raw LZMA2 stream from b->in to b->out. */
|
/* Decode raw LZMA2 stream from b->in to b->out. */
|
||||||
XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
|
XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
|
||||||
struct xz_buf *b);
|
struct xz_buf *b);
|
||||||
|
|
||||||
/* Free the memory allocated for the LZMA2 decoder. */
|
/* Free the memory allocated for the LZMA2 decoder. */
|
||||||
XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
|
XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
|
||||||
@@ -146,8 +146,8 @@ XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
|
|||||||
* must be called directly.
|
* must be called directly.
|
||||||
*/
|
*/
|
||||||
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
|
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||||
struct xz_dec_lzma2 *lzma2,
|
struct xz_dec_lzma2 *lzma2,
|
||||||
struct xz_buf *b);
|
struct xz_buf *b);
|
||||||
|
|
||||||
/* Free the memory allocated for the BCJ filters. */
|
/* Free the memory allocated for the BCJ filters. */
|
||||||
#define xz_dec_bcj_end(s) kfree(s)
|
#define xz_dec_bcj_end(s) kfree(s)
|
||||||
|
10
native/jni/external/xz-embedded/xz_stream.h
vendored
10
native/jni/external/xz-embedded/xz_stream.h
vendored
@@ -14,7 +14,7 @@
|
|||||||
# include <linux/crc32.h>
|
# include <linux/crc32.h>
|
||||||
# undef crc32
|
# undef crc32
|
||||||
# define xz_crc32(buf, size, crc) \
|
# define xz_crc32(buf, size, crc) \
|
||||||
(~crc32_le(~(uint32_t)(crc), buf, size))
|
(~crc32_le(~(uint32_t)(crc), buf, size))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -50,10 +50,10 @@ typedef uint64_t vli_type;
|
|||||||
|
|
||||||
/* Integrity Check types */
|
/* Integrity Check types */
|
||||||
enum xz_check {
|
enum xz_check {
|
||||||
XZ_CHECK_NONE = 0,
|
XZ_CHECK_NONE = 0,
|
||||||
XZ_CHECK_CRC32 = 1,
|
XZ_CHECK_CRC32 = 1,
|
||||||
XZ_CHECK_CRC64 = 4,
|
XZ_CHECK_CRC64 = 4,
|
||||||
XZ_CHECK_SHA256 = 10
|
XZ_CHECK_SHA256 = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Maximum possible Check ID */
|
/* Maximum possible Check ID */
|
||||||
|
@@ -2,75 +2,57 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <socket.hpp>
|
#include <socket.hpp>
|
||||||
|
|
||||||
// Daemon command codes
|
// Daemon command codes
|
||||||
enum {
|
enum {
|
||||||
START_DAEMON,
|
START_DAEMON,
|
||||||
SUPERUSER,
|
SUPERUSER,
|
||||||
CHECK_VERSION,
|
CHECK_VERSION,
|
||||||
CHECK_VERSION_CODE,
|
CHECK_VERSION_CODE,
|
||||||
POST_FS_DATA,
|
POST_FS_DATA,
|
||||||
LATE_START,
|
LATE_START,
|
||||||
BOOT_COMPLETE,
|
BOOT_COMPLETE,
|
||||||
MAGISKHIDE,
|
MAGISKHIDE,
|
||||||
SQLITE_CMD,
|
SQLITE_CMD,
|
||||||
REMOVE_MODULES,
|
REMOVE_MODULES,
|
||||||
GET_PATH,
|
GET_PATH,
|
||||||
DAEMON_CODE_END,
|
DAEMON_CODE_END,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return codes for daemon
|
// Return codes for daemon
|
||||||
enum {
|
enum {
|
||||||
DAEMON_ERROR = -1,
|
DAEMON_ERROR = -1,
|
||||||
DAEMON_SUCCESS = 0,
|
DAEMON_SUCCESS = 0,
|
||||||
ROOT_REQUIRED,
|
ROOT_REQUIRED,
|
||||||
DAEMON_LAST
|
DAEMON_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
// Daemon state
|
// Daemon state
|
||||||
enum {
|
enum {
|
||||||
STATE_NONE,
|
STATE_NONE,
|
||||||
STATE_POST_FS_DATA,
|
STATE_POST_FS_DATA,
|
||||||
STATE_POST_FS_DATA_DONE,
|
STATE_POST_FS_DATA_DONE,
|
||||||
STATE_LATE_START_DONE,
|
STATE_LATE_START_DONE,
|
||||||
STATE_BOOT_COMPLETE
|
STATE_BOOT_COMPLETE
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int SDK_INT;
|
int connect_daemon(bool create = false);
|
||||||
extern bool RECOVERY_MODE;
|
|
||||||
extern int DAEMON_STATE;
|
|
||||||
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")
|
|
||||||
|
|
||||||
// Daemon handlers
|
// Daemon handlers
|
||||||
void post_fs_data(int client);
|
void post_fs_data(int client);
|
||||||
void late_start(int client);
|
void late_start(int client);
|
||||||
void boot_complete(int client);
|
void boot_complete(int client);
|
||||||
void magiskhide_handler(int client);
|
void magiskhide_handler(int client, ucred *cred);
|
||||||
void su_daemon_handler(int client, ucred *credential);
|
void su_daemon_handler(int client, ucred *credential);
|
||||||
|
|
||||||
// Misc
|
|
||||||
int connect_daemon(bool create = false);
|
|
||||||
void unlock_blocks();
|
|
||||||
void reboot();
|
|
||||||
void setup_logfile(bool reset);
|
|
||||||
|
|
||||||
// Module stuffs
|
|
||||||
void handle_modules();
|
|
||||||
void magic_mount();
|
|
||||||
void disable_modules();
|
|
||||||
void remove_modules();
|
|
||||||
void exec_module_scripts(const char *stage);
|
|
||||||
|
|
||||||
// MagiskHide
|
// MagiskHide
|
||||||
void auto_start_magiskhide();
|
void auto_start_magiskhide(bool late_props);
|
||||||
int stop_magiskhide();
|
int stop_magiskhide();
|
||||||
|
|
||||||
// Scripting
|
#if ENABLE_INJECT
|
||||||
void exec_script(const char *script);
|
// For injected process to access daemon
|
||||||
void exec_common_scripts(const char *stage);
|
int remote_check_hide(int uid, const char *process);
|
||||||
void exec_module_scripts(const char *stage, const std::vector<std::string> &module_list);
|
void remote_request_hide();
|
||||||
void install_apk(const char *apk);
|
#endif
|
||||||
[[noreturn]] void install_module(const char *file);
|
|
||||||
|
@@ -9,25 +9,25 @@
|
|||||||
template <class T, size_t num>
|
template <class T, size_t num>
|
||||||
class db_data_base {
|
class db_data_base {
|
||||||
public:
|
public:
|
||||||
T& operator [](std::string_view key) {
|
T& operator [](std::string_view key) {
|
||||||
return data[getKeyIdx(key)];
|
return data[getKeyIdx(key)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator [](std::string_view key) const {
|
const T& operator [](std::string_view key) const {
|
||||||
return data[getKeyIdx(key)];
|
return data[getKeyIdx(key)];
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator [](int key) {
|
T& operator [](int key) {
|
||||||
return data[key];
|
return data[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator [](int key) const {
|
const T& operator [](int key) const {
|
||||||
return data[key];
|
return data[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
T data[num + 1];
|
T data[num + 1];
|
||||||
virtual int getKeyIdx(std::string_view key) const = 0;
|
virtual int getKeyIdx(std::string_view key) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
@@ -46,40 +46,40 @@ protected:
|
|||||||
|
|
||||||
// Settings keys
|
// Settings keys
|
||||||
enum {
|
enum {
|
||||||
ROOT_ACCESS = 0,
|
ROOT_ACCESS = 0,
|
||||||
SU_MULTIUSER_MODE,
|
SU_MULTIUSER_MODE,
|
||||||
SU_MNT_NS,
|
SU_MNT_NS,
|
||||||
HIDE_CONFIG
|
HIDE_CONFIG
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values for root_access
|
// Values for root_access
|
||||||
enum {
|
enum {
|
||||||
ROOT_ACCESS_DISABLED = 0,
|
ROOT_ACCESS_DISABLED = 0,
|
||||||
ROOT_ACCESS_APPS_ONLY,
|
ROOT_ACCESS_APPS_ONLY,
|
||||||
ROOT_ACCESS_ADB_ONLY,
|
ROOT_ACCESS_ADB_ONLY,
|
||||||
ROOT_ACCESS_APPS_AND_ADB
|
ROOT_ACCESS_APPS_AND_ADB
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values for multiuser_mode
|
// Values for multiuser_mode
|
||||||
enum {
|
enum {
|
||||||
MULTIUSER_MODE_OWNER_ONLY = 0,
|
MULTIUSER_MODE_OWNER_ONLY = 0,
|
||||||
MULTIUSER_MODE_OWNER_MANAGED,
|
MULTIUSER_MODE_OWNER_MANAGED,
|
||||||
MULTIUSER_MODE_USER
|
MULTIUSER_MODE_USER
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values for mnt_ns
|
// Values for mnt_ns
|
||||||
enum {
|
enum {
|
||||||
NAMESPACE_MODE_GLOBAL = 0,
|
NAMESPACE_MODE_GLOBAL = 0,
|
||||||
NAMESPACE_MODE_REQUESTER,
|
NAMESPACE_MODE_REQUESTER,
|
||||||
NAMESPACE_MODE_ISOLATE
|
NAMESPACE_MODE_ISOLATE
|
||||||
};
|
};
|
||||||
|
|
||||||
class db_settings : public db_data_base<int, DB_SETTINGS_NUM> {
|
class db_settings : public db_data_base<int, DB_SETTINGS_NUM> {
|
||||||
public:
|
public:
|
||||||
db_settings();
|
db_settings();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int getKeyIdx(std::string_view key) const override;
|
int getKeyIdx(std::string_view key) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**************
|
/**************
|
||||||
@@ -95,12 +95,12 @@ protected:
|
|||||||
|
|
||||||
// Strings keys
|
// Strings keys
|
||||||
enum {
|
enum {
|
||||||
SU_MANAGER = 0
|
SU_MANAGER = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
class db_strings : public db_data_base<std::string, DB_STRING_NUM> {
|
class db_strings : public db_data_base<std::string, DB_STRING_NUM> {
|
||||||
protected:
|
protected:
|
||||||
int getKeyIdx(std::string_view key) const override;
|
int getKeyIdx(std::string_view key) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
@@ -108,15 +108,15 @@ protected:
|
|||||||
*************/
|
*************/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUERY = 0,
|
QUERY = 0,
|
||||||
DENY = 1,
|
DENY = 1,
|
||||||
ALLOW = 2,
|
ALLOW = 2,
|
||||||
} policy_t;
|
} policy_t;
|
||||||
|
|
||||||
struct su_access {
|
struct su_access {
|
||||||
policy_t policy;
|
policy_t policy;
|
||||||
int log;
|
int log;
|
||||||
int notify;
|
int notify;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_SU_ACCESS (su_access) { \
|
#define DEFAULT_SU_ACCESS (su_access) { \
|
||||||
|
@@ -30,9 +30,13 @@ constexpr const char *init_applet[] = { "magiskpolicy", "supolicy", nullptr };
|
|||||||
#define POST_FS_DATA_WAIT_TIME 40
|
#define POST_FS_DATA_WAIT_TIME 40
|
||||||
#define POST_FS_DATA_SCRIPT_MAX_TIME 35
|
#define POST_FS_DATA_SCRIPT_MAX_TIME 35
|
||||||
|
|
||||||
|
extern int SDK_INT;
|
||||||
|
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")
|
||||||
|
|
||||||
// Multi-call entrypoints
|
// Multi-call entrypoints
|
||||||
int magisk_main(int argc, char *argv[]);
|
int magisk_main(int argc, char *argv[]);
|
||||||
int magiskhide_main(int argc, char *argv[]);
|
int magiskhide_main(int argc, char *argv[]);
|
||||||
int magiskpolicy_main(int argc, char *argv[]);
|
int magiskpolicy_main(int argc, char *argv[]);
|
||||||
int su_client_main(int argc, char *argv[]);
|
int su_client_main(int argc, char *argv[]);
|
||||||
int resetprop_main(int argc, char *argv[]);
|
int resetprop_main(int argc, char *argv[]);
|
||||||
|
int app_process_main(int argc, char *argv[]);
|
||||||
|
@@ -9,52 +9,52 @@ struct policydb;
|
|||||||
|
|
||||||
class sepolicy {
|
class sepolicy {
|
||||||
public:
|
public:
|
||||||
typedef const char * c_str;
|
typedef const char * c_str;
|
||||||
~sepolicy();
|
~sepolicy();
|
||||||
|
|
||||||
// Public static factory functions
|
// Public static factory functions
|
||||||
static sepolicy *from_file(c_str file);
|
static sepolicy *from_file(c_str file);
|
||||||
static sepolicy *from_split();
|
static sepolicy *from_split();
|
||||||
static sepolicy *compile_split();
|
static sepolicy *compile_split();
|
||||||
|
|
||||||
// External APIs
|
// External APIs
|
||||||
bool to_file(c_str file);
|
bool to_file(c_str file);
|
||||||
void parse_statement(c_str stmt);
|
void parse_statement(c_str stmt);
|
||||||
void load_rule_file(c_str file);
|
void load_rule_file(c_str file);
|
||||||
|
|
||||||
// Operation on types
|
// Operation on types
|
||||||
bool type(c_str name, c_str attr);
|
bool type(c_str name, c_str attr);
|
||||||
bool attribute(c_str name);
|
bool attribute(c_str name);
|
||||||
bool permissive(c_str type);
|
bool permissive(c_str type);
|
||||||
bool enforce(c_str type);
|
bool enforce(c_str type);
|
||||||
bool typeattribute(c_str type, c_str attr);
|
bool typeattribute(c_str type, c_str attr);
|
||||||
bool exists(c_str type);
|
bool exists(c_str type);
|
||||||
|
|
||||||
// Access vector rules
|
// Access vector rules
|
||||||
bool allow(c_str src, c_str tgt, c_str cls, c_str perm);
|
bool allow(c_str src, c_str tgt, c_str cls, c_str perm);
|
||||||
bool deny(c_str src, c_str tgt, c_str cls, c_str perm);
|
bool deny(c_str src, c_str tgt, c_str cls, c_str perm);
|
||||||
bool auditallow(c_str src, c_str tgt, c_str cls, c_str perm);
|
bool auditallow(c_str src, c_str tgt, c_str cls, c_str perm);
|
||||||
bool dontaudit(c_str src, c_str tgt, c_str cls, c_str perm);
|
bool dontaudit(c_str src, c_str tgt, c_str cls, c_str perm);
|
||||||
|
|
||||||
// Extended permissions access vector rules
|
// Extended permissions access vector rules
|
||||||
bool allowxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
bool allowxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
||||||
bool auditallowxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
bool auditallowxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
||||||
bool dontauditxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
bool dontauditxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
||||||
|
|
||||||
// Type rules
|
// Type rules
|
||||||
bool type_transition(c_str src, c_str tgt, c_str cls, c_str def, c_str obj = nullptr);
|
bool type_transition(c_str src, c_str tgt, c_str cls, c_str def, c_str obj = nullptr);
|
||||||
bool type_change(c_str src, c_str tgt, c_str cls, c_str def);
|
bool type_change(c_str src, c_str tgt, c_str cls, c_str def);
|
||||||
bool type_member(c_str src, c_str tgt, c_str cls, c_str def);
|
bool type_member(c_str src, c_str tgt, c_str cls, c_str def);
|
||||||
|
|
||||||
// File system labeling
|
// File system labeling
|
||||||
bool genfscon(c_str fs_name, c_str path, c_str ctx);
|
bool genfscon(c_str fs_name, c_str path, c_str ctx);
|
||||||
|
|
||||||
// Magisk
|
// Magisk
|
||||||
void magisk_rules();
|
void magisk_rules();
|
||||||
|
|
||||||
// Deprecate
|
// Deprecate
|
||||||
bool create(c_str name) { return type(name, "domain"); }
|
bool create(c_str name) { return type(name, "domain"); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
policydb *db;
|
policydb *db;
|
||||||
};
|
};
|
||||||
|
@@ -6,6 +6,6 @@
|
|||||||
int setprop(const char *name, const char *value, bool prop_svc = true);
|
int setprop(const char *name, const char *value, bool prop_svc = true);
|
||||||
std::string getprop(const char *name, bool persist = false);
|
std::string getprop(const char *name, bool persist = false);
|
||||||
void getprops(void (*callback)(const char *, const char *, void *),
|
void getprops(void (*callback)(const char *, const char *, void *),
|
||||||
void *cookie = nullptr, bool persist = false);
|
void *cookie = nullptr, bool persist = false);
|
||||||
int delprop(const char *name, bool persist = false);
|
int delprop(const char *name, bool persist = false);
|
||||||
void load_prop_file(const char *filename, bool prop_svc = true);
|
void load_prop_file(const char *filename, bool prop_svc = true);
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name);
|
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name);
|
||||||
int socket_accept(int sockfd, int timeout);
|
int socket_accept(int sockfd, int timeout);
|
||||||
@@ -12,9 +13,6 @@ int read_int(int fd);
|
|||||||
int read_int_be(int fd);
|
int read_int_be(int fd);
|
||||||
void write_int(int fd, int val);
|
void write_int(int fd, int val);
|
||||||
void write_int_be(int fd, int val);
|
void write_int_be(int fd, int val);
|
||||||
char *read_string(int fd);
|
std::string read_string(int fd);
|
||||||
char *read_string_be(int fd);
|
void read_string(int fd, std::string &str);
|
||||||
void write_string(int fd, const char *val);
|
void write_string(int fd, std::string_view str);
|
||||||
void write_string_be(int fd, const char *val);
|
|
||||||
void write_key_value(int fd, const char *key, const char *val);
|
|
||||||
void write_key_token(int fd, const char *key, int tok);
|
|
||||||
|
@@ -11,123 +11,125 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
vector<string> mount_list;
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
static void parse_cmdline(const Func &fn) {
|
static void parse_cmdline(const Func &fn) {
|
||||||
char cmdline[4096];
|
char cmdline[4096];
|
||||||
int fd = xopen("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
int fd = xopen("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
||||||
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
|
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
char *tok, *eql, *tmp, *saveptr;
|
char *tok, *eql, *tmp, *saveptr;
|
||||||
saveptr = cmdline;
|
saveptr = cmdline;
|
||||||
while ((tok = strtok_r(nullptr, " \n", &saveptr)) != nullptr) {
|
while ((tok = strtok_r(nullptr, " \n", &saveptr)) != nullptr) {
|
||||||
eql = strchr(tok, '=');
|
eql = strchr(tok, '=');
|
||||||
if (eql) {
|
if (eql) {
|
||||||
*eql = '\0';
|
*eql = '\0';
|
||||||
if (eql[1] == '"') {
|
if (eql[1] == '"') {
|
||||||
tmp = strchr(saveptr, '"');
|
tmp = strchr(saveptr, '"');
|
||||||
if (tmp != nullptr) {
|
if (tmp != nullptr) {
|
||||||
*tmp = '\0';
|
*tmp = '\0';
|
||||||
saveptr[-1] = ' ';
|
saveptr[-1] = ' ';
|
||||||
saveptr = tmp + 1;
|
saveptr = tmp + 1;
|
||||||
eql++;
|
eql++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn(tok, eql + 1);
|
fn(tok, eql + 1);
|
||||||
} else {
|
} else {
|
||||||
fn(tok, "");
|
fn(tok, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
||||||
|
|
||||||
static bool check_key_combo() {
|
static bool check_key_combo() {
|
||||||
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
||||||
vector<int> events;
|
vector<int> events;
|
||||||
constexpr const char *name = "/event";
|
constexpr const char *name = "/event";
|
||||||
|
|
||||||
for (int minor = 64; minor < 96; ++minor) {
|
for (int minor = 64; minor < 96; ++minor) {
|
||||||
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
||||||
continue;
|
continue;
|
||||||
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
||||||
unlink(name);
|
unlink(name);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
continue;
|
continue;
|
||||||
memset(bitmask, 0, sizeof(bitmask));
|
memset(bitmask, 0, sizeof(bitmask));
|
||||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
||||||
if (test_bit(KEY_VOLUMEUP, bitmask))
|
if (test_bit(KEY_VOLUMEUP, bitmask))
|
||||||
events.push_back(fd);
|
events.push_back(fd);
|
||||||
else
|
else
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
if (events.empty())
|
if (events.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
|
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
|
||||||
|
|
||||||
// Return true if volume up key is held for more than 3 seconds
|
// Return true if volume up key is held for more than 3 seconds
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < 500; ++i) {
|
for (int i = 0; i < 500; ++i) {
|
||||||
for (const int &fd : events) {
|
for (const int &fd : events) {
|
||||||
memset(bitmask, 0, sizeof(bitmask));
|
memset(bitmask, 0, sizeof(bitmask));
|
||||||
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
||||||
if (test_bit(KEY_VOLUMEUP, bitmask)) {
|
if (test_bit(KEY_VOLUMEUP, bitmask)) {
|
||||||
count++;
|
count++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count >= 300) {
|
if (count >= 300) {
|
||||||
LOGD("KEY_VOLUMEUP detected: disable system-as-root\n");
|
LOGD("KEY_VOLUMEUP detected: disable system-as-root\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Check every 10ms
|
// Check every 10ms
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE *kmsg;
|
static FILE *kmsg;
|
||||||
static char kmsg_buf[4096];
|
static char kmsg_buf[4096];
|
||||||
static int vprintk(const char *fmt, va_list ap) {
|
static int vprintk(const char *fmt, va_list ap) {
|
||||||
vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap);
|
vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap);
|
||||||
return fprintf(kmsg, "%s", kmsg_buf);
|
return fprintf(kmsg, "%s", kmsg_buf);
|
||||||
}
|
}
|
||||||
void setup_klog() {
|
void setup_klog() {
|
||||||
// Shut down first 3 fds
|
// Shut down first 3 fds
|
||||||
int fd;
|
int fd;
|
||||||
if (access("/dev/null", W_OK) == 0) {
|
if (access("/dev/null", W_OK) == 0) {
|
||||||
fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
|
fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
|
||||||
} else {
|
} else {
|
||||||
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
|
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
|
||||||
fd = xopen("/null", O_RDWR | O_CLOEXEC);
|
fd = xopen("/null", O_RDWR | O_CLOEXEC);
|
||||||
unlink("/null");
|
unlink("/null");
|
||||||
}
|
}
|
||||||
xdup3(fd, STDIN_FILENO, O_CLOEXEC);
|
xdup3(fd, STDIN_FILENO, O_CLOEXEC);
|
||||||
xdup3(fd, STDOUT_FILENO, O_CLOEXEC);
|
xdup3(fd, STDOUT_FILENO, O_CLOEXEC);
|
||||||
xdup3(fd, STDERR_FILENO, O_CLOEXEC);
|
xdup3(fd, STDERR_FILENO, O_CLOEXEC);
|
||||||
if (fd > STDERR_FILENO)
|
if (fd > STDERR_FILENO)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
if (access("/dev/kmsg", W_OK) == 0) {
|
if (access("/dev/kmsg", W_OK) == 0) {
|
||||||
fd = xopen("/dev/kmsg", O_WRONLY | O_CLOEXEC);
|
fd = xopen("/dev/kmsg", O_WRONLY | O_CLOEXEC);
|
||||||
} else {
|
} else {
|
||||||
mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11));
|
mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11));
|
||||||
fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC);
|
fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC);
|
||||||
unlink("/kmsg");
|
unlink("/kmsg");
|
||||||
}
|
}
|
||||||
|
|
||||||
kmsg = fdopen(fd, "w");
|
kmsg = fdopen(fd, "w");
|
||||||
setbuf(kmsg, nullptr);
|
setbuf(kmsg, nullptr);
|
||||||
log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk;
|
log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk;
|
||||||
log_cb.ex = nop_ex;
|
log_cb.ex = nop_ex;
|
||||||
strcpy(kmsg_buf, "magiskinit: ");
|
strcpy(kmsg_buf, "magiskinit: ");
|
||||||
|
|
||||||
// Disable kmsg rate limiting
|
// Disable kmsg rate limiting
|
||||||
if (FILE *rate = fopen("/proc/sys/kernel/printk_devkmsg", "w")) {
|
if (FILE *rate = fopen("/proc/sys/kernel/printk_devkmsg", "w")) {
|
||||||
fprintf(rate, "on\n");
|
fprintf(rate, "on\n");
|
||||||
fclose(rate);
|
fclose(rate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define read_dt(name, key) \
|
#define read_dt(name, key) \
|
||||||
@@ -141,75 +143,81 @@ if (access(file_name, R_OK) == 0){ \
|
|||||||
}
|
}
|
||||||
|
|
||||||
void load_kernel_info(cmdline *cmd) {
|
void load_kernel_info(cmdline *cmd) {
|
||||||
// Get kernel data using procfs and sysfs
|
// Get kernel data using procfs and sysfs
|
||||||
xmkdir("/proc", 0755);
|
xmkdir("/proc", 0755);
|
||||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||||
xmkdir("/sys", 0755);
|
xmkdir("/sys", 0755);
|
||||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||||
|
|
||||||
// Log to kernel
|
mount_list.emplace_back("/proc");
|
||||||
setup_klog();
|
mount_list.emplace_back("/sys");
|
||||||
|
|
||||||
parse_cmdline([=](string_view key, const char *value) -> void {
|
// Log to kernel
|
||||||
if (key == "androidboot.slot_suffix") {
|
setup_klog();
|
||||||
strcpy(cmd->slot, value);
|
|
||||||
} else if (key == "androidboot.slot") {
|
|
||||||
cmd->slot[0] = '_';
|
|
||||||
strcpy(cmd->slot + 1, value);
|
|
||||||
} else if (key == "skip_initramfs") {
|
|
||||||
cmd->skip_initramfs = true;
|
|
||||||
} else if (key == "androidboot.force_normal_boot") {
|
|
||||||
cmd->force_normal_boot = value[0] == '1';
|
|
||||||
} else if (key == "androidboot.android_dt_dir") {
|
|
||||||
strcpy(cmd->dt_dir, value);
|
|
||||||
} else if (key == "androidboot.hardware") {
|
|
||||||
strcpy(cmd->hardware, value);
|
|
||||||
} else if (key == "androidboot.hardware.platform") {
|
|
||||||
strcpy(cmd->hardware_plat, value);
|
|
||||||
} else if (key == "androidboot.fstab_suffix") {
|
|
||||||
strcpy(cmd->fstab_suffix, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
LOGD("Kernel cmdline info:\n");
|
parse_cmdline([=](string_view key, const char *value) {
|
||||||
LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs);
|
if (key == "androidboot.slot_suffix") {
|
||||||
LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot);
|
strcpy(cmd->slot, value);
|
||||||
LOGD("slot=[%s]\n", cmd->slot);
|
} else if (key == "androidboot.slot") {
|
||||||
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
|
cmd->slot[0] = '_';
|
||||||
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
|
strcpy(cmd->slot + 1, value);
|
||||||
LOGD("hardware=[%s]\n", cmd->hardware);
|
} else if (key == "skip_initramfs") {
|
||||||
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
|
cmd->skip_initramfs = true;
|
||||||
|
} else if (key == "androidboot.force_normal_boot") {
|
||||||
|
cmd->force_normal_boot = value[0] == '1';
|
||||||
|
} else if (key == "rootwait") {
|
||||||
|
cmd->rootwait = true;
|
||||||
|
} else if (key == "androidboot.android_dt_dir") {
|
||||||
|
strcpy(cmd->dt_dir, value);
|
||||||
|
} else if (key == "androidboot.hardware") {
|
||||||
|
strcpy(cmd->hardware, value);
|
||||||
|
} else if (key == "androidboot.hardware.platform") {
|
||||||
|
strcpy(cmd->hardware_plat, value);
|
||||||
|
} else if (key == "androidboot.fstab_suffix") {
|
||||||
|
strcpy(cmd->fstab_suffix, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
|
LOGD("Kernel cmdline info:\n");
|
||||||
if (key == "RECOVERYMODE" && value == "true") {
|
LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs);
|
||||||
LOGD("Running in recovery mode, waiting for key...\n");
|
LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot);
|
||||||
cmd->skip_initramfs = !check_key_combo();
|
LOGD("rootwait=[%d]\n", cmd->rootwait);
|
||||||
return false;
|
LOGD("slot=[%s]\n", cmd->slot);
|
||||||
}
|
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
|
||||||
return true;
|
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
|
||||||
});
|
LOGD("hardware=[%s]\n", cmd->hardware);
|
||||||
|
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
|
||||||
|
|
||||||
if (cmd->dt_dir[0] == '\0')
|
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
|
||||||
strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
|
if (key == "RECOVERYMODE" && value == "true") {
|
||||||
|
LOGD("Running in recovery mode, waiting for key...\n");
|
||||||
|
cmd->skip_initramfs = !check_key_combo();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
char file_name[128];
|
if (cmd->dt_dir[0] == '\0')
|
||||||
read_dt("fstab_suffix", fstab_suffix)
|
strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
|
||||||
read_dt("hardware", hardware)
|
|
||||||
read_dt("hardware.platform", hardware_plat)
|
|
||||||
|
|
||||||
LOGD("Device tree info:\n");
|
char file_name[128];
|
||||||
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
|
read_dt("fstab_suffix", fstab_suffix)
|
||||||
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
|
read_dt("hardware", hardware)
|
||||||
LOGD("hardware=[%s]\n", cmd->hardware);
|
read_dt("hardware.platform", hardware_plat)
|
||||||
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
|
|
||||||
|
LOGD("Device tree info:\n");
|
||||||
|
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
|
||||||
|
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
|
||||||
|
LOGD("hardware=[%s]\n", cmd->hardware);
|
||||||
|
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_two_stage() {
|
bool check_two_stage() {
|
||||||
if (access("/apex", F_OK) == 0)
|
if (access("/apex", F_OK) == 0)
|
||||||
return true;
|
return true;
|
||||||
if (access("/system/bin/init", F_OK) == 0)
|
if (access("/system/bin/init", F_OK) == 0)
|
||||||
return true;
|
return true;
|
||||||
// If we still have no indication, parse the original init and see what's up
|
// If we still have no indication, parse the original init and see what's up
|
||||||
auto init = raw_data::mmap_ro("/.backup/init");
|
auto init = mmap_data::ro("/.backup/init");
|
||||||
return init.contains("selinux_setup");
|
return init.contains("selinux_setup");
|
||||||
}
|
}
|
||||||
|
@@ -24,163 +24,163 @@ using namespace std;
|
|||||||
#define ENABLE_TEST 0
|
#define ENABLE_TEST 0
|
||||||
|
|
||||||
constexpr int (*init_applet_main[])(int, char *[]) =
|
constexpr int (*init_applet_main[])(int, char *[]) =
|
||||||
{ magiskpolicy_main, magiskpolicy_main, nullptr };
|
{ magiskpolicy_main, magiskpolicy_main, nullptr };
|
||||||
|
|
||||||
static bool unxz(int fd, const uint8_t *buf, size_t size) {
|
static bool unxz(int fd, const uint8_t *buf, size_t size) {
|
||||||
uint8_t out[8192];
|
uint8_t out[8192];
|
||||||
xz_crc32_init();
|
xz_crc32_init();
|
||||||
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
||||||
struct xz_buf b = {
|
struct xz_buf b = {
|
||||||
.in = buf,
|
.in = buf,
|
||||||
.in_pos = 0,
|
.in_pos = 0,
|
||||||
.in_size = size,
|
.in_size = size,
|
||||||
.out = out,
|
.out = out,
|
||||||
.out_pos = 0,
|
.out_pos = 0,
|
||||||
.out_size = sizeof(out)
|
.out_size = sizeof(out)
|
||||||
};
|
};
|
||||||
enum xz_ret ret;
|
enum xz_ret ret;
|
||||||
do {
|
do {
|
||||||
ret = xz_dec_run(dec, &b);
|
ret = xz_dec_run(dec, &b);
|
||||||
if (ret != XZ_OK && ret != XZ_STREAM_END)
|
if (ret != XZ_OK && ret != XZ_STREAM_END)
|
||||||
return false;
|
return false;
|
||||||
write(fd, out, b.out_pos);
|
write(fd, out, b.out_pos);
|
||||||
b.out_pos = 0;
|
b.out_pos = 0;
|
||||||
} while (b.in_pos != size);
|
} while (b.in_pos != size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dump_magisk(const char *path, mode_t mode) {
|
int dump_magisk(const char *path, mode_t mode) {
|
||||||
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return 1;
|
return 1;
|
||||||
if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
|
if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
|
||||||
return 1;
|
return 1;
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dump_manager(const char *path, mode_t mode) {
|
static int dump_manager(const char *path, mode_t mode) {
|
||||||
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return 1;
|
return 1;
|
||||||
if (!unxz(fd, manager_xz, sizeof(manager_xz)))
|
if (!unxz(fd, manager_xz, sizeof(manager_xz)))
|
||||||
return 1;
|
return 1;
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecoveryInit : public BaseInit {
|
class RecoveryInit : public BaseInit {
|
||||||
public:
|
public:
|
||||||
RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
||||||
void start() override {
|
void start() override {
|
||||||
LOGD("Ramdisk is recovery, abort\n");
|
LOGD("Ramdisk is recovery, abort\n");
|
||||||
rename("/.backup/init", "/init");
|
rename("/.backup/init", "/init");
|
||||||
rm_rf("/.backup");
|
rm_rf("/.backup");
|
||||||
exec_init();
|
exec_init();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ENABLE_TEST
|
#if ENABLE_TEST
|
||||||
class TestInit : public BaseInit {
|
class TestInit : public BaseInit {
|
||||||
public:
|
public:
|
||||||
TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
|
TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
|
||||||
void start() override {
|
void start() override {
|
||||||
// Place init tests here
|
// Place init tests here
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int test_main(int argc, char *argv[]) {
|
static int test_main(int argc, char *argv[]) {
|
||||||
// Log to console
|
// Log to console
|
||||||
cmdline_logging();
|
cmdline_logging();
|
||||||
log_cb.ex = nop_ex;
|
log_cb.ex = nop_ex;
|
||||||
|
|
||||||
// Switch to isolate namespace
|
// Switch to isolate namespace
|
||||||
xunshare(CLONE_NEWNS);
|
xunshare(CLONE_NEWNS);
|
||||||
xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr);
|
xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr);
|
||||||
|
|
||||||
// Unmount everything in reverse
|
// Unmount everything in reverse
|
||||||
vector<string> mounts;
|
vector<string> mounts;
|
||||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||||
if (me->mnt_dir != "/"sv)
|
if (me->mnt_dir != "/"sv)
|
||||||
mounts.emplace_back(me->mnt_dir);
|
mounts.emplace_back(me->mnt_dir);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
for (auto &m : reversed(mounts))
|
for (auto &m : reversed(mounts))
|
||||||
xumount(m.data());
|
xumount(m.data());
|
||||||
|
|
||||||
// chroot jail
|
// chroot jail
|
||||||
chdir(dirname(argv[0]));
|
chdir(dirname(argv[0]));
|
||||||
chroot(".");
|
chroot(".");
|
||||||
chdir("/");
|
chdir("/");
|
||||||
|
|
||||||
cmdline cmd{};
|
cmdline cmd{};
|
||||||
load_kernel_info(&cmd);
|
load_kernel_info(&cmd);
|
||||||
|
|
||||||
auto init = make_unique<TestInit>(argv, &cmd);
|
auto init = make_unique<TestInit>(argv, &cmd);
|
||||||
init->start();
|
init->start();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif // ENABLE_TEST
|
#endif // ENABLE_TEST
|
||||||
|
|
||||||
static int magisk_proxy_main(int argc, char *argv[]) {
|
static int magisk_proxy_main(int argc, char *argv[]) {
|
||||||
setup_klog();
|
setup_klog();
|
||||||
auto init = make_unique<MagiskProxy>(argv);
|
auto init = make_unique<MagiskProxy>(argv);
|
||||||
init->start();
|
init->start();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
umask(0);
|
umask(0);
|
||||||
|
|
||||||
auto name = basename(argv[0]);
|
auto name = basename(argv[0]);
|
||||||
if (name == "magisk"sv)
|
if (name == "magisk"sv)
|
||||||
return magisk_proxy_main(argc, argv);
|
return magisk_proxy_main(argc, argv);
|
||||||
for (int i = 0; init_applet[i]; ++i) {
|
for (int i = 0; init_applet[i]; ++i) {
|
||||||
if (strcmp(name, init_applet[i]) == 0)
|
if (strcmp(name, init_applet[i]) == 0)
|
||||||
return (*init_applet_main[i])(argc, argv);
|
return (*init_applet_main[i])(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_TEST
|
#if ENABLE_TEST
|
||||||
if (getenv("INIT_TEST") != nullptr)
|
if (getenv("INIT_TEST") != nullptr)
|
||||||
return test_main(argc, argv);
|
return test_main(argc, argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (argc > 1 && argv[1] == "-x"sv) {
|
if (argc > 1 && argv[1] == "-x"sv) {
|
||||||
if (argv[2] == "magisk"sv)
|
if (argv[2] == "magisk"sv)
|
||||||
return dump_magisk(argv[3], 0755);
|
return dump_magisk(argv[3], 0755);
|
||||||
else if (argv[2] == "manager"sv)
|
else if (argv[2] == "manager"sv)
|
||||||
return dump_manager(argv[3], 0644);
|
return dump_manager(argv[3], 0644);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getpid() != 1)
|
if (getpid() != 1)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
BaseInit *init;
|
BaseInit *init;
|
||||||
cmdline cmd{};
|
cmdline cmd{};
|
||||||
|
|
||||||
if (argc > 1 && argv[1] == "selinux_setup"sv) {
|
if (argc > 1 && argv[1] == "selinux_setup"sv) {
|
||||||
setup_klog();
|
setup_klog();
|
||||||
init = new SecondStageInit(argv);
|
init = new SecondStageInit(argv);
|
||||||
} else {
|
} else {
|
||||||
// This will also mount /sys and /proc
|
// This will also mount /sys and /proc
|
||||||
load_kernel_info(&cmd);
|
load_kernel_info(&cmd);
|
||||||
|
|
||||||
if (cmd.skip_initramfs) {
|
if (cmd.skip_initramfs) {
|
||||||
init = new SARInit(argv, &cmd);
|
init = new SARInit(argv, &cmd);
|
||||||
} else {
|
} else {
|
||||||
if (cmd.force_normal_boot)
|
if (cmd.force_normal_boot)
|
||||||
init = new FirstStageInit(argv, &cmd);
|
init = new FirstStageInit(argv, &cmd);
|
||||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||||
init = new RecoveryInit(argv, &cmd);
|
init = new RecoveryInit(argv, &cmd);
|
||||||
else if (check_two_stage())
|
else if (check_two_stage())
|
||||||
init = new FirstStageInit(argv, &cmd);
|
init = new FirstStageInit(argv, &cmd);
|
||||||
else
|
else
|
||||||
init = new RootFSInit(argv, &cmd);
|
init = new RootFSInit(argv, &cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the main routine
|
// Run the main routine
|
||||||
init->start();
|
init->start();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@@ -3,31 +3,34 @@
|
|||||||
#include "raw_data.hpp"
|
#include "raw_data.hpp"
|
||||||
|
|
||||||
struct cmdline {
|
struct cmdline {
|
||||||
bool skip_initramfs;
|
bool skip_initramfs;
|
||||||
bool force_normal_boot;
|
bool force_normal_boot;
|
||||||
char slot[3];
|
bool rootwait;
|
||||||
char dt_dir[64];
|
char slot[3];
|
||||||
char fstab_suffix[32];
|
char dt_dir[64];
|
||||||
char hardware[32];
|
char fstab_suffix[32];
|
||||||
char hardware_plat[32];
|
char hardware[32];
|
||||||
|
char hardware_plat[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fstab_entry {
|
struct fstab_entry {
|
||||||
std::string dev;
|
std::string dev;
|
||||||
std::string mnt_point;
|
std::string mnt_point;
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string mnt_flags;
|
std::string mnt_flags;
|
||||||
std::string fsmgr_flags;
|
std::string fsmgr_flags;
|
||||||
|
|
||||||
fstab_entry() = default;
|
fstab_entry() = default;
|
||||||
fstab_entry(const fstab_entry &) = delete;
|
fstab_entry(const fstab_entry &) = delete;
|
||||||
fstab_entry(fstab_entry &&) = default;
|
fstab_entry(fstab_entry &&) = default;
|
||||||
void to_file(FILE *fp);
|
void to_file(FILE *fp);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INIT_SOCKET "MAGISKINIT"
|
#define INIT_SOCKET "MAGISKINIT"
|
||||||
#define DEFAULT_DT_DIR "/proc/device-tree/firmware/android"
|
#define DEFAULT_DT_DIR "/proc/device-tree/firmware/android"
|
||||||
|
|
||||||
|
extern std::vector<std::string> mount_list;
|
||||||
|
|
||||||
void load_kernel_info(cmdline *cmd);
|
void load_kernel_info(cmdline *cmd);
|
||||||
bool check_two_stage();
|
bool check_two_stage();
|
||||||
int dump_magisk(const char *path, mode_t mode);
|
int dump_magisk(const char *path, mode_t mode);
|
||||||
@@ -39,41 +42,40 @@ void setup_klog();
|
|||||||
|
|
||||||
class BaseInit {
|
class BaseInit {
|
||||||
protected:
|
protected:
|
||||||
cmdline *cmd;
|
cmdline *cmd;
|
||||||
char **argv;
|
char **argv;
|
||||||
std::vector<std::string> mount_list;
|
|
||||||
|
|
||||||
[[noreturn]] void exec_init();
|
[[noreturn]] void exec_init();
|
||||||
void read_dt_fstab(std::vector<fstab_entry> &fstab);
|
void read_dt_fstab(std::vector<fstab_entry> &fstab);
|
||||||
public:
|
public:
|
||||||
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {}
|
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv) {}
|
||||||
virtual ~BaseInit() = default;
|
virtual ~BaseInit() = default;
|
||||||
virtual void start() = 0;
|
virtual void start() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MagiskInit : public BaseInit {
|
class MagiskInit : public BaseInit {
|
||||||
protected:
|
protected:
|
||||||
auto_data<HEAP> self;
|
mmap_data self;
|
||||||
auto_data<HEAP> config;
|
mmap_data config;
|
||||||
std::string custom_rules_dir;
|
std::string custom_rules_dir;
|
||||||
|
|
||||||
void mount_with_dt();
|
void mount_with_dt();
|
||||||
bool patch_sepolicy(const char *file);
|
bool patch_sepolicy(const char *file);
|
||||||
void setup_tmp(const char *path);
|
void setup_tmp(const char *path);
|
||||||
void mount_rules_dir(const char *dev_base, const char *mnt_base);
|
void mount_rules_dir(const char *dev_base, const char *mnt_base);
|
||||||
public:
|
public:
|
||||||
MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SARBase : public MagiskInit {
|
class SARBase : public MagiskInit {
|
||||||
protected:
|
protected:
|
||||||
std::vector<raw_file> overlays;
|
std::vector<raw_file> overlays;
|
||||||
|
|
||||||
void backup_files();
|
void backup_files();
|
||||||
void patch_rootdir();
|
void patch_rootdir();
|
||||||
void mount_system_root();
|
void mount_system_root();
|
||||||
public:
|
public:
|
||||||
SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}
|
SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
@@ -82,31 +84,29 @@ public:
|
|||||||
|
|
||||||
class FirstStageInit : public BaseInit {
|
class FirstStageInit : public BaseInit {
|
||||||
private:
|
private:
|
||||||
void prepare();
|
void prepare();
|
||||||
public:
|
public:
|
||||||
FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {
|
FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {
|
||||||
LOGD("%s\n", __FUNCTION__);
|
LOGD("%s\n", __FUNCTION__);
|
||||||
};
|
};
|
||||||
void start() override {
|
void start() override {
|
||||||
prepare();
|
prepare();
|
||||||
exec_init();
|
exec_init();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SecondStageInit : public SARBase {
|
class SecondStageInit : public SARBase {
|
||||||
private:
|
private:
|
||||||
void prepare();
|
void prepare();
|
||||||
public:
|
public:
|
||||||
SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {
|
SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {
|
||||||
LOGD("%s\n", __FUNCTION__);
|
LOGD("%s\n", __FUNCTION__);
|
||||||
// Do not unmount /sys and /proc
|
};
|
||||||
mount_list.clear();
|
void start() override {
|
||||||
};
|
prepare();
|
||||||
void start() override {
|
patch_rootdir();
|
||||||
prepare();
|
exec_init();
|
||||||
patch_rootdir();
|
}
|
||||||
exec_init();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
@@ -115,22 +115,22 @@ public:
|
|||||||
|
|
||||||
class SARInit : public SARBase {
|
class SARInit : public SARBase {
|
||||||
private:
|
private:
|
||||||
bool is_two_stage;
|
bool is_two_stage;
|
||||||
|
|
||||||
void early_mount();
|
void early_mount();
|
||||||
void first_stage_prep();
|
void first_stage_prep();
|
||||||
public:
|
public:
|
||||||
SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd), is_two_stage(false) {
|
SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd), is_two_stage(false) {
|
||||||
LOGD("%s\n", __FUNCTION__);
|
LOGD("%s\n", __FUNCTION__);
|
||||||
};
|
};
|
||||||
void start() override {
|
void start() override {
|
||||||
early_mount();
|
early_mount();
|
||||||
if (is_two_stage)
|
if (is_two_stage)
|
||||||
first_stage_prep();
|
first_stage_prep();
|
||||||
else
|
else
|
||||||
patch_rootdir();
|
patch_rootdir();
|
||||||
exec_init();
|
exec_init();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/************
|
/************
|
||||||
@@ -139,23 +139,23 @@ public:
|
|||||||
|
|
||||||
class RootFSInit : public MagiskInit {
|
class RootFSInit : public MagiskInit {
|
||||||
private:
|
private:
|
||||||
void early_mount();
|
void early_mount();
|
||||||
void patch_rootfs();
|
void patch_rootfs();
|
||||||
public:
|
public:
|
||||||
RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
|
RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
|
||||||
LOGD("%s\n", __FUNCTION__);
|
LOGD("%s\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
void start() override {
|
void start() override {
|
||||||
early_mount();
|
early_mount();
|
||||||
patch_rootfs();
|
patch_rootfs();
|
||||||
exec_init();
|
exec_init();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MagiskProxy : public MagiskInit {
|
class MagiskProxy : public MagiskInit {
|
||||||
public:
|
public:
|
||||||
explicit MagiskProxy(char *argv[]) : MagiskInit(argv, nullptr) {
|
explicit MagiskProxy(char *argv[]) : MagiskInit(argv, nullptr) {
|
||||||
LOGD("%s\n", __FUNCTION__);
|
LOGD("%s\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
void start() override;
|
void start() override;
|
||||||
};
|
};
|
||||||
|
@@ -11,401 +11,404 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static string rtrim(string &&str) {
|
static string rtrim(string &&str) {
|
||||||
// Trim space, newline, and null byte from end of string
|
// Trim space, newline, and null byte from end of string
|
||||||
while (memchr(" \n\r", str[str.length() - 1], 4))
|
while (memchr(" \n\r", str[str.length() - 1], 4))
|
||||||
str.pop_back();
|
str.pop_back();
|
||||||
return std::move(str);
|
return std::move(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct devinfo {
|
struct devinfo {
|
||||||
int major;
|
int major;
|
||||||
int minor;
|
int minor;
|
||||||
char devname[32];
|
char devname[32];
|
||||||
char partname[32];
|
char partname[32];
|
||||||
char dmname[32];
|
char dmname[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
static vector<devinfo> dev_list;
|
static vector<devinfo> dev_list;
|
||||||
|
|
||||||
static void parse_device(devinfo *dev, const char *uevent) {
|
static void parse_device(devinfo *dev, const char *uevent) {
|
||||||
dev->partname[0] = '\0';
|
dev->partname[0] = '\0';
|
||||||
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
|
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
|
||||||
if (key == "MAJOR")
|
if (key == "MAJOR")
|
||||||
dev->major = parse_int(value.data());
|
dev->major = parse_int(value.data());
|
||||||
else if (key == "MINOR")
|
else if (key == "MINOR")
|
||||||
dev->minor = parse_int(value.data());
|
dev->minor = parse_int(value.data());
|
||||||
else if (key == "DEVNAME")
|
else if (key == "DEVNAME")
|
||||||
strcpy(dev->devname, value.data());
|
strcpy(dev->devname, value.data());
|
||||||
else if (key == "PARTNAME")
|
else if (key == "PARTNAME")
|
||||||
strcpy(dev->partname, value.data());
|
strcpy(dev->partname, value.data());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void collect_devices() {
|
static void collect_devices() {
|
||||||
char path[128];
|
char path[128];
|
||||||
devinfo dev{};
|
devinfo dev{};
|
||||||
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
|
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
|
||||||
for (dirent *entry; (entry = readdir(dir.get()));) {
|
for (dirent *entry; (entry = readdir(dir.get()));) {
|
||||||
if (entry->d_name == "."sv || entry->d_name == ".."sv)
|
if (entry->d_name == "."sv || entry->d_name == ".."sv)
|
||||||
continue;
|
continue;
|
||||||
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
|
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
|
||||||
parse_device(&dev, path);
|
parse_device(&dev, path);
|
||||||
sprintf(path, "/sys/dev/block/%s/dm/name", entry->d_name);
|
sprintf(path, "/sys/dev/block/%s/dm/name", entry->d_name);
|
||||||
if (access(path, F_OK) == 0) {
|
if (access(path, F_OK) == 0) {
|
||||||
auto name = rtrim(full_read(path));
|
auto name = rtrim(full_read(path));
|
||||||
strcpy(dev.dmname, name.data());
|
strcpy(dev.dmname, name.data());
|
||||||
}
|
}
|
||||||
dev_list.push_back(dev);
|
dev_list.push_back(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
char partname[32];
|
char partname[32];
|
||||||
char block_dev[64];
|
char block_dev[64];
|
||||||
} blk_info;
|
} blk_info;
|
||||||
|
|
||||||
static int64_t setup_block(bool write_block) {
|
static int64_t setup_block(bool write_block) {
|
||||||
if (dev_list.empty())
|
if (dev_list.empty())
|
||||||
collect_devices();
|
collect_devices();
|
||||||
xmkdir("/dev", 0755);
|
xmkdir("/dev", 0755);
|
||||||
xmkdir("/dev/block", 0755);
|
xmkdir("/dev/block", 0755);
|
||||||
|
|
||||||
for (int tries = 0; tries < 3; ++tries) {
|
for (int tries = 0; tries < 3; ++tries) {
|
||||||
for (auto &dev : dev_list) {
|
for (auto &dev : dev_list) {
|
||||||
if (strcasecmp(dev.partname, blk_info.partname) == 0)
|
if (strcasecmp(dev.partname, blk_info.partname) == 0)
|
||||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
|
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
|
||||||
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
|
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
|
||||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
|
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (write_block) {
|
if (write_block) {
|
||||||
sprintf(blk_info.block_dev, "/dev/block/%s", dev.devname);
|
sprintf(blk_info.block_dev, "/dev/block/%s", dev.devname);
|
||||||
}
|
}
|
||||||
dev_t rdev = makedev(dev.major, dev.minor);
|
dev_t rdev = makedev(dev.major, dev.minor);
|
||||||
mknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
|
mknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
|
||||||
return rdev;
|
return rdev;
|
||||||
}
|
}
|
||||||
// Wait 10ms and try again
|
// Wait 10ms and try again
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
dev_list.clear();
|
dev_list.clear();
|
||||||
collect_devices();
|
collect_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The requested partname does not exist
|
// The requested partname does not exist
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_lnk(const char *name) {
|
static bool is_lnk(const char *name) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(name, &st))
|
if (lstat(name, &st))
|
||||||
return false;
|
return false;
|
||||||
return S_ISLNK(st.st_mode);
|
return S_ISLNK(st.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define read_info(val) \
|
#define read_info(val) \
|
||||||
if (access(#val, F_OK) == 0) {\
|
if (access(#val, F_OK) == 0) {\
|
||||||
entry.val = rtrim(full_read(#val)); \
|
entry.val = rtrim(full_read(#val)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInit::read_dt_fstab(vector<fstab_entry> &fstab) {
|
void BaseInit::read_dt_fstab(vector<fstab_entry> &fstab) {
|
||||||
if (access(cmd->dt_dir, F_OK) != 0)
|
if (access(cmd->dt_dir, F_OK) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char cwd[128];
|
char cwd[128];
|
||||||
getcwd(cwd, sizeof(cwd));
|
getcwd(cwd, sizeof(cwd));
|
||||||
chdir(cmd->dt_dir);
|
chdir(cmd->dt_dir);
|
||||||
run_finally cd([&]{ chdir(cwd); });
|
run_finally cd([&]{ chdir(cwd); });
|
||||||
|
|
||||||
if (access("fstab", F_OK) != 0)
|
if (access("fstab", F_OK) != 0)
|
||||||
return;
|
return;
|
||||||
chdir("fstab");
|
chdir("fstab");
|
||||||
|
|
||||||
// Make sure dt fstab is enabled
|
// Make sure dt fstab is enabled
|
||||||
if (access("status", F_OK) == 0) {
|
if (access("status", F_OK) == 0) {
|
||||||
auto status = rtrim(full_read("status"));
|
auto status = rtrim(full_read("status"));
|
||||||
if (status != "okay" && status != "ok")
|
if (status != "okay" && status != "ok")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dir = xopen_dir(".");
|
auto dir = xopen_dir(".");
|
||||||
for (dirent *dp; (dp = xreaddir(dir.get()));) {
|
for (dirent *dp; (dp = xreaddir(dir.get()));) {
|
||||||
if (dp->d_type != DT_DIR)
|
if (dp->d_type != DT_DIR)
|
||||||
continue;
|
continue;
|
||||||
chdir(dp->d_name);
|
chdir(dp->d_name);
|
||||||
run_finally f([]{ chdir(".."); });
|
run_finally f([]{ chdir(".."); });
|
||||||
|
|
||||||
if (access("status", F_OK) == 0) {
|
if (access("status", F_OK) == 0) {
|
||||||
auto status = rtrim(full_read("status"));
|
auto status = rtrim(full_read("status"));
|
||||||
if (status != "okay" && status != "ok")
|
if (status != "okay" && status != "ok")
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fstab_entry entry;
|
fstab_entry entry;
|
||||||
|
|
||||||
read_info(dev);
|
read_info(dev);
|
||||||
read_info(mnt_point) else {
|
read_info(mnt_point) else {
|
||||||
entry.mnt_point = "/";
|
entry.mnt_point = "/";
|
||||||
entry.mnt_point += dp->d_name;
|
entry.mnt_point += dp->d_name;
|
||||||
}
|
}
|
||||||
read_info(type);
|
read_info(type);
|
||||||
read_info(mnt_flags);
|
read_info(mnt_flags);
|
||||||
read_info(fsmgr_flags);
|
read_info(fsmgr_flags);
|
||||||
|
|
||||||
fstab.emplace_back(std::move(entry));
|
fstab.emplace_back(std::move(entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagiskInit::mount_with_dt() {
|
void MagiskInit::mount_with_dt() {
|
||||||
vector<fstab_entry> fstab;
|
vector<fstab_entry> fstab;
|
||||||
read_dt_fstab(fstab);
|
read_dt_fstab(fstab);
|
||||||
for (const auto &entry : fstab) {
|
for (const auto &entry : fstab) {
|
||||||
if (is_lnk(entry.mnt_point.data()))
|
if (is_lnk(entry.mnt_point.data()))
|
||||||
continue;
|
continue;
|
||||||
// Derive partname from dev
|
// Derive partname from dev
|
||||||
sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot);
|
sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot);
|
||||||
setup_block(true);
|
setup_block(true);
|
||||||
xmkdir(entry.mnt_point.data(), 0755);
|
xmkdir(entry.mnt_point.data(), 0755);
|
||||||
xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr);
|
xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr);
|
||||||
mount_list.push_back(entry.mnt_point);
|
mount_list.push_back(entry.mnt_point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void switch_root(const string &path) {
|
static void switch_root(const string &path) {
|
||||||
LOGD("Switch root to %s\n", path.data());
|
LOGD("Switch root to %s\n", path.data());
|
||||||
int root = xopen("/", O_RDONLY);
|
int root = xopen("/", O_RDONLY);
|
||||||
vector<string> mounts;
|
vector<string> mounts;
|
||||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||||
// Skip root and self
|
// Skip root and self
|
||||||
if (me->mnt_dir == "/"sv || me->mnt_dir == path)
|
if (me->mnt_dir == "/"sv || me->mnt_dir == path)
|
||||||
return true;
|
return true;
|
||||||
// Do not include subtrees
|
// Do not include subtrees
|
||||||
for (const auto &m : mounts) {
|
for (const auto &m : mounts) {
|
||||||
if (strncmp(me->mnt_dir, m.data(), m.length()) == 0 && me->mnt_dir[m.length()] == '/')
|
if (strncmp(me->mnt_dir, m.data(), m.length()) == 0 && me->mnt_dir[m.length()] == '/')
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
mounts.emplace_back(me->mnt_dir);
|
mounts.emplace_back(me->mnt_dir);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
for (auto &dir : mounts) {
|
for (auto &dir : mounts) {
|
||||||
auto new_path = path + dir;
|
auto new_path = path + dir;
|
||||||
mkdir(new_path.data(), 0755);
|
mkdir(new_path.data(), 0755);
|
||||||
xmount(dir.data(), new_path.data(), nullptr, MS_MOVE, nullptr);
|
xmount(dir.data(), new_path.data(), nullptr, MS_MOVE, nullptr);
|
||||||
}
|
}
|
||||||
chdir(path.data());
|
chdir(path.data());
|
||||||
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
|
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
|
||||||
chroot(".");
|
chroot(".");
|
||||||
|
|
||||||
LOGD("Cleaning rootfs\n");
|
LOGD("Cleaning rootfs\n");
|
||||||
frm_rf(root);
|
frm_rf(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) {
|
void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) {
|
||||||
char path[128];
|
char path[128];
|
||||||
xrealpath(dev_base, blk_info.block_dev);
|
xrealpath(dev_base, blk_info.block_dev);
|
||||||
xrealpath(mnt_base, path);
|
xrealpath(mnt_base, path);
|
||||||
char *b = blk_info.block_dev + strlen(blk_info.block_dev);
|
char *b = blk_info.block_dev + strlen(blk_info.block_dev);
|
||||||
char *p = path + strlen(path);
|
char *p = path + strlen(path);
|
||||||
|
|
||||||
auto do_mount = [&](const char *type) -> bool {
|
auto do_mount = [&](const char *type) -> bool {
|
||||||
xmkdir(path, 0755);
|
xmkdir(path, 0755);
|
||||||
bool success = xmount(blk_info.block_dev, path, type, 0, nullptr) == 0;
|
bool success = xmount(blk_info.block_dev, path, type, 0, nullptr) == 0;
|
||||||
if (success)
|
if (success)
|
||||||
mount_list.emplace_back(path);
|
mount_list.emplace_back(path);
|
||||||
return success;
|
return success;
|
||||||
};
|
};
|
||||||
|
|
||||||
// First try userdata
|
// First try userdata
|
||||||
strcpy(blk_info.partname, "userdata");
|
strcpy(blk_info.partname, "userdata");
|
||||||
strcpy(b, "/data");
|
strcpy(b, "/data");
|
||||||
strcpy(p, "/data");
|
strcpy(p, "/data");
|
||||||
if (setup_block(false) < 0) {
|
if (setup_block(false) < 0) {
|
||||||
// Try NVIDIA naming scheme
|
// Try NVIDIA naming scheme
|
||||||
strcpy(blk_info.partname, "UDA");
|
strcpy(blk_info.partname, "UDA");
|
||||||
if (setup_block(false) < 0)
|
if (setup_block(false) < 0)
|
||||||
goto cache;
|
goto cache;
|
||||||
}
|
}
|
||||||
// Try to mount with either ext4 or f2fs
|
// WARNING: DO NOT ATTEMPT TO MOUNT F2FS AS IT MAY CRASH THE KERNEL
|
||||||
// Failure means either FDE or metadata encryption
|
// Failure means either f2fs, FDE, or metadata encryption
|
||||||
if (!do_mount("ext4") && !do_mount("f2fs"))
|
if (!do_mount("ext4"))
|
||||||
goto cache;
|
goto cache;
|
||||||
|
|
||||||
strcpy(p, "/data/unencrypted");
|
strcpy(p, "/data/unencrypted");
|
||||||
if (access(path, F_OK) == 0) {
|
if (access(path, F_OK) == 0) {
|
||||||
// FBE, need to use an unencrypted path
|
// FBE, need to use an unencrypted path
|
||||||
custom_rules_dir = path + "/magisk"s;
|
custom_rules_dir = path + "/magisk"s;
|
||||||
} else {
|
} else {
|
||||||
// Skip if /data/adb does not exist
|
// Skip if /data/adb does not exist
|
||||||
strcpy(p, "/data/adb");
|
strcpy(p, "/data/adb");
|
||||||
if (access(path, F_OK) != 0)
|
if (access(path, F_OK) != 0)
|
||||||
return;
|
return;
|
||||||
// Unencrypted, directly use module paths
|
// Unencrypted, directly use module paths
|
||||||
custom_rules_dir = string(mnt_base) + MODULEROOT;
|
custom_rules_dir = string(mnt_base) + MODULEROOT;
|
||||||
}
|
}
|
||||||
goto success;
|
goto success;
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
// Fallback to cache
|
// Fallback to cache
|
||||||
strcpy(blk_info.partname, "cache");
|
strcpy(blk_info.partname, "cache");
|
||||||
strcpy(b, "/cache");
|
strcpy(b, "/cache");
|
||||||
strcpy(p, "/cache");
|
strcpy(p, "/cache");
|
||||||
if (setup_block(false) < 0) {
|
if (setup_block(false) < 0) {
|
||||||
// Try NVIDIA naming scheme
|
// Try NVIDIA naming scheme
|
||||||
strcpy(blk_info.partname, "CAC");
|
strcpy(blk_info.partname, "CAC");
|
||||||
if (setup_block(false) < 0)
|
if (setup_block(false) < 0)
|
||||||
goto metadata;
|
goto metadata;
|
||||||
}
|
}
|
||||||
if (!do_mount("ext4"))
|
if (!do_mount("ext4"))
|
||||||
goto metadata;
|
goto metadata;
|
||||||
custom_rules_dir = path + "/magisk"s;
|
custom_rules_dir = path + "/magisk"s;
|
||||||
goto success;
|
goto success;
|
||||||
|
|
||||||
metadata:
|
metadata:
|
||||||
// Fallback to metadata
|
// Fallback to metadata
|
||||||
strcpy(blk_info.partname, "metadata");
|
strcpy(blk_info.partname, "metadata");
|
||||||
strcpy(b, "/metadata");
|
strcpy(b, "/metadata");
|
||||||
strcpy(p, "/metadata");
|
strcpy(p, "/metadata");
|
||||||
if (setup_block(false) < 0 || !do_mount("ext4"))
|
if (setup_block(false) < 0 || !do_mount("ext4"))
|
||||||
goto persist;
|
goto persist;
|
||||||
custom_rules_dir = path + "/magisk"s;
|
custom_rules_dir = path + "/magisk"s;
|
||||||
goto success;
|
goto success;
|
||||||
|
|
||||||
persist:
|
persist:
|
||||||
// Fallback to persist
|
// Fallback to persist
|
||||||
strcpy(blk_info.partname, "persist");
|
strcpy(blk_info.partname, "persist");
|
||||||
strcpy(b, "/persist");
|
strcpy(b, "/persist");
|
||||||
strcpy(p, "/persist");
|
strcpy(p, "/persist");
|
||||||
if (setup_block(false) < 0 || !do_mount("ext4"))
|
if (setup_block(false) < 0 || !do_mount("ext4"))
|
||||||
return;
|
return;
|
||||||
custom_rules_dir = path + "/magisk"s;
|
custom_rules_dir = path + "/magisk"s;
|
||||||
|
|
||||||
success:
|
success:
|
||||||
// Create symlinks so we don't need to go through this logic again
|
// Create symlinks so we don't need to go through this logic again
|
||||||
strcpy(p, "/sepolicy.rules");
|
strcpy(p, "/sepolicy.rules");
|
||||||
xsymlink(custom_rules_dir.data(), path);
|
xsymlink(custom_rules_dir.data(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootFSInit::early_mount() {
|
void RootFSInit::early_mount() {
|
||||||
self = raw_data::read("/init");
|
self = mmap_data::ro("/init");
|
||||||
|
|
||||||
LOGD("Restoring /init\n");
|
LOGD("Restoring /init\n");
|
||||||
rename("/.backup/init", "/init");
|
rename("/.backup/init", "/init");
|
||||||
|
|
||||||
mount_with_dt();
|
mount_with_dt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SARBase::backup_files() {
|
void SARBase::backup_files() {
|
||||||
if (access("/overlay.d", F_OK) == 0)
|
if (access("/overlay.d", F_OK) == 0)
|
||||||
backup_folder("/overlay.d", overlays);
|
backup_folder("/overlay.d", overlays);
|
||||||
|
|
||||||
self = raw_data::read("/proc/self/exe");
|
self = mmap_data::ro("/proc/self/exe");
|
||||||
if (access("/.backup/.magisk", R_OK) == 0)
|
if (access("/.backup/.magisk", R_OK) == 0)
|
||||||
config = raw_data::read("/.backup/.magisk");
|
config = mmap_data::ro("/.backup/.magisk");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SARBase::mount_system_root() {
|
void SARBase::mount_system_root() {
|
||||||
LOGD("Early mount system_root\n");
|
LOGD("Early mount system_root\n");
|
||||||
strcpy(blk_info.block_dev, "/dev/root");
|
strcpy(blk_info.block_dev, "/dev/root");
|
||||||
// Try legacy SAR dm-verity
|
|
||||||
strcpy(blk_info.partname, "vroot");
|
|
||||||
auto dev = setup_block(false);
|
|
||||||
if (dev >= 0)
|
|
||||||
goto mount_root;
|
|
||||||
|
|
||||||
// Try NVIDIA naming scheme
|
do {
|
||||||
strcpy(blk_info.partname, "APP");
|
// Try legacy SAR dm-verity
|
||||||
dev = setup_block(false);
|
strcpy(blk_info.partname, "vroot");
|
||||||
if (dev >= 0)
|
auto dev = setup_block(false);
|
||||||
goto mount_root;
|
if (dev >= 0)
|
||||||
|
goto mount_root;
|
||||||
|
|
||||||
sprintf(blk_info.partname, "system%s", cmd->slot);
|
// Try NVIDIA naming scheme
|
||||||
dev = setup_block(false);
|
strcpy(blk_info.partname, "APP");
|
||||||
if (dev >= 0)
|
dev = setup_block(false);
|
||||||
goto mount_root;
|
if (dev >= 0)
|
||||||
|
goto mount_root;
|
||||||
|
|
||||||
// We don't really know what to do at this point...
|
sprintf(blk_info.partname, "system%s", cmd->slot);
|
||||||
LOGE("Cannot find root partition, abort\n");
|
dev = setup_block(false);
|
||||||
exit(1);
|
if (dev >= 0)
|
||||||
|
goto mount_root;
|
||||||
|
|
||||||
|
// Poll forever if rootwait was given in cmdline
|
||||||
|
} while (cmd->rootwait);
|
||||||
|
|
||||||
|
// We don't really know what to do at this point...
|
||||||
|
LOGE("Cannot find root partition, abort\n");
|
||||||
|
exit(1);
|
||||||
mount_root:
|
mount_root:
|
||||||
xmkdir("/system_root", 0755);
|
xmkdir("/system_root", 0755);
|
||||||
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
|
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
|
||||||
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
|
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SARInit::early_mount() {
|
void SARInit::early_mount() {
|
||||||
backup_files();
|
backup_files();
|
||||||
mount_system_root();
|
mount_system_root();
|
||||||
switch_root("/system_root");
|
switch_root("/system_root");
|
||||||
|
|
||||||
{
|
// Use the apex folder to determine whether 2SI (Android 10+)
|
||||||
auto init = raw_data::mmap_ro("/init");
|
is_two_stage = access("/apex", F_OK) == 0;
|
||||||
is_two_stage = init.contains("selinux_setup");
|
LOGD("is_two_stage: [%d]\n", is_two_stage);
|
||||||
}
|
|
||||||
LOGD("is_two_stage: [%d]\n", is_two_stage);
|
|
||||||
|
|
||||||
if (!is_two_stage) {
|
if (!is_two_stage) {
|
||||||
// Make dev writable
|
// Make dev writable
|
||||||
xmkdir("/dev", 0755);
|
xmkdir("/dev", 0755);
|
||||||
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
||||||
mount_list.emplace_back("/dev");
|
mount_list.emplace_back("/dev");
|
||||||
mount_with_dt();
|
mount_with_dt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecondStageInit::prepare() {
|
void SecondStageInit::prepare() {
|
||||||
backup_files();
|
backup_files();
|
||||||
|
|
||||||
umount2("/init", MNT_DETACH);
|
umount2("/init", MNT_DETACH);
|
||||||
umount2("/proc/self/exe", MNT_DETACH);
|
umount2("/proc/self/exe", MNT_DETACH);
|
||||||
|
|
||||||
if (access("/system_root", F_OK) == 0)
|
if (access("/system_root", F_OK) == 0)
|
||||||
switch_root("/system_root");
|
switch_root("/system_root");
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInit::exec_init() {
|
void BaseInit::exec_init() {
|
||||||
// Unmount in reverse order
|
// Unmount in reverse order
|
||||||
for (auto &p : reversed(mount_list)) {
|
for (auto &p : reversed(mount_list)) {
|
||||||
if (xumount(p.data()) == 0)
|
if (xumount(p.data()) == 0)
|
||||||
LOGD("Unmount [%s]\n", p.data());
|
LOGD("Unmount [%s]\n", p.data());
|
||||||
}
|
}
|
||||||
execv("/init", argv);
|
execv("/init", argv);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void patch_socket_name(const char *path) {
|
static void patch_socket_name(const char *path) {
|
||||||
char rstr[16];
|
char rstr[16];
|
||||||
gen_rand_str(rstr, sizeof(rstr));
|
gen_rand_str(rstr, sizeof(rstr));
|
||||||
auto bin = raw_data::mmap_rw(path);
|
auto bin = mmap_data::rw(path);
|
||||||
bin.patch({ make_pair(MAIN_SOCKET, rstr) });
|
bin.patch({ make_pair(MAIN_SOCKET, rstr) });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagiskInit::setup_tmp(const char *path) {
|
void MagiskInit::setup_tmp(const char *path) {
|
||||||
LOGD("Setup Magisk tmp at %s\n", path);
|
LOGD("Setup Magisk tmp at %s\n", path);
|
||||||
xmount("tmpfs", path, "tmpfs", 0, "mode=755");
|
xmount("tmpfs", path, "tmpfs", 0, "mode=755");
|
||||||
|
|
||||||
chdir(path);
|
chdir(path);
|
||||||
|
|
||||||
xmkdir(INTLROOT, 0755);
|
xmkdir(INTLROOT, 0755);
|
||||||
xmkdir(MIRRDIR, 0);
|
xmkdir(MIRRDIR, 0);
|
||||||
xmkdir(BLOCKDIR, 0);
|
xmkdir(BLOCKDIR, 0);
|
||||||
|
|
||||||
int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
|
int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
|
||||||
xwrite(fd, config.buf, config.sz);
|
xwrite(fd, config.buf, config.sz);
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755);
|
fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755);
|
||||||
xwrite(fd, self.buf, self.sz);
|
xwrite(fd, self.buf, self.sz);
|
||||||
close(fd);
|
close(fd);
|
||||||
dump_magisk("magisk", 0755);
|
dump_magisk("magisk", 0755);
|
||||||
patch_socket_name("magisk");
|
patch_socket_name("magisk");
|
||||||
|
|
||||||
// Create applet symlinks
|
// Create applet symlinks
|
||||||
for (int i = 0; applet_names[i]; ++i)
|
for (int i = 0; applet_names[i]; ++i)
|
||||||
xsymlink("./magisk", applet_names[i]);
|
xsymlink("./magisk", applet_names[i]);
|
||||||
xsymlink("./magiskinit", "magiskpolicy");
|
xsymlink("./magiskinit", "magiskpolicy");
|
||||||
xsymlink("./magiskinit", "supolicy");
|
xsymlink("./magiskinit", "supolicy");
|
||||||
|
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
|
@@ -2,63 +2,51 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int data_holder::patch(str_pairs list) {
|
int mmap_data::patch(str_pairs list) {
|
||||||
if (buf == nullptr)
|
if (buf == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
||||||
for (auto [from, to] : list) {
|
for (auto [from, to] : list) {
|
||||||
if (memcmp(p, from.data(), from.length() + 1) == 0) {
|
if (memcmp(p, from.data(), from.length() + 1) == 0) {
|
||||||
LOGD("Replace [%s] -> [%s]\n", from.data(), to.data());
|
LOGD("Replace [%s] -> [%s]\n", from.data(), to.data());
|
||||||
memset(p, 0, from.length());
|
memset(p, 0, from.length());
|
||||||
memcpy(p, to.data(), to.length());
|
memcpy(p, to.data(), to.length());
|
||||||
++count;
|
++count;
|
||||||
p += from.length();
|
p += from.length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool data_holder::contains(string_view pattern) {
|
bool mmap_data::contains(string_view pattern) {
|
||||||
if (buf == nullptr)
|
if (buf == nullptr)
|
||||||
return false;
|
return false;
|
||||||
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
||||||
if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) {
|
if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) {
|
||||||
LOGD("Found pattern [%s]\n", pattern.data());
|
LOGD("Found pattern [%s]\n", pattern.data());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void data_holder::consume(data_holder &other) {
|
void mmap_data::consume(mmap_data &other) {
|
||||||
buf = other.buf;
|
buf = other.buf;
|
||||||
sz = other.sz;
|
sz = other.sz;
|
||||||
other.buf = nullptr;
|
other.buf = nullptr;
|
||||||
other.sz = 0;
|
other.sz = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_data<HEAP> raw_data::read(int fd) {
|
mmap_data mmap_data::rw(const char *name) {
|
||||||
auto_data<HEAP> data;
|
mmap_data data;
|
||||||
fd_full_read(fd, data.buf, data.sz);
|
mmap_rw(name, data.buf, data.sz);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_data<HEAP> raw_data::read(const char *name) {
|
mmap_data mmap_data::ro(const char *name) {
|
||||||
auto_data<HEAP> data;
|
mmap_data data;
|
||||||
full_read(name, data.buf, data.sz);
|
mmap_ro(name, data.buf, data.sz);
|
||||||
return data;
|
return data;
|
||||||
}
|
|
||||||
|
|
||||||
auto_data<MMAP> raw_data::mmap_rw(const char *name) {
|
|
||||||
auto_data<MMAP> data;
|
|
||||||
::mmap_rw(name, data.buf, data.sz);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto_data<MMAP> raw_data::mmap_ro(const char *name) {
|
|
||||||
auto_data<MMAP> data;
|
|
||||||
::mmap_ro(name, data.buf, data.sz);
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
@@ -2,31 +2,23 @@
|
|||||||
|
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
struct data_holder {
|
struct mmap_data {
|
||||||
uint8_t *buf = nullptr;
|
uint8_t *buf = nullptr;
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
using str_pairs = std::initializer_list<std::pair<std::string_view, std::string_view>>;
|
|
||||||
int patch(str_pairs list);
|
|
||||||
bool contains(std::string_view pattern);
|
|
||||||
protected:
|
|
||||||
void consume(data_holder &other);
|
|
||||||
};
|
|
||||||
|
|
||||||
enum data_type { HEAP, MMAP };
|
mmap_data() = default;
|
||||||
template <data_type T>
|
mmap_data(const mmap_data&) = delete;
|
||||||
struct auto_data : public data_holder {
|
mmap_data(mmap_data &&other) { consume(other); }
|
||||||
auto_data<T>() = default;
|
~mmap_data() { if (buf) munmap(buf, sz); }
|
||||||
auto_data<T>(const auto_data&) = delete;
|
mmap_data& operator=(mmap_data &&other) { consume(other); return *this; }
|
||||||
auto_data<T>(auto_data<T> &&other) { consume(other); }
|
|
||||||
~auto_data<T>() {}
|
|
||||||
auto_data<T>& operator=(auto_data<T> &&other) { consume(other); return *this; }
|
|
||||||
};
|
|
||||||
template <> inline auto_data<MMAP>::~auto_data<MMAP>() { if (buf) munmap(buf, sz); }
|
|
||||||
template <> inline auto_data<HEAP>::~auto_data<HEAP>() { free(buf); }
|
|
||||||
|
|
||||||
namespace raw_data {
|
using str_pairs = std::initializer_list<std::pair<std::string_view, std::string_view>>;
|
||||||
auto_data<HEAP> read(const char *name);
|
int patch(str_pairs list);
|
||||||
auto_data<HEAP> read(int fd);
|
bool contains(std::string_view pattern);
|
||||||
auto_data<MMAP> mmap_rw(const char *name);
|
|
||||||
auto_data<MMAP> mmap_ro(const char *name);
|
static mmap_data rw(const char *name);
|
||||||
}
|
static mmap_data ro(const char *name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void consume(mmap_data &other);
|
||||||
|
};
|
||||||
|
@@ -9,346 +9,348 @@
|
|||||||
#include "init.hpp"
|
#include "init.hpp"
|
||||||
#include "magiskrc.inc"
|
#include "magiskrc.inc"
|
||||||
|
|
||||||
#ifdef USE_64BIT
|
|
||||||
#define LIBNAME "lib64"
|
|
||||||
#else
|
|
||||||
#define LIBNAME "lib"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static vector<string> rc_list;
|
static vector<string> rc_list;
|
||||||
|
|
||||||
static void patch_init_rc(const char *src, const char *dest, const char *tmp_dir) {
|
static void patch_init_rc(const char *src, const char *dest, const char *tmp_dir) {
|
||||||
FILE *rc = xfopen(dest, "we");
|
FILE *rc = xfopen(dest, "we");
|
||||||
file_readline(src, [=](string_view line) -> bool {
|
file_readline(src, [=](string_view line) -> bool {
|
||||||
// Do not start vaultkeeper
|
// Do not start vaultkeeper
|
||||||
if (str_contains(line, "start vaultkeeper")) {
|
if (str_contains(line, "start vaultkeeper")) {
|
||||||
LOGD("Remove vaultkeeper\n");
|
LOGD("Remove vaultkeeper\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Do not run flash_recovery
|
// Do not run flash_recovery
|
||||||
if (str_starts(line, "service flash_recovery")) {
|
if (str_starts(line, "service flash_recovery")) {
|
||||||
LOGD("Remove flash_recovery\n");
|
LOGD("Remove flash_recovery\n");
|
||||||
fprintf(rc, "service flash_recovery /system/bin/xxxxx\n");
|
fprintf(rc, "service flash_recovery /system/bin/xxxxx\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Else just write the line
|
// Else just write the line
|
||||||
fprintf(rc, "%s", line.data());
|
fprintf(rc, "%s", line.data());
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
fprintf(rc, "\n");
|
fprintf(rc, "\n");
|
||||||
|
|
||||||
// Inject custom rc scripts
|
// Inject custom rc scripts
|
||||||
for (auto &script : rc_list) {
|
for (auto &script : rc_list) {
|
||||||
// Replace template arguments of rc scripts with dynamic paths
|
// Replace template arguments of rc scripts with dynamic paths
|
||||||
replace_all(script, "${MAGISKTMP}", tmp_dir);
|
replace_all(script, "${MAGISKTMP}", tmp_dir);
|
||||||
fprintf(rc, "\n%s\n", script.data());
|
fprintf(rc, "\n%s\n", script.data());
|
||||||
}
|
}
|
||||||
rc_list.clear();
|
rc_list.clear();
|
||||||
|
|
||||||
// Inject Magisk rc scripts
|
// Inject Magisk rc scripts
|
||||||
char pfd_svc[16], ls_svc[16], bc_svc[16];
|
char pfd_svc[16], ls_svc[16], bc_svc[16];
|
||||||
gen_rand_str(pfd_svc, sizeof(pfd_svc));
|
gen_rand_str(pfd_svc, sizeof(pfd_svc));
|
||||||
gen_rand_str(ls_svc, sizeof(ls_svc));
|
gen_rand_str(ls_svc, sizeof(ls_svc));
|
||||||
gen_rand_str(bc_svc, sizeof(bc_svc));
|
gen_rand_str(bc_svc, sizeof(bc_svc));
|
||||||
LOGD("Inject magisk services: [%s] [%s] [%s]\n", pfd_svc, ls_svc, bc_svc);
|
LOGD("Inject magisk services: [%s] [%s] [%s]\n", pfd_svc, ls_svc, bc_svc);
|
||||||
fprintf(rc, MAGISK_RC, tmp_dir, pfd_svc, ls_svc, bc_svc);
|
fprintf(rc, MAGISK_RC, tmp_dir, pfd_svc, ls_svc, bc_svc);
|
||||||
|
|
||||||
fclose(rc);
|
fclose(rc);
|
||||||
clone_attr(src, dest);
|
clone_attr(src, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_overlay_rc(const char *overlay) {
|
static void load_overlay_rc(const char *overlay) {
|
||||||
auto dir = open_dir(overlay);
|
auto dir = open_dir(overlay);
|
||||||
if (!dir) return;
|
if (!dir) return;
|
||||||
|
|
||||||
int dfd = dirfd(dir.get());
|
int dfd = dirfd(dir.get());
|
||||||
// Do not allow overwrite init.rc
|
// Do not allow overwrite init.rc
|
||||||
unlinkat(dfd, "init.rc", 0);
|
unlinkat(dfd, "init.rc", 0);
|
||||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||||
if (strend(entry->d_name, ".rc") == 0) {
|
if (str_ends(entry->d_name, ".rc")) {
|
||||||
LOGD("Found rc script [%s]\n", entry->d_name);
|
LOGD("Found rc script [%s]\n", entry->d_name);
|
||||||
int rc = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
int rc = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||||
rc_list.push_back(fd_full_read(rc));
|
rc_list.push_back(fd_full_read(rc));
|
||||||
close(rc);
|
close(rc);
|
||||||
unlinkat(dfd, entry->d_name, 0);
|
unlinkat(dfd, entry->d_name, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MagiskInit::patch_sepolicy(const char *file) {
|
bool MagiskInit::patch_sepolicy(const char *file) {
|
||||||
bool patch_init = false;
|
bool patch_init = false;
|
||||||
sepolicy *sepol = nullptr;
|
sepolicy *sepol = nullptr;
|
||||||
|
|
||||||
if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
|
if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
|
||||||
LOGD("sepol: split policy\n");
|
LOGD("sepol: split policy\n");
|
||||||
patch_init = true;
|
patch_init = true;
|
||||||
} else if (access("/sepolicy", R_OK) == 0) {
|
} else if (access("/sepolicy", R_OK) == 0) {
|
||||||
LOGD("sepol: monolithic policy\n");
|
LOGD("sepol: monolithic policy\n");
|
||||||
sepol = sepolicy::from_file("/sepolicy");
|
sepol = sepolicy::from_file("/sepolicy");
|
||||||
} else {
|
} else {
|
||||||
LOGD("sepol: no selinux\n");
|
LOGD("sepol: no selinux\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (access(SELINUX_VERSION, F_OK) != 0) {
|
if (access(SELINUX_VERSION, F_OK) != 0) {
|
||||||
// Mount selinuxfs to communicate with kernel
|
// Mount selinuxfs to communicate with kernel
|
||||||
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
|
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
|
||||||
mount_list.emplace_back(SELINUX_MNT);
|
mount_list.emplace_back(SELINUX_MNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch_init)
|
if (patch_init)
|
||||||
sepol = sepolicy::from_split();
|
sepol = sepolicy::from_split();
|
||||||
|
|
||||||
sepol->magisk_rules();
|
sepol->magisk_rules();
|
||||||
|
|
||||||
// Custom rules
|
// Custom rules
|
||||||
if (!custom_rules_dir.empty()) {
|
if (!custom_rules_dir.empty()) {
|
||||||
if (auto dir = open_dir(custom_rules_dir.data())) {
|
if (auto dir = open_dir(custom_rules_dir.data())) {
|
||||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||||
auto rule = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
|
auto rule = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
|
||||||
if (access(rule.data(), R_OK) == 0) {
|
if (access(rule.data(), R_OK) == 0) {
|
||||||
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
|
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
|
||||||
sepol->load_rule_file(rule.data());
|
sepol->load_rule_file(rule.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGD("Dumping sepolicy to: [%s]\n", file);
|
LOGD("Dumping sepolicy to: [%s]\n", file);
|
||||||
sepol->to_file(file);
|
sepol->to_file(file);
|
||||||
delete sepol;
|
delete sepol;
|
||||||
|
|
||||||
// Remove OnePlus stupid debug sepolicy and use our own
|
// Remove OnePlus stupid debug sepolicy and use our own
|
||||||
if (access("/sepolicy_debug", F_OK) == 0) {
|
if (access("/sepolicy_debug", F_OK) == 0) {
|
||||||
unlink("/sepolicy_debug");
|
unlink("/sepolicy_debug");
|
||||||
link("/sepolicy", "/sepolicy_debug");
|
link("/sepolicy", "/sepolicy_debug");
|
||||||
}
|
}
|
||||||
|
|
||||||
return patch_init;
|
return patch_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recreate_sbin(const char *mirror, bool use_bind_mount) {
|
static void recreate_sbin(const char *mirror, bool use_bind_mount) {
|
||||||
auto dp = xopen_dir(mirror);
|
auto dp = xopen_dir(mirror);
|
||||||
int src = dirfd(dp.get());
|
int src = dirfd(dp.get());
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
for (dirent *entry; (entry = xreaddir(dp.get()));) {
|
for (dirent *entry; (entry = xreaddir(dp.get()));) {
|
||||||
string sbin_path = "/sbin/"s + entry->d_name;
|
string sbin_path = "/sbin/"s + entry->d_name;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
|
fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
|
||||||
if (S_ISLNK(st.st_mode)) {
|
if (S_ISLNK(st.st_mode)) {
|
||||||
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
||||||
xsymlink(buf, sbin_path.data());
|
xsymlink(buf, sbin_path.data());
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf, "%s/%s", mirror, entry->d_name);
|
sprintf(buf, "%s/%s", mirror, entry->d_name);
|
||||||
if (use_bind_mount) {
|
if (use_bind_mount) {
|
||||||
auto mode = st.st_mode & 0777;
|
auto mode = st.st_mode & 0777;
|
||||||
// Create dummy
|
// Create dummy
|
||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode))
|
||||||
xmkdir(sbin_path.data(), mode);
|
xmkdir(sbin_path.data(), mode);
|
||||||
else
|
else
|
||||||
close(xopen(sbin_path.data(), O_CREAT | O_WRONLY | O_CLOEXEC, mode));
|
close(xopen(sbin_path.data(), O_CREAT | O_WRONLY | O_CLOEXEC, mode));
|
||||||
|
|
||||||
xmount(buf, sbin_path.data(), nullptr, MS_BIND, nullptr);
|
xmount(buf, sbin_path.data(), nullptr, MS_BIND, nullptr);
|
||||||
} else {
|
} else {
|
||||||
xsymlink(buf, sbin_path.data());
|
xsymlink(buf, sbin_path.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static string magic_mount_list;
|
static string magic_mount_list;
|
||||||
|
|
||||||
static void magic_mount(const string &sdir, const string &ddir = "") {
|
static void magic_mount(const string &sdir, const string &ddir = "") {
|
||||||
auto dir = xopen_dir(sdir.data());
|
auto dir = xopen_dir(sdir.data());
|
||||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||||
string src = sdir + "/" + entry->d_name;
|
string src = sdir + "/" + entry->d_name;
|
||||||
string dest = ddir + "/" + entry->d_name;
|
string dest = ddir + "/" + entry->d_name;
|
||||||
if (access(dest.data(), F_OK) == 0) {
|
if (access(dest.data(), F_OK) == 0) {
|
||||||
if (entry->d_type == DT_DIR) {
|
if (entry->d_type == DT_DIR) {
|
||||||
// Recursive
|
// Recursive
|
||||||
magic_mount(src, dest);
|
magic_mount(src, dest);
|
||||||
} else {
|
} else {
|
||||||
LOGD("Mount [%s] -> [%s]\n", src.data(), dest.data());
|
LOGD("Mount [%s] -> [%s]\n", src.data(), dest.data());
|
||||||
xmount(src.data(), dest.data(), nullptr, MS_BIND, nullptr);
|
xmount(src.data(), dest.data(), nullptr, MS_BIND, nullptr);
|
||||||
magic_mount_list += dest;
|
magic_mount_list += dest;
|
||||||
magic_mount_list += '\n';
|
magic_mount_list += '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ROOTMIR MIRRDIR "/system_root"
|
#define ROOTMIR MIRRDIR "/system_root"
|
||||||
#define MONOPOLICY "/sepolicy"
|
#define MONOPOLICY "/sepolicy"
|
||||||
#define LIBSELINUX "/system/" LIBNAME "/libselinux.so"
|
|
||||||
#define NEW_INITRC "/system/etc/init/hw/init.rc"
|
#define NEW_INITRC "/system/etc/init/hw/init.rc"
|
||||||
|
|
||||||
void SARBase::patch_rootdir() {
|
void SARBase::patch_rootdir() {
|
||||||
string tmp_dir;
|
string tmp_dir;
|
||||||
const char *sepol;
|
const char *sepol;
|
||||||
|
|
||||||
if (access("/sbin", F_OK) == 0) {
|
if (access("/sbin", F_OK) == 0) {
|
||||||
tmp_dir = "/sbin";
|
tmp_dir = "/sbin";
|
||||||
sepol = "/sbin/.se";
|
sepol = "/sbin/.se";
|
||||||
} else {
|
} else {
|
||||||
char buf[8];
|
char buf[8];
|
||||||
gen_rand_str(buf, sizeof(buf));
|
gen_rand_str(buf, sizeof(buf));
|
||||||
tmp_dir = "/dev/"s + buf;
|
tmp_dir = "/dev/"s + buf;
|
||||||
xmkdir(tmp_dir.data(), 0);
|
xmkdir(tmp_dir.data(), 0);
|
||||||
sepol = "/dev/.se";
|
sepol = "/dev/.se";
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_tmp(tmp_dir.data());
|
setup_tmp(tmp_dir.data());
|
||||||
chdir(tmp_dir.data());
|
chdir(tmp_dir.data());
|
||||||
|
|
||||||
mount_rules_dir(BLOCKDIR, MIRRDIR);
|
mount_rules_dir(BLOCKDIR, MIRRDIR);
|
||||||
|
|
||||||
// Mount system_root mirror
|
// Mount system_root mirror
|
||||||
xmkdir(ROOTMIR, 0755);
|
xmkdir(ROOTMIR, 0755);
|
||||||
xmount("/", ROOTMIR, nullptr, MS_BIND, nullptr);
|
xmount("/", ROOTMIR, nullptr, MS_BIND, nullptr);
|
||||||
mount_list.emplace_back(tmp_dir + "/" ROOTMIR);
|
mount_list.emplace_back(tmp_dir + "/" ROOTMIR);
|
||||||
|
|
||||||
// Recreate original sbin structure if necessary
|
// Recreate original sbin structure if necessary
|
||||||
if (tmp_dir == "/sbin")
|
if (tmp_dir == "/sbin")
|
||||||
recreate_sbin(ROOTMIR "/sbin", true);
|
recreate_sbin(ROOTMIR "/sbin", true);
|
||||||
|
|
||||||
// Patch init
|
// Patch init
|
||||||
int patch_count;
|
int patch_count;
|
||||||
{
|
{
|
||||||
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
|
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
|
||||||
auto init = raw_data::read(src);
|
auto init = mmap_data::ro("/init");
|
||||||
patch_count = init.patch({
|
patch_count = init.patch({
|
||||||
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
|
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
|
||||||
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
|
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
|
||||||
});
|
});
|
||||||
xmkdir(ROOTOVL, 0);
|
xmkdir(ROOTOVL, 0);
|
||||||
int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
||||||
xwrite(dest, init.buf, init.sz);
|
xwrite(dest, init.buf, init.sz);
|
||||||
fclone_attr(src, dest);
|
fclone_attr(src, dest);
|
||||||
close(src);
|
close(src);
|
||||||
close(dest);
|
close(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch_count != 2 && access(LIBSELINUX, F_OK) == 0) {
|
if (patch_count != 2) {
|
||||||
// init is dynamically linked, need to patch libselinux
|
// init is dynamically linked, need to patch libselinux
|
||||||
auto lib = raw_data::read(LIBSELINUX);
|
const char *path = "/system/lib64/libselinux.so";
|
||||||
lib.patch({make_pair(MONOPOLICY, sepol)});
|
if (access(path, F_OK) != 0) {
|
||||||
xmkdirs(dirname(ROOTOVL LIBSELINUX), 0755);
|
path = "/system/lib/libselinux.so";
|
||||||
int dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
if (access(path, F_OK) != 0)
|
||||||
xwrite(dest, lib.buf, lib.sz);
|
path = nullptr;
|
||||||
close(dest);
|
}
|
||||||
clone_attr(LIBSELINUX, ROOTOVL LIBSELINUX);
|
if (path) {
|
||||||
}
|
char ovl[128];
|
||||||
|
sprintf(ovl, ROOTOVL "%s", path);
|
||||||
|
auto lib = mmap_data::ro(path);
|
||||||
|
lib.patch({make_pair(MONOPOLICY, sepol)});
|
||||||
|
xmkdirs(dirname(ovl), 0755);
|
||||||
|
int dest = xopen(ovl, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
||||||
|
xwrite(dest, lib.buf, lib.sz);
|
||||||
|
close(dest);
|
||||||
|
clone_attr(path, ovl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sepolicy
|
// sepolicy
|
||||||
patch_sepolicy(sepol);
|
patch_sepolicy(sepol);
|
||||||
|
|
||||||
// Restore backup files
|
// Restore backup files
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sun;
|
||||||
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
|
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
|
||||||
LOGD("ACK init daemon to write backup files\n");
|
LOGD("ACK init daemon to write backup files\n");
|
||||||
// Let daemon know where tmp_dir is
|
// Let daemon know where tmp_dir is
|
||||||
write_string(sockfd, tmp_dir.data());
|
write_string(sockfd, tmp_dir);
|
||||||
// Wait for daemon to finish restoring files
|
// Wait for daemon to finish restoring files
|
||||||
int ack;
|
read_int(sockfd);
|
||||||
read(sockfd, &ack, sizeof(ack));
|
} else {
|
||||||
} else {
|
LOGD("Restore backup files locally\n");
|
||||||
LOGD("Restore backup files locally\n");
|
restore_folder(ROOTOVL, overlays);
|
||||||
restore_folder(ROOTOVL, overlays);
|
overlays.clear();
|
||||||
overlays.clear();
|
}
|
||||||
}
|
close(sockfd);
|
||||||
close(sockfd);
|
|
||||||
|
|
||||||
// Handle overlay.d
|
// Handle overlay.d
|
||||||
load_overlay_rc(ROOTOVL);
|
load_overlay_rc(ROOTOVL);
|
||||||
if (access(ROOTOVL "/sbin", F_OK) == 0) {
|
if (access(ROOTOVL "/sbin", F_OK) == 0) {
|
||||||
// Move files in overlay.d/sbin into tmp_dir
|
// Move files in overlay.d/sbin into tmp_dir
|
||||||
mv_path(ROOTOVL "/sbin", ".");
|
mv_path(ROOTOVL "/sbin", ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch init.rc
|
// Patch init.rc
|
||||||
if (access("/init.rc", F_OK) == 0) {
|
if (access("/init.rc", F_OK) == 0) {
|
||||||
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
|
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
|
||||||
} else {
|
} else {
|
||||||
// Android 11's new init.rc
|
// Android 11's new init.rc
|
||||||
xmkdirs(dirname(ROOTOVL NEW_INITRC), 0755);
|
xmkdirs(dirname(ROOTOVL NEW_INITRC), 0755);
|
||||||
patch_init_rc(NEW_INITRC, ROOTOVL NEW_INITRC, tmp_dir.data());
|
patch_init_rc(NEW_INITRC, ROOTOVL NEW_INITRC, tmp_dir.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount rootdir
|
// Mount rootdir
|
||||||
magic_mount(ROOTOVL);
|
magic_mount(ROOTOVL);
|
||||||
int dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC, 0);
|
int dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC, 0);
|
||||||
write(dest, magic_mount_list.data(), magic_mount_list.length());
|
write(dest, magic_mount_list.data(), magic_mount_list.length());
|
||||||
close(dest);
|
close(dest);
|
||||||
|
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TMP_MNTDIR "/dev/mnt"
|
#define TMP_MNTDIR "/dev/mnt"
|
||||||
#define TMP_RULESDIR "/.backup/.sepolicy.rules"
|
#define TMP_RULESDIR "/.backup/.sepolicy.rules"
|
||||||
|
|
||||||
void RootFSInit::patch_rootfs() {
|
void RootFSInit::patch_rootfs() {
|
||||||
// Handle custom sepolicy rules
|
// Handle custom sepolicy rules
|
||||||
xmkdir(TMP_MNTDIR, 0755);
|
xmkdir(TMP_MNTDIR, 0755);
|
||||||
mount_rules_dir("/dev/block", TMP_MNTDIR);
|
mount_rules_dir("/dev/block", TMP_MNTDIR);
|
||||||
// Preserve custom rule path
|
// Preserve custom rule path
|
||||||
if (!custom_rules_dir.empty()) {
|
if (!custom_rules_dir.empty()) {
|
||||||
string rules_dir = "./" + custom_rules_dir.substr(sizeof(TMP_MNTDIR));
|
string rules_dir = "./" + custom_rules_dir.substr(sizeof(TMP_MNTDIR));
|
||||||
xsymlink(rules_dir.data(), TMP_RULESDIR);
|
xsymlink(rules_dir.data(), TMP_RULESDIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch_sepolicy("/sepolicy")) {
|
if (patch_sepolicy("/sepolicy")) {
|
||||||
auto init = raw_data::mmap_rw("/init");
|
auto init = mmap_data::rw("/init");
|
||||||
init.patch({ make_pair(SPLIT_PLAT_CIL, "xxx") });
|
init.patch({ make_pair(SPLIT_PLAT_CIL, "xxx") });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle overlays
|
// Handle overlays
|
||||||
if (access("/overlay.d", F_OK) == 0) {
|
if (access("/overlay.d", F_OK) == 0) {
|
||||||
LOGD("Merge overlay.d\n");
|
LOGD("Merge overlay.d\n");
|
||||||
load_overlay_rc("/overlay.d");
|
load_overlay_rc("/overlay.d");
|
||||||
mv_path("/overlay.d", "/");
|
mv_path("/overlay.d", "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
patch_init_rc("/init.rc", "/init.p.rc", "/sbin");
|
patch_init_rc("/init.rc", "/init.p.rc", "/sbin");
|
||||||
rename("/init.p.rc", "/init.rc");
|
rename("/init.p.rc", "/init.rc");
|
||||||
|
|
||||||
// Create hardlink mirror of /sbin to /root
|
// Create hardlink mirror of /sbin to /root
|
||||||
mkdir("/root", 0750);
|
mkdir("/root", 0750);
|
||||||
clone_attr("/sbin", "/root");
|
clone_attr("/sbin", "/root");
|
||||||
link_path("/sbin", "/root");
|
link_path("/sbin", "/root");
|
||||||
|
|
||||||
// Dump magiskinit as magisk
|
// Dump magiskinit as magisk
|
||||||
int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755);
|
int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755);
|
||||||
write(fd, self.buf, self.sz);
|
write(fd, self.buf, self.sz);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MagiskProxy::start() {
|
void MagiskProxy::start() {
|
||||||
// Mount rootfs as rw to do post-init rootfs patches
|
// Mount rootfs as rw to do post-init rootfs patches
|
||||||
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
|
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
|
||||||
|
|
||||||
// Backup stuffs before removing them
|
// Backup stuffs before removing them
|
||||||
self = raw_data::read("/sbin/magisk");
|
self = mmap_data::ro("/sbin/magisk");
|
||||||
config = raw_data::read("/.backup/.magisk");
|
config = mmap_data::ro("/.backup/.magisk");
|
||||||
char custom_rules_dir[64];
|
char custom_rules_dir[64];
|
||||||
custom_rules_dir[0] = '\0';
|
custom_rules_dir[0] = '\0';
|
||||||
xreadlink(TMP_RULESDIR, custom_rules_dir, sizeof(custom_rules_dir));
|
xreadlink(TMP_RULESDIR, custom_rules_dir, sizeof(custom_rules_dir));
|
||||||
|
|
||||||
unlink("/sbin/magisk");
|
unlink("/sbin/magisk");
|
||||||
rm_rf("/.backup");
|
rm_rf("/.backup");
|
||||||
|
|
||||||
setup_tmp("/sbin");
|
setup_tmp("/sbin");
|
||||||
|
|
||||||
// Create symlinks pointing back to /root
|
// Create symlinks pointing back to /root
|
||||||
recreate_sbin("/root", false);
|
recreate_sbin("/root", false);
|
||||||
|
|
||||||
if (custom_rules_dir[0])
|
if (custom_rules_dir[0])
|
||||||
xsymlink(custom_rules_dir, "/sbin/" RULESDIR);
|
xsymlink(custom_rules_dir, "/sbin/" RULESDIR);
|
||||||
|
|
||||||
// Tell magiskd to remount rootfs
|
// Tell magiskd to remount rootfs
|
||||||
setenv("REMOUNT_ROOT", "1", 1);
|
setenv("REMOUNT_ROOT", "1", 1);
|
||||||
execv("/sbin/magisk", argv);
|
execv("/sbin/magisk", argv);
|
||||||
}
|
}
|
||||||
|
@@ -9,8 +9,8 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void fstab_entry::to_file(FILE *fp) {
|
void fstab_entry::to_file(FILE *fp) {
|
||||||
fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(),
|
fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(),
|
||||||
type.data(), mnt_flags.data(), fsmgr_flags.data());
|
type.data(), mnt_flags.data(), fsmgr_flags.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
#define set_info(val) \
|
#define set_info(val) \
|
||||||
@@ -22,193 +22,187 @@ entry.val = &line[val##0];
|
|||||||
extern uint32_t patch_verity(void *buf, uint32_t size);
|
extern uint32_t patch_verity(void *buf, uint32_t size);
|
||||||
|
|
||||||
void FirstStageInit::prepare() {
|
void FirstStageInit::prepare() {
|
||||||
if (cmd->force_normal_boot) {
|
if (cmd->force_normal_boot) {
|
||||||
xmkdirs(FSR "/system/bin", 0755);
|
xmkdirs(FSR "/system/bin", 0755);
|
||||||
rename("/init" /* magiskinit */, FSR "/system/bin/init");
|
rename("/init" /* magiskinit */, FSR "/system/bin/init");
|
||||||
symlink("/system/bin/init", FSR "/init");
|
symlink("/system/bin/init", FSR "/init");
|
||||||
rename("/.backup", FSR "/.backup");
|
rename("/.backup", FSR "/.backup");
|
||||||
rename("/overlay.d", FSR "/overlay.d");
|
rename("/overlay.d", FSR "/overlay.d");
|
||||||
xsymlink("/system/bin/init", "/init");
|
xsymlink("/system/bin/init", "/init");
|
||||||
|
|
||||||
chdir(FSR);
|
chdir(FSR);
|
||||||
} else {
|
} else {
|
||||||
xmkdir("/system", 0755);
|
xmkdir("/system", 0755);
|
||||||
xmkdir("/system/bin", 0755);
|
xmkdir("/system/bin", 0755);
|
||||||
rename("/init" /* magiskinit */ , "/system/bin/init");
|
rename("/init" /* magiskinit */ , "/system/bin/init");
|
||||||
rename("/.backup/init", "/init");
|
rename("/.backup/init", "/init");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load fstab from dt
|
char fstab_file[128];
|
||||||
vector<fstab_entry> fstab;
|
fstab_file[0] = '\0';
|
||||||
read_dt_fstab(fstab);
|
|
||||||
|
|
||||||
char fstab_file[128];
|
// Find existing fstab file
|
||||||
fstab_file[0] = '\0';
|
for (const char *suffix : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
|
||||||
|
if (suffix[0] == '\0')
|
||||||
|
continue;
|
||||||
|
for (const char *prefix: { "odm/etc/fstab", "vendor/etc/fstab", "fstab" }) {
|
||||||
|
sprintf(fstab_file, "%s.%s", prefix, suffix);
|
||||||
|
if (access(fstab_file, F_OK) != 0) {
|
||||||
|
fstab_file[0] = '\0';
|
||||||
|
} else {
|
||||||
|
LOGD("Found fstab file: %s\n", fstab_file);
|
||||||
|
goto exit_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit_loop:
|
||||||
|
|
||||||
// Find existing fstab file
|
// Try to load dt fstab
|
||||||
for (const char *hw : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
|
vector<fstab_entry> fstab;
|
||||||
if (hw[0] == '\0')
|
read_dt_fstab(fstab);
|
||||||
continue;
|
|
||||||
sprintf(fstab_file, "fstab.%s", hw);
|
|
||||||
if (access(fstab_file, F_OK) != 0) {
|
|
||||||
fstab_file[0] = '\0';
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
LOGD("Found fstab file: %s\n", fstab_file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fstab.empty()) {
|
if (!fstab.empty()) {
|
||||||
// fstab has to be somewhere in ramdisk
|
// Dump dt fstab to fstab file in rootfs and force init to use it instead
|
||||||
if (fstab_file[0] == '\0') {
|
|
||||||
LOGE("Cannot find fstab file in ramdisk!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse and load fstab file
|
// All dt fstab entries should be first_stage_mount
|
||||||
file_readline(fstab_file, [&](string_view l) -> bool {
|
for (auto &entry : fstab) {
|
||||||
if (l[0] == '#' || l.length() == 1)
|
if (!str_contains(entry.fsmgr_flags, "first_stage_mount")) {
|
||||||
return true;
|
if (!entry.fsmgr_flags.empty())
|
||||||
char *line = (char *) l.data();
|
entry.fsmgr_flags += ',';
|
||||||
|
entry.fsmgr_flags += "first_stage_mount";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int dev0, dev1, mnt_point0, mnt_point1, type0, type1,
|
if (fstab_file[0] == '\0') {
|
||||||
mnt_flags0, mnt_flags1, fsmgr_flags0, fsmgr_flags1;
|
const char *suffix =
|
||||||
|
cmd->fstab_suffix[0] ? cmd->fstab_suffix :
|
||||||
|
(cmd->hardware[0] ? cmd->hardware :
|
||||||
|
(cmd->hardware_plat[0] ? cmd->hardware_plat : nullptr));
|
||||||
|
if (suffix == nullptr) {
|
||||||
|
LOGE("Cannot determine fstab suffix!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sprintf(fstab_file, "fstab.%s", suffix);
|
||||||
|
}
|
||||||
|
|
||||||
sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n",
|
// Patch init to force IsDtFstabCompatible() return false
|
||||||
&dev0, &dev1, &mnt_point0, &mnt_point1, &type0, &type1,
|
auto init = mmap_data::rw("/init");
|
||||||
&mnt_flags0, &mnt_flags1, &fsmgr_flags0, &fsmgr_flags1);
|
init.patch({ make_pair("android,fstab", "xxx") });
|
||||||
|
} else {
|
||||||
|
// Parse and load the fstab file
|
||||||
|
file_readline(fstab_file, [&](string_view l) -> bool {
|
||||||
|
if (l[0] == '#' || l.length() == 1)
|
||||||
|
return true;
|
||||||
|
char *line = (char *) l.data();
|
||||||
|
|
||||||
fstab_entry entry;
|
int dev0, dev1, mnt_point0, mnt_point1, type0, type1,
|
||||||
|
mnt_flags0, mnt_flags1, fsmgr_flags0, fsmgr_flags1;
|
||||||
|
|
||||||
set_info(dev);
|
sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n",
|
||||||
set_info(mnt_point);
|
&dev0, &dev1, &mnt_point0, &mnt_point1, &type0, &type1,
|
||||||
set_info(type);
|
&mnt_flags0, &mnt_flags1, &fsmgr_flags0, &fsmgr_flags1);
|
||||||
set_info(mnt_flags);
|
|
||||||
set_info(fsmgr_flags);
|
|
||||||
|
|
||||||
fstab.emplace_back(std::move(entry));
|
fstab_entry entry;
|
||||||
return true;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// All dt fstab entries should be first_stage_mount
|
|
||||||
for (auto &entry : fstab) {
|
|
||||||
if (!str_contains(entry.fsmgr_flags, "first_stage_mount")) {
|
|
||||||
if (!entry.fsmgr_flags.empty())
|
|
||||||
entry.fsmgr_flags += ',';
|
|
||||||
entry.fsmgr_flags += "first_stage_mount";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump dt fstab to fstab file in rootfs
|
set_info(dev);
|
||||||
if (fstab_file[0] == '\0') {
|
set_info(mnt_point);
|
||||||
const char *suffix =
|
set_info(type);
|
||||||
cmd->fstab_suffix[0] ? cmd->fstab_suffix :
|
set_info(mnt_flags);
|
||||||
(cmd->hardware[0] ? cmd->hardware :
|
set_info(fsmgr_flags);
|
||||||
(cmd->hardware_plat[0] ? cmd->hardware_plat : nullptr));
|
|
||||||
if (suffix == nullptr) {
|
|
||||||
LOGE("Cannot determine fstab suffix!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sprintf(fstab_file, "fstab.%s", suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Patch init to force IsDtFstabCompatible() return false
|
fstab.emplace_back(std::move(entry));
|
||||||
auto init = raw_data::mmap_rw("/init");
|
return true;
|
||||||
init.patch({ make_pair("android,fstab", "xxx") });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
LOGD("Write fstab file: %s\n", fstab_file);
|
LOGD("Write fstab file: %s\n", fstab_file);
|
||||||
auto fp = xopen_file(fstab_file, "we");
|
auto fp = xopen_file(fstab_file, "we");
|
||||||
for (auto &entry : fstab) {
|
for (auto &entry : fstab) {
|
||||||
// Redirect system mnt_point so init won't switch root in first stage init
|
// Redirect system mnt_point so init won't switch root in first stage init
|
||||||
if (entry.mnt_point == "/system")
|
if (entry.mnt_point == "/system")
|
||||||
entry.mnt_point = "/system_root";
|
entry.mnt_point = "/system_root";
|
||||||
|
|
||||||
// Force remove AVB for 2SI since it may bootloop some devices
|
// Force remove AVB for 2SI since it may bootloop some devices
|
||||||
auto len = patch_verity(entry.fsmgr_flags.data(), entry.fsmgr_flags.length());
|
auto len = patch_verity(entry.fsmgr_flags.data(), entry.fsmgr_flags.length());
|
||||||
entry.fsmgr_flags.resize(len);
|
entry.fsmgr_flags.resize(len);
|
||||||
|
|
||||||
entry.to_file(fp.get());
|
entry.to_file(fp.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chmod(fstab_file, 0644);
|
chmod(fstab_file, 0644);
|
||||||
|
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INIT_PATH "/system/bin/init"
|
#define INIT_PATH "/system/bin/init"
|
||||||
#define REDIR_PATH "/system/bin/am"
|
#define REDIR_PATH "/system/bin/am"
|
||||||
|
|
||||||
void SARInit::first_stage_prep() {
|
void SARInit::first_stage_prep() {
|
||||||
int pid = getpid();
|
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
||||||
|
|
||||||
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
// Patch init binary
|
||||||
|
int src = xopen("/init", O_RDONLY);
|
||||||
|
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
|
||||||
|
{
|
||||||
|
auto init = mmap_data::ro("/init");
|
||||||
|
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
|
||||||
|
write(dest, init.buf, init.sz);
|
||||||
|
fclone_attr(src, dest);
|
||||||
|
close(dest);
|
||||||
|
}
|
||||||
|
|
||||||
// Patch init binary
|
// Replace redirect init with magiskinit
|
||||||
int src = xopen("/init", O_RDONLY);
|
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
|
||||||
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
|
write(dest, self.buf, self.sz);
|
||||||
{
|
fclone_attr(src, dest);
|
||||||
auto init = raw_data::read(src);
|
close(src);
|
||||||
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
|
close(dest);
|
||||||
write(dest, init.buf, init.sz);
|
|
||||||
fclone_attr(src, dest);
|
|
||||||
close(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace redirect init with magiskinit
|
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
|
||||||
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
|
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
|
||||||
write(dest, self.buf, self.sz);
|
xumount2("/dev", MNT_DETACH);
|
||||||
fclone_attr(src, dest);
|
|
||||||
close(src);
|
|
||||||
close(dest);
|
|
||||||
|
|
||||||
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
|
// Block SIGUSR1
|
||||||
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
|
sigset_t block, old;
|
||||||
xumount2("/dev", MNT_DETACH);
|
sigemptyset(&block);
|
||||||
|
sigaddset(&block, SIGUSR1);
|
||||||
|
sigprocmask(SIG_BLOCK, &block, &old);
|
||||||
|
|
||||||
// Block SIGUSR1
|
if (int child = xfork()) {
|
||||||
sigset_t block, old;
|
LOGD("init daemon [%d]\n", child);
|
||||||
sigemptyset(&block);
|
// Wait for children signal
|
||||||
sigaddset(&block, SIGUSR1);
|
int sig;
|
||||||
sigprocmask(SIG_BLOCK, &block, &old);
|
sigwait(&block, &sig);
|
||||||
|
|
||||||
if (int child = xfork(); child) {
|
// Restore sigmask
|
||||||
LOGD("init daemon [%d]\n", child);
|
sigprocmask(SIG_SETMASK, &old, nullptr);
|
||||||
// Wait for children signal
|
} else {
|
||||||
int sig;
|
// Establish socket for 2nd stage ack
|
||||||
sigwait(&block, &sig);
|
struct sockaddr_un sun;
|
||||||
|
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
|
xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET));
|
||||||
|
xlisten(sockfd, 1);
|
||||||
|
|
||||||
// Restore sigmask
|
// Resume parent
|
||||||
sigprocmask(SIG_SETMASK, &old, nullptr);
|
kill(getppid(), SIGUSR1);
|
||||||
} else {
|
|
||||||
// Establish socket for 2nd stage ack
|
|
||||||
struct sockaddr_un sun;
|
|
||||||
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
||||||
xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET));
|
|
||||||
xlisten(sockfd, 1);
|
|
||||||
|
|
||||||
// Resume parent
|
// Wait for second stage ack
|
||||||
kill(pid, SIGUSR1);
|
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||||
|
|
||||||
// Wait for second stage ack
|
// Write backup files
|
||||||
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
string tmp_dir = read_string(client);
|
||||||
|
chdir(tmp_dir.data());
|
||||||
|
int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
|
||||||
|
xwrite(cfg, config.buf, config.sz);
|
||||||
|
close(cfg);
|
||||||
|
restore_folder(ROOTOVL, overlays);
|
||||||
|
|
||||||
// Write backup files
|
// Ack and bail out!
|
||||||
char *tmp_dir = read_string(client);
|
write_int(sockfd, 0);
|
||||||
chdir(tmp_dir);
|
close(client);
|
||||||
free(tmp_dir);
|
close(sockfd);
|
||||||
int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
|
|
||||||
xwrite(cfg, config.buf, config.sz);
|
|
||||||
close(cfg);
|
|
||||||
restore_folder(ROOTOVL, overlays);
|
|
||||||
|
|
||||||
// Ack and bail out!
|
exit(0);
|
||||||
write(sockfd, &sockfd, sizeof(sockfd));
|
}
|
||||||
close(client);
|
|
||||||
close(sockfd);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
151
native/jni/inject/entry.cpp
Normal file
151
native/jni/inject/entry.cpp
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
#include <libgen.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/sendfile.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include <utils.hpp>
|
||||||
|
|
||||||
|
#include "inject.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static void *self_handle = nullptr;
|
||||||
|
static atomic<int> active_threads = -1;
|
||||||
|
|
||||||
|
#define alog(prio) [](auto fmt, auto ap){ \
|
||||||
|
return __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); }
|
||||||
|
static void inject_logging() {
|
||||||
|
log_cb.d = alog(DEBUG);
|
||||||
|
log_cb.i = alog(INFO);
|
||||||
|
log_cb.w = alog(WARN);
|
||||||
|
log_cb.e = alog(ERROR);
|
||||||
|
log_cb.ex = nop_ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((destructor))
|
||||||
|
static void inject_cleanup() {
|
||||||
|
if (active_threads < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Setup 1ms
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
|
||||||
|
|
||||||
|
// Check flag in busy loop
|
||||||
|
while (active_threads)
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
|
||||||
|
// Wait another 1ms to make sure all threads left our code
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void self_unload() {
|
||||||
|
LOGD("hook: Request to self unload\n");
|
||||||
|
// If unhook failed, do not unload or else it will cause SIGSEGV
|
||||||
|
if (!unhook_functions())
|
||||||
|
return;
|
||||||
|
new_daemon_thread(reinterpret_cast<void *(*)(void *)>(&dlclose), self_handle);
|
||||||
|
active_threads--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *unload_first_stage(void *) {
|
||||||
|
// Setup 1ms
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
|
||||||
|
|
||||||
|
while (getenv(INJECT_ENV_1))
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
|
||||||
|
// Wait another 1ms to make sure all threads left our code
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
|
|
||||||
|
unmap_all(INJECT_LIB_1);
|
||||||
|
active_threads--;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure /proc/self/environ does not reveal our secrets
|
||||||
|
// Copy all env to a contiguous memory and set the memory region as MM_ENV
|
||||||
|
static void sanitize_environ() {
|
||||||
|
static string env;
|
||||||
|
|
||||||
|
for (int i = 0; environ[i]; ++i) {
|
||||||
|
if (str_starts(environ[i], INJECT_ENV_1 "="))
|
||||||
|
continue;
|
||||||
|
env += environ[i];
|
||||||
|
env += '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
bool success = true;
|
||||||
|
success &= (0 <= prctl(PR_SET_MM, PR_SET_MM_ENV_START, env.data(), 0, 0));
|
||||||
|
success &= (0 <= prctl(PR_SET_MM, PR_SET_MM_ENV_END, env.data() + env.size(), 0, 0));
|
||||||
|
if (success)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void inject_init() {
|
||||||
|
inject_logging();
|
||||||
|
|
||||||
|
if (getenv(INJECT_ENV_2)) {
|
||||||
|
LOGD("zygote: inject 2nd stage\n");
|
||||||
|
active_threads = 1;
|
||||||
|
unsetenv(INJECT_ENV_2);
|
||||||
|
|
||||||
|
// Get our own handle
|
||||||
|
self_handle = dlopen(INJECT_LIB_2, RTLD_LAZY);
|
||||||
|
dlclose(self_handle);
|
||||||
|
|
||||||
|
hook_functions();
|
||||||
|
|
||||||
|
// Some cleanup
|
||||||
|
sanitize_environ();
|
||||||
|
active_threads++;
|
||||||
|
new_daemon_thread(&unload_first_stage);
|
||||||
|
} else if (char *env = getenv(INJECT_ENV_1)) {
|
||||||
|
LOGD("zygote: inject 1st stage\n");
|
||||||
|
|
||||||
|
if (env[0] == '1')
|
||||||
|
unsetenv("LD_PRELOAD");
|
||||||
|
else
|
||||||
|
setenv("LD_PRELOAD", env, 1); // Restore original LD_PRELOAD
|
||||||
|
|
||||||
|
// Setup second stage
|
||||||
|
setenv(INJECT_ENV_2, "1", 1);
|
||||||
|
cp_afc(INJECT_LIB_1, INJECT_LIB_2);
|
||||||
|
dlopen(INJECT_LIB_2, RTLD_LAZY);
|
||||||
|
|
||||||
|
unsetenv(INJECT_ENV_1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int app_process_main(int argc, char *argv[]) {
|
||||||
|
inject_logging();
|
||||||
|
char buf[4096];
|
||||||
|
if (realpath("/proc/self/exe", buf) == nullptr)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int in = xopen(buf, O_RDONLY);
|
||||||
|
int out = xopen(INJECT_LIB_1, O_CREAT | O_WRONLY | O_TRUNC, 0777);
|
||||||
|
sendfile(out, in, nullptr, INT_MAX);
|
||||||
|
close(in);
|
||||||
|
close(out);
|
||||||
|
|
||||||
|
if (char *ld = getenv("LD_PRELOAD")) {
|
||||||
|
char env[128];
|
||||||
|
sprintf(env, "%s:" INJECT_LIB_1, ld);
|
||||||
|
setenv("LD_PRELOAD", env, 1);
|
||||||
|
setenv(INJECT_ENV_1, ld, 1); // Backup original LD_PRELOAD
|
||||||
|
} else {
|
||||||
|
setenv("LD_PRELOAD", INJECT_LIB_1, 1);
|
||||||
|
setenv(INJECT_ENV_1, "1", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute real app_process
|
||||||
|
xumount2(buf, MNT_DETACH);
|
||||||
|
execve(buf, argv, environ);
|
||||||
|
return 1;
|
||||||
|
}
|
275
native/jni/inject/hook.cpp
Normal file
275
native/jni/inject/hook.cpp
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include <xhook.h>
|
||||||
|
#include <utils.hpp>
|
||||||
|
#include <flags.hpp>
|
||||||
|
#include <daemon.hpp>
|
||||||
|
|
||||||
|
#include "inject.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define DCL_HOOK_FUNC(ret, func, ...) \
|
||||||
|
static ret (*old_##func)(__VA_ARGS__); \
|
||||||
|
static ret new_##func(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define DCL_JNI_FUNC(name) \
|
||||||
|
static const JNINativeMethod *name##_orig = nullptr; \
|
||||||
|
extern const JNINativeMethod name##_methods[]; \
|
||||||
|
extern const int name##_methods_num;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct HookContext {
|
||||||
|
int pid;
|
||||||
|
bool do_hide;
|
||||||
|
};
|
||||||
|
|
||||||
|
// JNI method declarations
|
||||||
|
DCL_JNI_FUNC(nativeForkAndSpecialize)
|
||||||
|
DCL_JNI_FUNC(nativeSpecializeAppProcess)
|
||||||
|
DCL_JNI_FUNC(nativeForkSystemServer)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// For some reason static vectors won't work, use pointers instead
|
||||||
|
static vector<tuple<const char *, const char *, void **>> *xhook_list;
|
||||||
|
static vector<JNINativeMethod> *jni_list;
|
||||||
|
|
||||||
|
static JavaVM *g_jvm;
|
||||||
|
static int prev_fork_pid = -1;
|
||||||
|
static HookContext *current_ctx;
|
||||||
|
|
||||||
|
#define HOOK_JNI(method) \
|
||||||
|
if (newMethods[i].name == #method##sv) { \
|
||||||
|
auto orig = new JNINativeMethod(); \
|
||||||
|
memcpy(orig, &newMethods[i], sizeof(JNINativeMethod)); \
|
||||||
|
method##_orig = orig; \
|
||||||
|
jni_list->push_back(newMethods[i]); \
|
||||||
|
for (int j = 0; j < method##_methods_num; ++j) { \
|
||||||
|
if (strcmp(newMethods[i].signature, method##_methods[j].signature) == 0) { \
|
||||||
|
newMethods[i] = method##_methods[j]; \
|
||||||
|
LOGI("hook: replaced #" #method "\n"); \
|
||||||
|
++hooked; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
DCL_HOOK_FUNC(int, jniRegisterNativeMethods,
|
||||||
|
JNIEnv *env, const char *className, const JNINativeMethod *methods, int numMethods) {
|
||||||
|
LOGD("hook: jniRegisterNativeMethods %s", className);
|
||||||
|
|
||||||
|
unique_ptr<JNINativeMethod[]> newMethods;
|
||||||
|
int hooked = 0;
|
||||||
|
|
||||||
|
if (g_jvm == nullptr) {
|
||||||
|
// Save for later unhooking
|
||||||
|
env->GetJavaVM(&g_jvm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (className == "com/android/internal/os/Zygote"sv) {
|
||||||
|
newMethods = make_unique<JNINativeMethod[]>(numMethods);
|
||||||
|
memcpy(newMethods.get(), methods, sizeof(JNINativeMethod) * numMethods);
|
||||||
|
for (int i = 0; i < numMethods && hooked < 3; ++i) {
|
||||||
|
HOOK_JNI(nativeForkAndSpecialize);
|
||||||
|
HOOK_JNI(nativeSpecializeAppProcess);
|
||||||
|
HOOK_JNI(nativeForkSystemServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return old_jniRegisterNativeMethods(env, className, newMethods.get() ?: methods, numMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
DCL_HOOK_FUNC(int, fork) {
|
||||||
|
if (prev_fork_pid < 0)
|
||||||
|
return old_fork();
|
||||||
|
|
||||||
|
// Skip an actual fork and return the previous fork result
|
||||||
|
int pid = prev_fork_pid;
|
||||||
|
prev_fork_pid = -1;
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCL_HOOK_FUNC(int, selinux_android_setcontext,
|
||||||
|
uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname) {
|
||||||
|
if (current_ctx && current_ctx->do_hide) {
|
||||||
|
// Ask magiskd to hide ourselves before switching context
|
||||||
|
// because magiskd socket is not accessible on Android 8.0+
|
||||||
|
remote_request_hide();
|
||||||
|
LOGD("hook: process successfully hidden\n");
|
||||||
|
}
|
||||||
|
return old_selinux_android_setcontext(uid, isSystemServer, seinfo, pkgname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sigmask(int how, int signum) {
|
||||||
|
sigset_t set;
|
||||||
|
sigemptyset(&set);
|
||||||
|
sigaddset(&set, signum);
|
||||||
|
return sigprocmask(how, &set, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pre_specialize_fork() {
|
||||||
|
// First block SIGCHLD, unblock after original fork is done
|
||||||
|
sigmask(SIG_BLOCK, SIGCHLD);
|
||||||
|
prev_fork_pid = old_fork();
|
||||||
|
return prev_fork_pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
static void nativeSpecializeAppProcess_pre(HookContext *ctx,
|
||||||
|
JNIEnv *env, jclass clazz, jint &uid, jint &gid, jintArray &gids, jint &runtime_flags,
|
||||||
|
jobjectArray &rlimits, jint &mount_external, jstring &se_info, jstring &nice_name,
|
||||||
|
jboolean &is_child_zygote, jstring &instruction_set, jstring &app_data_dir,
|
||||||
|
jboolean &is_top_app, jobjectArray &pkg_data_info_list,
|
||||||
|
jobjectArray &whitelisted_data_info_list, jboolean &mount_data_dirs,
|
||||||
|
jboolean &mount_storage_dirs) {
|
||||||
|
|
||||||
|
current_ctx = ctx;
|
||||||
|
|
||||||
|
const char *process = env->GetStringUTFChars(nice_name, nullptr);
|
||||||
|
LOGD("hook: %s %s\n", __FUNCTION__, process);
|
||||||
|
|
||||||
|
if (mount_external != 0 /* TODO: Handle MOUNT_EXTERNAL_NONE cases */
|
||||||
|
&& remote_check_hide(uid, process)) {
|
||||||
|
ctx->do_hide = true;
|
||||||
|
LOGI("hook: [%s] should be hidden\n", process);
|
||||||
|
}
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(nice_name, process);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nativeSpecializeAppProcess_post(HookContext *ctx, JNIEnv *env, jclass clazz) {
|
||||||
|
LOGD("hook: %s\n", __FUNCTION__);
|
||||||
|
|
||||||
|
if (ctx->do_hide)
|
||||||
|
self_unload();
|
||||||
|
|
||||||
|
current_ctx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
static void nativeForkAndSpecialize_pre(HookContext *ctx,
|
||||||
|
JNIEnv *env, jclass clazz, jint &uid, jint &gid, jintArray &gids, jint &runtime_flags,
|
||||||
|
jobjectArray &rlimits, jint &mount_external, jstring &se_info, jstring &nice_name,
|
||||||
|
jintArray fds_to_close, jintArray fds_to_ignore, /* These 2 arguments are unique to fork */
|
||||||
|
jboolean &is_child_zygote, jstring &instruction_set, jstring &app_data_dir,
|
||||||
|
jboolean &is_top_app, jobjectArray &pkg_data_info_list,
|
||||||
|
jobjectArray &whitelisted_data_info_list, jboolean &mount_data_dirs,
|
||||||
|
jboolean &mount_storage_dirs) {
|
||||||
|
|
||||||
|
// Do our own fork before loading any 3rd party code
|
||||||
|
ctx->pid = pre_specialize_fork();
|
||||||
|
if (ctx->pid != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nativeSpecializeAppProcess_pre(
|
||||||
|
ctx, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
|
||||||
|
nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app,
|
||||||
|
pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nativeForkAndSpecialize_post(HookContext *ctx, JNIEnv *env, jclass clazz) {
|
||||||
|
// Unblock SIGCHLD in case the original method didn't
|
||||||
|
sigmask(SIG_UNBLOCK, SIGCHLD);
|
||||||
|
if (ctx->pid != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nativeSpecializeAppProcess_post(ctx, env, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
static void nativeForkSystemServer_pre(HookContext *ctx,
|
||||||
|
JNIEnv *env, jclass clazz, uid_t &uid, gid_t &gid, jintArray &gids, jint &runtime_flags,
|
||||||
|
jobjectArray &rlimits, jlong &permitted_capabilities, jlong &effective_capabilities) {
|
||||||
|
|
||||||
|
// Do our own fork before loading any 3rd party code
|
||||||
|
ctx->pid = pre_specialize_fork();
|
||||||
|
if (ctx->pid != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
current_ctx = ctx;
|
||||||
|
LOGD("hook: %s\n", __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nativeForkSystemServer_post(HookContext *ctx, JNIEnv *env, jclass clazz) {
|
||||||
|
// Unblock SIGCHLD in case the original method didn't
|
||||||
|
sigmask(SIG_UNBLOCK, SIGCHLD);
|
||||||
|
|
||||||
|
if (ctx->pid != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOGD("hook: %s\n", __FUNCTION__);
|
||||||
|
current_ctx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
static bool hook_refresh() {
|
||||||
|
if (xhook_refresh(0) == 0) {
|
||||||
|
xhook_clear();
|
||||||
|
LOGI("hook: xhook success\n");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
LOGE("hook: xhook failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hook_register(const char *path, const char *symbol, void *new_func, void **old_func) {
|
||||||
|
int ret = xhook_register(path, symbol, new_func, old_func);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOGE("hook: Failed to register hook \"%s\"\n", symbol);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
xhook_list->emplace_back(path, symbol, old_func);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define XHOOK_REGISTER(PATH_REGEX, NAME) \
|
||||||
|
hook_register(PATH_REGEX, #NAME, (void*) new_##NAME, (void **) &old_##NAME)
|
||||||
|
|
||||||
|
void hook_functions() {
|
||||||
|
#ifdef MAGISK_DEBUG
|
||||||
|
xhook_enable_debug(1);
|
||||||
|
xhook_enable_sigsegv_protection(0);
|
||||||
|
#endif
|
||||||
|
xhook_list = new remove_pointer_t<decltype(xhook_list)>();
|
||||||
|
jni_list = new remove_pointer_t<decltype(jni_list)>();
|
||||||
|
|
||||||
|
XHOOK_REGISTER(".*\\libandroid_runtime.so$", jniRegisterNativeMethods);
|
||||||
|
XHOOK_REGISTER(".*\\libandroid_runtime.so$", fork);
|
||||||
|
XHOOK_REGISTER(".*\\libandroid_runtime.so$", selinux_android_setcontext);
|
||||||
|
hook_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unhook_functions() {
|
||||||
|
JNIEnv* env;
|
||||||
|
if (g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Unhook JNI methods
|
||||||
|
if (!jni_list->empty() && old_jniRegisterNativeMethods(env,
|
||||||
|
"com/android/internal/os/Zygote",
|
||||||
|
jni_list->data(), jni_list->size()) != 0) {
|
||||||
|
LOGE("hook: Failed to register JNI hook\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
delete jni_list;
|
||||||
|
|
||||||
|
// Unhook xhook
|
||||||
|
for (auto &[path, sym, old_func] : *xhook_list) {
|
||||||
|
if (xhook_register(path, sym, *old_func, nullptr) != 0) {
|
||||||
|
LOGE("hook: Failed to register hook \"%s\"\n", sym);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete xhook_list;
|
||||||
|
return hook_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "jni_hooks.hpp"
|
22
native/jni/inject/inject.hpp
Normal file
22
native/jni/inject/inject.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#define INJECT_LIB_1 "/dev/tmp/magisk.1.so"
|
||||||
|
#define INJECT_LIB_2 "/dev/tmp/magisk.2.so"
|
||||||
|
#define INJECT_ENV_1 "MAGISK_INJ_1"
|
||||||
|
#define INJECT_ENV_2 "MAGISK_INJ_2"
|
||||||
|
|
||||||
|
// Unmap all pages matching the name
|
||||||
|
void unmap_all(const char *name);
|
||||||
|
|
||||||
|
// Get library name and base address that contains the function
|
||||||
|
uintptr_t get_function_lib(uintptr_t addr, char *lib);
|
||||||
|
|
||||||
|
// Get library base address with name
|
||||||
|
uintptr_t get_remote_lib(int pid, const char *lib);
|
||||||
|
|
||||||
|
void self_unload();
|
||||||
|
void hook_functions();
|
||||||
|
bool unhook_functions();
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user