mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-19 10:42:46 -08:00
Compare commits
34 Commits
v21.2
...
manager-v8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- 'app/**'
|
||||
- 'native/**'
|
||||
- 'stub/**'
|
||||
- 'buildSrc/**'
|
||||
- 'build.py'
|
||||
- 'gradle.properties'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
@@ -43,6 +50,7 @@ jobs:
|
||||
echo "ANDROID_SDK_ROOT=$sdk_root" >> $env:GITHUB_ENV
|
||||
echo "ANDROID_HOME=$sdk_root" >> $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)
|
||||
if: runner.os != 'Windows'
|
||||
@@ -57,7 +65,6 @@ jobs:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/**/*.lock
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -25,6 +25,9 @@
|
||||
[submodule "pcre"]
|
||||
path = native/jni/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"]
|
||||
path = tools/termux-elf-cleaner
|
||||
url = https://github.com/termux/termux-elf-cleaner.git
|
||||
|
||||
@@ -15,11 +15,11 @@ Here are some feature highlights:
|
||||
|
||||
## 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.4/MagiskManager-v8.0.4.apk)
|
||||
[](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
|
||||
<br>
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v20.4)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.1)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v21.2)
|
||||
|
||||
## Useful Links
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ object Const {
|
||||
fun atLeast_20_2() = Info.env.magiskVersionCode >= 20200 || isCanary()
|
||||
fun atLeast_20_4() = Info.env.magiskVersionCode >= 20400 || 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
|
||||
}
|
||||
|
||||
@@ -36,7 +37,6 @@ object Const {
|
||||
// notifications
|
||||
const val MAGISK_UPDATE_NOTIFICATION_ID = 4
|
||||
const val APK_UPDATE_NOTIFICATION_ID = 5
|
||||
const val HIDE_MANAGER_NOTIFICATION_ID = 8
|
||||
const val UPDATE_NOTIFICATION_CHANNEL = "update"
|
||||
const val PROGRESS_NOTIFICATION_CHANNEL = "progress"
|
||||
const val CHECK_MAGISK_UPDATE_WORKER_ID = "magisk_update"
|
||||
|
||||
@@ -27,13 +27,13 @@ class LocalModule(path: String) : Module() {
|
||||
val dir = "$PERSIST/$id"
|
||||
if (enable) {
|
||||
disableFile.delete()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
|
||||
} else {
|
||||
!disableFile.createNewFile()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("rm -rf $dir").submit()
|
||||
@@ -45,13 +45,13 @@ class LocalModule(path: String) : Module() {
|
||||
set(remove) {
|
||||
if (remove) {
|
||||
removeFile.createNewFile()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("rm -rf $PERSIST/$id").submit()
|
||||
} else {
|
||||
!removeFile.delete()
|
||||
if (Const.Version.isCanary())
|
||||
if (Const.Version.atLeast_21_2())
|
||||
Shell.su("copy_sepolicy_rules").submit()
|
||||
else
|
||||
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
|
||||
|
||||
@@ -7,9 +7,11 @@ import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
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.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS
|
||||
import android.content.pm.ServiceInfo.FLAG_USE_APP_ZYGOTE
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
@@ -57,32 +59,10 @@ import java.lang.reflect.Array as JArray
|
||||
|
||||
val packageName: String get() = get<Context>().packageName
|
||||
|
||||
val ApplicationInfo.processes: List<String> @SuppressLint("InlinedApi") get() {
|
||||
val pm = get<PackageManager>()
|
||||
val appProcessName = processName ?: packageName
|
||||
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 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()
|
||||
}
|
||||
}
|
||||
val ServiceInfo.isIsolated get() = (flags and FLAG_ISOLATED_PROCESS) != 0
|
||||
|
||||
@get:SuppressLint("InlinedApi")
|
||||
val ServiceInfo.useAppZygote get() = (flags and FLAG_USE_APP_ZYGOTE) != 0
|
||||
|
||||
fun Context.rawResource(id: Int) = resources.openRawResource(id)
|
||||
|
||||
|
||||
@@ -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 kotlin.math.roundToInt
|
||||
|
||||
class HideItem(
|
||||
app: HideAppTarget
|
||||
) : ObservableItem<HideItem>(), Comparable<HideItem> {
|
||||
class HideRvItem(
|
||||
val info: HideAppInfo
|
||||
) : 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 = app.processes.map { HideProcessItem(it) }
|
||||
val processes = info.processes.map { HideProcessRvItem(it) }
|
||||
|
||||
@get:Bindable
|
||||
var isExpanded = false
|
||||
@@ -41,11 +40,10 @@ class HideItem(
|
||||
if (value == true) {
|
||||
processes
|
||||
.filterNot { it.isHidden }
|
||||
.filter { isExpanded || it.process.name == it.process.packageName }
|
||||
.filter { isExpanded || it.defaultSelection }
|
||||
} else {
|
||||
processes
|
||||
.filter { it.isHidden }
|
||||
.filter { isExpanded || it.process.name == it.process.packageName }
|
||||
}.forEach { it.toggle() }
|
||||
}
|
||||
|
||||
@@ -69,14 +67,19 @@ class HideItem(
|
||||
else -> null
|
||||
}
|
||||
} 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 {
|
||||
private val comparator = compareBy<HideItem>(
|
||||
private val comparator = compareBy<HideRvItem>(
|
||||
{ it.itemsChecked == 0 },
|
||||
{ it.info }
|
||||
)
|
||||
@@ -84,16 +87,17 @@ class HideItem(
|
||||
|
||||
}
|
||||
|
||||
class HideProcessItem(
|
||||
class HideProcessRvItem(
|
||||
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
|
||||
var isHidden = process.isHidden
|
||||
set(value) = set(value, field, { field = it }, BR.hidden) {
|
||||
val arg = if (isHidden) "add" else "rm"
|
||||
var isHidden
|
||||
get() = process.isHidden
|
||||
set(value) = set(value, process.isHidden, { process.isHidden = it }, BR.hidden) {
|
||||
val arg = if (it) "add" else "rm"
|
||||
val (name, pkg) = process
|
||||
Shell.su("magiskhide --$arg $pkg $name").submit()
|
||||
}
|
||||
@@ -102,7 +106,10 @@ class HideProcessItem(
|
||||
isHidden = !isHidden
|
||||
}
|
||||
|
||||
override fun contentSameAs(other: HideProcessItem) = process == other.process
|
||||
override fun itemSameAs(other: HideProcessItem) = process.name == other.process.name
|
||||
val defaultSelection get() =
|
||||
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.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
import android.os.Process
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -14,7 +15,6 @@ import com.topjohnwu.magisk.arch.itemBindingOf
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import com.topjohnwu.magisk.ktx.packageName
|
||||
import com.topjohnwu.magisk.ktx.processes
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.set
|
||||
import com.topjohnwu.superuser.Shell
|
||||
@@ -45,11 +45,11 @@ class HideViewModel : BaseViewModel(), Queryable {
|
||||
submitQuery()
|
||||
}
|
||||
|
||||
val items = filterableListOf<HideItem>()
|
||||
val itemBinding = itemBindingOf<HideItem> {
|
||||
val items = filterableListOf<HideRvItem>()
|
||||
val itemBinding = itemBindingOf<HideRvItem> {
|
||||
it.bindExtra(BR.viewModel, this)
|
||||
}
|
||||
val itemInternalBinding = itemBindingOf<HideProcessItem> {
|
||||
val itemInternalBinding = itemBindingOf<HideProcessRvItem> {
|
||||
it.bindExtra(BR.viewModel, this)
|
||||
}
|
||||
|
||||
@@ -62,14 +62,13 @@ class HideViewModel : BaseViewModel(), Queryable {
|
||||
state = State.LOADING
|
||||
val (apps, diff) = withContext(Dispatchers.Default) {
|
||||
val pm = get<PackageManager>()
|
||||
val hides = Shell.su("magiskhide --ls").exec().out.map { HideTarget(it) }
|
||||
val apps = pm.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES)
|
||||
val hideList = Shell.su("magiskhide --ls").exec().out.map { CmdlineHiddenItem(it) }
|
||||
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES)
|
||||
.asSequence()
|
||||
.filter { it.enabled && !blacklist.contains(it.packageName) }
|
||||
.map { HideAppInfo(it, pm) }
|
||||
.map { createTarget(it, hides) }
|
||||
.map { HideAppInfo(it, pm, hideList) }
|
||||
.filter { it.processes.isNotEmpty() }
|
||||
.map { HideItem(it) }
|
||||
.map { HideRvItem(it) }
|
||||
.toList()
|
||||
.sorted()
|
||||
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() {
|
||||
items.filter {
|
||||
fun showHidden() = it.itemsChecked != 0
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.topjohnwu.magisk.ui.hide.HideItem" />
|
||||
type="com.topjohnwu.magisk.ui.hide.HideRvItem" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.topjohnwu.magisk.ui.hide.HideProcessItem" />
|
||||
type="com.topjohnwu.magisk.ui.hide.HideProcessRvItem" />
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## v8.0.5
|
||||
|
||||
- Fix sepolicy rule copying
|
||||
|
||||
## v8.0.4
|
||||
|
||||
- A lot of stability changes and minor bug fixes
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<string name="no_connection">Keine Verbindung verfügbar</string>
|
||||
<string name="app_changelog">Änderungen</string>
|
||||
<string name="manager">Manager</string>
|
||||
<string name="loading">Lädt…</string>
|
||||
<string name="loading">Laden…</string>
|
||||
<string name="update">Update</string>
|
||||
<string name="not_available">N/A</string>
|
||||
<string name="hide">Verstecken</string>
|
||||
@@ -40,7 +40,7 @@
|
||||
<string name="recovery_mode">Recovery Modus</string>
|
||||
<string name="install_options_title">Optionen</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="manager_download_install">Tippen zum Herunterladen und Installieren</string>
|
||||
<string name="download_zip_only">Nur Zip herunterladen</string>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="install_next">Ďalej</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="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="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>
|
||||
|
||||
@@ -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_status_normal">Normale</string>
|
||||
<string name="home_status_stub">Stub</string>
|
||||
<string name="home_installed_version">Instaluar</string>
|
||||
<string name="home_latest_version">Më të fundit</string>
|
||||
<string name="home_installed_version">E instaluar</string>
|
||||
<string name="home_latest_version">Më e fundit</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_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>
|
||||
|
||||
<!--Install-->
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="safetynet_res_invalid">Përgjigjja është e pavlefshme </string>
|
||||
<string name="safetynet_attest_success">Suksese!</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>
|
||||
|
||||
<!--MagiskHide-->
|
||||
@@ -111,7 +111,7 @@
|
||||
<string name="reboot_userspace">Ristartim normal</string>
|
||||
<string name="reboot_recovery">Ristartoni në recovery</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="module_version_author">%1$s nga %2$s</string>
|
||||
<string name="module_state_remove">Hiq</string>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Release Notes
|
||||
|
||||
- [v21.2](21200.md)
|
||||
- [v21.1](21100.md)
|
||||
- [v21.0](21000.md)
|
||||
- [v20.4](20400.md)
|
||||
|
||||
@@ -27,6 +27,6 @@ android.injected.testOnly=false
|
||||
kapt.incremental.apt=true
|
||||
|
||||
# Magisk
|
||||
magisk.versionCode=21200
|
||||
magisk.versionCode=21201
|
||||
magisk.ndkVersion=21d
|
||||
magisk.fullNdkVersion=21.3.6528147
|
||||
|
||||
@@ -8,29 +8,32 @@ ifdef B_MAGISK
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magisk
|
||||
LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils
|
||||
LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils libxhook
|
||||
LOCAL_C_INCLUDES := jni/include
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
core/applets.cpp \
|
||||
core/magisk.cpp \
|
||||
core/daemon.cpp \
|
||||
core/bootstages.cpp \
|
||||
core/socket.cpp \
|
||||
core/db.cpp \
|
||||
core/scripting.cpp \
|
||||
core/restorecon.cpp \
|
||||
core/module.cpp \
|
||||
magiskhide/magiskhide.cpp \
|
||||
magiskhide/proc_monitor.cpp \
|
||||
magiskhide/hide_utils.cpp \
|
||||
magiskhide/hide_policy.cpp \
|
||||
resetprop/persist_properties.cpp \
|
||||
resetprop/resetprop.cpp \
|
||||
su/su.cpp \
|
||||
su/connect.cpp \
|
||||
su/pts.cpp \
|
||||
su/su_daemon.cpp
|
||||
core/applets.cpp \
|
||||
core/magisk.cpp \
|
||||
core/daemon.cpp \
|
||||
core/bootstages.cpp \
|
||||
core/socket.cpp \
|
||||
core/db.cpp \
|
||||
core/scripting.cpp \
|
||||
core/restorecon.cpp \
|
||||
core/module.cpp \
|
||||
magiskhide/magiskhide.cpp \
|
||||
magiskhide/proc_monitor.cpp \
|
||||
magiskhide/hide_utils.cpp \
|
||||
magiskhide/hide_policy.cpp \
|
||||
resetprop/persist_properties.cpp \
|
||||
resetprop/resetprop.cpp \
|
||||
su/su.cpp \
|
||||
su/connect.cpp \
|
||||
su/pts.cpp \
|
||||
su/su_daemon.cpp \
|
||||
inject/entry.cpp \
|
||||
inject/utils.cpp \
|
||||
inject/hook.cpp
|
||||
|
||||
LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_EXECUTABLE)
|
||||
@@ -52,24 +55,24 @@ ifdef BB_INIT
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libsepol libxz libutils
|
||||
LOCAL_C_INCLUDES := \
|
||||
jni/include \
|
||||
out \
|
||||
out/$(TARGET_ARCH_ABI)
|
||||
jni/include \
|
||||
out \
|
||||
out/$(TARGET_ARCH_ABI)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
init/init.cpp \
|
||||
init/mount.cpp \
|
||||
init/rootdir.cpp \
|
||||
init/getinfo.cpp \
|
||||
init/twostage.cpp \
|
||||
init/raw_data.cpp \
|
||||
core/socket.cpp \
|
||||
magiskpolicy/sepolicy.cpp \
|
||||
magiskpolicy/magiskpolicy.cpp \
|
||||
magiskpolicy/rules.cpp \
|
||||
magiskpolicy/policydb.cpp \
|
||||
magiskpolicy/statement.cpp \
|
||||
magiskboot/pattern.cpp
|
||||
init/init.cpp \
|
||||
init/mount.cpp \
|
||||
init/rootdir.cpp \
|
||||
init/getinfo.cpp \
|
||||
init/twostage.cpp \
|
||||
init/raw_data.cpp \
|
||||
core/socket.cpp \
|
||||
magiskpolicy/sepolicy.cpp \
|
||||
magiskpolicy/magiskpolicy.cpp \
|
||||
magiskpolicy/rules.cpp \
|
||||
magiskpolicy/policydb.cpp \
|
||||
magiskpolicy/statement.cpp \
|
||||
magiskboot/pattern.cpp
|
||||
|
||||
LOCAL_LDFLAGS := -static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
@@ -84,15 +87,15 @@ LOCAL_STATIC_LIBRARIES := libmincrypt liblzma liblz4 libbz2 libfdt libutils
|
||||
LOCAL_C_INCLUDES := jni/include
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
magiskboot/main.cpp \
|
||||
magiskboot/bootimg.cpp \
|
||||
magiskboot/hexpatch.cpp \
|
||||
magiskboot/compress.cpp \
|
||||
magiskboot/format.cpp \
|
||||
magiskboot/dtb.cpp \
|
||||
magiskboot/ramdisk.cpp \
|
||||
magiskboot/pattern.cpp \
|
||||
utils/cpio.cpp
|
||||
magiskboot/main.cpp \
|
||||
magiskboot/bootimg.cpp \
|
||||
magiskboot/hexpatch.cpp \
|
||||
magiskboot/compress.cpp \
|
||||
magiskboot/format.cpp \
|
||||
magiskboot/dtb.cpp \
|
||||
magiskboot/ramdisk.cpp \
|
||||
magiskboot/pattern.cpp \
|
||||
utils/cpio.cpp
|
||||
|
||||
LOCAL_LDLIBS := -lz
|
||||
LOCAL_LDFLAGS := -static
|
||||
@@ -108,12 +111,12 @@ LOCAL_STATIC_LIBRARIES := libsepol libutils
|
||||
LOCAL_C_INCLUDES := jni/include
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
core/applet_stub.cpp \
|
||||
magiskpolicy/sepolicy.cpp \
|
||||
magiskpolicy/magiskpolicy.cpp \
|
||||
magiskpolicy/rules.cpp \
|
||||
magiskpolicy/policydb.cpp \
|
||||
magiskpolicy/statement.cpp
|
||||
core/applet_stub.cpp \
|
||||
magiskpolicy/sepolicy.cpp \
|
||||
magiskpolicy/magiskpolicy.cpp \
|
||||
magiskpolicy/rules.cpp \
|
||||
magiskpolicy/policydb.cpp \
|
||||
magiskpolicy/statement.cpp
|
||||
|
||||
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=magiskpolicy_main
|
||||
LOCAL_LDFLAGS := -static
|
||||
@@ -129,9 +132,9 @@ LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils
|
||||
LOCAL_C_INCLUDES := jni/include
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
core/applet_stub.cpp \
|
||||
resetprop/persist_properties.cpp \
|
||||
resetprop/resetprop.cpp \
|
||||
core/applet_stub.cpp \
|
||||
resetprop/persist_properties.cpp \
|
||||
resetprop/resetprop.cpp \
|
||||
|
||||
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=resetprop_main
|
||||
LOCAL_LDFLAGS := -static
|
||||
@@ -140,15 +143,16 @@ include $(BUILD_EXECUTABLE)
|
||||
endif
|
||||
|
||||
ifdef B_TEST
|
||||
ifneq (,$(wildcard jni/test.cpp))
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := test
|
||||
LOCAL_STATIC_LIBRARIES := libutils
|
||||
LOCAL_C_INCLUDES := jni/include
|
||||
LOCAL_SRC_FILES := test.cpp
|
||||
LOCAL_LDFLAGS := -static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef B_BB
|
||||
@@ -161,5 +165,4 @@ endif
|
||||
# Libraries
|
||||
########################
|
||||
include jni/utils/Android.mk
|
||||
include jni/systemproperties/Android.mk
|
||||
include jni/external/Android.mk
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <utils.hpp>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
cmdline_logging();
|
||||
return APPLET_STUB_MAIN(argc, argv);
|
||||
umask(0);
|
||||
cmdline_logging();
|
||||
return APPLET_STUB_MAIN(argc, argv);
|
||||
}
|
||||
|
||||
@@ -8,39 +8,44 @@
|
||||
#include <selinux.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
using namespace std;
|
||||
|
||||
using main_fun = int (*)(int, char *[]);
|
||||
|
||||
static main_fun applet_main[] = { su_client_main, resetprop_main, magiskhide_main, nullptr };
|
||||
|
||||
[[noreturn]] static void call_applet(int argc, char **argv) {
|
||||
// Applets
|
||||
for (int i = 0; applet_names[i]; ++i) {
|
||||
if (strcmp(basename(argv[0]), applet_names[i]) == 0) {
|
||||
exit((*applet_main[i])(argc, argv));
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
|
||||
exit(1);
|
||||
static int call_applet(int argc, char *argv[]) {
|
||||
// Applets
|
||||
string_view base = basename(argv[0]);
|
||||
for (int i = 0; applet_names[i]; ++i) {
|
||||
if (base == applet_names[i]) {
|
||||
return (*applet_main[i])(argc, argv);
|
||||
}
|
||||
}
|
||||
if (str_starts(base, "app_process")) {
|
||||
return app_process_main(argc, argv);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: applet not found\n", base.data());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
dload_selinux();
|
||||
cmdline_logging();
|
||||
init_argv0(argc, argv);
|
||||
umask(0);
|
||||
dload_selinux();
|
||||
cmdline_logging();
|
||||
init_argv0(argc, argv);
|
||||
|
||||
if (basename(argv[0]) == "magisk"sv) {
|
||||
if (argc > 1 && argv[1][0] != '-') {
|
||||
// Calling applet via magisk [applet] args
|
||||
--argc;
|
||||
++argv;
|
||||
} else {
|
||||
return magisk_main(argc, argv);
|
||||
}
|
||||
}
|
||||
if (basename(argv[0]) == "magisk"sv) {
|
||||
if (argc > 1 && argv[1][0] != '-') {
|
||||
// Calling applet via magisk [applet] args
|
||||
--argc;
|
||||
++argv;
|
||||
} else {
|
||||
return magisk_main(argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
call_applet(argc, argv);
|
||||
return call_applet(argc, argv);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,64 +37,64 @@ static bool safe_mode = false;
|
||||
|
||||
#define mount_mirror(part, flag) \
|
||||
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) \
|
||||
SETMIR(buf1, part); \
|
||||
if (access("/system/" #part, F_OK) == 0 && access(buf1, F_OK) != 0) { \
|
||||
xsymlink("./system/" #part, buf1); \
|
||||
LOGI("link: %s\n", buf1); \
|
||||
xsymlink("./system/" #part, buf1); \
|
||||
LOGI("link: %s\n", buf1); \
|
||||
}
|
||||
|
||||
#define link_orig_dir(dir, part) \
|
||||
else if (MNT_DIR_IS(dir) && me->mnt_type != "tmpfs"sv) { \
|
||||
SETMIR(buf1, part); \
|
||||
rmdir(buf1); \
|
||||
xsymlink(dir, buf1); \
|
||||
LOGI("link: %s\n", buf1); \
|
||||
SETMIR(buf1, part); \
|
||||
rmdir(buf1); \
|
||||
xsymlink(dir, buf1); \
|
||||
LOGI("link: %s\n", buf1); \
|
||||
}
|
||||
|
||||
#define link_orig(part) link_orig_dir("/" #part, part)
|
||||
|
||||
static void mount_mirrors() {
|
||||
char buf1[4096];
|
||||
char buf2[4096];
|
||||
char buf1[4096];
|
||||
char buf2[4096];
|
||||
|
||||
LOGI("* Mounting mirrors\n");
|
||||
LOGI("* Mounting mirrors\n");
|
||||
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
struct stat st;
|
||||
if (0) {}
|
||||
mount_mirror(system, MS_RDONLY)
|
||||
mount_mirror(vendor, MS_RDONLY)
|
||||
mount_mirror(product, MS_RDONLY)
|
||||
mount_mirror(system_ext, MS_RDONLY)
|
||||
mount_mirror(data, 0)
|
||||
link_orig(cache)
|
||||
link_orig(metadata)
|
||||
link_orig(persist)
|
||||
link_orig_dir("/mnt/vendor/persist", persist)
|
||||
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");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
SETMIR(buf1, system);
|
||||
if (access(buf1, F_OK) != 0) {
|
||||
xsymlink("./system_root/system", buf1);
|
||||
LOGI("link: %s\n", buf1);
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
struct stat st;
|
||||
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
|
||||
do_mount_mirror(system_root, MS_RDONLY)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
link_mirror(vendor)
|
||||
link_mirror(product)
|
||||
link_mirror(system_ext)
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
struct stat st;
|
||||
if (0) {}
|
||||
mount_mirror(system, MS_RDONLY)
|
||||
mount_mirror(vendor, MS_RDONLY)
|
||||
mount_mirror(product, MS_RDONLY)
|
||||
mount_mirror(system_ext, MS_RDONLY)
|
||||
mount_mirror(data, 0)
|
||||
link_orig(cache)
|
||||
link_orig(metadata)
|
||||
link_orig(persist)
|
||||
link_orig_dir("/mnt/vendor/persist", persist)
|
||||
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");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
SETMIR(buf1, system);
|
||||
if (access(buf1, F_OK) != 0) {
|
||||
xsymlink("./system_root/system", buf1);
|
||||
LOGI("link: %s\n", buf1);
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
struct stat st;
|
||||
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
|
||||
do_mount_mirror(system_root, MS_RDONLY)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
link_mirror(vendor)
|
||||
link_mirror(product)
|
||||
link_mirror(system_ext)
|
||||
}
|
||||
|
||||
constexpr char bb_script[] = R"EOF(
|
||||
@@ -105,167 +105,167 @@ exec /data/adb/magisk/busybox.bin "$@"
|
||||
)EOF";
|
||||
|
||||
static bool magisk_env() {
|
||||
char buf[4096];
|
||||
char buf[4096];
|
||||
|
||||
LOGI("* Initializing Magisk environment\n");
|
||||
LOGI("* Initializing Magisk environment\n");
|
||||
|
||||
string pkg;
|
||||
check_manager(&pkg);
|
||||
string 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
|
||||
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
|
||||
for (auto alt : alt_bin) {
|
||||
struct stat st;
|
||||
if (lstat(alt, &st) == 0) {
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
unlink(alt);
|
||||
continue;
|
||||
}
|
||||
rm_rf(DATABIN);
|
||||
cp_afc(alt, DATABIN);
|
||||
rm_rf(alt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Alternative binaries paths
|
||||
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
|
||||
for (auto alt : alt_bin) {
|
||||
struct stat st;
|
||||
if (lstat(alt, &st) == 0) {
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
unlink(alt);
|
||||
continue;
|
||||
}
|
||||
rm_rf(DATABIN);
|
||||
cp_afc(alt, DATABIN);
|
||||
rm_rf(alt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove stuffs
|
||||
rm_rf("/cache/data_adb");
|
||||
rm_rf("/data/adb/modules/.core");
|
||||
unlink("/data/adb/magisk.img");
|
||||
unlink("/data/adb/magisk_merge.img");
|
||||
unlink("/data/magisk.img");
|
||||
unlink("/data/magisk_merge.img");
|
||||
unlink("/data/magisk_debug.log");
|
||||
// Remove stuffs
|
||||
rm_rf("/cache/data_adb");
|
||||
rm_rf("/data/adb/modules/.core");
|
||||
unlink("/data/adb/magisk.img");
|
||||
unlink("/data/adb/magisk_merge.img");
|
||||
unlink("/data/magisk.img");
|
||||
unlink("/data/magisk_merge.img");
|
||||
unlink("/data/magisk_debug.log");
|
||||
|
||||
// Directories in /data/adb
|
||||
xmkdir(DATABIN, 0755);
|
||||
xmkdir(MODULEROOT, 0755);
|
||||
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
|
||||
xmkdir(SECURE_DIR "/service.d", 0755);
|
||||
// Directories in /data/adb
|
||||
xmkdir(DATABIN, 0755);
|
||||
xmkdir(MODULEROOT, 0755);
|
||||
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
|
||||
xmkdir(SECURE_DIR "/service.d", 0755);
|
||||
|
||||
// Disable/remove magiskhide, resetprop
|
||||
if (SDK_INT < 19) {
|
||||
unlink("/sbin/resetprop");
|
||||
unlink("/sbin/magiskhide");
|
||||
}
|
||||
// Disable/remove magiskhide, resetprop
|
||||
if (SDK_INT < 19) {
|
||||
unlink("/sbin/resetprop");
|
||||
unlink("/sbin/magiskhide");
|
||||
}
|
||||
|
||||
if (access(DATABIN "/busybox.bin", X_OK)) {
|
||||
if (access(DATABIN "/busybox", X_OK))
|
||||
return false;
|
||||
rename(DATABIN "/busybox", DATABIN "/busybox.bin");
|
||||
}
|
||||
if (access(DATABIN "/busybox.bin", X_OK)) {
|
||||
if (access(DATABIN "/busybox", X_OK))
|
||||
return false;
|
||||
rename(DATABIN "/busybox", DATABIN "/busybox.bin");
|
||||
}
|
||||
|
||||
sprintf(buf, "%s/" BBPATH "/busybox", MAGISKTMP.data());
|
||||
{
|
||||
auto fp = open_file(DATABIN "/busybox", "we");
|
||||
fprintf(fp.get(), bb_script, buf);
|
||||
}
|
||||
chmod(DATABIN "/busybox", 0755);
|
||||
mkdir(dirname(buf), 0755);
|
||||
cp_afc(DATABIN "/busybox.bin", buf);
|
||||
exec_command_async(buf, "--install", "-s", dirname(buf));
|
||||
sprintf(buf, "%s/" BBPATH "/busybox", MAGISKTMP.data());
|
||||
{
|
||||
auto fp = open_file(DATABIN "/busybox", "we");
|
||||
fprintf(fp.get(), bb_script, buf);
|
||||
}
|
||||
chmod(DATABIN "/busybox", 0755);
|
||||
mkdir(dirname(buf), 0755);
|
||||
cp_afc(DATABIN "/busybox.bin", buf);
|
||||
exec_command_async(buf, "--install", "-s", dirname(buf));
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void reboot() {
|
||||
if (RECOVERY_MODE)
|
||||
exec_command_sync("/system/bin/reboot", "recovery");
|
||||
else
|
||||
exec_command_sync("/system/bin/reboot");
|
||||
if (RECOVERY_MODE)
|
||||
exec_command_sync("/system/bin/reboot", "recovery");
|
||||
else
|
||||
exec_command_sync("/system/bin/reboot");
|
||||
}
|
||||
|
||||
static bool check_data() {
|
||||
bool mnt = false;
|
||||
file_readline("/proc/mounts", [&](string_view s) {
|
||||
if (str_contains(s, " /data ") && !str_contains(s, "tmpfs")) {
|
||||
mnt = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!mnt)
|
||||
return false;
|
||||
auto crypto = getprop("ro.crypto.state");
|
||||
if (!crypto.empty()) {
|
||||
if (crypto == "unencrypted") {
|
||||
// Unencrypted, we can directly access data
|
||||
return true;
|
||||
} else {
|
||||
// Encrypted, check whether vold is started
|
||||
return !getprop("init.svc.vold").empty();
|
||||
}
|
||||
}
|
||||
// ro.crypto.state is not set, assume it's unencrypted
|
||||
return true;
|
||||
bool mnt = false;
|
||||
file_readline("/proc/mounts", [&](string_view s) {
|
||||
if (str_contains(s, " /data ") && !str_contains(s, "tmpfs")) {
|
||||
mnt = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!mnt)
|
||||
return false;
|
||||
auto crypto = getprop("ro.crypto.state");
|
||||
if (!crypto.empty()) {
|
||||
if (crypto == "unencrypted") {
|
||||
// Unencrypted, we can directly access data
|
||||
return true;
|
||||
} else {
|
||||
// Encrypted, check whether vold is started
|
||||
return !getprop("init.svc.vold").empty();
|
||||
}
|
||||
}
|
||||
// ro.crypto.state is not set, assume it's unencrypted
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock_blocks() {
|
||||
int fd, dev, OFF = 0;
|
||||
int fd, dev, OFF = 0;
|
||||
|
||||
auto dir = xopen_dir("/dev/block");
|
||||
if (!dir)
|
||||
return;
|
||||
dev = dirfd(dir.get());
|
||||
auto dir = xopen_dir("/dev/block");
|
||||
if (!dir)
|
||||
return;
|
||||
dev = dirfd(dir.get());
|
||||
|
||||
for (dirent *entry; (entry = readdir(dir.get()));) {
|
||||
if (entry->d_type == DT_BLK) {
|
||||
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
|
||||
continue;
|
||||
if (ioctl(fd, BLKROSET, &OFF) < 0)
|
||||
PLOGE("unlock %s", entry->d_name);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
for (dirent *entry; (entry = readdir(dir.get()));) {
|
||||
if (entry->d_type == DT_BLK) {
|
||||
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
|
||||
continue;
|
||||
if (ioctl(fd, BLKROSET, &OFF) < 0)
|
||||
PLOGE("unlock %s", entry->d_name);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
||||
|
||||
static bool check_key_combo() {
|
||||
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
||||
vector<int> events;
|
||||
constexpr char name[] = "/dev/.ev";
|
||||
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
||||
vector<int> events;
|
||||
constexpr char name[] = "/dev/.ev";
|
||||
|
||||
// First collect candidate events that accepts volume down
|
||||
for (int minor = 64; minor < 96; ++minor) {
|
||||
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
||||
continue;
|
||||
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
||||
unlink(name);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEDOWN, bitmask))
|
||||
events.push_back(fd);
|
||||
else
|
||||
close(fd);
|
||||
}
|
||||
if (events.empty())
|
||||
return false;
|
||||
// First collect candidate events that accepts volume down
|
||||
for (int minor = 64; minor < 96; ++minor) {
|
||||
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
||||
continue;
|
||||
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
||||
unlink(name);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEDOWN, bitmask))
|
||||
events.push_back(fd);
|
||||
else
|
||||
close(fd);
|
||||
}
|
||||
if (events.empty())
|
||||
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
|
||||
for (int i = 0; i < 300; ++i) {
|
||||
bool pressed = false;
|
||||
for (const int &fd : events) {
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
|
||||
pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pressed)
|
||||
return false;
|
||||
// Check every 10ms
|
||||
usleep(10000);
|
||||
}
|
||||
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
|
||||
return true;
|
||||
// Check if volume down key is held continuously for more than 3 seconds
|
||||
for (int i = 0; i < 300; ++i) {
|
||||
bool pressed = false;
|
||||
for (const int &fd : events) {
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
|
||||
pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pressed)
|
||||
return false;
|
||||
// Check every 10ms
|
||||
usleep(10000);
|
||||
}
|
||||
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************
|
||||
@@ -275,114 +275,114 @@ static bool check_key_combo() {
|
||||
static pthread_mutex_t stage_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void post_fs_data(int client) {
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
|
||||
mutex_guard lock(stage_lock);
|
||||
mutex_guard lock(stage_lock);
|
||||
|
||||
if (getenv("REMOUNT_ROOT"))
|
||||
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
|
||||
if (getenv("REMOUNT_ROOT"))
|
||||
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
|
||||
|
||||
if (!check_data())
|
||||
goto unblock_init;
|
||||
if (!check_data())
|
||||
goto unblock_init;
|
||||
|
||||
DAEMON_STATE = STATE_POST_FS_DATA;
|
||||
setup_logfile(true);
|
||||
DAEMON_STATE = STATE_POST_FS_DATA;
|
||||
setup_logfile(true);
|
||||
|
||||
LOGI("** post-fs-data mode running\n");
|
||||
LOGI("** post-fs-data mode running\n");
|
||||
|
||||
unlock_blocks();
|
||||
mount_mirrors();
|
||||
unlock_blocks();
|
||||
mount_mirrors();
|
||||
|
||||
if (access(SECURE_DIR, F_OK) != 0) {
|
||||
if (SDK_INT < 24) {
|
||||
// There is no FBE pre 7.0, we can directly create the folder without issues
|
||||
xmkdir(SECURE_DIR, 0700);
|
||||
} else {
|
||||
// If the folder is not automatically created by Android,
|
||||
// do NOT proceed further. Manual creation of the folder
|
||||
// will cause bootloops on FBE devices.
|
||||
LOGE(SECURE_DIR " is not present, abort\n");
|
||||
goto early_abort;
|
||||
}
|
||||
}
|
||||
if (access(SECURE_DIR, F_OK) != 0) {
|
||||
if (SDK_INT < 24) {
|
||||
// There is no FBE pre 7.0, we can directly create the folder without issues
|
||||
xmkdir(SECURE_DIR, 0700);
|
||||
} else {
|
||||
// If the folder is not automatically created by Android,
|
||||
// do NOT proceed further. Manual creation of the folder
|
||||
// will cause bootloops on FBE devices.
|
||||
LOGE(SECURE_DIR " is not present, abort\n");
|
||||
goto early_abort;
|
||||
}
|
||||
}
|
||||
|
||||
if (!magisk_env()) {
|
||||
LOGE("* Magisk environment incomplete, abort\n");
|
||||
goto early_abort;
|
||||
}
|
||||
if (!magisk_env()) {
|
||||
LOGE("* Magisk environment incomplete, abort\n");
|
||||
goto early_abort;
|
||||
}
|
||||
|
||||
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
|
||||
safe_mode = true;
|
||||
// Disable all modules and magiskhide so next boot will be clean
|
||||
disable_modules();
|
||||
stop_magiskhide();
|
||||
} else {
|
||||
exec_common_scripts("post-fs-data");
|
||||
auto_start_magiskhide();
|
||||
handle_modules();
|
||||
}
|
||||
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
|
||||
safe_mode = true;
|
||||
// Disable all modules and magiskhide so next boot will be clean
|
||||
disable_modules();
|
||||
stop_magiskhide();
|
||||
} else {
|
||||
exec_common_scripts("post-fs-data");
|
||||
auto_start_magiskhide();
|
||||
handle_modules();
|
||||
}
|
||||
|
||||
early_abort:
|
||||
// We still do magic mount because root itself might need it
|
||||
magic_mount();
|
||||
DAEMON_STATE = STATE_POST_FS_DATA_DONE;
|
||||
// We still do magic mount because root itself might need it
|
||||
magic_mount();
|
||||
DAEMON_STATE = STATE_POST_FS_DATA_DONE;
|
||||
|
||||
unblock_init:
|
||||
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
|
||||
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
|
||||
}
|
||||
|
||||
void late_start(int client) {
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
|
||||
mutex_guard lock(stage_lock);
|
||||
run_finally fin([]{ DAEMON_STATE = STATE_LATE_START_DONE; });
|
||||
setup_logfile(false);
|
||||
mutex_guard lock(stage_lock);
|
||||
run_finally fin([]{ DAEMON_STATE = STATE_LATE_START_DONE; });
|
||||
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)
|
||||
return;
|
||||
if (DAEMON_STATE < STATE_POST_FS_DATA_DONE || safe_mode)
|
||||
return;
|
||||
|
||||
exec_common_scripts("service");
|
||||
exec_module_scripts("service");
|
||||
exec_common_scripts("service");
|
||||
exec_module_scripts("service");
|
||||
}
|
||||
|
||||
void boot_complete(int client) {
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
|
||||
mutex_guard lock(stage_lock);
|
||||
DAEMON_STATE = STATE_BOOT_COMPLETE;
|
||||
setup_logfile(false);
|
||||
mutex_guard lock(stage_lock);
|
||||
DAEMON_STATE = STATE_BOOT_COMPLETE;
|
||||
setup_logfile(false);
|
||||
|
||||
LOGI("** boot_complete triggered\n");
|
||||
LOGI("** boot_complete triggered\n");
|
||||
|
||||
if (safe_mode)
|
||||
return;
|
||||
if (safe_mode)
|
||||
return;
|
||||
|
||||
// At this point it's safe to create the folder
|
||||
if (access(SECURE_DIR, F_OK) != 0)
|
||||
xmkdir(SECURE_DIR, 0700);
|
||||
// At this point it's safe to create the folder
|
||||
if (access(SECURE_DIR, F_OK) != 0)
|
||||
xmkdir(SECURE_DIR, 0700);
|
||||
|
||||
auto_start_magiskhide();
|
||||
auto_start_magiskhide();
|
||||
|
||||
if (!check_manager()) {
|
||||
if (access(MANAGERAPK, F_OK) == 0) {
|
||||
// Only try to install APK when no manager is installed
|
||||
// Magisk Manager should be upgraded by itself, not through recovery installs
|
||||
rename(MANAGERAPK, "/data/magisk.apk");
|
||||
install_apk("/data/magisk.apk");
|
||||
} else {
|
||||
// Install stub
|
||||
auto init = MAGISKTMP + "/magiskinit";
|
||||
exec_command_sync(init.data(), "-x", "manager", "/data/magisk.apk");
|
||||
install_apk("/data/magisk.apk");
|
||||
}
|
||||
}
|
||||
unlink(MANAGERAPK);
|
||||
if (!check_manager()) {
|
||||
if (access(MANAGERAPK, F_OK) == 0) {
|
||||
// Only try to install APK when no manager is installed
|
||||
// Magisk Manager should be upgraded by itself, not through recovery installs
|
||||
rename(MANAGERAPK, "/data/magisk.apk");
|
||||
install_apk("/data/magisk.apk");
|
||||
} else {
|
||||
// Install stub
|
||||
auto init = MAGISKTMP + "/magiskinit";
|
||||
exec_command_sync(init.data(), "-x", "manager", "/data/magisk.apk");
|
||||
install_apk("/data/magisk.apk");
|
||||
}
|
||||
}
|
||||
unlink(MANAGERAPK);
|
||||
}
|
||||
|
||||
@@ -26,101 +26,101 @@ int DAEMON_STATE = STATE_NONE;
|
||||
static struct stat self_st;
|
||||
|
||||
static bool verify_client(pid_t pid) {
|
||||
// Verify caller is the same as server
|
||||
char path[32];
|
||||
sprintf(path, "/proc/%d/exe", pid);
|
||||
struct stat st;
|
||||
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
|
||||
// Verify caller is the same as server
|
||||
char path[32];
|
||||
sprintf(path, "/proc/%d/exe", pid);
|
||||
struct stat st;
|
||||
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
|
||||
}
|
||||
|
||||
static void request_handler(int client, int req_code, ucred cred) {
|
||||
switch (req_code) {
|
||||
case MAGISKHIDE:
|
||||
magiskhide_handler(client);
|
||||
break;
|
||||
case SUPERUSER:
|
||||
su_daemon_handler(client, &cred);
|
||||
break;
|
||||
case POST_FS_DATA:
|
||||
post_fs_data(client);
|
||||
break;
|
||||
case LATE_START:
|
||||
late_start(client);
|
||||
break;
|
||||
case BOOT_COMPLETE:
|
||||
boot_complete(client);
|
||||
break;
|
||||
case SQLITE_CMD:
|
||||
exec_sql(client);
|
||||
break;
|
||||
case REMOVE_MODULES:
|
||||
remove_modules();
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
reboot();
|
||||
break;
|
||||
default:
|
||||
close(client);
|
||||
break;
|
||||
}
|
||||
switch (req_code) {
|
||||
case MAGISKHIDE:
|
||||
magiskhide_handler(client);
|
||||
break;
|
||||
case SUPERUSER:
|
||||
su_daemon_handler(client, &cred);
|
||||
break;
|
||||
case POST_FS_DATA:
|
||||
post_fs_data(client);
|
||||
break;
|
||||
case LATE_START:
|
||||
late_start(client);
|
||||
break;
|
||||
case BOOT_COMPLETE:
|
||||
boot_complete(client);
|
||||
break;
|
||||
case SQLITE_CMD:
|
||||
exec_sql(client);
|
||||
break;
|
||||
case REMOVE_MODULES:
|
||||
remove_modules();
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
reboot();
|
||||
break;
|
||||
default:
|
||||
close(client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_request(int client) {
|
||||
int req_code;
|
||||
int req_code;
|
||||
|
||||
// Verify client credentials
|
||||
ucred cred;
|
||||
get_client_cred(client, &cred);
|
||||
if (cred.uid != 0 && !verify_client(cred.pid))
|
||||
goto shortcut;
|
||||
// Verify client credentials
|
||||
ucred cred;
|
||||
get_client_cred(client, &cred);
|
||||
if (cred.uid != 0 && !verify_client(cred.pid))
|
||||
goto shortcut;
|
||||
|
||||
req_code = read_int(client);
|
||||
if (req_code < 0 || req_code >= DAEMON_CODE_END)
|
||||
goto shortcut;
|
||||
req_code = read_int(client);
|
||||
if (req_code < 0 || req_code >= DAEMON_CODE_END)
|
||||
goto shortcut;
|
||||
|
||||
// Check client permissions
|
||||
switch (req_code) {
|
||||
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;
|
||||
}
|
||||
// Check client permissions
|
||||
switch (req_code) {
|
||||
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
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
// Create new thread to handle complex requests
|
||||
new_daemon_thread([=] { return request_handler(client, req_code, cred); });
|
||||
return;
|
||||
|
||||
shortcut:
|
||||
close(client);
|
||||
close(client);
|
||||
}
|
||||
|
||||
static shared_ptr<FILE> log_file;
|
||||
@@ -130,185 +130,186 @@ static char *log_buf;
|
||||
static size_t log_buf_len;
|
||||
|
||||
void setup_logfile(bool reset) {
|
||||
if (file_backed.test_and_set(memory_order_relaxed))
|
||||
return;
|
||||
if (reset)
|
||||
rename(LOGFILE, LOGFILE ".bak");
|
||||
if (file_backed.test_and_set(memory_order_relaxed))
|
||||
return;
|
||||
if (reset)
|
||||
rename(LOGFILE, LOGFILE ".bak");
|
||||
|
||||
int fd = xopen(LOGFILE, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
|
||||
if (fd < 0) {
|
||||
log_file.reset();
|
||||
return;
|
||||
}
|
||||
int fd = xopen(LOGFILE, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
|
||||
if (fd < 0) {
|
||||
log_file.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// Dump all logs in memory (if exists)
|
||||
if (log_buf)
|
||||
write(fd, log_buf, log_buf_len);
|
||||
// Dump all logs in memory (if exists)
|
||||
if (log_buf)
|
||||
write(fd, log_buf, log_buf_len);
|
||||
|
||||
if (FILE *fp = fdopen(fd, "a")) {
|
||||
setbuf(fp, nullptr);
|
||||
log_file.reset(fp, &fclose);
|
||||
}
|
||||
if (FILE *fp = fdopen(fd, "a")) {
|
||||
setbuf(fp, nullptr);
|
||||
log_file.reset(fp, &fclose);
|
||||
}
|
||||
}
|
||||
|
||||
static int magisk_log(int prio, const char *fmt, va_list ap) {
|
||||
va_list args;
|
||||
va_copy(args, ap);
|
||||
va_list args;
|
||||
va_copy(args, ap);
|
||||
|
||||
// Log to logcat
|
||||
__android_log_vprint(prio, "Magisk", fmt, ap);
|
||||
// Log to logcat
|
||||
__android_log_vprint(prio, "Magisk", fmt, ap);
|
||||
|
||||
auto local_log_file = log_file;
|
||||
if (!local_log_file)
|
||||
return 0;
|
||||
auto local_log_file = log_file;
|
||||
if (!local_log_file)
|
||||
return 0;
|
||||
|
||||
char buf[4096];
|
||||
timeval tv;
|
||||
tm tm;
|
||||
char type;
|
||||
switch (prio) {
|
||||
case ANDROID_LOG_DEBUG:
|
||||
type = 'D';
|
||||
break;
|
||||
case ANDROID_LOG_INFO:
|
||||
type = 'I';
|
||||
break;
|
||||
case ANDROID_LOG_WARN:
|
||||
type = 'W';
|
||||
break;
|
||||
default:
|
||||
type = 'E';
|
||||
break;
|
||||
}
|
||||
gettimeofday(&tv, nullptr);
|
||||
localtime_r(&tv.tv_sec, &tm);
|
||||
size_t len = strftime(buf, sizeof(buf), "%m-%d %T", &tm);
|
||||
int ms = tv.tv_usec / 1000;
|
||||
len += sprintf(buf + len, ".%03d %c : ", ms, type);
|
||||
strcpy(buf + len, fmt);
|
||||
return vfprintf(local_log_file.get(), buf, args);
|
||||
char buf[4096];
|
||||
timeval tv;
|
||||
tm tm;
|
||||
char type;
|
||||
switch (prio) {
|
||||
case ANDROID_LOG_DEBUG:
|
||||
type = 'D';
|
||||
break;
|
||||
case ANDROID_LOG_INFO:
|
||||
type = 'I';
|
||||
break;
|
||||
case ANDROID_LOG_WARN:
|
||||
type = 'W';
|
||||
break;
|
||||
default:
|
||||
type = 'E';
|
||||
break;
|
||||
}
|
||||
gettimeofday(&tv, nullptr);
|
||||
localtime_r(&tv.tv_sec, &tm);
|
||||
size_t len = strftime(buf, sizeof(buf), "%m-%d %T", &tm);
|
||||
int ms = tv.tv_usec / 1000;
|
||||
len += sprintf(buf + len, ".%03d %c : ", ms, type);
|
||||
strcpy(buf + len, fmt);
|
||||
return vfprintf(local_log_file.get(), buf, args);
|
||||
}
|
||||
|
||||
static void android_logging() {
|
||||
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
|
||||
log_file.reset(in_mem_file.release(), [](FILE *) {
|
||||
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.w = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_WARN, fmt, ap); };
|
||||
log_cb.e = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_ERROR, fmt, ap); };
|
||||
log_cb.ex = nop_ex;
|
||||
#define mlog(prio) [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_##prio, fmt, ap); }
|
||||
static void magisk_logging() {
|
||||
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
|
||||
log_file.reset(in_mem_file.release(), [](FILE *) {
|
||||
free(log_buf);
|
||||
log_buf = nullptr;
|
||||
});
|
||||
log_cb.d = mlog(DEBUG);
|
||||
log_cb.i = mlog(INFO);
|
||||
log_cb.w = mlog(WARN);
|
||||
log_cb.e = mlog(ERROR);
|
||||
log_cb.ex = nop_ex;
|
||||
}
|
||||
|
||||
static void daemon_entry(int ppid) {
|
||||
android_logging();
|
||||
magisk_logging();
|
||||
|
||||
int fd = xopen("/dev/null", O_WRONLY);
|
||||
xdup2(fd, STDOUT_FILENO);
|
||||
xdup2(fd, STDERR_FILENO);
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
fd = xopen("/dev/zero", O_RDONLY);
|
||||
xdup2(fd, STDIN_FILENO);
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
int fd = xopen("/dev/null", O_WRONLY);
|
||||
xdup2(fd, STDOUT_FILENO);
|
||||
xdup2(fd, STDERR_FILENO);
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
fd = xopen("/dev/zero", O_RDONLY);
|
||||
xdup2(fd, STDIN_FILENO);
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
|
||||
setsid();
|
||||
setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
|
||||
setsid();
|
||||
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
|
||||
char src[64], dest[64];
|
||||
sprintf(src, "/acct/uid_0/pid_%d", ppid);
|
||||
sprintf(dest, "/acct/uid_0/pid_%d", getpid());
|
||||
rename(src, dest);
|
||||
// Make sure ppid is not in acct
|
||||
char src[64], dest[64];
|
||||
sprintf(src, "/acct/uid_0/pid_%d", ppid);
|
||||
sprintf(dest, "/acct/uid_0/pid_%d", getpid());
|
||||
rename(src, dest);
|
||||
|
||||
// Get self stat
|
||||
xreadlink("/proc/self/exe", src, sizeof(src));
|
||||
MAGISKTMP = dirname(src);
|
||||
xstat("/proc/self/exe", &self_st);
|
||||
// Get self stat
|
||||
xreadlink("/proc/self/exe", src, sizeof(src));
|
||||
MAGISKTMP = dirname(src);
|
||||
xstat("/proc/self/exe", &self_st);
|
||||
|
||||
// Get API level
|
||||
parse_prop_file("/system/build.prop", [](auto key, auto val) -> bool {
|
||||
if (key == "ro.build.version.sdk") {
|
||||
SDK_INT = parse_int(val);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (SDK_INT < 0) {
|
||||
// In case some devices do not store this info in build.prop, fallback to getprop
|
||||
auto sdk = getprop("ro.build.version.sdk");
|
||||
if (!sdk.empty()) {
|
||||
SDK_INT = parse_int(sdk);
|
||||
}
|
||||
}
|
||||
LOGI("* Device API level: %d\n", SDK_INT);
|
||||
// Get API level
|
||||
parse_prop_file("/system/build.prop", [](auto key, auto val) -> bool {
|
||||
if (key == "ro.build.version.sdk") {
|
||||
SDK_INT = parse_int(val);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (SDK_INT < 0) {
|
||||
// In case some devices do not store this info in build.prop, fallback to getprop
|
||||
auto sdk = getprop("ro.build.version.sdk");
|
||||
if (!sdk.empty()) {
|
||||
SDK_INT = parse_int(sdk);
|
||||
}
|
||||
}
|
||||
LOGI("* Device API level: %d\n", SDK_INT);
|
||||
|
||||
restore_tmpcon();
|
||||
restore_tmpcon();
|
||||
|
||||
// SAR cleanups
|
||||
auto mount_list = MAGISKTMP + "/" ROOTMNT;
|
||||
if (access(mount_list.data(), F_OK) == 0) {
|
||||
file_readline(true, mount_list.data(), [](string_view line) -> bool {
|
||||
umount2(line.data(), MNT_DETACH);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
unlink("/dev/.se");
|
||||
// SAR cleanups
|
||||
auto mount_list = MAGISKTMP + "/" ROOTMNT;
|
||||
if (access(mount_list.data(), F_OK) == 0) {
|
||||
file_readline(true, mount_list.data(), [](string_view line) -> bool {
|
||||
umount2(line.data(), MNT_DETACH);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
unlink("/dev/.se");
|
||||
|
||||
// Load config status
|
||||
auto config = MAGISKTMP + "/" INTLROOT "/config";
|
||||
parse_prop_file(config.data(), [](auto key, auto val) -> bool {
|
||||
if (key == "RECOVERYMODE" && val == "true")
|
||||
RECOVERY_MODE = true;
|
||||
return true;
|
||||
});
|
||||
// Load config status
|
||||
auto config = MAGISKTMP + "/" INTLROOT "/config";
|
||||
parse_prop_file(config.data(), [](auto key, auto val) -> bool {
|
||||
if (key == "RECOVERYMODE" && val == "true")
|
||||
RECOVERY_MODE = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
struct sockaddr_un sun;
|
||||
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
||||
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (xbind(fd, (struct sockaddr*) &sun, len))
|
||||
exit(1);
|
||||
xlisten(fd, 10);
|
||||
struct sockaddr_un sun;
|
||||
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
||||
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (xbind(fd, (struct sockaddr*) &sun, len))
|
||||
exit(1);
|
||||
xlisten(fd, 10);
|
||||
|
||||
// Change process name
|
||||
set_nice_name("magiskd");
|
||||
// Change process name
|
||||
set_nice_name("magiskd");
|
||||
|
||||
// Block all signals
|
||||
sigset_t block_set;
|
||||
sigfillset(&block_set);
|
||||
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
|
||||
// Block all signals
|
||||
sigset_t block_set;
|
||||
sigfillset(&block_set);
|
||||
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
|
||||
|
||||
// Loop forever to listen for requests
|
||||
for (;;) {
|
||||
int client = xaccept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
handle_request(client);
|
||||
}
|
||||
// Loop forever to listen for requests
|
||||
for (;;) {
|
||||
int client = xaccept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
handle_request(client);
|
||||
}
|
||||
}
|
||||
|
||||
int connect_daemon(bool create) {
|
||||
struct sockaddr_un sun;
|
||||
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
||||
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (connect(fd, (struct sockaddr*) &sun, len)) {
|
||||
if (!create || getuid() != UID_ROOT || getgid() != UID_ROOT) {
|
||||
LOGE("No daemon is currently running!\n");
|
||||
exit(1);
|
||||
}
|
||||
struct sockaddr_un sun;
|
||||
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
|
||||
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (connect(fd, (struct sockaddr*) &sun, len)) {
|
||||
if (!create || getuid() != UID_ROOT || getgid() != UID_ROOT) {
|
||||
LOGE("No daemon is currently running!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int ppid = getpid();
|
||||
LOGD("client: launching new main daemon process\n");
|
||||
if (fork_dont_care() == 0) {
|
||||
close(fd);
|
||||
daemon_entry(ppid);
|
||||
}
|
||||
int ppid = getpid();
|
||||
LOGD("client: launching new main daemon process\n");
|
||||
if (fork_dont_care() == 0) {
|
||||
close(fd);
|
||||
daemon_entry(ppid);
|
||||
}
|
||||
|
||||
while (connect(fd, (struct sockaddr*) &sun, len))
|
||||
usleep(10000);
|
||||
}
|
||||
return fd;
|
||||
while (connect(fd, (struct sockaddr*) &sun, len))
|
||||
usleep(10000);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -26,19 +26,19 @@ static sqlite3 *mDB = nullptr;
|
||||
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
||||
|
||||
static int (*sqlite3_open_v2)(
|
||||
const char *filename,
|
||||
sqlite3 **ppDb,
|
||||
int flags,
|
||||
const char *zVfs);
|
||||
const char *filename,
|
||||
sqlite3 **ppDb,
|
||||
int flags,
|
||||
const char *zVfs);
|
||||
static const char *(*sqlite3_errmsg)(sqlite3 *db);
|
||||
static int (*sqlite3_close)(sqlite3 *db);
|
||||
static void (*sqlite3_free)(void *v);
|
||||
static int (*sqlite3_exec)(
|
||||
sqlite3 *db,
|
||||
const char *sql,
|
||||
int (*callback)(void*, int, char**, char**),
|
||||
void *v,
|
||||
char **errmsg);
|
||||
sqlite3 *db,
|
||||
const char *sql,
|
||||
int (*callback)(void*, int, char**, char**),
|
||||
void *v,
|
||||
char **errmsg);
|
||||
|
||||
// Internal Android linker APIs
|
||||
|
||||
@@ -46,14 +46,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);
|
||||
|
||||
#define DLERR(ptr) if (!(ptr)) { \
|
||||
LOGE("db: %s\n", dlerror()); \
|
||||
return false; \
|
||||
LOGE("db: %s\n", dlerror()); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define DLOAD(handle, arg) {\
|
||||
auto f = dlsym(handle, #arg); \
|
||||
DLERR(f) \
|
||||
*(void **) &(arg) = f; \
|
||||
auto f = dlsym(handle, #arg); \
|
||||
DLERR(f) \
|
||||
*(void **) &(arg) = f; \
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
@@ -65,339 +65,339 @@ constexpr char apex_path[] = "/apex/com.android.runtime/lib:/apex/com.android.ar
|
||||
static int dl_init = 0;
|
||||
|
||||
static bool dload_sqlite() {
|
||||
if (dl_init)
|
||||
return dl_init > 0;
|
||||
dl_init = -1;
|
||||
if (dl_init)
|
||||
return dl_init > 0;
|
||||
dl_init = -1;
|
||||
|
||||
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||
if (!sqlite) {
|
||||
// Should only happen on Android 10+
|
||||
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
|
||||
DLERR(dl);
|
||||
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||
if (!sqlite) {
|
||||
// Should only happen on Android 10+
|
||||
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
|
||||
DLERR(dl);
|
||||
|
||||
DLOAD(dl, android_get_LD_LIBRARY_PATH);
|
||||
DLOAD(dl, android_update_LD_LIBRARY_PATH);
|
||||
DLOAD(dl, android_get_LD_LIBRARY_PATH);
|
||||
DLOAD(dl, android_update_LD_LIBRARY_PATH);
|
||||
|
||||
// Inject APEX into LD_LIBRARY_PATH
|
||||
char ld_path[4096];
|
||||
memcpy(ld_path, apex_path, sizeof(apex_path));
|
||||
constexpr int len = sizeof(apex_path) - 1;
|
||||
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
|
||||
android_update_LD_LIBRARY_PATH(ld_path);
|
||||
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||
// Inject APEX into LD_LIBRARY_PATH
|
||||
char ld_path[4096];
|
||||
memcpy(ld_path, apex_path, sizeof(apex_path));
|
||||
constexpr int len = sizeof(apex_path) - 1;
|
||||
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
|
||||
android_update_LD_LIBRARY_PATH(ld_path);
|
||||
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
|
||||
|
||||
// Revert LD_LIBRARY_PATH just in case
|
||||
android_update_LD_LIBRARY_PATH(ld_path + len);
|
||||
}
|
||||
DLERR(sqlite);
|
||||
// Revert LD_LIBRARY_PATH just in case
|
||||
android_update_LD_LIBRARY_PATH(ld_path + len);
|
||||
}
|
||||
DLERR(sqlite);
|
||||
|
||||
DLOAD(sqlite, sqlite3_open_v2);
|
||||
DLOAD(sqlite, sqlite3_errmsg);
|
||||
DLOAD(sqlite, sqlite3_close);
|
||||
DLOAD(sqlite, sqlite3_exec);
|
||||
DLOAD(sqlite, sqlite3_free);
|
||||
DLOAD(sqlite, sqlite3_open_v2);
|
||||
DLOAD(sqlite, sqlite3_errmsg);
|
||||
DLOAD(sqlite, sqlite3_close);
|
||||
DLOAD(sqlite, sqlite3_exec);
|
||||
DLOAD(sqlite, sqlite3_free);
|
||||
|
||||
dl_init = 1;
|
||||
return true;
|
||||
dl_init = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
int db_strings::getKeyIdx(string_view key) const {
|
||||
int idx = DB_STRING_NUM;
|
||||
for (int i = 0; i < DB_STRING_NUM; ++i) {
|
||||
if (key == DB_STRING_KEYS[i])
|
||||
idx = i;
|
||||
}
|
||||
return idx;
|
||||
int idx = DB_STRING_NUM;
|
||||
for (int i = 0; i < DB_STRING_NUM; ++i) {
|
||||
if (key == DB_STRING_KEYS[i])
|
||||
idx = i;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
db_settings::db_settings() {
|
||||
// Default settings
|
||||
data[ROOT_ACCESS] = ROOT_ACCESS_APPS_AND_ADB;
|
||||
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
|
||||
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
|
||||
data[HIDE_CONFIG] = false;
|
||||
// Default settings
|
||||
data[ROOT_ACCESS] = ROOT_ACCESS_APPS_AND_ADB;
|
||||
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
|
||||
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
|
||||
data[HIDE_CONFIG] = false;
|
||||
}
|
||||
|
||||
int db_settings::getKeyIdx(string_view key) const {
|
||||
int idx = DB_SETTINGS_NUM;
|
||||
for (int i = 0; i < DB_SETTINGS_NUM; ++i) {
|
||||
if (key == DB_SETTING_KEYS[i])
|
||||
idx = i;
|
||||
}
|
||||
return idx;
|
||||
int idx = DB_SETTINGS_NUM;
|
||||
for (int i = 0; i < DB_SETTINGS_NUM; ++i) {
|
||||
if (key == DB_SETTING_KEYS[i])
|
||||
idx = i;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int ver_cb(void *ver, int, char **data, char **) {
|
||||
*((int *) ver) = parse_int(data[0]);
|
||||
return 0;
|
||||
*((int *) ver) = parse_int(data[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define err_ret(e) if (e) return e;
|
||||
|
||||
static char *open_and_init_db(sqlite3 *&db) {
|
||||
if (!dload_sqlite())
|
||||
return strdup("Cannot load libsqlite.so");
|
||||
if (!dload_sqlite())
|
||||
return strdup("Cannot load libsqlite.so");
|
||||
|
||||
int ret = sqlite3_open_v2(MAGISKDB, &db,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
|
||||
if (ret)
|
||||
return strdup(sqlite3_errmsg(db));
|
||||
int ver;
|
||||
bool upgrade = false;
|
||||
char *err;
|
||||
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
|
||||
err_ret(err);
|
||||
if (ver > DB_VERSION) {
|
||||
// Don't support downgrading database
|
||||
sqlite3_close(db);
|
||||
return nullptr;
|
||||
}
|
||||
if (ver < 3) {
|
||||
// Policies
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS policies "
|
||||
"(uid INT, package_name TEXT, policy INT, until INT, "
|
||||
"logging INT, notification INT, PRIMARY KEY(uid))",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
// Settings
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS settings "
|
||||
"(key TEXT, value INT, PRIMARY KEY(key))",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 3;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 4) {
|
||||
// Strings
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS strings "
|
||||
"(key TEXT, value TEXT, PRIMARY KEY(key))",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 4;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 5) {
|
||||
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
/* Directly jump to version 6 */
|
||||
ver = 6;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 7) {
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
/* Directly jump to version 9 */
|
||||
ver = 9;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 8) {
|
||||
sqlite3_exec(db,
|
||||
"BEGIN TRANSACTION;"
|
||||
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
||||
"INSERT INTO hidelist SELECT process as package_name, process FROM hidelist_tmp;"
|
||||
"DROP TABLE hidelist_tmp;"
|
||||
"COMMIT;",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
/* Directly jump to version 9 */
|
||||
ver = 9;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 9) {
|
||||
sqlite3_exec(db,
|
||||
"BEGIN TRANSACTION;"
|
||||
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
||||
"INSERT INTO hidelist SELECT * FROM hidelist_tmp;"
|
||||
"DROP TABLE hidelist_tmp;"
|
||||
"COMMIT;",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 9;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 10) {
|
||||
sqlite3_exec(db, "DROP TABLE IF EXISTS logs", nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 10;
|
||||
upgrade = true;
|
||||
}
|
||||
int ret = sqlite3_open_v2(MAGISKDB, &db,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
|
||||
if (ret)
|
||||
return strdup(sqlite3_errmsg(db));
|
||||
int ver;
|
||||
bool upgrade = false;
|
||||
char *err;
|
||||
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
|
||||
err_ret(err);
|
||||
if (ver > DB_VERSION) {
|
||||
// Don't support downgrading database
|
||||
sqlite3_close(db);
|
||||
return nullptr;
|
||||
}
|
||||
if (ver < 3) {
|
||||
// Policies
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS policies "
|
||||
"(uid INT, package_name TEXT, policy INT, until INT, "
|
||||
"logging INT, notification INT, PRIMARY KEY(uid))",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
// Settings
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS settings "
|
||||
"(key TEXT, value INT, PRIMARY KEY(key))",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 3;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 4) {
|
||||
// Strings
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS strings "
|
||||
"(key TEXT, value TEXT, PRIMARY KEY(key))",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 4;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 5) {
|
||||
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
/* Directly jump to version 6 */
|
||||
ver = 6;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 7) {
|
||||
sqlite3_exec(db,
|
||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
/* Directly jump to version 9 */
|
||||
ver = 9;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 8) {
|
||||
sqlite3_exec(db,
|
||||
"BEGIN TRANSACTION;"
|
||||
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
||||
"INSERT INTO hidelist SELECT process as package_name, process FROM hidelist_tmp;"
|
||||
"DROP TABLE hidelist_tmp;"
|
||||
"COMMIT;",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
/* Directly jump to version 9 */
|
||||
ver = 9;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 9) {
|
||||
sqlite3_exec(db,
|
||||
"BEGIN TRANSACTION;"
|
||||
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
|
||||
"CREATE TABLE IF NOT EXISTS hidelist "
|
||||
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
|
||||
"INSERT INTO hidelist SELECT * FROM hidelist_tmp;"
|
||||
"DROP TABLE hidelist_tmp;"
|
||||
"COMMIT;",
|
||||
nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 9;
|
||||
upgrade = true;
|
||||
}
|
||||
if (ver < 10) {
|
||||
sqlite3_exec(db, "DROP TABLE IF EXISTS logs", nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
ver = 10;
|
||||
upgrade = true;
|
||||
}
|
||||
|
||||
if (upgrade) {
|
||||
// Set version
|
||||
char query[32];
|
||||
sprintf(query, "PRAGMA user_version=%d", ver);
|
||||
sqlite3_exec(db, query, nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
}
|
||||
return nullptr;
|
||||
if (upgrade) {
|
||||
// Set version
|
||||
char query[32];
|
||||
sprintf(query, "PRAGMA user_version=%d", ver);
|
||||
sqlite3_exec(db, query, nullptr, nullptr, &err);
|
||||
err_ret(err);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *db_exec(const char *sql) {
|
||||
char *err;
|
||||
if (mDB == nullptr) {
|
||||
err = open_and_init_db(mDB);
|
||||
db_err_cmd(err,
|
||||
// Open fails, remove and reconstruct
|
||||
unlink(MAGISKDB);
|
||||
err = open_and_init_db(mDB);
|
||||
err_ret(err);
|
||||
);
|
||||
}
|
||||
if (mDB) {
|
||||
sqlite3_exec(mDB, sql, nullptr, nullptr, &err);
|
||||
return err;
|
||||
}
|
||||
return nullptr;
|
||||
char *err;
|
||||
if (mDB == nullptr) {
|
||||
err = open_and_init_db(mDB);
|
||||
db_err_cmd(err,
|
||||
// Open fails, remove and reconstruct
|
||||
unlink(MAGISKDB);
|
||||
err = open_and_init_db(mDB);
|
||||
err_ret(err);
|
||||
);
|
||||
}
|
||||
if (mDB) {
|
||||
sqlite3_exec(mDB, sql, nullptr, nullptr, &err);
|
||||
return err;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *db_exec(const char *sql, const db_row_cb &fn) {
|
||||
char *err;
|
||||
if (mDB == nullptr) {
|
||||
err = open_and_init_db(mDB);
|
||||
db_err_cmd(err,
|
||||
// Open fails, remove and reconstruct
|
||||
unlink(MAGISKDB);
|
||||
err = open_and_init_db(mDB);
|
||||
err_ret(err);
|
||||
);
|
||||
}
|
||||
if (mDB) {
|
||||
sqlite3_exec(mDB, sql, [](void *cb, int col_num, char **data, char **col_name) -> int {
|
||||
auto &func = *reinterpret_cast<const db_row_cb*>(cb);
|
||||
db_row row;
|
||||
for (int i = 0; i < col_num; ++i)
|
||||
row[col_name[i]] = data[i];
|
||||
return func(row) ? 0 : 1;
|
||||
}, (void *) &fn, &err);
|
||||
return err;
|
||||
}
|
||||
return nullptr;
|
||||
char *err;
|
||||
if (mDB == nullptr) {
|
||||
err = open_and_init_db(mDB);
|
||||
db_err_cmd(err,
|
||||
// Open fails, remove and reconstruct
|
||||
unlink(MAGISKDB);
|
||||
err = open_and_init_db(mDB);
|
||||
err_ret(err);
|
||||
);
|
||||
}
|
||||
if (mDB) {
|
||||
sqlite3_exec(mDB, sql, [](void *cb, int col_num, char **data, char **col_name) -> int {
|
||||
auto &func = *reinterpret_cast<const db_row_cb*>(cb);
|
||||
db_row row;
|
||||
for (int i = 0; i < col_num; ++i)
|
||||
row[col_name[i]] = data[i];
|
||||
return func(row) ? 0 : 1;
|
||||
}, (void *) &fn, &err);
|
||||
return err;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int get_db_settings(db_settings &cfg, int key) {
|
||||
char *err;
|
||||
auto settings_cb = [&](db_row &row) -> bool {
|
||||
cfg[row["key"]] = parse_int(row["value"]);
|
||||
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||
return true;
|
||||
};
|
||||
if (key >= 0) {
|
||||
char query[128];
|
||||
sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]);
|
||||
err = db_exec(query, settings_cb);
|
||||
} else {
|
||||
err = db_exec("SELECT key, value FROM settings", settings_cb);
|
||||
}
|
||||
db_err_cmd(err, return 1);
|
||||
return 0;
|
||||
char *err;
|
||||
auto settings_cb = [&](db_row &row) -> bool {
|
||||
cfg[row["key"]] = parse_int(row["value"]);
|
||||
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||
return true;
|
||||
};
|
||||
if (key >= 0) {
|
||||
char query[128];
|
||||
sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]);
|
||||
err = db_exec(query, settings_cb);
|
||||
} else {
|
||||
err = db_exec("SELECT key, value FROM settings", settings_cb);
|
||||
}
|
||||
db_err_cmd(err, return 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_db_strings(db_strings &str, int key) {
|
||||
char *err;
|
||||
auto string_cb = [&](db_row &row) -> bool {
|
||||
str[row["key"]] = row["value"];
|
||||
return true;
|
||||
};
|
||||
if (key >= 0) {
|
||||
char query[128];
|
||||
sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]);
|
||||
err = db_exec(query, string_cb);
|
||||
} else {
|
||||
err = db_exec("SELECT key, value FROM strings", string_cb);
|
||||
}
|
||||
db_err_cmd(err, return 1);
|
||||
return 0;
|
||||
char *err;
|
||||
auto string_cb = [&](db_row &row) -> bool {
|
||||
str[row["key"]] = row["value"];
|
||||
return true;
|
||||
};
|
||||
if (key >= 0) {
|
||||
char query[128];
|
||||
sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]);
|
||||
err = db_exec(query, string_cb);
|
||||
} else {
|
||||
err = db_exec("SELECT key, value FROM strings", string_cb);
|
||||
}
|
||||
db_err_cmd(err, return 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_uid_policy(su_access &su, int uid) {
|
||||
char query[256], *err;
|
||||
sprintf(query, "SELECT policy, logging, notification FROM policies "
|
||||
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
||||
err = db_exec(query, [&](db_row &row) -> bool {
|
||||
su.policy = (policy_t) parse_int(row["policy"]);
|
||||
su.log = parse_int(row["logging"]);
|
||||
su.notify = parse_int(row["notification"]);
|
||||
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify);
|
||||
return true;
|
||||
});
|
||||
db_err_cmd(err, return 1);
|
||||
return 0;
|
||||
char query[256], *err;
|
||||
sprintf(query, "SELECT policy, logging, notification FROM policies "
|
||||
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
||||
err = db_exec(query, [&](db_row &row) -> bool {
|
||||
su.policy = (policy_t) parse_int(row["policy"]);
|
||||
su.log = parse_int(row["logging"]);
|
||||
su.notify = parse_int(row["notification"]);
|
||||
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify);
|
||||
return true;
|
||||
});
|
||||
db_err_cmd(err, return 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool check_manager(string *pkg) {
|
||||
db_strings str;
|
||||
get_db_strings(str, SU_MANAGER);
|
||||
bool ret = validate_manager(str[SU_MANAGER], 0, nullptr);
|
||||
if (pkg) {
|
||||
if (ret)
|
||||
pkg->swap(str[SU_MANAGER]);
|
||||
else
|
||||
*pkg = "xxx"; /* Make sure the return pkg can never exist */
|
||||
}
|
||||
return ret;
|
||||
db_strings str;
|
||||
get_db_strings(str, SU_MANAGER);
|
||||
bool ret = validate_manager(str[SU_MANAGER], 0, nullptr);
|
||||
if (pkg) {
|
||||
if (ret)
|
||||
pkg->swap(str[SU_MANAGER]);
|
||||
else
|
||||
*pkg = "xxx"; /* Make sure the return pkg can never exist */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool validate_manager(string &pkg, int userid, struct stat *st) {
|
||||
struct stat tmp_st;
|
||||
if (st == nullptr)
|
||||
st = &tmp_st;
|
||||
struct stat tmp_st;
|
||||
if (st == nullptr)
|
||||
st = &tmp_st;
|
||||
|
||||
// Prefer DE storage
|
||||
char app_path[128];
|
||||
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, pkg.data());
|
||||
if (pkg.empty() || stat(app_path, st)) {
|
||||
// Check the official package name
|
||||
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid);
|
||||
if (stat(app_path, st)) {
|
||||
LOGE("su: cannot find manager\n");
|
||||
memset(st, 0, sizeof(*st));
|
||||
pkg.clear();
|
||||
return false;
|
||||
} else {
|
||||
// Switch to official package if exists
|
||||
pkg = JAVA_PACKAGE_NAME;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
// Prefer DE storage
|
||||
char app_path[128];
|
||||
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, pkg.data());
|
||||
if (pkg.empty() || stat(app_path, st)) {
|
||||
// Check the official package name
|
||||
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid);
|
||||
if (stat(app_path, st)) {
|
||||
LOGE("su: cannot find manager\n");
|
||||
memset(st, 0, sizeof(*st));
|
||||
pkg.clear();
|
||||
return false;
|
||||
} else {
|
||||
// Switch to official package if exists
|
||||
pkg = JAVA_PACKAGE_NAME;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void exec_sql(int client) {
|
||||
run_finally f([=]{ close(client); });
|
||||
char *sql = read_string(client);
|
||||
char *err = db_exec(sql, [&](db_row &row) -> bool {
|
||||
string out;
|
||||
bool first = true;
|
||||
for (auto it : row) {
|
||||
if (first) first = false;
|
||||
else out += '|';
|
||||
out += it.first;
|
||||
out += '=';
|
||||
out += it.second;
|
||||
}
|
||||
write_int(client, out.length());
|
||||
xwrite(client, out.data(), out.length());
|
||||
return true;
|
||||
});
|
||||
free(sql);
|
||||
write_int(client, 0);
|
||||
db_err_cmd(err, return; );
|
||||
run_finally f([=]{ close(client); });
|
||||
char *sql = read_string(client);
|
||||
char *err = db_exec(sql, [&](db_row &row) -> bool {
|
||||
string out;
|
||||
bool first = true;
|
||||
for (auto it : row) {
|
||||
if (first) first = false;
|
||||
else out += '|';
|
||||
out += it.first;
|
||||
out += '=';
|
||||
out += it.second;
|
||||
}
|
||||
write_int(client, out.length());
|
||||
xwrite(client, out.data(), out.length());
|
||||
return true;
|
||||
});
|
||||
free(sql);
|
||||
write_int(client, 0);
|
||||
db_err_cmd(err, return; );
|
||||
}
|
||||
|
||||
bool db_err(char *e) {
|
||||
if (e) {
|
||||
LOGE("sqlite3_exec: %s\n", e);
|
||||
sqlite3_free(e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (e) {
|
||||
LOGE("sqlite3_exec: %s\n", e);
|
||||
sqlite3_free(e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
using namespace std;
|
||||
|
||||
[[noreturn]] static void usage() {
|
||||
fprintf(stderr,
|
||||
fprintf(stderr,
|
||||
R"EOF(Magisk - Multi-purpose Utility
|
||||
|
||||
Usage: magisk [applet [arguments]...]
|
||||
@@ -39,92 +39,92 @@ Advanced Options (Internal APIs):
|
||||
Available applets:
|
||||
)EOF");
|
||||
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
fprintf(stderr, i ? ", %s" : " %s", applet_names[i]);
|
||||
fprintf(stderr, "\n\n");
|
||||
exit(1);
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
fprintf(stderr, i ? ", %s" : " %s", applet_names[i]);
|
||||
fprintf(stderr, "\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int magisk_main(int argc, char *argv[]) {
|
||||
if (argc < 2)
|
||||
usage();
|
||||
if (argv[1] == "-c"sv) {
|
||||
printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n");
|
||||
return 0;
|
||||
} else if (argv[1] == "-v"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION);
|
||||
char *v = read_string(fd);
|
||||
printf("%s\n", v);
|
||||
free(v);
|
||||
return 0;
|
||||
} else if (argv[1] == "-V"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION_CODE);
|
||||
printf("%d\n", read_int(fd));
|
||||
return 0;
|
||||
} else if (argv[1] == "--list"sv) {
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
printf("%s\n", applet_names[i]);
|
||||
return 0;
|
||||
} else if (argv[1] == "--unlock-blocks"sv) {
|
||||
unlock_blocks();
|
||||
return 0;
|
||||
} else if (argv[1] == "--restorecon"sv) {
|
||||
restorecon();
|
||||
return 0;
|
||||
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
|
||||
clone_attr(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (argc >= 4 && argv[1] == "--clone"sv) {
|
||||
cp_afc(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (argv[1] == "--daemon"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, START_DAEMON);
|
||||
return 0;
|
||||
} else if (argv[1] == "--post-fs-data"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, POST_FS_DATA);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--service"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, LATE_START);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--boot-complete"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, BOOT_COMPLETE);
|
||||
return read_int(fd);
|
||||
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, SQLITE_CMD);
|
||||
write_string(fd, argv[2]);
|
||||
for (;;) {
|
||||
char *res = read_string(fd);
|
||||
if (res[0] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
printf("%s\n", res);
|
||||
free(res);
|
||||
}
|
||||
} else if (argv[1] == "--remove-modules"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, REMOVE_MODULES);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--path"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, GET_PATH);
|
||||
char *path = read_string(fd);
|
||||
printf("%s\n", path);
|
||||
return 0;
|
||||
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
|
||||
install_module(argv[2]);
|
||||
}
|
||||
if (argc < 2)
|
||||
usage();
|
||||
if (argv[1] == "-c"sv) {
|
||||
printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n");
|
||||
return 0;
|
||||
} else if (argv[1] == "-v"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION);
|
||||
char *v = read_string(fd);
|
||||
printf("%s\n", v);
|
||||
free(v);
|
||||
return 0;
|
||||
} else if (argv[1] == "-V"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION_CODE);
|
||||
printf("%d\n", read_int(fd));
|
||||
return 0;
|
||||
} else if (argv[1] == "--list"sv) {
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
printf("%s\n", applet_names[i]);
|
||||
return 0;
|
||||
} else if (argv[1] == "--unlock-blocks"sv) {
|
||||
unlock_blocks();
|
||||
return 0;
|
||||
} else if (argv[1] == "--restorecon"sv) {
|
||||
restorecon();
|
||||
return 0;
|
||||
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
|
||||
clone_attr(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (argc >= 4 && argv[1] == "--clone"sv) {
|
||||
cp_afc(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (argv[1] == "--daemon"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, START_DAEMON);
|
||||
return 0;
|
||||
} else if (argv[1] == "--post-fs-data"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, POST_FS_DATA);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--service"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, LATE_START);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--boot-complete"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, BOOT_COMPLETE);
|
||||
return read_int(fd);
|
||||
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, SQLITE_CMD);
|
||||
write_string(fd, argv[2]);
|
||||
for (;;) {
|
||||
char *res = read_string(fd);
|
||||
if (res[0] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
printf("%s\n", res);
|
||||
free(res);
|
||||
}
|
||||
} else if (argv[1] == "--remove-modules"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, REMOVE_MODULES);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--path"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, GET_PATH);
|
||||
char *path = read_string(fd);
|
||||
printf("%s\n", path);
|
||||
return 0;
|
||||
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
|
||||
install_module(argv[2]);
|
||||
}
|
||||
#if 0
|
||||
/* Entry point for testing stuffs */
|
||||
else if (argv[1] == "--test"sv) {
|
||||
return 0;
|
||||
}
|
||||
/* Entry point for testing stuffs */
|
||||
else if (argv[1] == "--test"sv) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
usage();
|
||||
usage();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,89 +15,89 @@ using namespace std;
|
||||
#define EXEC_CON "u:object_r:" SEPOL_EXEC_TYPE ":s0"
|
||||
|
||||
static void restore_syscon(int dirfd) {
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
char *con;
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
char *con;
|
||||
|
||||
fgetfilecon(dirfd, &con);
|
||||
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
|
||||
fsetfilecon(dirfd, SYSTEM_CON);
|
||||
freecon(con);
|
||||
fgetfilecon(dirfd, &con);
|
||||
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
|
||||
fsetfilecon(dirfd, SYSTEM_CON);
|
||||
freecon(con);
|
||||
|
||||
dir = xfdopendir(dirfd);
|
||||
while ((entry = xreaddir(dir))) {
|
||||
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
if (entry->d_type == DT_DIR) {
|
||||
restore_syscon(fd);
|
||||
} else if (entry->d_type == DT_REG) {
|
||||
fgetfilecon(fd, &con);
|
||||
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
||||
fsetfilecon(fd, SYSTEM_CON);
|
||||
freecon(con);
|
||||
} else if (entry->d_type == DT_LNK) {
|
||||
getfilecon_at(dirfd, entry->d_name, &con);
|
||||
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
||||
setfilecon_at(dirfd, entry->d_name, con);
|
||||
freecon(con);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
dir = xfdopendir(dirfd);
|
||||
while ((entry = xreaddir(dir))) {
|
||||
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
if (entry->d_type == DT_DIR) {
|
||||
restore_syscon(fd);
|
||||
} else if (entry->d_type == DT_REG) {
|
||||
fgetfilecon(fd, &con);
|
||||
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
||||
fsetfilecon(fd, SYSTEM_CON);
|
||||
freecon(con);
|
||||
} else if (entry->d_type == DT_LNK) {
|
||||
getfilecon_at(dirfd, entry->d_name, &con);
|
||||
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
|
||||
setfilecon_at(dirfd, entry->d_name, con);
|
||||
freecon(con);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void restore_magiskcon(int dirfd) {
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
|
||||
fsetfilecon(dirfd, MAGISK_CON);
|
||||
fchown(dirfd, 0, 0);
|
||||
fsetfilecon(dirfd, MAGISK_CON);
|
||||
fchown(dirfd, 0, 0);
|
||||
|
||||
dir = xfdopendir(dirfd);
|
||||
while ((entry = xreaddir(dir))) {
|
||||
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
if (entry->d_type == DT_DIR) {
|
||||
restore_magiskcon(fd);
|
||||
} else if (entry->d_type) {
|
||||
fsetfilecon(fd, MAGISK_CON);
|
||||
fchown(fd, 0, 0);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
dir = xfdopendir(dirfd);
|
||||
while ((entry = xreaddir(dir))) {
|
||||
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
if (entry->d_type == DT_DIR) {
|
||||
restore_magiskcon(fd);
|
||||
} else if (entry->d_type) {
|
||||
fsetfilecon(fd, MAGISK_CON);
|
||||
fchown(fd, 0, 0);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void restorecon() {
|
||||
int fd = xopen(SELINUX_CONTEXT, O_WRONLY | O_CLOEXEC);
|
||||
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
|
||||
lsetfilecon(SECURE_DIR, ADB_CON);
|
||||
close(fd);
|
||||
lsetfilecon(MODULEROOT, SYSTEM_CON);
|
||||
fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
|
||||
restore_syscon(fd);
|
||||
close(fd);
|
||||
fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC);
|
||||
restore_magiskcon(fd);
|
||||
close(fd);
|
||||
int fd = xopen(SELINUX_CONTEXT, O_WRONLY | O_CLOEXEC);
|
||||
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
|
||||
lsetfilecon(SECURE_DIR, ADB_CON);
|
||||
close(fd);
|
||||
lsetfilecon(MODULEROOT, SYSTEM_CON);
|
||||
fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
|
||||
restore_syscon(fd);
|
||||
close(fd);
|
||||
fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC);
|
||||
restore_magiskcon(fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void restore_tmpcon() {
|
||||
if (MAGISKTMP == "/system/bin") {
|
||||
// Running with emulator.sh
|
||||
if (SDK_INT >= 26)
|
||||
lsetfilecon("/system/bin/magisk", EXEC_CON);
|
||||
return;
|
||||
}
|
||||
if (MAGISKTMP == "/system/bin") {
|
||||
// Running with emulator.sh
|
||||
if (SDK_INT >= 26)
|
||||
lsetfilecon("/system/bin/magisk", EXEC_CON);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MAGISKTMP == "/sbin")
|
||||
setfilecon(MAGISKTMP.data(), ROOT_CON);
|
||||
else
|
||||
chmod(MAGISKTMP.data(), 0700);
|
||||
if (MAGISKTMP == "/sbin")
|
||||
setfilecon(MAGISKTMP.data(), ROOT_CON);
|
||||
else
|
||||
chmod(MAGISKTMP.data(), 0700);
|
||||
|
||||
auto dir = xopen_dir(MAGISKTMP.data());
|
||||
int dfd = dirfd(dir.get());
|
||||
auto dir = xopen_dir(MAGISKTMP.data());
|
||||
int dfd = dirfd(dir.get());
|
||||
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (SDK_INT >= 26 && entry->d_name == "magisk"sv)
|
||||
setfilecon_at(dfd, entry->d_name, EXEC_CON);
|
||||
else
|
||||
setfilecon_at(dfd, entry->d_name, SYSTEM_CON);
|
||||
}
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (SDK_INT >= 26 && entry->d_name == "magisk"sv)
|
||||
setfilecon_at(dfd, entry->d_name, EXEC_CON);
|
||||
else
|
||||
setfilecon_at(dfd, entry->d_name, SYSTEM_CON);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,139 +11,139 @@ using namespace std;
|
||||
#define BBEXEC_CMD bbpath(), "sh"
|
||||
|
||||
static const char *bbpath() {
|
||||
static string path;
|
||||
if (path.empty())
|
||||
path = MAGISKTMP + "/" BBPATH "/busybox";
|
||||
return path.data();
|
||||
static string path;
|
||||
if (path.empty())
|
||||
path = MAGISKTMP + "/" BBPATH "/busybox";
|
||||
return path.data();
|
||||
}
|
||||
|
||||
static void set_script_env() {
|
||||
setenv("ASH_STANDALONE", "1", 1);
|
||||
char new_path[4096];
|
||||
sprintf(new_path, "%s:%s", getenv("PATH"), MAGISKTMP.data());
|
||||
setenv("PATH", new_path, 1);
|
||||
setenv("ASH_STANDALONE", "1", 1);
|
||||
char new_path[4096];
|
||||
sprintf(new_path, "%s:%s", getenv("PATH"), MAGISKTMP.data());
|
||||
setenv("PATH", new_path, 1);
|
||||
};
|
||||
|
||||
void exec_script(const char *script) {
|
||||
exec_t exec {
|
||||
.pre_exec = set_script_env,
|
||||
.fork = fork_no_orphan
|
||||
};
|
||||
exec_command_sync(exec, BBEXEC_CMD, script);
|
||||
exec_t exec {
|
||||
.pre_exec = set_script_env,
|
||||
.fork = fork_no_orphan
|
||||
};
|
||||
exec_command_sync(exec, BBEXEC_CMD, script);
|
||||
}
|
||||
|
||||
static timespec pfs_timeout;
|
||||
|
||||
#define PFS_SETUP() \
|
||||
if (pfs) { \
|
||||
if (int pid = xfork()) { \
|
||||
if (pid < 0) \
|
||||
return; \
|
||||
/* In parent process, simply wait for child to finish */ \
|
||||
waitpid(pid, nullptr, 0); \
|
||||
return; \
|
||||
} \
|
||||
timer_pid = xfork(); \
|
||||
if (timer_pid == 0) { \
|
||||
/* In timer process, count down */ \
|
||||
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pfs_timeout, nullptr); \
|
||||
exit(0); \
|
||||
} \
|
||||
if (int pid = xfork()) { \
|
||||
if (pid < 0) \
|
||||
return; \
|
||||
/* In parent process, simply wait for child to finish */ \
|
||||
waitpid(pid, nullptr, 0); \
|
||||
return; \
|
||||
} \
|
||||
timer_pid = xfork(); \
|
||||
if (timer_pid == 0) { \
|
||||
/* In timer process, count down */ \
|
||||
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pfs_timeout, nullptr); \
|
||||
exit(0); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PFS_WAIT() \
|
||||
if (pfs) { \
|
||||
/* If we ran out of time, don't block */ \
|
||||
if (timer_pid < 0) \
|
||||
continue; \
|
||||
if (int pid = waitpid(-1, nullptr, 0); pid == timer_pid) { \
|
||||
LOGW("* post-fs-data scripts blocking phase timeout\n"); \
|
||||
timer_pid = -1; \
|
||||
} \
|
||||
/* If we ran out of time, don't block */ \
|
||||
if (timer_pid < 0) \
|
||||
continue; \
|
||||
if (int pid = waitpid(-1, nullptr, 0); pid == timer_pid) { \
|
||||
LOGW("* post-fs-data scripts blocking phase timeout\n"); \
|
||||
timer_pid = -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PFS_DONE() \
|
||||
if (pfs) { \
|
||||
if (timer_pid > 0) \
|
||||
kill(timer_pid, SIGKILL); \
|
||||
exit(0); \
|
||||
if (timer_pid > 0) \
|
||||
kill(timer_pid, SIGKILL); \
|
||||
exit(0); \
|
||||
}
|
||||
|
||||
void exec_common_scripts(const char *stage) {
|
||||
LOGI("* Running %s.d scripts\n", stage);
|
||||
char path[4096];
|
||||
char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage);
|
||||
auto dir = xopen_dir(path);
|
||||
if (!dir) return;
|
||||
LOGI("* Running %s.d scripts\n", stage);
|
||||
char path[4096];
|
||||
char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage);
|
||||
auto dir = xopen_dir(path);
|
||||
if (!dir) return;
|
||||
|
||||
bool pfs = stage == "post-fs-data"sv;
|
||||
int timer_pid = -1;
|
||||
if (pfs) {
|
||||
// Setup timer
|
||||
clock_gettime(CLOCK_MONOTONIC, &pfs_timeout);
|
||||
pfs_timeout.tv_sec += POST_FS_DATA_SCRIPT_MAX_TIME;
|
||||
}
|
||||
PFS_SETUP()
|
||||
bool pfs = stage == "post-fs-data"sv;
|
||||
int timer_pid = -1;
|
||||
if (pfs) {
|
||||
// Setup timer
|
||||
clock_gettime(CLOCK_MONOTONIC, &pfs_timeout);
|
||||
pfs_timeout.tv_sec += POST_FS_DATA_SCRIPT_MAX_TIME;
|
||||
}
|
||||
PFS_SETUP()
|
||||
|
||||
*(name++) = '/';
|
||||
int dfd = dirfd(dir.get());
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (entry->d_type == DT_REG) {
|
||||
if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
|
||||
continue;
|
||||
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
|
||||
strcpy(name, entry->d_name);
|
||||
exec_t exec {
|
||||
.pre_exec = set_script_env,
|
||||
.fork = pfs ? xfork : fork_dont_care
|
||||
};
|
||||
exec_command(exec, BBEXEC_CMD, path);
|
||||
PFS_WAIT()
|
||||
}
|
||||
}
|
||||
*(name++) = '/';
|
||||
int dfd = dirfd(dir.get());
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (entry->d_type == DT_REG) {
|
||||
if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
|
||||
continue;
|
||||
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
|
||||
strcpy(name, entry->d_name);
|
||||
exec_t exec {
|
||||
.pre_exec = set_script_env,
|
||||
.fork = pfs ? xfork : fork_dont_care
|
||||
};
|
||||
exec_command(exec, BBEXEC_CMD, path);
|
||||
PFS_WAIT()
|
||||
}
|
||||
}
|
||||
|
||||
PFS_DONE()
|
||||
PFS_DONE()
|
||||
}
|
||||
|
||||
// Return if a > b
|
||||
static bool timespec_larger(timespec *a, timespec *b) {
|
||||
if (a->tv_sec != b->tv_sec)
|
||||
return a->tv_sec > b->tv_sec;
|
||||
return a->tv_nsec > b->tv_nsec;
|
||||
if (a->tv_sec != b->tv_sec)
|
||||
return a->tv_sec > b->tv_sec;
|
||||
return a->tv_nsec > b->tv_nsec;
|
||||
}
|
||||
|
||||
void exec_module_scripts(const char *stage, const vector<string> &module_list) {
|
||||
LOGI("* Running module %s scripts\n", stage);
|
||||
if (module_list.empty())
|
||||
return;
|
||||
LOGI("* Running module %s scripts\n", stage);
|
||||
if (module_list.empty())
|
||||
return;
|
||||
|
||||
bool pfs = stage == "post-fs-data"sv;
|
||||
if (pfs) {
|
||||
timespec now{};
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
// If we had already timed out, treat it as service mode
|
||||
if (timespec_larger(&now, &pfs_timeout))
|
||||
pfs = false;
|
||||
}
|
||||
int timer_pid = -1;
|
||||
PFS_SETUP()
|
||||
bool pfs = stage == "post-fs-data"sv;
|
||||
if (pfs) {
|
||||
timespec now{};
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
// If we had already timed out, treat it as service mode
|
||||
if (timespec_larger(&now, &pfs_timeout))
|
||||
pfs = false;
|
||||
}
|
||||
int timer_pid = -1;
|
||||
PFS_SETUP()
|
||||
|
||||
char path[4096];
|
||||
for (auto &m : module_list) {
|
||||
const char* module = m.data();
|
||||
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
|
||||
if (access(path, F_OK) == -1)
|
||||
continue;
|
||||
LOGI("%s: exec [%s.sh]\n", module, stage);
|
||||
exec_t exec {
|
||||
.pre_exec = set_script_env,
|
||||
.fork = pfs ? xfork : fork_dont_care
|
||||
};
|
||||
exec_command(exec, BBEXEC_CMD, path);
|
||||
PFS_WAIT()
|
||||
}
|
||||
char path[4096];
|
||||
for (auto &m : module_list) {
|
||||
const char* module = m.data();
|
||||
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
|
||||
if (access(path, F_OK) == -1)
|
||||
continue;
|
||||
LOGI("%s: exec [%s.sh]\n", module, stage);
|
||||
exec_t exec {
|
||||
.pre_exec = set_script_env,
|
||||
.fork = pfs ? xfork : fork_dont_care
|
||||
};
|
||||
exec_command(exec, BBEXEC_CMD, path);
|
||||
PFS_WAIT()
|
||||
}
|
||||
|
||||
PFS_DONE()
|
||||
PFS_DONE()
|
||||
}
|
||||
|
||||
constexpr char install_script[] = R"EOF(
|
||||
@@ -154,23 +154,23 @@ rm -f $APK
|
||||
)EOF";
|
||||
|
||||
void install_apk(const char *apk) {
|
||||
setfilecon(apk, "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
||||
exec_t exec {
|
||||
.fork = fork_no_orphan
|
||||
};
|
||||
char cmds[sizeof(install_script) + 4096];
|
||||
sprintf(cmds, install_script, apk);
|
||||
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
|
||||
setfilecon(apk, "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
||||
exec_t exec {
|
||||
.fork = fork_no_orphan
|
||||
};
|
||||
char cmds[sizeof(install_script) + 4096];
|
||||
sprintf(cmds, install_script, apk);
|
||||
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
|
||||
}
|
||||
|
||||
[[noreturn]] __printflike(2, 3)
|
||||
static void abort(FILE *fp, const char *fmt, ...) {
|
||||
va_list valist;
|
||||
va_start(valist, fmt);
|
||||
vfprintf(fp, fmt, valist);
|
||||
fprintf(fp, "\n\n");
|
||||
va_end(valist);
|
||||
exit(1);
|
||||
va_list valist;
|
||||
va_start(valist, fmt);
|
||||
vfprintf(fp, fmt, valist);
|
||||
fprintf(fp, "\n\n");
|
||||
va_end(valist);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
constexpr char install_module_script[] = R"EOF(
|
||||
@@ -181,24 +181,24 @@ exit 0'
|
||||
)EOF";
|
||||
|
||||
void install_module(const char *file) {
|
||||
if (getuid() != 0)
|
||||
abort(stderr, "Run this command with root");
|
||||
if (access(DATABIN, F_OK) ||
|
||||
access(DATABIN "/busybox", X_OK) ||
|
||||
access(DATABIN "/util_functions.sh", F_OK))
|
||||
abort(stderr, "Incomplete Magisk install");
|
||||
if (access(file, F_OK))
|
||||
abort(stderr, "'%s' does not exist", file);
|
||||
if (getuid() != 0)
|
||||
abort(stderr, "Run this command with root");
|
||||
if (access(DATABIN, F_OK) ||
|
||||
access(DATABIN "/busybox", X_OK) ||
|
||||
access(DATABIN "/util_functions.sh", F_OK))
|
||||
abort(stderr, "Incomplete Magisk install");
|
||||
if (access(file, F_OK))
|
||||
abort(stderr, "'%s' does not exist", file);
|
||||
|
||||
setenv("OUTFD", "1", 1);
|
||||
setenv("ZIPFILE", file, 1);
|
||||
setenv("ASH_STANDALONE", "1", 1);
|
||||
setenv("OUTFD", "1", 1);
|
||||
setenv("ZIPFILE", file, 1);
|
||||
setenv("ASH_STANDALONE", "1", 1);
|
||||
|
||||
int fd = xopen("/dev/null", O_RDONLY);
|
||||
xdup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
int fd = xopen("/dev/null", O_RDONLY);
|
||||
xdup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
|
||||
const char *argv[] = { "/system/bin/sh", "-c", install_module_script, nullptr };
|
||||
execve(argv[0], (char **) argv, environ);
|
||||
abort(stdout, "Failed to execute BusyBox shell");
|
||||
const char *argv[] = { "/system/bin/sh", "-c", install_module_script, nullptr };
|
||||
execve(argv[0], (char **) argv, environ);
|
||||
abort(stdout, "Failed to execute BusyBox shell");
|
||||
}
|
||||
|
||||
@@ -7,30 +7,30 @@
|
||||
#include <utils.hpp>
|
||||
|
||||
static size_t socket_len(sockaddr_un *sun) {
|
||||
if (sun->sun_path[0])
|
||||
return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
|
||||
else
|
||||
return sizeof(sa_family_t) + strlen(sun->sun_path + 1) + 1;
|
||||
if (sun->sun_path[0])
|
||||
return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
|
||||
else
|
||||
return sizeof(sa_family_t) + strlen(sun->sun_path + 1) + 1;
|
||||
}
|
||||
|
||||
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name) {
|
||||
memset(sun, 0, sizeof(*sun));
|
||||
sun->sun_family = AF_UNIX;
|
||||
strcpy(sun->sun_path + 1, name);
|
||||
return socket_len(sun);
|
||||
memset(sun, 0, sizeof(*sun));
|
||||
sun->sun_family = AF_UNIX;
|
||||
strcpy(sun->sun_path + 1, name);
|
||||
return socket_len(sun);
|
||||
}
|
||||
|
||||
int socket_accept(int sockfd, int timeout) {
|
||||
struct pollfd pfd = {
|
||||
.fd = sockfd,
|
||||
.events = POLL_IN
|
||||
};
|
||||
return xpoll(&pfd, 1, timeout * 1000) <= 0 ? -1 : xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
struct pollfd pfd = {
|
||||
.fd = sockfd,
|
||||
.events = POLL_IN
|
||||
};
|
||||
return xpoll(&pfd, 1, timeout * 1000) <= 0 ? -1 : xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
}
|
||||
|
||||
void get_client_cred(int fd, struct ucred *cred) {
|
||||
socklen_t ucred_length = sizeof(*cred);
|
||||
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length);
|
||||
socklen_t ucred_length = sizeof(*cred);
|
||||
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)
|
||||
*/
|
||||
int recv_fd(int sockfd) {
|
||||
// Need to receive data from the message, otherwise don't care about it.
|
||||
char iovbuf;
|
||||
struct cmsghdr *cmsg;
|
||||
// Need to receive data from the message, otherwise don't care about it.
|
||||
char iovbuf;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
struct iovec iov = {
|
||||
.iov_base = &iovbuf,
|
||||
.iov_len = 1,
|
||||
};
|
||||
struct iovec iov = {
|
||||
.iov_base = &iovbuf,
|
||||
.iov_len = 1,
|
||||
};
|
||||
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = sizeof(cmsgbuf),
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = sizeof(cmsgbuf),
|
||||
};
|
||||
|
||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||
|
||||
// Was a control message actually sent?
|
||||
switch (msg.msg_controllen) {
|
||||
case 0:
|
||||
// No, so the file descriptor was closed and won't be used.
|
||||
return -1;
|
||||
case sizeof(cmsgbuf):
|
||||
// Yes, grab the file descriptor from it.
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
// Was a control message actually sent?
|
||||
switch (msg.msg_controllen) {
|
||||
case 0:
|
||||
// No, so the file descriptor was closed and won't be used.
|
||||
return -1;
|
||||
case sizeof(cmsgbuf):
|
||||
// Yes, grab the file descriptor from it.
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
if (cmsg == nullptr ||
|
||||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
if (cmsg == nullptr ||
|
||||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
error:
|
||||
LOGE("unable to read fd\n");
|
||||
exit(-1);
|
||||
}
|
||||
LOGE("unable to read fd\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return *(int *)CMSG_DATA(cmsg);
|
||||
return *(int *)CMSG_DATA(cmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -99,106 +99,106 @@ error:
|
||||
* but no control message with the FD is sent.
|
||||
*/
|
||||
void send_fd(int sockfd, int fd) {
|
||||
// Need to send some data in the message, this will do.
|
||||
char junk[] = { '\0' };
|
||||
struct iovec iov = {
|
||||
.iov_base = junk,
|
||||
.iov_len = 1,
|
||||
};
|
||||
// Need to send some data in the message, this will do.
|
||||
char junk[] = { '\0' };
|
||||
struct iovec iov = {
|
||||
.iov_base = junk,
|
||||
.iov_len = 1,
|
||||
};
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
if (fd != -1) {
|
||||
// Is the file descriptor actually open?
|
||||
if (fcntl(fd, F_GETFD) == -1) {
|
||||
if (errno != EBADF) {
|
||||
PLOGE("unable to send fd");
|
||||
}
|
||||
// It's closed, don't send a control message or sendmsg will EBADF.
|
||||
} else {
|
||||
// It's open, send the file descriptor in a control message.
|
||||
msg.msg_control = cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
if (fd != -1) {
|
||||
// Is the file descriptor actually open?
|
||||
if (fcntl(fd, F_GETFD) == -1) {
|
||||
if (errno != EBADF) {
|
||||
PLOGE("unable to send fd");
|
||||
}
|
||||
// It's closed, don't send a control message or sendmsg will EBADF.
|
||||
} else {
|
||||
// It's open, send the file descriptor in a control message.
|
||||
msg.msg_control = 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_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
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 val;
|
||||
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
||||
return -1;
|
||||
return val;
|
||||
int val;
|
||||
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
||||
return -1;
|
||||
return val;
|
||||
}
|
||||
|
||||
int read_int_be(int fd) {
|
||||
uint32_t val;
|
||||
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
||||
return -1;
|
||||
return ntohl(val);
|
||||
uint32_t val;
|
||||
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
|
||||
return -1;
|
||||
return ntohl(val);
|
||||
}
|
||||
|
||||
void write_int(int fd, int val) {
|
||||
if (fd < 0) return;
|
||||
xwrite(fd, &val, sizeof(val));
|
||||
if (fd < 0) return;
|
||||
xwrite(fd, &val, sizeof(val));
|
||||
}
|
||||
|
||||
void write_int_be(int fd, int val) {
|
||||
uint32_t nl = htonl(val);
|
||||
xwrite(fd, &nl, sizeof(nl));
|
||||
uint32_t nl = htonl(val);
|
||||
xwrite(fd, &nl, sizeof(nl));
|
||||
}
|
||||
|
||||
static char *rd_str(int fd, int len) {
|
||||
char *val = (char *) xmalloc(sizeof(char) * (len + 1));
|
||||
xxread(fd, val, len);
|
||||
val[len] = '\0';
|
||||
return val;
|
||||
char *val = (char *) xmalloc(sizeof(char) * (len + 1));
|
||||
xxread(fd, val, len);
|
||||
val[len] = '\0';
|
||||
return val;
|
||||
}
|
||||
|
||||
char* read_string(int fd) {
|
||||
int len = read_int(fd);
|
||||
return rd_str(fd, len);
|
||||
int len = read_int(fd);
|
||||
return rd_str(fd, len);
|
||||
}
|
||||
|
||||
char* read_string_be(int fd) {
|
||||
int len = read_int_be(fd);
|
||||
return rd_str(fd, len);
|
||||
int len = read_int_be(fd);
|
||||
return rd_str(fd, len);
|
||||
}
|
||||
|
||||
void write_string(int fd, const char *val) {
|
||||
if (fd < 0) return;
|
||||
int len = strlen(val);
|
||||
write_int(fd, len);
|
||||
xwrite(fd, val, len);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_SRC_FILES := \
|
||||
xz-embedded/xz_crc32.c \
|
||||
xz-embedded/xz_dec_lzma2.c \
|
||||
xz-embedded/xz_dec_stream.c
|
||||
xz-embedded/xz_crc32.c \
|
||||
xz-embedded/xz_dec_lzma2.c \
|
||||
xz-embedded/xz_dec_stream.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libnanopb.a
|
||||
@@ -17,9 +17,9 @@ LOCAL_MODULE:= libnanopb
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/nanopb
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_SRC_FILES := \
|
||||
nanopb/pb_common.c \
|
||||
nanopb/pb_decode.c \
|
||||
nanopb/pb_encode.c
|
||||
nanopb/pb_common.c \
|
||||
nanopb/pb_decode.c \
|
||||
nanopb/pb_encode.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libfdt.a
|
||||
@@ -28,15 +28,15 @@ LOCAL_MODULE:= libfdt
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/dtc/libfdt
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_SRC_FILES := \
|
||||
dtc/libfdt/fdt.c \
|
||||
dtc/libfdt/fdt_addresses.c \
|
||||
dtc/libfdt/fdt_empty_tree.c \
|
||||
dtc/libfdt/fdt_overlay.c \
|
||||
dtc/libfdt/fdt_ro.c \
|
||||
dtc/libfdt/fdt_rw.c \
|
||||
dtc/libfdt/fdt_strerror.c \
|
||||
dtc/libfdt/fdt_sw.c \
|
||||
dtc/libfdt/fdt_wip.c
|
||||
dtc/libfdt/fdt.c \
|
||||
dtc/libfdt/fdt_addresses.c \
|
||||
dtc/libfdt/fdt_empty_tree.c \
|
||||
dtc/libfdt/fdt_overlay.c \
|
||||
dtc/libfdt/fdt_ro.c \
|
||||
dtc/libfdt/fdt_rw.c \
|
||||
dtc/libfdt/fdt_strerror.c \
|
||||
dtc/libfdt/fdt_sw.c \
|
||||
dtc/libfdt/fdt_wip.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# liblz4.a
|
||||
@@ -45,10 +45,10 @@ LOCAL_MODULE := liblz4
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/lz4/lib
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_SRC_FILES := \
|
||||
lz4/lib/lz4.c \
|
||||
lz4/lib/lz4frame.c \
|
||||
lz4/lib/lz4hc.c \
|
||||
lz4/lib/xxhash.c
|
||||
lz4/lib/lz4.c \
|
||||
lz4/lib/lz4frame.c \
|
||||
lz4/lib/lz4hc.c \
|
||||
lz4/lib/xxhash.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libbz2.a
|
||||
@@ -57,112 +57,112 @@ LOCAL_MODULE := libbz2
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/bzip2
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
||||
LOCAL_SRC_FILES := \
|
||||
bzip2/blocksort.c \
|
||||
bzip2/huffman.c \
|
||||
bzip2/crctable.c \
|
||||
bzip2/randtable.c \
|
||||
bzip2/compress.c \
|
||||
bzip2/decompress.c \
|
||||
bzip2/bzlib.c
|
||||
bzip2/blocksort.c \
|
||||
bzip2/huffman.c \
|
||||
bzip2/crctable.c \
|
||||
bzip2/randtable.c \
|
||||
bzip2/compress.c \
|
||||
bzip2/decompress.c \
|
||||
bzip2/bzlib.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# liblzma.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := liblzma
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/xz_config \
|
||||
$(LOCAL_PATH)/xz/src/common \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/api \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/check \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/common \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/delta \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/lz \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/lzma \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/rangecoder \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/simple \
|
||||
$(LOCAL_PATH)/xz/src/liblzma
|
||||
$(LOCAL_PATH)/xz_config \
|
||||
$(LOCAL_PATH)/xz/src/common \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/api \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/check \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/common \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/delta \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/lz \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/lzma \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/rangecoder \
|
||||
$(LOCAL_PATH)/xz/src/liblzma/simple \
|
||||
$(LOCAL_PATH)/xz/src/liblzma
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/xz/src/liblzma/api
|
||||
LOCAL_SRC_FILES := \
|
||||
xz/src/common/tuklib_cpucores.c \
|
||||
xz/src/common/tuklib_exit.c \
|
||||
xz/src/common/tuklib_mbstr_fw.c \
|
||||
xz/src/common/tuklib_mbstr_width.c \
|
||||
xz/src/common/tuklib_open_stdxxx.c \
|
||||
xz/src/common/tuklib_physmem.c \
|
||||
xz/src/common/tuklib_progname.c \
|
||||
xz/src/liblzma/check/check.c \
|
||||
xz/src/liblzma/check/crc32_fast.c \
|
||||
xz/src/liblzma/check/crc32_table.c \
|
||||
xz/src/liblzma/check/crc64_fast.c \
|
||||
xz/src/liblzma/check/crc64_table.c \
|
||||
xz/src/liblzma/check/sha256.c \
|
||||
xz/src/liblzma/common/alone_decoder.c \
|
||||
xz/src/liblzma/common/alone_encoder.c \
|
||||
xz/src/liblzma/common/auto_decoder.c \
|
||||
xz/src/liblzma/common/block_buffer_decoder.c \
|
||||
xz/src/liblzma/common/block_buffer_encoder.c \
|
||||
xz/src/liblzma/common/block_decoder.c \
|
||||
xz/src/liblzma/common/block_encoder.c \
|
||||
xz/src/liblzma/common/block_header_decoder.c \
|
||||
xz/src/liblzma/common/block_header_encoder.c \
|
||||
xz/src/liblzma/common/block_util.c \
|
||||
xz/src/liblzma/common/common.c \
|
||||
xz/src/liblzma/common/easy_buffer_encoder.c \
|
||||
xz/src/liblzma/common/easy_decoder_memusage.c \
|
||||
xz/src/liblzma/common/easy_encoder.c \
|
||||
xz/src/liblzma/common/easy_encoder_memusage.c \
|
||||
xz/src/liblzma/common/easy_preset.c \
|
||||
xz/src/liblzma/common/filter_buffer_decoder.c \
|
||||
xz/src/liblzma/common/filter_buffer_encoder.c \
|
||||
xz/src/liblzma/common/filter_common.c \
|
||||
xz/src/liblzma/common/filter_decoder.c \
|
||||
xz/src/liblzma/common/filter_encoder.c \
|
||||
xz/src/liblzma/common/filter_flags_decoder.c \
|
||||
xz/src/liblzma/common/filter_flags_encoder.c \
|
||||
xz/src/liblzma/common/hardware_cputhreads.c \
|
||||
xz/src/liblzma/common/hardware_physmem.c \
|
||||
xz/src/liblzma/common/index.c \
|
||||
xz/src/liblzma/common/index_decoder.c \
|
||||
xz/src/liblzma/common/index_encoder.c \
|
||||
xz/src/liblzma/common/index_hash.c \
|
||||
xz/src/liblzma/common/outqueue.c \
|
||||
xz/src/liblzma/common/stream_buffer_decoder.c \
|
||||
xz/src/liblzma/common/stream_buffer_encoder.c \
|
||||
xz/src/liblzma/common/stream_decoder.c \
|
||||
xz/src/liblzma/common/stream_encoder.c \
|
||||
xz/src/liblzma/common/stream_encoder_mt.c \
|
||||
xz/src/liblzma/common/stream_flags_common.c \
|
||||
xz/src/liblzma/common/stream_flags_decoder.c \
|
||||
xz/src/liblzma/common/stream_flags_encoder.c \
|
||||
xz/src/liblzma/common/vli_decoder.c \
|
||||
xz/src/liblzma/common/vli_encoder.c \
|
||||
xz/src/liblzma/common/vli_size.c \
|
||||
xz/src/liblzma/delta/delta_common.c \
|
||||
xz/src/liblzma/delta/delta_decoder.c \
|
||||
xz/src/liblzma/delta/delta_encoder.c \
|
||||
xz/src/liblzma/lz/lz_decoder.c \
|
||||
xz/src/liblzma/lz/lz_encoder.c \
|
||||
xz/src/liblzma/lz/lz_encoder_mf.c \
|
||||
xz/src/liblzma/lzma/fastpos_table.c \
|
||||
xz/src/liblzma/lzma/fastpos_tablegen.c \
|
||||
xz/src/liblzma/lzma/lzma2_decoder.c \
|
||||
xz/src/liblzma/lzma/lzma2_encoder.c \
|
||||
xz/src/liblzma/lzma/lzma_decoder.c \
|
||||
xz/src/liblzma/lzma/lzma_encoder.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_presets.c \
|
||||
xz/src/liblzma/rangecoder/price_table.c \
|
||||
xz/src/liblzma/rangecoder/price_tablegen.c \
|
||||
xz/src/liblzma/simple/arm.c \
|
||||
xz/src/liblzma/simple/armthumb.c \
|
||||
xz/src/liblzma/simple/ia64.c \
|
||||
xz/src/liblzma/simple/powerpc.c \
|
||||
xz/src/liblzma/simple/simple_coder.c \
|
||||
xz/src/liblzma/simple/simple_decoder.c \
|
||||
xz/src/liblzma/simple/simple_encoder.c \
|
||||
xz/src/liblzma/simple/sparc.c \
|
||||
xz/src/liblzma/simple/x86.c
|
||||
xz/src/common/tuklib_cpucores.c \
|
||||
xz/src/common/tuklib_exit.c \
|
||||
xz/src/common/tuklib_mbstr_fw.c \
|
||||
xz/src/common/tuklib_mbstr_width.c \
|
||||
xz/src/common/tuklib_open_stdxxx.c \
|
||||
xz/src/common/tuklib_physmem.c \
|
||||
xz/src/common/tuklib_progname.c \
|
||||
xz/src/liblzma/check/check.c \
|
||||
xz/src/liblzma/check/crc32_fast.c \
|
||||
xz/src/liblzma/check/crc32_table.c \
|
||||
xz/src/liblzma/check/crc64_fast.c \
|
||||
xz/src/liblzma/check/crc64_table.c \
|
||||
xz/src/liblzma/check/sha256.c \
|
||||
xz/src/liblzma/common/alone_decoder.c \
|
||||
xz/src/liblzma/common/alone_encoder.c \
|
||||
xz/src/liblzma/common/auto_decoder.c \
|
||||
xz/src/liblzma/common/block_buffer_decoder.c \
|
||||
xz/src/liblzma/common/block_buffer_encoder.c \
|
||||
xz/src/liblzma/common/block_decoder.c \
|
||||
xz/src/liblzma/common/block_encoder.c \
|
||||
xz/src/liblzma/common/block_header_decoder.c \
|
||||
xz/src/liblzma/common/block_header_encoder.c \
|
||||
xz/src/liblzma/common/block_util.c \
|
||||
xz/src/liblzma/common/common.c \
|
||||
xz/src/liblzma/common/easy_buffer_encoder.c \
|
||||
xz/src/liblzma/common/easy_decoder_memusage.c \
|
||||
xz/src/liblzma/common/easy_encoder.c \
|
||||
xz/src/liblzma/common/easy_encoder_memusage.c \
|
||||
xz/src/liblzma/common/easy_preset.c \
|
||||
xz/src/liblzma/common/filter_buffer_decoder.c \
|
||||
xz/src/liblzma/common/filter_buffer_encoder.c \
|
||||
xz/src/liblzma/common/filter_common.c \
|
||||
xz/src/liblzma/common/filter_decoder.c \
|
||||
xz/src/liblzma/common/filter_encoder.c \
|
||||
xz/src/liblzma/common/filter_flags_decoder.c \
|
||||
xz/src/liblzma/common/filter_flags_encoder.c \
|
||||
xz/src/liblzma/common/hardware_cputhreads.c \
|
||||
xz/src/liblzma/common/hardware_physmem.c \
|
||||
xz/src/liblzma/common/index.c \
|
||||
xz/src/liblzma/common/index_decoder.c \
|
||||
xz/src/liblzma/common/index_encoder.c \
|
||||
xz/src/liblzma/common/index_hash.c \
|
||||
xz/src/liblzma/common/outqueue.c \
|
||||
xz/src/liblzma/common/stream_buffer_decoder.c \
|
||||
xz/src/liblzma/common/stream_buffer_encoder.c \
|
||||
xz/src/liblzma/common/stream_decoder.c \
|
||||
xz/src/liblzma/common/stream_encoder.c \
|
||||
xz/src/liblzma/common/stream_encoder_mt.c \
|
||||
xz/src/liblzma/common/stream_flags_common.c \
|
||||
xz/src/liblzma/common/stream_flags_decoder.c \
|
||||
xz/src/liblzma/common/stream_flags_encoder.c \
|
||||
xz/src/liblzma/common/vli_decoder.c \
|
||||
xz/src/liblzma/common/vli_encoder.c \
|
||||
xz/src/liblzma/common/vli_size.c \
|
||||
xz/src/liblzma/delta/delta_common.c \
|
||||
xz/src/liblzma/delta/delta_decoder.c \
|
||||
xz/src/liblzma/delta/delta_encoder.c \
|
||||
xz/src/liblzma/lz/lz_decoder.c \
|
||||
xz/src/liblzma/lz/lz_encoder.c \
|
||||
xz/src/liblzma/lz/lz_encoder_mf.c \
|
||||
xz/src/liblzma/lzma/fastpos_table.c \
|
||||
xz/src/liblzma/lzma/fastpos_tablegen.c \
|
||||
xz/src/liblzma/lzma/lzma2_decoder.c \
|
||||
xz/src/liblzma/lzma/lzma2_encoder.c \
|
||||
xz/src/liblzma/lzma/lzma_decoder.c \
|
||||
xz/src/liblzma/lzma/lzma_encoder.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_presets.c \
|
||||
xz/src/liblzma/rangecoder/price_table.c \
|
||||
xz/src/liblzma/rangecoder/price_tablegen.c \
|
||||
xz/src/liblzma/simple/arm.c \
|
||||
xz/src/liblzma/simple/armthumb.c \
|
||||
xz/src/liblzma/simple/ia64.c \
|
||||
xz/src/liblzma/simple/powerpc.c \
|
||||
xz/src/liblzma/simple/simple_coder.c \
|
||||
xz/src/liblzma/simple/simple_decoder.c \
|
||||
xz/src/liblzma/simple/simple_encoder.c \
|
||||
xz/src/liblzma/simple/sparc.c \
|
||||
xz/src/liblzma/simple/x86.c
|
||||
LOCAL_CFLAGS := -DHAVE_CONFIG_H -Wno-implicit-function-declaration
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
@@ -175,72 +175,72 @@ LOCAL_MODULE := libsepol
|
||||
LOCAL_C_INCLUDES := $(LIBSEPOL) $(LOCAL_PATH)/selinux/libsepol/src
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LIBSEPOL)
|
||||
LOCAL_SRC_FILES := \
|
||||
selinux/libsepol/src/assertion.c \
|
||||
selinux/libsepol/src/avrule_block.c \
|
||||
selinux/libsepol/src/avtab.c \
|
||||
selinux/libsepol/src/boolean_record.c \
|
||||
selinux/libsepol/src/booleans.c \
|
||||
selinux/libsepol/src/conditional.c \
|
||||
selinux/libsepol/src/constraint.c \
|
||||
selinux/libsepol/src/context.c \
|
||||
selinux/libsepol/src/context_record.c \
|
||||
selinux/libsepol/src/debug.c \
|
||||
selinux/libsepol/src/deprecated_funcs.c \
|
||||
selinux/libsepol/src/ebitmap.c \
|
||||
selinux/libsepol/src/expand.c \
|
||||
selinux/libsepol/src/handle.c \
|
||||
selinux/libsepol/src/hashtab.c \
|
||||
selinux/libsepol/src/hierarchy.c \
|
||||
selinux/libsepol/src/ibendport_record.c \
|
||||
selinux/libsepol/src/ibendports.c \
|
||||
selinux/libsepol/src/ibpkey_record.c \
|
||||
selinux/libsepol/src/ibpkeys.c \
|
||||
selinux/libsepol/src/iface_record.c \
|
||||
selinux/libsepol/src/interfaces.c \
|
||||
selinux/libsepol/src/kernel_to_cil.c \
|
||||
selinux/libsepol/src/kernel_to_common.c \
|
||||
selinux/libsepol/src/kernel_to_conf.c \
|
||||
selinux/libsepol/src/link.c \
|
||||
selinux/libsepol/src/mls.c \
|
||||
selinux/libsepol/src/module.c \
|
||||
selinux/libsepol/src/module_to_cil.c \
|
||||
selinux/libsepol/src/node_record.c \
|
||||
selinux/libsepol/src/nodes.c \
|
||||
selinux/libsepol/src/optimize.c \
|
||||
selinux/libsepol/src/polcaps.c \
|
||||
selinux/libsepol/src/policydb.c \
|
||||
selinux/libsepol/src/policydb_convert.c \
|
||||
selinux/libsepol/src/policydb_public.c \
|
||||
selinux/libsepol/src/port_record.c \
|
||||
selinux/libsepol/src/ports.c \
|
||||
selinux/libsepol/src/roles.c \
|
||||
selinux/libsepol/src/services.c \
|
||||
selinux/libsepol/src/sidtab.c \
|
||||
selinux/libsepol/src/symtab.c \
|
||||
selinux/libsepol/src/user_record.c \
|
||||
selinux/libsepol/src/users.c \
|
||||
selinux/libsepol/src/util.c \
|
||||
selinux/libsepol/src/write.c \
|
||||
selinux/libsepol/cil/src/cil.c \
|
||||
selinux/libsepol/cil/src/cil_binary.c \
|
||||
selinux/libsepol/cil/src/cil_build_ast.c \
|
||||
selinux/libsepol/cil/src/cil_copy_ast.c \
|
||||
selinux/libsepol/cil/src/cil_find.c \
|
||||
selinux/libsepol/cil/src/cil_fqn.c \
|
||||
selinux/libsepol/cil/src/cil_lexer.c \
|
||||
selinux/libsepol/cil/src/cil_list.c \
|
||||
selinux/libsepol/cil/src/cil_log.c \
|
||||
selinux/libsepol/cil/src/cil_mem.c \
|
||||
selinux/libsepol/cil/src/cil_parser.c \
|
||||
selinux/libsepol/cil/src/cil_policy.c \
|
||||
selinux/libsepol/cil/src/cil_post.c \
|
||||
selinux/libsepol/cil/src/cil_reset_ast.c \
|
||||
selinux/libsepol/cil/src/cil_resolve_ast.c \
|
||||
selinux/libsepol/cil/src/cil_stack.c \
|
||||
selinux/libsepol/cil/src/cil_strpool.c \
|
||||
selinux/libsepol/cil/src/cil_symtab.c \
|
||||
selinux/libsepol/cil/src/cil_tree.c \
|
||||
selinux/libsepol/cil/src/cil_verify.c
|
||||
selinux/libsepol/src/assertion.c \
|
||||
selinux/libsepol/src/avrule_block.c \
|
||||
selinux/libsepol/src/avtab.c \
|
||||
selinux/libsepol/src/boolean_record.c \
|
||||
selinux/libsepol/src/booleans.c \
|
||||
selinux/libsepol/src/conditional.c \
|
||||
selinux/libsepol/src/constraint.c \
|
||||
selinux/libsepol/src/context.c \
|
||||
selinux/libsepol/src/context_record.c \
|
||||
selinux/libsepol/src/debug.c \
|
||||
selinux/libsepol/src/deprecated_funcs.c \
|
||||
selinux/libsepol/src/ebitmap.c \
|
||||
selinux/libsepol/src/expand.c \
|
||||
selinux/libsepol/src/handle.c \
|
||||
selinux/libsepol/src/hashtab.c \
|
||||
selinux/libsepol/src/hierarchy.c \
|
||||
selinux/libsepol/src/ibendport_record.c \
|
||||
selinux/libsepol/src/ibendports.c \
|
||||
selinux/libsepol/src/ibpkey_record.c \
|
||||
selinux/libsepol/src/ibpkeys.c \
|
||||
selinux/libsepol/src/iface_record.c \
|
||||
selinux/libsepol/src/interfaces.c \
|
||||
selinux/libsepol/src/kernel_to_cil.c \
|
||||
selinux/libsepol/src/kernel_to_common.c \
|
||||
selinux/libsepol/src/kernel_to_conf.c \
|
||||
selinux/libsepol/src/link.c \
|
||||
selinux/libsepol/src/mls.c \
|
||||
selinux/libsepol/src/module.c \
|
||||
selinux/libsepol/src/module_to_cil.c \
|
||||
selinux/libsepol/src/node_record.c \
|
||||
selinux/libsepol/src/nodes.c \
|
||||
selinux/libsepol/src/optimize.c \
|
||||
selinux/libsepol/src/polcaps.c \
|
||||
selinux/libsepol/src/policydb.c \
|
||||
selinux/libsepol/src/policydb_convert.c \
|
||||
selinux/libsepol/src/policydb_public.c \
|
||||
selinux/libsepol/src/port_record.c \
|
||||
selinux/libsepol/src/ports.c \
|
||||
selinux/libsepol/src/roles.c \
|
||||
selinux/libsepol/src/services.c \
|
||||
selinux/libsepol/src/sidtab.c \
|
||||
selinux/libsepol/src/symtab.c \
|
||||
selinux/libsepol/src/user_record.c \
|
||||
selinux/libsepol/src/users.c \
|
||||
selinux/libsepol/src/util.c \
|
||||
selinux/libsepol/src/write.c \
|
||||
selinux/libsepol/cil/src/cil.c \
|
||||
selinux/libsepol/cil/src/cil_binary.c \
|
||||
selinux/libsepol/cil/src/cil_build_ast.c \
|
||||
selinux/libsepol/cil/src/cil_copy_ast.c \
|
||||
selinux/libsepol/cil/src/cil_find.c \
|
||||
selinux/libsepol/cil/src/cil_fqn.c \
|
||||
selinux/libsepol/cil/src/cil_lexer.c \
|
||||
selinux/libsepol/cil/src/cil_list.c \
|
||||
selinux/libsepol/cil/src/cil_log.c \
|
||||
selinux/libsepol/cil/src/cil_mem.c \
|
||||
selinux/libsepol/cil/src/cil_parser.c \
|
||||
selinux/libsepol/cil/src/cil_policy.c \
|
||||
selinux/libsepol/cil/src/cil_post.c \
|
||||
selinux/libsepol/cil/src/cil_reset_ast.c \
|
||||
selinux/libsepol/cil/src/cil_resolve_ast.c \
|
||||
selinux/libsepol/cil/src/cil_stack.c \
|
||||
selinux/libsepol/cil/src/cil_strpool.c \
|
||||
selinux/libsepol/cil/src/cil_symtab.c \
|
||||
selinux/libsepol/cil/src/cil_tree.c \
|
||||
selinux/libsepol/cil/src/cil_verify.c
|
||||
LOCAL_CFLAGS := -Dgetline=__getline -Wno-implicit-function-declaration
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
@@ -252,67 +252,67 @@ LOCAL_C_INCLUDES := $(LIBSELINUX)
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LIBSELINUX)
|
||||
LOCAL_STATIC_LIBRARIES := libpcre2
|
||||
LOCAL_CFLAGS := \
|
||||
-Wno-implicit-function-declaration -Wno-int-conversion -Wno-unused-function \
|
||||
-D_GNU_SOURCE -DUSE_PCRE2 \
|
||||
-DNO_PERSISTENTLY_STORED_PATTERNS -DDISABLE_SETRANS -DDISABLE_BOOL \
|
||||
-DNO_MEDIA_BACKEND -DNO_X_BACKEND -DNO_DB_BACKEND -DNO_ANDROID_BACKEND
|
||||
-Wno-implicit-function-declaration -Wno-int-conversion -Wno-unused-function \
|
||||
-D_GNU_SOURCE -DUSE_PCRE2 \
|
||||
-DNO_PERSISTENTLY_STORED_PATTERNS -DDISABLE_SETRANS -DDISABLE_BOOL \
|
||||
-DNO_MEDIA_BACKEND -DNO_X_BACKEND -DNO_DB_BACKEND -DNO_ANDROID_BACKEND
|
||||
LOCAL_SRC_FILES := \
|
||||
selinux/libselinux/src/avc.c \
|
||||
selinux/libselinux/src/avc_internal.c \
|
||||
selinux/libselinux/src/avc_sidtab.c \
|
||||
selinux/libselinux/src/booleans.c \
|
||||
selinux/libselinux/src/callbacks.c \
|
||||
selinux/libselinux/src/canonicalize_context.c \
|
||||
selinux/libselinux/src/checkAccess.c \
|
||||
selinux/libselinux/src/check_context.c \
|
||||
selinux/libselinux/src/checkreqprot.c \
|
||||
selinux/libselinux/src/compute_av.c \
|
||||
selinux/libselinux/src/compute_create.c \
|
||||
selinux/libselinux/src/compute_member.c \
|
||||
selinux/libselinux/src/compute_relabel.c \
|
||||
selinux/libselinux/src/compute_user.c \
|
||||
selinux/libselinux/src/context.c \
|
||||
selinux/libselinux/src/deny_unknown.c \
|
||||
selinux/libselinux/src/disable.c \
|
||||
selinux/libselinux/src/enabled.c \
|
||||
selinux/libselinux/src/fgetfilecon.c \
|
||||
selinux/libselinux/src/freecon.c \
|
||||
selinux/libselinux/src/freeconary.c \
|
||||
selinux/libselinux/src/fsetfilecon.c \
|
||||
selinux/libselinux/src/get_context_list.c \
|
||||
selinux/libselinux/src/get_default_type.c \
|
||||
selinux/libselinux/src/get_initial_context.c \
|
||||
selinux/libselinux/src/getenforce.c \
|
||||
selinux/libselinux/src/getfilecon.c \
|
||||
selinux/libselinux/src/getpeercon.c \
|
||||
selinux/libselinux/src/init.c \
|
||||
selinux/libselinux/src/is_customizable_type.c \
|
||||
selinux/libselinux/src/label.c \
|
||||
selinux/libselinux/src/label_file.c \
|
||||
selinux/libselinux/src/label_support.c \
|
||||
selinux/libselinux/src/lgetfilecon.c \
|
||||
selinux/libselinux/src/load_policy.c \
|
||||
selinux/libselinux/src/lsetfilecon.c \
|
||||
selinux/libselinux/src/mapping.c \
|
||||
selinux/libselinux/src/matchmediacon.c \
|
||||
selinux/libselinux/src/matchpathcon.c \
|
||||
selinux/libselinux/src/policyvers.c \
|
||||
selinux/libselinux/src/procattr.c \
|
||||
selinux/libselinux/src/query_user_context.c \
|
||||
selinux/libselinux/src/regex.c \
|
||||
selinux/libselinux/src/reject_unknown.c \
|
||||
selinux/libselinux/src/selinux_check_securetty_context.c \
|
||||
selinux/libselinux/src/selinux_config.c \
|
||||
selinux/libselinux/src/selinux_restorecon.c \
|
||||
selinux/libselinux/src/sestatus.c \
|
||||
selinux/libselinux/src/setenforce.c \
|
||||
selinux/libselinux/src/setexecfilecon.c \
|
||||
selinux/libselinux/src/setfilecon.c \
|
||||
selinux/libselinux/src/setrans_client.c \
|
||||
selinux/libselinux/src/seusers.c \
|
||||
selinux/libselinux/src/sha1.c \
|
||||
selinux/libselinux/src/stringrep.c \
|
||||
selinux/libselinux/src/validatetrans.c
|
||||
selinux/libselinux/src/avc.c \
|
||||
selinux/libselinux/src/avc_internal.c \
|
||||
selinux/libselinux/src/avc_sidtab.c \
|
||||
selinux/libselinux/src/booleans.c \
|
||||
selinux/libselinux/src/callbacks.c \
|
||||
selinux/libselinux/src/canonicalize_context.c \
|
||||
selinux/libselinux/src/checkAccess.c \
|
||||
selinux/libselinux/src/check_context.c \
|
||||
selinux/libselinux/src/checkreqprot.c \
|
||||
selinux/libselinux/src/compute_av.c \
|
||||
selinux/libselinux/src/compute_create.c \
|
||||
selinux/libselinux/src/compute_member.c \
|
||||
selinux/libselinux/src/compute_relabel.c \
|
||||
selinux/libselinux/src/compute_user.c \
|
||||
selinux/libselinux/src/context.c \
|
||||
selinux/libselinux/src/deny_unknown.c \
|
||||
selinux/libselinux/src/disable.c \
|
||||
selinux/libselinux/src/enabled.c \
|
||||
selinux/libselinux/src/fgetfilecon.c \
|
||||
selinux/libselinux/src/freecon.c \
|
||||
selinux/libselinux/src/freeconary.c \
|
||||
selinux/libselinux/src/fsetfilecon.c \
|
||||
selinux/libselinux/src/get_context_list.c \
|
||||
selinux/libselinux/src/get_default_type.c \
|
||||
selinux/libselinux/src/get_initial_context.c \
|
||||
selinux/libselinux/src/getenforce.c \
|
||||
selinux/libselinux/src/getfilecon.c \
|
||||
selinux/libselinux/src/getpeercon.c \
|
||||
selinux/libselinux/src/init.c \
|
||||
selinux/libselinux/src/is_customizable_type.c \
|
||||
selinux/libselinux/src/label.c \
|
||||
selinux/libselinux/src/label_file.c \
|
||||
selinux/libselinux/src/label_support.c \
|
||||
selinux/libselinux/src/lgetfilecon.c \
|
||||
selinux/libselinux/src/load_policy.c \
|
||||
selinux/libselinux/src/lsetfilecon.c \
|
||||
selinux/libselinux/src/mapping.c \
|
||||
selinux/libselinux/src/matchmediacon.c \
|
||||
selinux/libselinux/src/matchpathcon.c \
|
||||
selinux/libselinux/src/policyvers.c \
|
||||
selinux/libselinux/src/procattr.c \
|
||||
selinux/libselinux/src/query_user_context.c \
|
||||
selinux/libselinux/src/regex.c \
|
||||
selinux/libselinux/src/reject_unknown.c \
|
||||
selinux/libselinux/src/selinux_check_securetty_context.c \
|
||||
selinux/libselinux/src/selinux_config.c \
|
||||
selinux/libselinux/src/selinux_restorecon.c \
|
||||
selinux/libselinux/src/sestatus.c \
|
||||
selinux/libselinux/src/setenforce.c \
|
||||
selinux/libselinux/src/setexecfilecon.c \
|
||||
selinux/libselinux/src/setfilecon.c \
|
||||
selinux/libselinux/src/setrans_client.c \
|
||||
selinux/libselinux/src/seusers.c \
|
||||
selinux/libselinux/src/sha1.c \
|
||||
selinux/libselinux/src/stringrep.c \
|
||||
selinux/libselinux/src/validatetrans.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libpcre2.a
|
||||
@@ -323,34 +323,53 @@ LOCAL_CFLAGS := -DHAVE_CONFIG_H
|
||||
LOCAL_C_INCLUDES := $(LIBPCRE2) $(LIBPCRE2)_internal
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LIBPCRE2)
|
||||
LOCAL_SRC_FILES := \
|
||||
pcre/dist2/src/pcre2_auto_possess.c \
|
||||
pcre/dist2/src/pcre2_chartables.c \
|
||||
pcre/dist2/src/pcre2_compile.c \
|
||||
pcre/dist2/src/pcre2_config.c \
|
||||
pcre/dist2/src/pcre2_context.c \
|
||||
pcre/dist2/src/pcre2_convert.c \
|
||||
pcre/dist2/src/pcre2_dfa_match.c \
|
||||
pcre/dist2/src/pcre2_error.c \
|
||||
pcre/dist2/src/pcre2_extuni.c \
|
||||
pcre/dist2/src/pcre2_find_bracket.c \
|
||||
pcre/dist2/src/pcre2_fuzzsupport.c \
|
||||
pcre/dist2/src/pcre2_jit_compile.c \
|
||||
pcre/dist2/src/pcre2_maketables.c \
|
||||
pcre/dist2/src/pcre2_match.c \
|
||||
pcre/dist2/src/pcre2_match_data.c \
|
||||
pcre/dist2/src/pcre2_newline.c \
|
||||
pcre/dist2/src/pcre2_ord2utf.c \
|
||||
pcre/dist2/src/pcre2_pattern_info.c \
|
||||
pcre/dist2/src/pcre2_script_run.c \
|
||||
pcre/dist2/src/pcre2_serialize.c \
|
||||
pcre/dist2/src/pcre2_string_utils.c \
|
||||
pcre/dist2/src/pcre2_study.c \
|
||||
pcre/dist2/src/pcre2_substitute.c \
|
||||
pcre/dist2/src/pcre2_substring.c \
|
||||
pcre/dist2/src/pcre2_tables.c \
|
||||
pcre/dist2/src/pcre2_ucd.c \
|
||||
pcre/dist2/src/pcre2_valid_utf.c \
|
||||
pcre/dist2/src/pcre2_xclass.c
|
||||
pcre/dist2/src/pcre2_auto_possess.c \
|
||||
pcre/dist2/src/pcre2_chartables.c \
|
||||
pcre/dist2/src/pcre2_compile.c \
|
||||
pcre/dist2/src/pcre2_config.c \
|
||||
pcre/dist2/src/pcre2_context.c \
|
||||
pcre/dist2/src/pcre2_convert.c \
|
||||
pcre/dist2/src/pcre2_dfa_match.c \
|
||||
pcre/dist2/src/pcre2_error.c \
|
||||
pcre/dist2/src/pcre2_extuni.c \
|
||||
pcre/dist2/src/pcre2_find_bracket.c \
|
||||
pcre/dist2/src/pcre2_fuzzsupport.c \
|
||||
pcre/dist2/src/pcre2_jit_compile.c \
|
||||
pcre/dist2/src/pcre2_maketables.c \
|
||||
pcre/dist2/src/pcre2_match.c \
|
||||
pcre/dist2/src/pcre2_match_data.c \
|
||||
pcre/dist2/src/pcre2_newline.c \
|
||||
pcre/dist2/src/pcre2_ord2utf.c \
|
||||
pcre/dist2/src/pcre2_pattern_info.c \
|
||||
pcre/dist2/src/pcre2_script_run.c \
|
||||
pcre/dist2/src/pcre2_serialize.c \
|
||||
pcre/dist2/src/pcre2_string_utils.c \
|
||||
pcre/dist2/src/pcre2_study.c \
|
||||
pcre/dist2/src/pcre2_substitute.c \
|
||||
pcre/dist2/src/pcre2_substring.c \
|
||||
pcre/dist2/src/pcre2_tables.c \
|
||||
pcre/dist2/src/pcre2_ucd.c \
|
||||
pcre/dist2/src/pcre2_valid_utf.c \
|
||||
pcre/dist2/src/pcre2_xclass.c
|
||||
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.
|
||||
*/
|
||||
enum xz_mode {
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,15 +110,15 @@ enum xz_mode {
|
||||
* is used instead of XZ_BUF_ERROR.
|
||||
*/
|
||||
enum xz_ret {
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,13 +138,13 @@ enum xz_ret {
|
||||
* the variables in_pos and out_pos are modified by the XZ code.
|
||||
*/
|
||||
struct xz_buf {
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
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
|
||||
# ifdef __GNUC__
|
||||
# define __always_inline \
|
||||
inline __attribute__((__always_inline__))
|
||||
inline __attribute__((__always_inline__))
|
||||
# else
|
||||
# define __always_inline inline
|
||||
# endif
|
||||
@@ -75,40 +75,40 @@ typedef unsigned char bool;
|
||||
#ifndef get_unaligned_le32
|
||||
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf[0]
|
||||
| ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16)
|
||||
| ((uint32_t)buf[3] << 24);
|
||||
return (uint32_t)buf[0]
|
||||
| ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16)
|
||||
| ((uint32_t)buf[3] << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef get_unaligned_be32
|
||||
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)(buf[0] << 24)
|
||||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| (uint32_t)buf[3];
|
||||
return (uint32_t)(buf[0] << 24)
|
||||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| (uint32_t)buf[3];
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_le32
|
||||
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)val;
|
||||
buf[1] = (uint8_t)(val >> 8);
|
||||
buf[2] = (uint8_t)(val >> 16);
|
||||
buf[3] = (uint8_t)(val >> 24);
|
||||
buf[0] = (uint8_t)val;
|
||||
buf[1] = (uint8_t)(val >> 8);
|
||||
buf[2] = (uint8_t)(val >> 16);
|
||||
buf[3] = (uint8_t)(val >> 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_be32
|
||||
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)val;
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)val;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t r;
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t r;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
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)
|
||||
{
|
||||
crc = ~crc;
|
||||
crc = ~crc;
|
||||
|
||||
while (size != 0) {
|
||||
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
while (size != 0) {
|
||||
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--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.
|
||||
*/
|
||||
enum lzma_state {
|
||||
STATE_LIT_LIT,
|
||||
STATE_MATCH_LIT_LIT,
|
||||
STATE_REP_LIT_LIT,
|
||||
STATE_SHORTREP_LIT_LIT,
|
||||
STATE_MATCH_LIT,
|
||||
STATE_REP_LIT,
|
||||
STATE_SHORTREP_LIT,
|
||||
STATE_LIT_MATCH,
|
||||
STATE_LIT_LONGREP,
|
||||
STATE_LIT_SHORTREP,
|
||||
STATE_NONLIT_MATCH,
|
||||
STATE_NONLIT_REP
|
||||
STATE_LIT_LIT,
|
||||
STATE_MATCH_LIT_LIT,
|
||||
STATE_REP_LIT_LIT,
|
||||
STATE_SHORTREP_LIT_LIT,
|
||||
STATE_MATCH_LIT,
|
||||
STATE_REP_LIT,
|
||||
STATE_SHORTREP_LIT,
|
||||
STATE_LIT_MATCH,
|
||||
STATE_LIT_LONGREP,
|
||||
STATE_LIT_SHORTREP,
|
||||
STATE_NONLIT_MATCH,
|
||||
STATE_NONLIT_REP
|
||||
};
|
||||
|
||||
/* Total number of states */
|
||||
@@ -63,36 +63,36 @@ enum lzma_state {
|
||||
/* Indicate that the latest symbol was a literal. */
|
||||
static inline void lzma_state_literal(enum lzma_state *state)
|
||||
{
|
||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||
*state = STATE_LIT_LIT;
|
||||
else if (*state <= STATE_LIT_SHORTREP)
|
||||
*state -= 3;
|
||||
else
|
||||
*state -= 6;
|
||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||
*state = STATE_LIT_LIT;
|
||||
else if (*state <= STATE_LIT_SHORTREP)
|
||||
*state -= 3;
|
||||
else
|
||||
*state -= 6;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a match. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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:
|
||||
@@ -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)
|
||||
{
|
||||
return len < DIST_STATES + MATCH_LEN_MIN
|
||||
? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||
return len < DIST_STATES + MATCH_LEN_MIN
|
||||
? 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/kernel.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
|
||||
# include <linux/slab.h>
|
||||
# include <linux/vmalloc.h>
|
||||
@@ -42,17 +42,17 @@
|
||||
# endif
|
||||
# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
|
||||
#else
|
||||
/*
|
||||
* For userspace builds, use a separate header to define the required
|
||||
* macros and functions. This makes it easier to adapt the code into
|
||||
* different environments and avoids clutter in the Linux kernel tree.
|
||||
*/
|
||||
/*
|
||||
* For userspace builds, use a separate header to define the required
|
||||
* macros and functions. This makes it easier to adapt the code into
|
||||
* different environments and avoids clutter in the Linux kernel tree.
|
||||
*/
|
||||
# include "xz_config.h"
|
||||
#endif
|
||||
|
||||
/* If no specific decoding mode is requested, enable support for all modes. */
|
||||
#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
|
||||
&& !defined(XZ_DEC_DYNALLOC)
|
||||
&& !defined(XZ_DEC_DYNALLOC)
|
||||
# define XZ_DEC_SINGLE
|
||||
# define XZ_DEC_PREALLOC
|
||||
# define XZ_DEC_DYNALLOC
|
||||
@@ -95,9 +95,9 @@
|
||||
*/
|
||||
#ifndef XZ_DEC_BCJ
|
||||
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|
||||
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|
||||
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|
||||
|| defined(XZ_DEC_SPARC)
|
||||
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|
||||
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|
||||
|| defined(XZ_DEC_SPARC)
|
||||
# define XZ_DEC_BCJ
|
||||
# endif
|
||||
#endif
|
||||
@@ -107,7 +107,7 @@
|
||||
* before calling xz_dec_lzma2_run().
|
||||
*/
|
||||
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
|
||||
@@ -116,11 +116,11 @@ XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
|
||||
* decoder doesn't support.
|
||||
*/
|
||||
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. */
|
||||
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. */
|
||||
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.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||
struct xz_dec_lzma2 *lzma2,
|
||||
struct xz_buf *b);
|
||||
struct xz_dec_lzma2 *lzma2,
|
||||
struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the BCJ filters. */
|
||||
#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>
|
||||
# undef crc32
|
||||
# define xz_crc32(buf, size, crc) \
|
||||
(~crc32_le(~(uint32_t)(crc), buf, size))
|
||||
(~crc32_le(~(uint32_t)(crc), buf, size))
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -50,10 +50,10 @@ typedef uint64_t vli_type;
|
||||
|
||||
/* Integrity Check types */
|
||||
enum xz_check {
|
||||
XZ_CHECK_NONE = 0,
|
||||
XZ_CHECK_CRC32 = 1,
|
||||
XZ_CHECK_CRC64 = 4,
|
||||
XZ_CHECK_SHA256 = 10
|
||||
XZ_CHECK_NONE = 0,
|
||||
XZ_CHECK_CRC32 = 1,
|
||||
XZ_CHECK_CRC64 = 4,
|
||||
XZ_CHECK_SHA256 = 10
|
||||
};
|
||||
|
||||
/* Maximum possible Check ID */
|
||||
|
||||
@@ -8,35 +8,35 @@
|
||||
|
||||
// Daemon command codes
|
||||
enum {
|
||||
START_DAEMON,
|
||||
SUPERUSER,
|
||||
CHECK_VERSION,
|
||||
CHECK_VERSION_CODE,
|
||||
POST_FS_DATA,
|
||||
LATE_START,
|
||||
BOOT_COMPLETE,
|
||||
MAGISKHIDE,
|
||||
SQLITE_CMD,
|
||||
REMOVE_MODULES,
|
||||
GET_PATH,
|
||||
DAEMON_CODE_END,
|
||||
START_DAEMON,
|
||||
SUPERUSER,
|
||||
CHECK_VERSION,
|
||||
CHECK_VERSION_CODE,
|
||||
POST_FS_DATA,
|
||||
LATE_START,
|
||||
BOOT_COMPLETE,
|
||||
MAGISKHIDE,
|
||||
SQLITE_CMD,
|
||||
REMOVE_MODULES,
|
||||
GET_PATH,
|
||||
DAEMON_CODE_END,
|
||||
};
|
||||
|
||||
// Return codes for daemon
|
||||
enum {
|
||||
DAEMON_ERROR = -1,
|
||||
DAEMON_SUCCESS = 0,
|
||||
ROOT_REQUIRED,
|
||||
DAEMON_LAST
|
||||
DAEMON_ERROR = -1,
|
||||
DAEMON_SUCCESS = 0,
|
||||
ROOT_REQUIRED,
|
||||
DAEMON_LAST
|
||||
};
|
||||
|
||||
// Daemon state
|
||||
enum {
|
||||
STATE_NONE,
|
||||
STATE_POST_FS_DATA,
|
||||
STATE_POST_FS_DATA_DONE,
|
||||
STATE_LATE_START_DONE,
|
||||
STATE_BOOT_COMPLETE
|
||||
STATE_NONE,
|
||||
STATE_POST_FS_DATA,
|
||||
STATE_POST_FS_DATA_DONE,
|
||||
STATE_LATE_START_DONE,
|
||||
STATE_BOOT_COMPLETE
|
||||
};
|
||||
|
||||
extern int SDK_INT;
|
||||
|
||||
@@ -9,25 +9,25 @@
|
||||
template <class T, size_t num>
|
||||
class db_data_base {
|
||||
public:
|
||||
T& operator [](std::string_view key) {
|
||||
return data[getKeyIdx(key)];
|
||||
}
|
||||
T& operator [](std::string_view key) {
|
||||
return data[getKeyIdx(key)];
|
||||
}
|
||||
|
||||
const T& operator [](std::string_view key) const {
|
||||
return data[getKeyIdx(key)];
|
||||
}
|
||||
const T& operator [](std::string_view key) const {
|
||||
return data[getKeyIdx(key)];
|
||||
}
|
||||
|
||||
T& operator [](int key) {
|
||||
return data[key];
|
||||
}
|
||||
T& operator [](int key) {
|
||||
return data[key];
|
||||
}
|
||||
|
||||
const T& operator [](int key) const {
|
||||
return data[key];
|
||||
}
|
||||
const T& operator [](int key) const {
|
||||
return data[key];
|
||||
}
|
||||
|
||||
protected:
|
||||
T data[num + 1];
|
||||
virtual int getKeyIdx(std::string_view key) const = 0;
|
||||
T data[num + 1];
|
||||
virtual int getKeyIdx(std::string_view key) const = 0;
|
||||
};
|
||||
|
||||
/***************
|
||||
@@ -46,40 +46,40 @@ protected:
|
||||
|
||||
// Settings keys
|
||||
enum {
|
||||
ROOT_ACCESS = 0,
|
||||
SU_MULTIUSER_MODE,
|
||||
SU_MNT_NS,
|
||||
HIDE_CONFIG
|
||||
ROOT_ACCESS = 0,
|
||||
SU_MULTIUSER_MODE,
|
||||
SU_MNT_NS,
|
||||
HIDE_CONFIG
|
||||
};
|
||||
|
||||
// Values for root_access
|
||||
enum {
|
||||
ROOT_ACCESS_DISABLED = 0,
|
||||
ROOT_ACCESS_APPS_ONLY,
|
||||
ROOT_ACCESS_ADB_ONLY,
|
||||
ROOT_ACCESS_APPS_AND_ADB
|
||||
ROOT_ACCESS_DISABLED = 0,
|
||||
ROOT_ACCESS_APPS_ONLY,
|
||||
ROOT_ACCESS_ADB_ONLY,
|
||||
ROOT_ACCESS_APPS_AND_ADB
|
||||
};
|
||||
|
||||
// Values for multiuser_mode
|
||||
enum {
|
||||
MULTIUSER_MODE_OWNER_ONLY = 0,
|
||||
MULTIUSER_MODE_OWNER_MANAGED,
|
||||
MULTIUSER_MODE_USER
|
||||
MULTIUSER_MODE_OWNER_ONLY = 0,
|
||||
MULTIUSER_MODE_OWNER_MANAGED,
|
||||
MULTIUSER_MODE_USER
|
||||
};
|
||||
|
||||
// Values for mnt_ns
|
||||
enum {
|
||||
NAMESPACE_MODE_GLOBAL = 0,
|
||||
NAMESPACE_MODE_REQUESTER,
|
||||
NAMESPACE_MODE_ISOLATE
|
||||
NAMESPACE_MODE_GLOBAL = 0,
|
||||
NAMESPACE_MODE_REQUESTER,
|
||||
NAMESPACE_MODE_ISOLATE
|
||||
};
|
||||
|
||||
class db_settings : public db_data_base<int, DB_SETTINGS_NUM> {
|
||||
public:
|
||||
db_settings();
|
||||
db_settings();
|
||||
|
||||
protected:
|
||||
int getKeyIdx(std::string_view key) const override;
|
||||
int getKeyIdx(std::string_view key) const override;
|
||||
};
|
||||
|
||||
/**************
|
||||
@@ -95,12 +95,12 @@ protected:
|
||||
|
||||
// Strings keys
|
||||
enum {
|
||||
SU_MANAGER = 0
|
||||
SU_MANAGER = 0
|
||||
};
|
||||
|
||||
class db_strings : public db_data_base<std::string, DB_STRING_NUM> {
|
||||
protected:
|
||||
int getKeyIdx(std::string_view key) const override;
|
||||
int getKeyIdx(std::string_view key) const override;
|
||||
};
|
||||
|
||||
/*************
|
||||
@@ -108,15 +108,15 @@ protected:
|
||||
*************/
|
||||
|
||||
typedef enum {
|
||||
QUERY = 0,
|
||||
DENY = 1,
|
||||
ALLOW = 2,
|
||||
QUERY = 0,
|
||||
DENY = 1,
|
||||
ALLOW = 2,
|
||||
} policy_t;
|
||||
|
||||
struct su_access {
|
||||
policy_t policy;
|
||||
int log;
|
||||
int notify;
|
||||
policy_t policy;
|
||||
int log;
|
||||
int notify;
|
||||
};
|
||||
|
||||
#define DEFAULT_SU_ACCESS (su_access) { \
|
||||
|
||||
@@ -36,3 +36,4 @@ int magiskhide_main(int argc, char *argv[]);
|
||||
int magiskpolicy_main(int argc, char *argv[]);
|
||||
int su_client_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 {
|
||||
public:
|
||||
typedef const char * c_str;
|
||||
~sepolicy();
|
||||
typedef const char * c_str;
|
||||
~sepolicy();
|
||||
|
||||
// Public static factory functions
|
||||
static sepolicy *from_file(c_str file);
|
||||
static sepolicy *from_split();
|
||||
static sepolicy *compile_split();
|
||||
// Public static factory functions
|
||||
static sepolicy *from_file(c_str file);
|
||||
static sepolicy *from_split();
|
||||
static sepolicy *compile_split();
|
||||
|
||||
// External APIs
|
||||
bool to_file(c_str file);
|
||||
void parse_statement(c_str stmt);
|
||||
void load_rule_file(c_str file);
|
||||
// External APIs
|
||||
bool to_file(c_str file);
|
||||
void parse_statement(c_str stmt);
|
||||
void load_rule_file(c_str file);
|
||||
|
||||
// Operation on types
|
||||
bool type(c_str name, c_str attr);
|
||||
bool attribute(c_str name);
|
||||
bool permissive(c_str type);
|
||||
bool enforce(c_str type);
|
||||
bool typeattribute(c_str type, c_str attr);
|
||||
bool exists(c_str type);
|
||||
// Operation on types
|
||||
bool type(c_str name, c_str attr);
|
||||
bool attribute(c_str name);
|
||||
bool permissive(c_str type);
|
||||
bool enforce(c_str type);
|
||||
bool typeattribute(c_str type, c_str attr);
|
||||
bool exists(c_str type);
|
||||
|
||||
// Access vector rules
|
||||
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 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);
|
||||
// Access vector rules
|
||||
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 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);
|
||||
|
||||
// Extended permissions access vector rules
|
||||
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 dontauditxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
||||
// Extended permissions access vector rules
|
||||
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 dontauditxperm(c_str src, c_str tgt, c_str cls, c_str range);
|
||||
|
||||
// Type rules
|
||||
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_member(c_str src, c_str tgt, c_str cls, c_str def);
|
||||
// Type rules
|
||||
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_member(c_str src, c_str tgt, c_str cls, c_str def);
|
||||
|
||||
// File system labeling
|
||||
bool genfscon(c_str fs_name, c_str path, c_str ctx);
|
||||
// File system labeling
|
||||
bool genfscon(c_str fs_name, c_str path, c_str ctx);
|
||||
|
||||
// Magisk
|
||||
void magisk_rules();
|
||||
// Magisk
|
||||
void magisk_rules();
|
||||
|
||||
// Deprecate
|
||||
bool create(c_str name) { return type(name, "domain"); }
|
||||
// Deprecate
|
||||
bool create(c_str name) { return type(name, "domain"); }
|
||||
|
||||
protected:
|
||||
policydb *db;
|
||||
policydb *db;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
int setprop(const char *name, const char *value, bool prop_svc = true);
|
||||
std::string getprop(const char *name, bool persist = false);
|
||||
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);
|
||||
void load_prop_file(const char *filename, bool prop_svc = true);
|
||||
|
||||
@@ -13,121 +13,121 @@ using namespace std;
|
||||
|
||||
template<typename Func>
|
||||
static void parse_cmdline(const Func &fn) {
|
||||
char cmdline[4096];
|
||||
int fd = xopen("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
||||
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
|
||||
close(fd);
|
||||
char cmdline[4096];
|
||||
int fd = xopen("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
||||
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
|
||||
close(fd);
|
||||
|
||||
char *tok, *eql, *tmp, *saveptr;
|
||||
saveptr = cmdline;
|
||||
while ((tok = strtok_r(nullptr, " \n", &saveptr)) != nullptr) {
|
||||
eql = strchr(tok, '=');
|
||||
if (eql) {
|
||||
*eql = '\0';
|
||||
if (eql[1] == '"') {
|
||||
tmp = strchr(saveptr, '"');
|
||||
if (tmp != nullptr) {
|
||||
*tmp = '\0';
|
||||
saveptr[-1] = ' ';
|
||||
saveptr = tmp + 1;
|
||||
eql++;
|
||||
}
|
||||
}
|
||||
fn(tok, eql + 1);
|
||||
} else {
|
||||
fn(tok, "");
|
||||
}
|
||||
}
|
||||
char *tok, *eql, *tmp, *saveptr;
|
||||
saveptr = cmdline;
|
||||
while ((tok = strtok_r(nullptr, " \n", &saveptr)) != nullptr) {
|
||||
eql = strchr(tok, '=');
|
||||
if (eql) {
|
||||
*eql = '\0';
|
||||
if (eql[1] == '"') {
|
||||
tmp = strchr(saveptr, '"');
|
||||
if (tmp != nullptr) {
|
||||
*tmp = '\0';
|
||||
saveptr[-1] = ' ';
|
||||
saveptr = tmp + 1;
|
||||
eql++;
|
||||
}
|
||||
}
|
||||
fn(tok, eql + 1);
|
||||
} else {
|
||||
fn(tok, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
||||
|
||||
static bool check_key_combo() {
|
||||
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
||||
vector<int> events;
|
||||
constexpr const char *name = "/event";
|
||||
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
||||
vector<int> events;
|
||||
constexpr const char *name = "/event";
|
||||
|
||||
for (int minor = 64; minor < 96; ++minor) {
|
||||
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
||||
continue;
|
||||
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
||||
unlink(name);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEUP, bitmask))
|
||||
events.push_back(fd);
|
||||
else
|
||||
close(fd);
|
||||
}
|
||||
if (events.empty())
|
||||
return false;
|
||||
for (int minor = 64; minor < 96; ++minor) {
|
||||
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
||||
continue;
|
||||
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
||||
unlink(name);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEUP, bitmask))
|
||||
events.push_back(fd);
|
||||
else
|
||||
close(fd);
|
||||
}
|
||||
if (events.empty())
|
||||
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
|
||||
int count = 0;
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
for (const int &fd : events) {
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEUP, bitmask)) {
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count >= 300) {
|
||||
LOGD("KEY_VOLUMEUP detected: disable system-as-root\n");
|
||||
return true;
|
||||
}
|
||||
// Check every 10ms
|
||||
usleep(10000);
|
||||
}
|
||||
return false;
|
||||
// Return true if volume up key is held for more than 3 seconds
|
||||
int count = 0;
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
for (const int &fd : events) {
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
||||
if (test_bit(KEY_VOLUMEUP, bitmask)) {
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count >= 300) {
|
||||
LOGD("KEY_VOLUMEUP detected: disable system-as-root\n");
|
||||
return true;
|
||||
}
|
||||
// Check every 10ms
|
||||
usleep(10000);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static FILE *kmsg;
|
||||
static char kmsg_buf[4096];
|
||||
static int vprintk(const char *fmt, va_list ap) {
|
||||
vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap);
|
||||
return fprintf(kmsg, "%s", kmsg_buf);
|
||||
vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap);
|
||||
return fprintf(kmsg, "%s", kmsg_buf);
|
||||
}
|
||||
void setup_klog() {
|
||||
// Shut down first 3 fds
|
||||
int fd;
|
||||
if (access("/dev/null", W_OK) == 0) {
|
||||
fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
|
||||
} else {
|
||||
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
|
||||
fd = xopen("/null", O_RDWR | O_CLOEXEC);
|
||||
unlink("/null");
|
||||
}
|
||||
xdup3(fd, STDIN_FILENO, O_CLOEXEC);
|
||||
xdup3(fd, STDOUT_FILENO, O_CLOEXEC);
|
||||
xdup3(fd, STDERR_FILENO, O_CLOEXEC);
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
// Shut down first 3 fds
|
||||
int fd;
|
||||
if (access("/dev/null", W_OK) == 0) {
|
||||
fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
|
||||
} else {
|
||||
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
|
||||
fd = xopen("/null", O_RDWR | O_CLOEXEC);
|
||||
unlink("/null");
|
||||
}
|
||||
xdup3(fd, STDIN_FILENO, O_CLOEXEC);
|
||||
xdup3(fd, STDOUT_FILENO, O_CLOEXEC);
|
||||
xdup3(fd, STDERR_FILENO, O_CLOEXEC);
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
|
||||
if (access("/dev/kmsg", W_OK) == 0) {
|
||||
fd = xopen("/dev/kmsg", O_WRONLY | O_CLOEXEC);
|
||||
} else {
|
||||
mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11));
|
||||
fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC);
|
||||
unlink("/kmsg");
|
||||
}
|
||||
if (access("/dev/kmsg", W_OK) == 0) {
|
||||
fd = xopen("/dev/kmsg", O_WRONLY | O_CLOEXEC);
|
||||
} else {
|
||||
mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11));
|
||||
fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC);
|
||||
unlink("/kmsg");
|
||||
}
|
||||
|
||||
kmsg = fdopen(fd, "w");
|
||||
setbuf(kmsg, nullptr);
|
||||
log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk;
|
||||
log_cb.ex = nop_ex;
|
||||
strcpy(kmsg_buf, "magiskinit: ");
|
||||
kmsg = fdopen(fd, "w");
|
||||
setbuf(kmsg, nullptr);
|
||||
log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk;
|
||||
log_cb.ex = nop_ex;
|
||||
strcpy(kmsg_buf, "magiskinit: ");
|
||||
|
||||
// Disable kmsg rate limiting
|
||||
if (FILE *rate = fopen("/proc/sys/kernel/printk_devkmsg", "w")) {
|
||||
fprintf(rate, "on\n");
|
||||
fclose(rate);
|
||||
}
|
||||
// Disable kmsg rate limiting
|
||||
if (FILE *rate = fopen("/proc/sys/kernel/printk_devkmsg", "w")) {
|
||||
fprintf(rate, "on\n");
|
||||
fclose(rate);
|
||||
}
|
||||
}
|
||||
|
||||
#define read_dt(name, key) \
|
||||
@@ -141,75 +141,78 @@ if (access(file_name, R_OK) == 0){ \
|
||||
}
|
||||
|
||||
void load_kernel_info(cmdline *cmd) {
|
||||
// Get kernel data using procfs and sysfs
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
// Get kernel data using procfs and sysfs
|
||||
xmkdir("/proc", 0755);
|
||||
xmount("proc", "/proc", "proc", 0, nullptr);
|
||||
xmkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
||||
|
||||
// Log to kernel
|
||||
setup_klog();
|
||||
// Log to kernel
|
||||
setup_klog();
|
||||
|
||||
parse_cmdline([=](string_view key, const char *value) -> void {
|
||||
if (key == "androidboot.slot_suffix") {
|
||||
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);
|
||||
}
|
||||
});
|
||||
parse_cmdline([=](string_view key, const char *value) -> void {
|
||||
if (key == "androidboot.slot_suffix") {
|
||||
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 == "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);
|
||||
}
|
||||
});
|
||||
|
||||
LOGD("Kernel cmdline info:\n");
|
||||
LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs);
|
||||
LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot);
|
||||
LOGD("slot=[%s]\n", cmd->slot);
|
||||
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);
|
||||
LOGD("Kernel cmdline info:\n");
|
||||
LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs);
|
||||
LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot);
|
||||
LOGD("rootwait=[%d]\n", cmd->rootwait);
|
||||
LOGD("slot=[%s]\n", cmd->slot);
|
||||
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);
|
||||
|
||||
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
|
||||
if (key == "RECOVERYMODE" && value == "true") {
|
||||
LOGD("Running in recovery mode, waiting for key...\n");
|
||||
cmd->skip_initramfs = !check_key_combo();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
|
||||
if (key == "RECOVERYMODE" && value == "true") {
|
||||
LOGD("Running in recovery mode, waiting for key...\n");
|
||||
cmd->skip_initramfs = !check_key_combo();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (cmd->dt_dir[0] == '\0')
|
||||
strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
|
||||
if (cmd->dt_dir[0] == '\0')
|
||||
strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
|
||||
|
||||
char file_name[128];
|
||||
read_dt("fstab_suffix", fstab_suffix)
|
||||
read_dt("hardware", hardware)
|
||||
read_dt("hardware.platform", hardware_plat)
|
||||
char file_name[128];
|
||||
read_dt("fstab_suffix", fstab_suffix)
|
||||
read_dt("hardware", hardware)
|
||||
read_dt("hardware.platform", 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);
|
||||
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() {
|
||||
if (access("/apex", F_OK) == 0)
|
||||
return true;
|
||||
if (access("/system/bin/init", F_OK) == 0)
|
||||
return true;
|
||||
// If we still have no indication, parse the original init and see what's up
|
||||
auto init = raw_data::mmap_ro("/.backup/init");
|
||||
return init.contains("selinux_setup");
|
||||
if (access("/apex", F_OK) == 0)
|
||||
return true;
|
||||
if (access("/system/bin/init", F_OK) == 0)
|
||||
return true;
|
||||
// If we still have no indication, parse the original init and see what's up
|
||||
auto init = raw_data::mmap_ro("/.backup/init");
|
||||
return init.contains("selinux_setup");
|
||||
}
|
||||
|
||||
@@ -24,163 +24,163 @@ using namespace std;
|
||||
#define ENABLE_TEST 0
|
||||
|
||||
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) {
|
||||
uint8_t out[8192];
|
||||
xz_crc32_init();
|
||||
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
||||
struct xz_buf b = {
|
||||
.in = buf,
|
||||
.in_pos = 0,
|
||||
.in_size = size,
|
||||
.out = out,
|
||||
.out_pos = 0,
|
||||
.out_size = sizeof(out)
|
||||
};
|
||||
enum xz_ret ret;
|
||||
do {
|
||||
ret = xz_dec_run(dec, &b);
|
||||
if (ret != XZ_OK && ret != XZ_STREAM_END)
|
||||
return false;
|
||||
write(fd, out, b.out_pos);
|
||||
b.out_pos = 0;
|
||||
} while (b.in_pos != size);
|
||||
return true;
|
||||
uint8_t out[8192];
|
||||
xz_crc32_init();
|
||||
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
||||
struct xz_buf b = {
|
||||
.in = buf,
|
||||
.in_pos = 0,
|
||||
.in_size = size,
|
||||
.out = out,
|
||||
.out_pos = 0,
|
||||
.out_size = sizeof(out)
|
||||
};
|
||||
enum xz_ret ret;
|
||||
do {
|
||||
ret = xz_dec_run(dec, &b);
|
||||
if (ret != XZ_OK && ret != XZ_STREAM_END)
|
||||
return false;
|
||||
write(fd, out, b.out_pos);
|
||||
b.out_pos = 0;
|
||||
} while (b.in_pos != size);
|
||||
return true;
|
||||
}
|
||||
|
||||
int dump_magisk(const char *path, mode_t mode) {
|
||||
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
|
||||
return 1;
|
||||
close(fd);
|
||||
return 0;
|
||||
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
|
||||
return 1;
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_manager(const char *path, mode_t mode) {
|
||||
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
if (!unxz(fd, manager_xz, sizeof(manager_xz)))
|
||||
return 1;
|
||||
close(fd);
|
||||
return 0;
|
||||
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
if (!unxz(fd, manager_xz, sizeof(manager_xz)))
|
||||
return 1;
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
class RecoveryInit : public BaseInit {
|
||||
public:
|
||||
RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
||||
void start() override {
|
||||
LOGD("Ramdisk is recovery, abort\n");
|
||||
rename("/.backup/init", "/init");
|
||||
rm_rf("/.backup");
|
||||
exec_init();
|
||||
}
|
||||
RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
||||
void start() override {
|
||||
LOGD("Ramdisk is recovery, abort\n");
|
||||
rename("/.backup/init", "/init");
|
||||
rm_rf("/.backup");
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
#if ENABLE_TEST
|
||||
class TestInit : public BaseInit {
|
||||
public:
|
||||
TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
|
||||
void start() override {
|
||||
// Place init tests here
|
||||
}
|
||||
TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
|
||||
void start() override {
|
||||
// Place init tests here
|
||||
}
|
||||
};
|
||||
|
||||
static int test_main(int argc, char *argv[]) {
|
||||
// Log to console
|
||||
cmdline_logging();
|
||||
log_cb.ex = nop_ex;
|
||||
// Log to console
|
||||
cmdline_logging();
|
||||
log_cb.ex = nop_ex;
|
||||
|
||||
// Switch to isolate namespace
|
||||
xunshare(CLONE_NEWNS);
|
||||
xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr);
|
||||
// Switch to isolate namespace
|
||||
xunshare(CLONE_NEWNS);
|
||||
xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr);
|
||||
|
||||
// Unmount everything in reverse
|
||||
vector<string> mounts;
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
if (me->mnt_dir != "/"sv)
|
||||
mounts.emplace_back(me->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
for (auto &m : reversed(mounts))
|
||||
xumount(m.data());
|
||||
// Unmount everything in reverse
|
||||
vector<string> mounts;
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
if (me->mnt_dir != "/"sv)
|
||||
mounts.emplace_back(me->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
for (auto &m : reversed(mounts))
|
||||
xumount(m.data());
|
||||
|
||||
// chroot jail
|
||||
chdir(dirname(argv[0]));
|
||||
chroot(".");
|
||||
chdir("/");
|
||||
// chroot jail
|
||||
chdir(dirname(argv[0]));
|
||||
chroot(".");
|
||||
chdir("/");
|
||||
|
||||
cmdline cmd{};
|
||||
load_kernel_info(&cmd);
|
||||
cmdline cmd{};
|
||||
load_kernel_info(&cmd);
|
||||
|
||||
auto init = make_unique<TestInit>(argv, &cmd);
|
||||
init->start();
|
||||
auto init = make_unique<TestInit>(argv, &cmd);
|
||||
init->start();
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
#endif // ENABLE_TEST
|
||||
|
||||
static int magisk_proxy_main(int argc, char *argv[]) {
|
||||
setup_klog();
|
||||
auto init = make_unique<MagiskProxy>(argv);
|
||||
init->start();
|
||||
return 1;
|
||||
setup_klog();
|
||||
auto init = make_unique<MagiskProxy>(argv);
|
||||
init->start();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
umask(0);
|
||||
|
||||
auto name = basename(argv[0]);
|
||||
if (name == "magisk"sv)
|
||||
return magisk_proxy_main(argc, argv);
|
||||
for (int i = 0; init_applet[i]; ++i) {
|
||||
if (strcmp(name, init_applet[i]) == 0)
|
||||
return (*init_applet_main[i])(argc, argv);
|
||||
}
|
||||
auto name = basename(argv[0]);
|
||||
if (name == "magisk"sv)
|
||||
return magisk_proxy_main(argc, argv);
|
||||
for (int i = 0; init_applet[i]; ++i) {
|
||||
if (strcmp(name, init_applet[i]) == 0)
|
||||
return (*init_applet_main[i])(argc, argv);
|
||||
}
|
||||
|
||||
#if ENABLE_TEST
|
||||
if (getenv("INIT_TEST") != nullptr)
|
||||
return test_main(argc, argv);
|
||||
if (getenv("INIT_TEST") != nullptr)
|
||||
return test_main(argc, argv);
|
||||
#endif
|
||||
|
||||
if (argc > 1 && argv[1] == "-x"sv) {
|
||||
if (argv[2] == "magisk"sv)
|
||||
return dump_magisk(argv[3], 0755);
|
||||
else if (argv[2] == "manager"sv)
|
||||
return dump_manager(argv[3], 0644);
|
||||
}
|
||||
if (argc > 1 && argv[1] == "-x"sv) {
|
||||
if (argv[2] == "magisk"sv)
|
||||
return dump_magisk(argv[3], 0755);
|
||||
else if (argv[2] == "manager"sv)
|
||||
return dump_manager(argv[3], 0644);
|
||||
}
|
||||
|
||||
if (getpid() != 1)
|
||||
return 1;
|
||||
if (getpid() != 1)
|
||||
return 1;
|
||||
|
||||
BaseInit *init;
|
||||
cmdline cmd{};
|
||||
BaseInit *init;
|
||||
cmdline cmd{};
|
||||
|
||||
if (argc > 1 && argv[1] == "selinux_setup"sv) {
|
||||
setup_klog();
|
||||
init = new SecondStageInit(argv);
|
||||
} else {
|
||||
// This will also mount /sys and /proc
|
||||
load_kernel_info(&cmd);
|
||||
if (argc > 1 && argv[1] == "selinux_setup"sv) {
|
||||
setup_klog();
|
||||
init = new SecondStageInit(argv);
|
||||
} else {
|
||||
// This will also mount /sys and /proc
|
||||
load_kernel_info(&cmd);
|
||||
|
||||
if (cmd.skip_initramfs) {
|
||||
init = new SARInit(argv, &cmd);
|
||||
} else {
|
||||
if (cmd.force_normal_boot)
|
||||
init = new FirstStageInit(argv, &cmd);
|
||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||
init = new RecoveryInit(argv, &cmd);
|
||||
else if (check_two_stage())
|
||||
init = new FirstStageInit(argv, &cmd);
|
||||
else
|
||||
init = new RootFSInit(argv, &cmd);
|
||||
}
|
||||
}
|
||||
if (cmd.skip_initramfs) {
|
||||
init = new SARInit(argv, &cmd);
|
||||
} else {
|
||||
if (cmd.force_normal_boot)
|
||||
init = new FirstStageInit(argv, &cmd);
|
||||
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
|
||||
init = new RecoveryInit(argv, &cmd);
|
||||
else if (check_two_stage())
|
||||
init = new FirstStageInit(argv, &cmd);
|
||||
else
|
||||
init = new RootFSInit(argv, &cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the main routine
|
||||
init->start();
|
||||
exit(1);
|
||||
// Run the main routine
|
||||
init->start();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -3,26 +3,27 @@
|
||||
#include "raw_data.hpp"
|
||||
|
||||
struct cmdline {
|
||||
bool skip_initramfs;
|
||||
bool force_normal_boot;
|
||||
char slot[3];
|
||||
char dt_dir[64];
|
||||
char fstab_suffix[32];
|
||||
char hardware[32];
|
||||
char hardware_plat[32];
|
||||
bool skip_initramfs;
|
||||
bool force_normal_boot;
|
||||
bool rootwait;
|
||||
char slot[3];
|
||||
char dt_dir[64];
|
||||
char fstab_suffix[32];
|
||||
char hardware[32];
|
||||
char hardware_plat[32];
|
||||
};
|
||||
|
||||
struct fstab_entry {
|
||||
std::string dev;
|
||||
std::string mnt_point;
|
||||
std::string type;
|
||||
std::string mnt_flags;
|
||||
std::string fsmgr_flags;
|
||||
std::string dev;
|
||||
std::string mnt_point;
|
||||
std::string type;
|
||||
std::string mnt_flags;
|
||||
std::string fsmgr_flags;
|
||||
|
||||
fstab_entry() = default;
|
||||
fstab_entry(const fstab_entry &) = delete;
|
||||
fstab_entry(fstab_entry &&) = default;
|
||||
void to_file(FILE *fp);
|
||||
fstab_entry() = default;
|
||||
fstab_entry(const fstab_entry &) = delete;
|
||||
fstab_entry(fstab_entry &&) = default;
|
||||
void to_file(FILE *fp);
|
||||
};
|
||||
|
||||
#define INIT_SOCKET "MAGISKINIT"
|
||||
@@ -39,41 +40,41 @@ void setup_klog();
|
||||
|
||||
class BaseInit {
|
||||
protected:
|
||||
cmdline *cmd;
|
||||
char **argv;
|
||||
std::vector<std::string> mount_list;
|
||||
cmdline *cmd;
|
||||
char **argv;
|
||||
std::vector<std::string> mount_list;
|
||||
|
||||
[[noreturn]] void exec_init();
|
||||
void read_dt_fstab(std::vector<fstab_entry> &fstab);
|
||||
[[noreturn]] void exec_init();
|
||||
void read_dt_fstab(std::vector<fstab_entry> &fstab);
|
||||
public:
|
||||
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {}
|
||||
virtual ~BaseInit() = default;
|
||||
virtual void start() = 0;
|
||||
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {}
|
||||
virtual ~BaseInit() = default;
|
||||
virtual void start() = 0;
|
||||
};
|
||||
|
||||
class MagiskInit : public BaseInit {
|
||||
protected:
|
||||
auto_data<HEAP> self;
|
||||
auto_data<HEAP> config;
|
||||
std::string custom_rules_dir;
|
||||
auto_data<HEAP> self;
|
||||
auto_data<HEAP> config;
|
||||
std::string custom_rules_dir;
|
||||
|
||||
void mount_with_dt();
|
||||
bool patch_sepolicy(const char *file);
|
||||
void setup_tmp(const char *path);
|
||||
void mount_rules_dir(const char *dev_base, const char *mnt_base);
|
||||
void mount_with_dt();
|
||||
bool patch_sepolicy(const char *file);
|
||||
void setup_tmp(const char *path);
|
||||
void mount_rules_dir(const char *dev_base, const char *mnt_base);
|
||||
public:
|
||||
MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
||||
MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
|
||||
};
|
||||
|
||||
class SARBase : public MagiskInit {
|
||||
protected:
|
||||
std::vector<raw_file> overlays;
|
||||
std::vector<raw_file> overlays;
|
||||
|
||||
void backup_files();
|
||||
void patch_rootdir();
|
||||
void mount_system_root();
|
||||
void backup_files();
|
||||
void patch_rootdir();
|
||||
void mount_system_root();
|
||||
public:
|
||||
SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}
|
||||
SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}
|
||||
};
|
||||
|
||||
/***************
|
||||
@@ -82,31 +83,31 @@ public:
|
||||
|
||||
class FirstStageInit : public BaseInit {
|
||||
private:
|
||||
void prepare();
|
||||
void prepare();
|
||||
public:
|
||||
FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare();
|
||||
exec_init();
|
||||
}
|
||||
FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
prepare();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
class SecondStageInit : public SARBase {
|
||||
private:
|
||||
void prepare();
|
||||
void prepare();
|
||||
public:
|
||||
SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
// Do not unmount /sys and /proc
|
||||
mount_list.clear();
|
||||
};
|
||||
void start() override {
|
||||
prepare();
|
||||
patch_rootdir();
|
||||
exec_init();
|
||||
}
|
||||
SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
// Do not unmount /sys and /proc
|
||||
mount_list.clear();
|
||||
};
|
||||
void start() override {
|
||||
prepare();
|
||||
patch_rootdir();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/*************
|
||||
@@ -115,22 +116,22 @@ public:
|
||||
|
||||
class SARInit : public SARBase {
|
||||
private:
|
||||
bool is_two_stage;
|
||||
bool is_two_stage;
|
||||
|
||||
void early_mount();
|
||||
void first_stage_prep();
|
||||
void early_mount();
|
||||
void first_stage_prep();
|
||||
public:
|
||||
SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd), is_two_stage(false) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
early_mount();
|
||||
if (is_two_stage)
|
||||
first_stage_prep();
|
||||
else
|
||||
patch_rootdir();
|
||||
exec_init();
|
||||
}
|
||||
SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd), is_two_stage(false) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
};
|
||||
void start() override {
|
||||
early_mount();
|
||||
if (is_two_stage)
|
||||
first_stage_prep();
|
||||
else
|
||||
patch_rootdir();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
/************
|
||||
@@ -139,23 +140,23 @@ public:
|
||||
|
||||
class RootFSInit : public MagiskInit {
|
||||
private:
|
||||
void early_mount();
|
||||
void patch_rootfs();
|
||||
void early_mount();
|
||||
void patch_rootfs();
|
||||
public:
|
||||
RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
}
|
||||
void start() override {
|
||||
early_mount();
|
||||
patch_rootfs();
|
||||
exec_init();
|
||||
}
|
||||
RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
}
|
||||
void start() override {
|
||||
early_mount();
|
||||
patch_rootfs();
|
||||
exec_init();
|
||||
}
|
||||
};
|
||||
|
||||
class MagiskProxy : public MagiskInit {
|
||||
public:
|
||||
explicit MagiskProxy(char *argv[]) : MagiskInit(argv, nullptr) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
}
|
||||
void start() override;
|
||||
explicit MagiskProxy(char *argv[]) : MagiskInit(argv, nullptr) {
|
||||
LOGD("%s\n", __FUNCTION__);
|
||||
}
|
||||
void start() override;
|
||||
};
|
||||
|
||||
@@ -11,401 +11,406 @@
|
||||
using namespace std;
|
||||
|
||||
static string rtrim(string &&str) {
|
||||
// Trim space, newline, and null byte from end of string
|
||||
while (memchr(" \n\r", str[str.length() - 1], 4))
|
||||
str.pop_back();
|
||||
return std::move(str);
|
||||
// Trim space, newline, and null byte from end of string
|
||||
while (memchr(" \n\r", str[str.length() - 1], 4))
|
||||
str.pop_back();
|
||||
return std::move(str);
|
||||
}
|
||||
|
||||
struct devinfo {
|
||||
int major;
|
||||
int minor;
|
||||
char devname[32];
|
||||
char partname[32];
|
||||
char dmname[32];
|
||||
int major;
|
||||
int minor;
|
||||
char devname[32];
|
||||
char partname[32];
|
||||
char dmname[32];
|
||||
};
|
||||
|
||||
static vector<devinfo> dev_list;
|
||||
|
||||
static void parse_device(devinfo *dev, const char *uevent) {
|
||||
dev->partname[0] = '\0';
|
||||
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
|
||||
if (key == "MAJOR")
|
||||
dev->major = parse_int(value.data());
|
||||
else if (key == "MINOR")
|
||||
dev->minor = parse_int(value.data());
|
||||
else if (key == "DEVNAME")
|
||||
strcpy(dev->devname, value.data());
|
||||
else if (key == "PARTNAME")
|
||||
strcpy(dev->partname, value.data());
|
||||
dev->partname[0] = '\0';
|
||||
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
|
||||
if (key == "MAJOR")
|
||||
dev->major = parse_int(value.data());
|
||||
else if (key == "MINOR")
|
||||
dev->minor = parse_int(value.data());
|
||||
else if (key == "DEVNAME")
|
||||
strcpy(dev->devname, value.data());
|
||||
else if (key == "PARTNAME")
|
||||
strcpy(dev->partname, value.data());
|
||||
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
static void collect_devices() {
|
||||
char path[128];
|
||||
devinfo dev{};
|
||||
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
|
||||
for (dirent *entry; (entry = readdir(dir.get()));) {
|
||||
if (entry->d_name == "."sv || entry->d_name == ".."sv)
|
||||
continue;
|
||||
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
|
||||
parse_device(&dev, path);
|
||||
sprintf(path, "/sys/dev/block/%s/dm/name", entry->d_name);
|
||||
if (access(path, F_OK) == 0) {
|
||||
auto name = rtrim(full_read(path));
|
||||
strcpy(dev.dmname, name.data());
|
||||
}
|
||||
dev_list.push_back(dev);
|
||||
}
|
||||
}
|
||||
char path[128];
|
||||
devinfo dev{};
|
||||
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
|
||||
for (dirent *entry; (entry = readdir(dir.get()));) {
|
||||
if (entry->d_name == "."sv || entry->d_name == ".."sv)
|
||||
continue;
|
||||
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
|
||||
parse_device(&dev, path);
|
||||
sprintf(path, "/sys/dev/block/%s/dm/name", entry->d_name);
|
||||
if (access(path, F_OK) == 0) {
|
||||
auto name = rtrim(full_read(path));
|
||||
strcpy(dev.dmname, name.data());
|
||||
}
|
||||
dev_list.push_back(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
char partname[32];
|
||||
char block_dev[64];
|
||||
char partname[32];
|
||||
char block_dev[64];
|
||||
} blk_info;
|
||||
|
||||
static int64_t setup_block(bool write_block) {
|
||||
if (dev_list.empty())
|
||||
collect_devices();
|
||||
xmkdir("/dev", 0755);
|
||||
xmkdir("/dev/block", 0755);
|
||||
if (dev_list.empty())
|
||||
collect_devices();
|
||||
xmkdir("/dev", 0755);
|
||||
xmkdir("/dev/block", 0755);
|
||||
|
||||
for (int tries = 0; tries < 3; ++tries) {
|
||||
for (auto &dev : dev_list) {
|
||||
if (strcasecmp(dev.partname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
|
||||
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
|
||||
else
|
||||
continue;
|
||||
for (int tries = 0; tries < 3; ++tries) {
|
||||
for (auto &dev : dev_list) {
|
||||
if (strcasecmp(dev.partname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
|
||||
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
|
||||
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (write_block) {
|
||||
sprintf(blk_info.block_dev, "/dev/block/%s", dev.devname);
|
||||
}
|
||||
dev_t rdev = makedev(dev.major, dev.minor);
|
||||
mknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
|
||||
return rdev;
|
||||
}
|
||||
// Wait 10ms and try again
|
||||
usleep(10000);
|
||||
dev_list.clear();
|
||||
collect_devices();
|
||||
}
|
||||
if (write_block) {
|
||||
sprintf(blk_info.block_dev, "/dev/block/%s", dev.devname);
|
||||
}
|
||||
dev_t rdev = makedev(dev.major, dev.minor);
|
||||
mknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
|
||||
return rdev;
|
||||
}
|
||||
// Wait 10ms and try again
|
||||
usleep(10000);
|
||||
dev_list.clear();
|
||||
collect_devices();
|
||||
}
|
||||
|
||||
// The requested partname does not exist
|
||||
return -1;
|
||||
// The requested partname does not exist
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool is_lnk(const char *name) {
|
||||
struct stat st;
|
||||
if (lstat(name, &st))
|
||||
return false;
|
||||
return S_ISLNK(st.st_mode);
|
||||
struct stat st;
|
||||
if (lstat(name, &st))
|
||||
return false;
|
||||
return S_ISLNK(st.st_mode);
|
||||
}
|
||||
|
||||
#define read_info(val) \
|
||||
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) {
|
||||
if (access(cmd->dt_dir, F_OK) != 0)
|
||||
return;
|
||||
if (access(cmd->dt_dir, F_OK) != 0)
|
||||
return;
|
||||
|
||||
char cwd[128];
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
chdir(cmd->dt_dir);
|
||||
run_finally cd([&]{ chdir(cwd); });
|
||||
char cwd[128];
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
chdir(cmd->dt_dir);
|
||||
run_finally cd([&]{ chdir(cwd); });
|
||||
|
||||
if (access("fstab", F_OK) != 0)
|
||||
return;
|
||||
chdir("fstab");
|
||||
if (access("fstab", F_OK) != 0)
|
||||
return;
|
||||
chdir("fstab");
|
||||
|
||||
// Make sure dt fstab is enabled
|
||||
if (access("status", F_OK) == 0) {
|
||||
auto status = rtrim(full_read("status"));
|
||||
if (status != "okay" && status != "ok")
|
||||
return;
|
||||
}
|
||||
// Make sure dt fstab is enabled
|
||||
if (access("status", F_OK) == 0) {
|
||||
auto status = rtrim(full_read("status"));
|
||||
if (status != "okay" && status != "ok")
|
||||
return;
|
||||
}
|
||||
|
||||
auto dir = xopen_dir(".");
|
||||
for (dirent *dp; (dp = xreaddir(dir.get()));) {
|
||||
if (dp->d_type != DT_DIR)
|
||||
continue;
|
||||
chdir(dp->d_name);
|
||||
run_finally f([]{ chdir(".."); });
|
||||
auto dir = xopen_dir(".");
|
||||
for (dirent *dp; (dp = xreaddir(dir.get()));) {
|
||||
if (dp->d_type != DT_DIR)
|
||||
continue;
|
||||
chdir(dp->d_name);
|
||||
run_finally f([]{ chdir(".."); });
|
||||
|
||||
if (access("status", F_OK) == 0) {
|
||||
auto status = rtrim(full_read("status"));
|
||||
if (status != "okay" && status != "ok")
|
||||
continue;
|
||||
}
|
||||
if (access("status", F_OK) == 0) {
|
||||
auto status = rtrim(full_read("status"));
|
||||
if (status != "okay" && status != "ok")
|
||||
continue;
|
||||
}
|
||||
|
||||
fstab_entry entry;
|
||||
fstab_entry entry;
|
||||
|
||||
read_info(dev);
|
||||
read_info(mnt_point) else {
|
||||
entry.mnt_point = "/";
|
||||
entry.mnt_point += dp->d_name;
|
||||
}
|
||||
read_info(type);
|
||||
read_info(mnt_flags);
|
||||
read_info(fsmgr_flags);
|
||||
read_info(dev);
|
||||
read_info(mnt_point) else {
|
||||
entry.mnt_point = "/";
|
||||
entry.mnt_point += dp->d_name;
|
||||
}
|
||||
read_info(type);
|
||||
read_info(mnt_flags);
|
||||
read_info(fsmgr_flags);
|
||||
|
||||
fstab.emplace_back(std::move(entry));
|
||||
}
|
||||
fstab.emplace_back(std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
void MagiskInit::mount_with_dt() {
|
||||
vector<fstab_entry> fstab;
|
||||
read_dt_fstab(fstab);
|
||||
for (const auto &entry : fstab) {
|
||||
if (is_lnk(entry.mnt_point.data()))
|
||||
continue;
|
||||
// Derive partname from dev
|
||||
sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot);
|
||||
setup_block(true);
|
||||
xmkdir(entry.mnt_point.data(), 0755);
|
||||
xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr);
|
||||
mount_list.push_back(entry.mnt_point);
|
||||
}
|
||||
vector<fstab_entry> fstab;
|
||||
read_dt_fstab(fstab);
|
||||
for (const auto &entry : fstab) {
|
||||
if (is_lnk(entry.mnt_point.data()))
|
||||
continue;
|
||||
// Derive partname from dev
|
||||
sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot);
|
||||
setup_block(true);
|
||||
xmkdir(entry.mnt_point.data(), 0755);
|
||||
xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr);
|
||||
mount_list.push_back(entry.mnt_point);
|
||||
}
|
||||
}
|
||||
|
||||
static void switch_root(const string &path) {
|
||||
LOGD("Switch root to %s\n", path.data());
|
||||
int root = xopen("/", O_RDONLY);
|
||||
vector<string> mounts;
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
// Skip root and self
|
||||
if (me->mnt_dir == "/"sv || me->mnt_dir == path)
|
||||
return true;
|
||||
// Do not include subtrees
|
||||
for (const auto &m : mounts) {
|
||||
if (strncmp(me->mnt_dir, m.data(), m.length()) == 0 && me->mnt_dir[m.length()] == '/')
|
||||
return true;
|
||||
}
|
||||
mounts.emplace_back(me->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
for (auto &dir : mounts) {
|
||||
auto new_path = path + dir;
|
||||
mkdir(new_path.data(), 0755);
|
||||
xmount(dir.data(), new_path.data(), nullptr, MS_MOVE, nullptr);
|
||||
}
|
||||
chdir(path.data());
|
||||
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
|
||||
chroot(".");
|
||||
LOGD("Switch root to %s\n", path.data());
|
||||
int root = xopen("/", O_RDONLY);
|
||||
vector<string> mounts;
|
||||
parse_mnt("/proc/mounts", [&](mntent *me) {
|
||||
// Skip root and self
|
||||
if (me->mnt_dir == "/"sv || me->mnt_dir == path)
|
||||
return true;
|
||||
// Do not include subtrees
|
||||
for (const auto &m : mounts) {
|
||||
if (strncmp(me->mnt_dir, m.data(), m.length()) == 0 && me->mnt_dir[m.length()] == '/')
|
||||
return true;
|
||||
}
|
||||
mounts.emplace_back(me->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
for (auto &dir : mounts) {
|
||||
auto new_path = path + dir;
|
||||
mkdir(new_path.data(), 0755);
|
||||
xmount(dir.data(), new_path.data(), nullptr, MS_MOVE, nullptr);
|
||||
}
|
||||
chdir(path.data());
|
||||
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
|
||||
chroot(".");
|
||||
|
||||
LOGD("Cleaning rootfs\n");
|
||||
frm_rf(root);
|
||||
LOGD("Cleaning rootfs\n");
|
||||
frm_rf(root);
|
||||
}
|
||||
|
||||
void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) {
|
||||
char path[128];
|
||||
xrealpath(dev_base, blk_info.block_dev);
|
||||
xrealpath(mnt_base, path);
|
||||
char *b = blk_info.block_dev + strlen(blk_info.block_dev);
|
||||
char *p = path + strlen(path);
|
||||
char path[128];
|
||||
xrealpath(dev_base, blk_info.block_dev);
|
||||
xrealpath(mnt_base, path);
|
||||
char *b = blk_info.block_dev + strlen(blk_info.block_dev);
|
||||
char *p = path + strlen(path);
|
||||
|
||||
auto do_mount = [&](const char *type) -> bool {
|
||||
xmkdir(path, 0755);
|
||||
bool success = xmount(blk_info.block_dev, path, type, 0, nullptr) == 0;
|
||||
if (success)
|
||||
mount_list.emplace_back(path);
|
||||
return success;
|
||||
};
|
||||
auto do_mount = [&](const char *type) -> bool {
|
||||
xmkdir(path, 0755);
|
||||
bool success = xmount(blk_info.block_dev, path, type, 0, nullptr) == 0;
|
||||
if (success)
|
||||
mount_list.emplace_back(path);
|
||||
return success;
|
||||
};
|
||||
|
||||
// First try userdata
|
||||
strcpy(blk_info.partname, "userdata");
|
||||
strcpy(b, "/data");
|
||||
strcpy(p, "/data");
|
||||
if (setup_block(false) < 0) {
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "UDA");
|
||||
if (setup_block(false) < 0)
|
||||
goto cache;
|
||||
}
|
||||
// Try to mount with either ext4 or f2fs
|
||||
// Failure means either FDE or metadata encryption
|
||||
if (!do_mount("ext4") && !do_mount("f2fs"))
|
||||
goto cache;
|
||||
// First try userdata
|
||||
strcpy(blk_info.partname, "userdata");
|
||||
strcpy(b, "/data");
|
||||
strcpy(p, "/data");
|
||||
if (setup_block(false) < 0) {
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "UDA");
|
||||
if (setup_block(false) < 0)
|
||||
goto cache;
|
||||
}
|
||||
// Try to mount with either ext4 or f2fs
|
||||
// Failure means either FDE or metadata encryption
|
||||
if (!do_mount("ext4") && !do_mount("f2fs"))
|
||||
goto cache;
|
||||
|
||||
strcpy(p, "/data/unencrypted");
|
||||
if (access(path, F_OK) == 0) {
|
||||
// FBE, need to use an unencrypted path
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
} else {
|
||||
// Skip if /data/adb does not exist
|
||||
strcpy(p, "/data/adb");
|
||||
if (access(path, F_OK) != 0)
|
||||
return;
|
||||
// Unencrypted, directly use module paths
|
||||
custom_rules_dir = string(mnt_base) + MODULEROOT;
|
||||
}
|
||||
goto success;
|
||||
strcpy(p, "/data/unencrypted");
|
||||
if (access(path, F_OK) == 0) {
|
||||
// FBE, need to use an unencrypted path
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
} else {
|
||||
// Skip if /data/adb does not exist
|
||||
strcpy(p, "/data/adb");
|
||||
if (access(path, F_OK) != 0)
|
||||
return;
|
||||
// Unencrypted, directly use module paths
|
||||
custom_rules_dir = string(mnt_base) + MODULEROOT;
|
||||
}
|
||||
goto success;
|
||||
|
||||
cache:
|
||||
// Fallback to cache
|
||||
strcpy(blk_info.partname, "cache");
|
||||
strcpy(b, "/cache");
|
||||
strcpy(p, "/cache");
|
||||
if (setup_block(false) < 0) {
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "CAC");
|
||||
if (setup_block(false) < 0)
|
||||
goto metadata;
|
||||
}
|
||||
if (!do_mount("ext4"))
|
||||
goto metadata;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
goto success;
|
||||
// Fallback to cache
|
||||
strcpy(blk_info.partname, "cache");
|
||||
strcpy(b, "/cache");
|
||||
strcpy(p, "/cache");
|
||||
if (setup_block(false) < 0) {
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "CAC");
|
||||
if (setup_block(false) < 0)
|
||||
goto metadata;
|
||||
}
|
||||
if (!do_mount("ext4"))
|
||||
goto metadata;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
goto success;
|
||||
|
||||
metadata:
|
||||
// Fallback to metadata
|
||||
strcpy(blk_info.partname, "metadata");
|
||||
strcpy(b, "/metadata");
|
||||
strcpy(p, "/metadata");
|
||||
if (setup_block(false) < 0 || !do_mount("ext4"))
|
||||
goto persist;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
goto success;
|
||||
// Fallback to metadata
|
||||
strcpy(blk_info.partname, "metadata");
|
||||
strcpy(b, "/metadata");
|
||||
strcpy(p, "/metadata");
|
||||
if (setup_block(false) < 0 || !do_mount("ext4"))
|
||||
goto persist;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
goto success;
|
||||
|
||||
persist:
|
||||
// Fallback to persist
|
||||
strcpy(blk_info.partname, "persist");
|
||||
strcpy(b, "/persist");
|
||||
strcpy(p, "/persist");
|
||||
if (setup_block(false) < 0 || !do_mount("ext4"))
|
||||
return;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
// Fallback to persist
|
||||
strcpy(blk_info.partname, "persist");
|
||||
strcpy(b, "/persist");
|
||||
strcpy(p, "/persist");
|
||||
if (setup_block(false) < 0 || !do_mount("ext4"))
|
||||
return;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
|
||||
success:
|
||||
// Create symlinks so we don't need to go through this logic again
|
||||
strcpy(p, "/sepolicy.rules");
|
||||
xsymlink(custom_rules_dir.data(), path);
|
||||
// Create symlinks so we don't need to go through this logic again
|
||||
strcpy(p, "/sepolicy.rules");
|
||||
xsymlink(custom_rules_dir.data(), path);
|
||||
}
|
||||
|
||||
void RootFSInit::early_mount() {
|
||||
self = raw_data::read("/init");
|
||||
self = raw_data::read("/init");
|
||||
|
||||
LOGD("Restoring /init\n");
|
||||
rename("/.backup/init", "/init");
|
||||
LOGD("Restoring /init\n");
|
||||
rename("/.backup/init", "/init");
|
||||
|
||||
mount_with_dt();
|
||||
mount_with_dt();
|
||||
}
|
||||
|
||||
void SARBase::backup_files() {
|
||||
if (access("/overlay.d", F_OK) == 0)
|
||||
backup_folder("/overlay.d", overlays);
|
||||
if (access("/overlay.d", F_OK) == 0)
|
||||
backup_folder("/overlay.d", overlays);
|
||||
|
||||
self = raw_data::read("/proc/self/exe");
|
||||
if (access("/.backup/.magisk", R_OK) == 0)
|
||||
config = raw_data::read("/.backup/.magisk");
|
||||
self = raw_data::read("/proc/self/exe");
|
||||
if (access("/.backup/.magisk", R_OK) == 0)
|
||||
config = raw_data::read("/.backup/.magisk");
|
||||
}
|
||||
|
||||
void SARBase::mount_system_root() {
|
||||
LOGD("Early mount system_root\n");
|
||||
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;
|
||||
LOGD("Early mount system_root\n");
|
||||
strcpy(blk_info.block_dev, "/dev/root");
|
||||
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "APP");
|
||||
dev = setup_block(false);
|
||||
if (dev >= 0)
|
||||
goto mount_root;
|
||||
do {
|
||||
// Try legacy SAR dm-verity
|
||||
strcpy(blk_info.partname, "vroot");
|
||||
auto dev = setup_block(false);
|
||||
if (dev >= 0)
|
||||
goto mount_root;
|
||||
|
||||
sprintf(blk_info.partname, "system%s", cmd->slot);
|
||||
dev = setup_block(false);
|
||||
if (dev >= 0)
|
||||
goto mount_root;
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "APP");
|
||||
dev = setup_block(false);
|
||||
if (dev >= 0)
|
||||
goto mount_root;
|
||||
|
||||
// We don't really know what to do at this point...
|
||||
LOGE("Cannot find root partition, abort\n");
|
||||
exit(1);
|
||||
sprintf(blk_info.partname, "system%s", cmd->slot);
|
||||
dev = setup_block(false);
|
||||
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:
|
||||
xmkdir("/system_root", 0755);
|
||||
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
|
||||
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
|
||||
xmkdir("/system_root", 0755);
|
||||
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
|
||||
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
|
||||
}
|
||||
|
||||
void SARInit::early_mount() {
|
||||
backup_files();
|
||||
mount_system_root();
|
||||
switch_root("/system_root");
|
||||
backup_files();
|
||||
mount_system_root();
|
||||
switch_root("/system_root");
|
||||
|
||||
{
|
||||
auto init = raw_data::mmap_ro("/init");
|
||||
is_two_stage = init.contains("selinux_setup");
|
||||
}
|
||||
LOGD("is_two_stage: [%d]\n", is_two_stage);
|
||||
{
|
||||
auto init = raw_data::mmap_ro("/init");
|
||||
is_two_stage = init.contains("selinux_setup");
|
||||
}
|
||||
LOGD("is_two_stage: [%d]\n", is_two_stage);
|
||||
|
||||
if (!is_two_stage) {
|
||||
// Make dev writable
|
||||
xmkdir("/dev", 0755);
|
||||
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
||||
mount_list.emplace_back("/dev");
|
||||
mount_with_dt();
|
||||
}
|
||||
if (!is_two_stage) {
|
||||
// Make dev writable
|
||||
xmkdir("/dev", 0755);
|
||||
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
||||
mount_list.emplace_back("/dev");
|
||||
mount_with_dt();
|
||||
}
|
||||
}
|
||||
|
||||
void SecondStageInit::prepare() {
|
||||
backup_files();
|
||||
backup_files();
|
||||
|
||||
umount2("/init", MNT_DETACH);
|
||||
umount2("/proc/self/exe", MNT_DETACH);
|
||||
umount2("/init", MNT_DETACH);
|
||||
umount2("/proc/self/exe", MNT_DETACH);
|
||||
|
||||
if (access("/system_root", F_OK) == 0)
|
||||
switch_root("/system_root");
|
||||
if (access("/system_root", F_OK) == 0)
|
||||
switch_root("/system_root");
|
||||
}
|
||||
|
||||
void BaseInit::exec_init() {
|
||||
// Unmount in reverse order
|
||||
for (auto &p : reversed(mount_list)) {
|
||||
if (xumount(p.data()) == 0)
|
||||
LOGD("Unmount [%s]\n", p.data());
|
||||
}
|
||||
execv("/init", argv);
|
||||
exit(1);
|
||||
// Unmount in reverse order
|
||||
for (auto &p : reversed(mount_list)) {
|
||||
if (xumount(p.data()) == 0)
|
||||
LOGD("Unmount [%s]\n", p.data());
|
||||
}
|
||||
execv("/init", argv);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void patch_socket_name(const char *path) {
|
||||
char rstr[16];
|
||||
gen_rand_str(rstr, sizeof(rstr));
|
||||
auto bin = raw_data::mmap_rw(path);
|
||||
bin.patch({ make_pair(MAIN_SOCKET, rstr) });
|
||||
char rstr[16];
|
||||
gen_rand_str(rstr, sizeof(rstr));
|
||||
auto bin = raw_data::mmap_rw(path);
|
||||
bin.patch({ make_pair(MAIN_SOCKET, rstr) });
|
||||
}
|
||||
|
||||
void MagiskInit::setup_tmp(const char *path) {
|
||||
LOGD("Setup Magisk tmp at %s\n", path);
|
||||
xmount("tmpfs", path, "tmpfs", 0, "mode=755");
|
||||
LOGD("Setup Magisk tmp at %s\n", path);
|
||||
xmount("tmpfs", path, "tmpfs", 0, "mode=755");
|
||||
|
||||
chdir(path);
|
||||
chdir(path);
|
||||
|
||||
xmkdir(INTLROOT, 0755);
|
||||
xmkdir(MIRRDIR, 0);
|
||||
xmkdir(BLOCKDIR, 0);
|
||||
xmkdir(INTLROOT, 0755);
|
||||
xmkdir(MIRRDIR, 0);
|
||||
xmkdir(BLOCKDIR, 0);
|
||||
|
||||
int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
|
||||
xwrite(fd, config.buf, config.sz);
|
||||
close(fd);
|
||||
fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755);
|
||||
xwrite(fd, self.buf, self.sz);
|
||||
close(fd);
|
||||
dump_magisk("magisk", 0755);
|
||||
patch_socket_name("magisk");
|
||||
int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
|
||||
xwrite(fd, config.buf, config.sz);
|
||||
close(fd);
|
||||
fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755);
|
||||
xwrite(fd, self.buf, self.sz);
|
||||
close(fd);
|
||||
dump_magisk("magisk", 0755);
|
||||
patch_socket_name("magisk");
|
||||
|
||||
// Create applet symlinks
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
xsymlink("./magisk", applet_names[i]);
|
||||
xsymlink("./magiskinit", "magiskpolicy");
|
||||
xsymlink("./magiskinit", "supolicy");
|
||||
// Create applet symlinks
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
xsymlink("./magisk", applet_names[i]);
|
||||
xsymlink("./magiskinit", "magiskpolicy");
|
||||
xsymlink("./magiskinit", "supolicy");
|
||||
|
||||
chdir("/");
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
@@ -3,62 +3,62 @@
|
||||
using namespace std;
|
||||
|
||||
int data_holder::patch(str_pairs list) {
|
||||
if (buf == nullptr)
|
||||
return 0;
|
||||
int count = 0;
|
||||
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
||||
for (auto [from, to] : list) {
|
||||
if (memcmp(p, from.data(), from.length() + 1) == 0) {
|
||||
LOGD("Replace [%s] -> [%s]\n", from.data(), to.data());
|
||||
memset(p, 0, from.length());
|
||||
memcpy(p, to.data(), to.length());
|
||||
++count;
|
||||
p += from.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
if (buf == nullptr)
|
||||
return 0;
|
||||
int count = 0;
|
||||
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
||||
for (auto [from, to] : list) {
|
||||
if (memcmp(p, from.data(), from.length() + 1) == 0) {
|
||||
LOGD("Replace [%s] -> [%s]\n", from.data(), to.data());
|
||||
memset(p, 0, from.length());
|
||||
memcpy(p, to.data(), to.length());
|
||||
++count;
|
||||
p += from.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool data_holder::contains(string_view pattern) {
|
||||
if (buf == nullptr)
|
||||
return false;
|
||||
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
||||
if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) {
|
||||
LOGD("Found pattern [%s]\n", pattern.data());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (buf == nullptr)
|
||||
return false;
|
||||
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
|
||||
if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) {
|
||||
LOGD("Found pattern [%s]\n", pattern.data());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void data_holder::consume(data_holder &other) {
|
||||
buf = other.buf;
|
||||
sz = other.sz;
|
||||
other.buf = nullptr;
|
||||
other.sz = 0;
|
||||
buf = other.buf;
|
||||
sz = other.sz;
|
||||
other.buf = nullptr;
|
||||
other.sz = 0;
|
||||
}
|
||||
|
||||
auto_data<HEAP> raw_data::read(int fd) {
|
||||
auto_data<HEAP> data;
|
||||
fd_full_read(fd, data.buf, data.sz);
|
||||
return data;
|
||||
auto_data<HEAP> data;
|
||||
fd_full_read(fd, data.buf, data.sz);
|
||||
return data;
|
||||
}
|
||||
|
||||
auto_data<HEAP> raw_data::read(const char *name) {
|
||||
auto_data<HEAP> data;
|
||||
full_read(name, data.buf, data.sz);
|
||||
return data;
|
||||
auto_data<HEAP> data;
|
||||
full_read(name, data.buf, data.sz);
|
||||
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> 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;
|
||||
auto_data<MMAP> data;
|
||||
::mmap_ro(name, data.buf, data.sz);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -3,30 +3,30 @@
|
||||
#include <utils.hpp>
|
||||
|
||||
struct data_holder {
|
||||
uint8_t *buf = nullptr;
|
||||
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);
|
||||
uint8_t *buf = nullptr;
|
||||
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);
|
||||
void consume(data_holder &other);
|
||||
};
|
||||
|
||||
enum data_type { HEAP, MMAP };
|
||||
template <data_type T>
|
||||
struct auto_data : public data_holder {
|
||||
auto_data<T>() = default;
|
||||
auto_data<T>(const auto_data&) = delete;
|
||||
auto_data<T>(auto_data<T> &&other) { consume(other); }
|
||||
~auto_data<T>() {}
|
||||
auto_data<T>& operator=(auto_data<T> &&other) { consume(other); return *this; }
|
||||
auto_data<T>() = default;
|
||||
auto_data<T>(const auto_data&) = delete;
|
||||
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 {
|
||||
auto_data<HEAP> read(const char *name);
|
||||
auto_data<HEAP> read(int fd);
|
||||
auto_data<MMAP> mmap_rw(const char *name);
|
||||
auto_data<MMAP> mmap_ro(const char *name);
|
||||
auto_data<HEAP> read(const char *name);
|
||||
auto_data<HEAP> read(int fd);
|
||||
auto_data<MMAP> mmap_rw(const char *name);
|
||||
auto_data<MMAP> mmap_ro(const char *name);
|
||||
}
|
||||
|
||||
@@ -20,164 +20,164 @@ using namespace std;
|
||||
static vector<string> rc_list;
|
||||
|
||||
static void patch_init_rc(const char *src, const char *dest, const char *tmp_dir) {
|
||||
FILE *rc = xfopen(dest, "we");
|
||||
file_readline(src, [=](string_view line) -> bool {
|
||||
// Do not start vaultkeeper
|
||||
if (str_contains(line, "start vaultkeeper")) {
|
||||
LOGD("Remove vaultkeeper\n");
|
||||
return true;
|
||||
}
|
||||
// Do not run flash_recovery
|
||||
if (str_starts(line, "service flash_recovery")) {
|
||||
LOGD("Remove flash_recovery\n");
|
||||
fprintf(rc, "service flash_recovery /system/bin/xxxxx\n");
|
||||
return true;
|
||||
}
|
||||
// Else just write the line
|
||||
fprintf(rc, "%s", line.data());
|
||||
return true;
|
||||
});
|
||||
FILE *rc = xfopen(dest, "we");
|
||||
file_readline(src, [=](string_view line) -> bool {
|
||||
// Do not start vaultkeeper
|
||||
if (str_contains(line, "start vaultkeeper")) {
|
||||
LOGD("Remove vaultkeeper\n");
|
||||
return true;
|
||||
}
|
||||
// Do not run flash_recovery
|
||||
if (str_starts(line, "service flash_recovery")) {
|
||||
LOGD("Remove flash_recovery\n");
|
||||
fprintf(rc, "service flash_recovery /system/bin/xxxxx\n");
|
||||
return true;
|
||||
}
|
||||
// Else just write the line
|
||||
fprintf(rc, "%s", line.data());
|
||||
return true;
|
||||
});
|
||||
|
||||
fprintf(rc, "\n");
|
||||
fprintf(rc, "\n");
|
||||
|
||||
// Inject custom rc scripts
|
||||
for (auto &script : rc_list) {
|
||||
// Replace template arguments of rc scripts with dynamic paths
|
||||
replace_all(script, "${MAGISKTMP}", tmp_dir);
|
||||
fprintf(rc, "\n%s\n", script.data());
|
||||
}
|
||||
rc_list.clear();
|
||||
// Inject custom rc scripts
|
||||
for (auto &script : rc_list) {
|
||||
// Replace template arguments of rc scripts with dynamic paths
|
||||
replace_all(script, "${MAGISKTMP}", tmp_dir);
|
||||
fprintf(rc, "\n%s\n", script.data());
|
||||
}
|
||||
rc_list.clear();
|
||||
|
||||
// Inject Magisk rc scripts
|
||||
char pfd_svc[16], ls_svc[16], bc_svc[16];
|
||||
gen_rand_str(pfd_svc, sizeof(pfd_svc));
|
||||
gen_rand_str(ls_svc, sizeof(ls_svc));
|
||||
gen_rand_str(bc_svc, sizeof(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);
|
||||
// Inject Magisk rc scripts
|
||||
char pfd_svc[16], ls_svc[16], bc_svc[16];
|
||||
gen_rand_str(pfd_svc, sizeof(pfd_svc));
|
||||
gen_rand_str(ls_svc, sizeof(ls_svc));
|
||||
gen_rand_str(bc_svc, sizeof(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);
|
||||
|
||||
fclose(rc);
|
||||
clone_attr(src, dest);
|
||||
fclose(rc);
|
||||
clone_attr(src, dest);
|
||||
}
|
||||
|
||||
static void load_overlay_rc(const char *overlay) {
|
||||
auto dir = open_dir(overlay);
|
||||
if (!dir) return;
|
||||
auto dir = open_dir(overlay);
|
||||
if (!dir) return;
|
||||
|
||||
int dfd = dirfd(dir.get());
|
||||
// Do not allow overwrite init.rc
|
||||
unlinkat(dfd, "init.rc", 0);
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (strend(entry->d_name, ".rc") == 0) {
|
||||
LOGD("Found rc script [%s]\n", entry->d_name);
|
||||
int rc = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
rc_list.push_back(fd_full_read(rc));
|
||||
close(rc);
|
||||
unlinkat(dfd, entry->d_name, 0);
|
||||
}
|
||||
}
|
||||
int dfd = dirfd(dir.get());
|
||||
// Do not allow overwrite init.rc
|
||||
unlinkat(dfd, "init.rc", 0);
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
if (str_ends(entry->d_name, ".rc")) {
|
||||
LOGD("Found rc script [%s]\n", entry->d_name);
|
||||
int rc = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
rc_list.push_back(fd_full_read(rc));
|
||||
close(rc);
|
||||
unlinkat(dfd, entry->d_name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MagiskInit::patch_sepolicy(const char *file) {
|
||||
bool patch_init = false;
|
||||
sepolicy *sepol = nullptr;
|
||||
bool patch_init = false;
|
||||
sepolicy *sepol = nullptr;
|
||||
|
||||
if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
|
||||
LOGD("sepol: split policy\n");
|
||||
patch_init = true;
|
||||
} else if (access("/sepolicy", R_OK) == 0) {
|
||||
LOGD("sepol: monolithic policy\n");
|
||||
sepol = sepolicy::from_file("/sepolicy");
|
||||
} else {
|
||||
LOGD("sepol: no selinux\n");
|
||||
return false;
|
||||
}
|
||||
if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
|
||||
LOGD("sepol: split policy\n");
|
||||
patch_init = true;
|
||||
} else if (access("/sepolicy", R_OK) == 0) {
|
||||
LOGD("sepol: monolithic policy\n");
|
||||
sepol = sepolicy::from_file("/sepolicy");
|
||||
} else {
|
||||
LOGD("sepol: no selinux\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (access(SELINUX_VERSION, F_OK) != 0) {
|
||||
// Mount selinuxfs to communicate with kernel
|
||||
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
|
||||
mount_list.emplace_back(SELINUX_MNT);
|
||||
}
|
||||
if (access(SELINUX_VERSION, F_OK) != 0) {
|
||||
// Mount selinuxfs to communicate with kernel
|
||||
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
|
||||
mount_list.emplace_back(SELINUX_MNT);
|
||||
}
|
||||
|
||||
if (patch_init)
|
||||
sepol = sepolicy::from_split();
|
||||
if (patch_init)
|
||||
sepol = sepolicy::from_split();
|
||||
|
||||
sepol->magisk_rules();
|
||||
sepol->magisk_rules();
|
||||
|
||||
// Custom rules
|
||||
if (!custom_rules_dir.empty()) {
|
||||
if (auto dir = open_dir(custom_rules_dir.data())) {
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
auto rule = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
|
||||
if (access(rule.data(), R_OK) == 0) {
|
||||
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
|
||||
sepol->load_rule_file(rule.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Custom rules
|
||||
if (!custom_rules_dir.empty()) {
|
||||
if (auto dir = open_dir(custom_rules_dir.data())) {
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
auto rule = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
|
||||
if (access(rule.data(), R_OK) == 0) {
|
||||
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
|
||||
sepol->load_rule_file(rule.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOGD("Dumping sepolicy to: [%s]\n", file);
|
||||
sepol->to_file(file);
|
||||
delete sepol;
|
||||
LOGD("Dumping sepolicy to: [%s]\n", file);
|
||||
sepol->to_file(file);
|
||||
delete sepol;
|
||||
|
||||
// Remove OnePlus stupid debug sepolicy and use our own
|
||||
if (access("/sepolicy_debug", F_OK) == 0) {
|
||||
unlink("/sepolicy_debug");
|
||||
link("/sepolicy", "/sepolicy_debug");
|
||||
}
|
||||
// Remove OnePlus stupid debug sepolicy and use our own
|
||||
if (access("/sepolicy_debug", F_OK) == 0) {
|
||||
unlink("/sepolicy_debug");
|
||||
link("/sepolicy", "/sepolicy_debug");
|
||||
}
|
||||
|
||||
return patch_init;
|
||||
return patch_init;
|
||||
}
|
||||
|
||||
static void recreate_sbin(const char *mirror, bool use_bind_mount) {
|
||||
auto dp = xopen_dir(mirror);
|
||||
int src = dirfd(dp.get());
|
||||
char buf[4096];
|
||||
for (dirent *entry; (entry = xreaddir(dp.get()));) {
|
||||
string sbin_path = "/sbin/"s + entry->d_name;
|
||||
struct stat st;
|
||||
fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
||||
xsymlink(buf, sbin_path.data());
|
||||
} else {
|
||||
sprintf(buf, "%s/%s", mirror, entry->d_name);
|
||||
if (use_bind_mount) {
|
||||
auto mode = st.st_mode & 0777;
|
||||
// Create dummy
|
||||
if (S_ISDIR(st.st_mode))
|
||||
xmkdir(sbin_path.data(), mode);
|
||||
else
|
||||
close(xopen(sbin_path.data(), O_CREAT | O_WRONLY | O_CLOEXEC, mode));
|
||||
auto dp = xopen_dir(mirror);
|
||||
int src = dirfd(dp.get());
|
||||
char buf[4096];
|
||||
for (dirent *entry; (entry = xreaddir(dp.get()));) {
|
||||
string sbin_path = "/sbin/"s + entry->d_name;
|
||||
struct stat st;
|
||||
fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
||||
xsymlink(buf, sbin_path.data());
|
||||
} else {
|
||||
sprintf(buf, "%s/%s", mirror, entry->d_name);
|
||||
if (use_bind_mount) {
|
||||
auto mode = st.st_mode & 0777;
|
||||
// Create dummy
|
||||
if (S_ISDIR(st.st_mode))
|
||||
xmkdir(sbin_path.data(), mode);
|
||||
else
|
||||
close(xopen(sbin_path.data(), O_CREAT | O_WRONLY | O_CLOEXEC, mode));
|
||||
|
||||
xmount(buf, sbin_path.data(), nullptr, MS_BIND, nullptr);
|
||||
} else {
|
||||
xsymlink(buf, sbin_path.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
xmount(buf, sbin_path.data(), nullptr, MS_BIND, nullptr);
|
||||
} else {
|
||||
xsymlink(buf, sbin_path.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string magic_mount_list;
|
||||
|
||||
static void magic_mount(const string &sdir, const string &ddir = "") {
|
||||
auto dir = xopen_dir(sdir.data());
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
string src = sdir + "/" + entry->d_name;
|
||||
string dest = ddir + "/" + entry->d_name;
|
||||
if (access(dest.data(), F_OK) == 0) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
// Recursive
|
||||
magic_mount(src, dest);
|
||||
} else {
|
||||
LOGD("Mount [%s] -> [%s]\n", src.data(), dest.data());
|
||||
xmount(src.data(), dest.data(), nullptr, MS_BIND, nullptr);
|
||||
magic_mount_list += dest;
|
||||
magic_mount_list += '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
auto dir = xopen_dir(sdir.data());
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
string src = sdir + "/" + entry->d_name;
|
||||
string dest = ddir + "/" + entry->d_name;
|
||||
if (access(dest.data(), F_OK) == 0) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
// Recursive
|
||||
magic_mount(src, dest);
|
||||
} else {
|
||||
LOGD("Mount [%s] -> [%s]\n", src.data(), dest.data());
|
||||
xmount(src.data(), dest.data(), nullptr, MS_BIND, nullptr);
|
||||
magic_mount_list += dest;
|
||||
magic_mount_list += '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ROOTMIR MIRRDIR "/system_root"
|
||||
@@ -186,169 +186,169 @@ static void magic_mount(const string &sdir, const string &ddir = "") {
|
||||
#define NEW_INITRC "/system/etc/init/hw/init.rc"
|
||||
|
||||
void SARBase::patch_rootdir() {
|
||||
string tmp_dir;
|
||||
const char *sepol;
|
||||
string tmp_dir;
|
||||
const char *sepol;
|
||||
|
||||
if (access("/sbin", F_OK) == 0) {
|
||||
tmp_dir = "/sbin";
|
||||
sepol = "/sbin/.se";
|
||||
} else {
|
||||
char buf[8];
|
||||
gen_rand_str(buf, sizeof(buf));
|
||||
tmp_dir = "/dev/"s + buf;
|
||||
xmkdir(tmp_dir.data(), 0);
|
||||
sepol = "/dev/.se";
|
||||
}
|
||||
if (access("/sbin", F_OK) == 0) {
|
||||
tmp_dir = "/sbin";
|
||||
sepol = "/sbin/.se";
|
||||
} else {
|
||||
char buf[8];
|
||||
gen_rand_str(buf, sizeof(buf));
|
||||
tmp_dir = "/dev/"s + buf;
|
||||
xmkdir(tmp_dir.data(), 0);
|
||||
sepol = "/dev/.se";
|
||||
}
|
||||
|
||||
setup_tmp(tmp_dir.data());
|
||||
chdir(tmp_dir.data());
|
||||
setup_tmp(tmp_dir.data());
|
||||
chdir(tmp_dir.data());
|
||||
|
||||
mount_rules_dir(BLOCKDIR, MIRRDIR);
|
||||
mount_rules_dir(BLOCKDIR, MIRRDIR);
|
||||
|
||||
// Mount system_root mirror
|
||||
xmkdir(ROOTMIR, 0755);
|
||||
xmount("/", ROOTMIR, nullptr, MS_BIND, nullptr);
|
||||
mount_list.emplace_back(tmp_dir + "/" ROOTMIR);
|
||||
// Mount system_root mirror
|
||||
xmkdir(ROOTMIR, 0755);
|
||||
xmount("/", ROOTMIR, nullptr, MS_BIND, nullptr);
|
||||
mount_list.emplace_back(tmp_dir + "/" ROOTMIR);
|
||||
|
||||
// Recreate original sbin structure if necessary
|
||||
if (tmp_dir == "/sbin")
|
||||
recreate_sbin(ROOTMIR "/sbin", true);
|
||||
// Recreate original sbin structure if necessary
|
||||
if (tmp_dir == "/sbin")
|
||||
recreate_sbin(ROOTMIR "/sbin", true);
|
||||
|
||||
// Patch init
|
||||
int patch_count;
|
||||
{
|
||||
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
|
||||
auto init = raw_data::read(src);
|
||||
patch_count = init.patch({
|
||||
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
|
||||
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
|
||||
});
|
||||
xmkdir(ROOTOVL, 0);
|
||||
int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
||||
xwrite(dest, init.buf, init.sz);
|
||||
fclone_attr(src, dest);
|
||||
close(src);
|
||||
close(dest);
|
||||
}
|
||||
// Patch init
|
||||
int patch_count;
|
||||
{
|
||||
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
|
||||
auto init = raw_data::read(src);
|
||||
patch_count = init.patch({
|
||||
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
|
||||
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
|
||||
});
|
||||
xmkdir(ROOTOVL, 0);
|
||||
int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
||||
xwrite(dest, init.buf, init.sz);
|
||||
fclone_attr(src, dest);
|
||||
close(src);
|
||||
close(dest);
|
||||
}
|
||||
|
||||
if (patch_count != 2 && access(LIBSELINUX, F_OK) == 0) {
|
||||
// init is dynamically linked, need to patch libselinux
|
||||
auto lib = raw_data::read(LIBSELINUX);
|
||||
lib.patch({make_pair(MONOPOLICY, sepol)});
|
||||
xmkdirs(dirname(ROOTOVL LIBSELINUX), 0755);
|
||||
int dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
||||
xwrite(dest, lib.buf, lib.sz);
|
||||
close(dest);
|
||||
clone_attr(LIBSELINUX, ROOTOVL LIBSELINUX);
|
||||
}
|
||||
if (patch_count != 2 && access(LIBSELINUX, F_OK) == 0) {
|
||||
// init is dynamically linked, need to patch libselinux
|
||||
auto lib = raw_data::read(LIBSELINUX);
|
||||
lib.patch({make_pair(MONOPOLICY, sepol)});
|
||||
xmkdirs(dirname(ROOTOVL LIBSELINUX), 0755);
|
||||
int dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
|
||||
xwrite(dest, lib.buf, lib.sz);
|
||||
close(dest);
|
||||
clone_attr(LIBSELINUX, ROOTOVL LIBSELINUX);
|
||||
}
|
||||
|
||||
// sepolicy
|
||||
patch_sepolicy(sepol);
|
||||
// sepolicy
|
||||
patch_sepolicy(sepol);
|
||||
|
||||
// Restore backup files
|
||||
struct sockaddr_un sun;
|
||||
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
|
||||
LOGD("ACK init daemon to write backup files\n");
|
||||
// Let daemon know where tmp_dir is
|
||||
write_string(sockfd, tmp_dir.data());
|
||||
// Wait for daemon to finish restoring files
|
||||
int ack;
|
||||
read(sockfd, &ack, sizeof(ack));
|
||||
} else {
|
||||
LOGD("Restore backup files locally\n");
|
||||
restore_folder(ROOTOVL, overlays);
|
||||
overlays.clear();
|
||||
}
|
||||
close(sockfd);
|
||||
// Restore backup files
|
||||
struct sockaddr_un sun;
|
||||
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
|
||||
LOGD("ACK init daemon to write backup files\n");
|
||||
// Let daemon know where tmp_dir is
|
||||
write_string(sockfd, tmp_dir.data());
|
||||
// Wait for daemon to finish restoring files
|
||||
int ack;
|
||||
read(sockfd, &ack, sizeof(ack));
|
||||
} else {
|
||||
LOGD("Restore backup files locally\n");
|
||||
restore_folder(ROOTOVL, overlays);
|
||||
overlays.clear();
|
||||
}
|
||||
close(sockfd);
|
||||
|
||||
// Handle overlay.d
|
||||
load_overlay_rc(ROOTOVL);
|
||||
if (access(ROOTOVL "/sbin", F_OK) == 0) {
|
||||
// Move files in overlay.d/sbin into tmp_dir
|
||||
mv_path(ROOTOVL "/sbin", ".");
|
||||
}
|
||||
// Handle overlay.d
|
||||
load_overlay_rc(ROOTOVL);
|
||||
if (access(ROOTOVL "/sbin", F_OK) == 0) {
|
||||
// Move files in overlay.d/sbin into tmp_dir
|
||||
mv_path(ROOTOVL "/sbin", ".");
|
||||
}
|
||||
|
||||
// Patch init.rc
|
||||
if (access("/init.rc", F_OK) == 0) {
|
||||
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
|
||||
} else {
|
||||
// Android 11's new init.rc
|
||||
xmkdirs(dirname(ROOTOVL NEW_INITRC), 0755);
|
||||
patch_init_rc(NEW_INITRC, ROOTOVL NEW_INITRC, tmp_dir.data());
|
||||
}
|
||||
// Patch init.rc
|
||||
if (access("/init.rc", F_OK) == 0) {
|
||||
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
|
||||
} else {
|
||||
// Android 11's new init.rc
|
||||
xmkdirs(dirname(ROOTOVL NEW_INITRC), 0755);
|
||||
patch_init_rc(NEW_INITRC, ROOTOVL NEW_INITRC, tmp_dir.data());
|
||||
}
|
||||
|
||||
// Mount rootdir
|
||||
magic_mount(ROOTOVL);
|
||||
int dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC, 0);
|
||||
write(dest, magic_mount_list.data(), magic_mount_list.length());
|
||||
close(dest);
|
||||
// Mount rootdir
|
||||
magic_mount(ROOTOVL);
|
||||
int dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC, 0);
|
||||
write(dest, magic_mount_list.data(), magic_mount_list.length());
|
||||
close(dest);
|
||||
|
||||
chdir("/");
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
#define TMP_MNTDIR "/dev/mnt"
|
||||
#define TMP_RULESDIR "/.backup/.sepolicy.rules"
|
||||
|
||||
void RootFSInit::patch_rootfs() {
|
||||
// Handle custom sepolicy rules
|
||||
xmkdir(TMP_MNTDIR, 0755);
|
||||
mount_rules_dir("/dev/block", TMP_MNTDIR);
|
||||
// Preserve custom rule path
|
||||
if (!custom_rules_dir.empty()) {
|
||||
string rules_dir = "./" + custom_rules_dir.substr(sizeof(TMP_MNTDIR));
|
||||
xsymlink(rules_dir.data(), TMP_RULESDIR);
|
||||
}
|
||||
// Handle custom sepolicy rules
|
||||
xmkdir(TMP_MNTDIR, 0755);
|
||||
mount_rules_dir("/dev/block", TMP_MNTDIR);
|
||||
// Preserve custom rule path
|
||||
if (!custom_rules_dir.empty()) {
|
||||
string rules_dir = "./" + custom_rules_dir.substr(sizeof(TMP_MNTDIR));
|
||||
xsymlink(rules_dir.data(), TMP_RULESDIR);
|
||||
}
|
||||
|
||||
if (patch_sepolicy("/sepolicy")) {
|
||||
auto init = raw_data::mmap_rw("/init");
|
||||
init.patch({ make_pair(SPLIT_PLAT_CIL, "xxx") });
|
||||
}
|
||||
if (patch_sepolicy("/sepolicy")) {
|
||||
auto init = raw_data::mmap_rw("/init");
|
||||
init.patch({ make_pair(SPLIT_PLAT_CIL, "xxx") });
|
||||
}
|
||||
|
||||
// Handle overlays
|
||||
if (access("/overlay.d", F_OK) == 0) {
|
||||
LOGD("Merge overlay.d\n");
|
||||
load_overlay_rc("/overlay.d");
|
||||
mv_path("/overlay.d", "/");
|
||||
}
|
||||
// Handle overlays
|
||||
if (access("/overlay.d", F_OK) == 0) {
|
||||
LOGD("Merge overlay.d\n");
|
||||
load_overlay_rc("/overlay.d");
|
||||
mv_path("/overlay.d", "/");
|
||||
}
|
||||
|
||||
patch_init_rc("/init.rc", "/init.p.rc", "/sbin");
|
||||
rename("/init.p.rc", "/init.rc");
|
||||
patch_init_rc("/init.rc", "/init.p.rc", "/sbin");
|
||||
rename("/init.p.rc", "/init.rc");
|
||||
|
||||
// Create hardlink mirror of /sbin to /root
|
||||
mkdir("/root", 0750);
|
||||
clone_attr("/sbin", "/root");
|
||||
link_path("/sbin", "/root");
|
||||
// Create hardlink mirror of /sbin to /root
|
||||
mkdir("/root", 0750);
|
||||
clone_attr("/sbin", "/root");
|
||||
link_path("/sbin", "/root");
|
||||
|
||||
// Dump magiskinit as magisk
|
||||
int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755);
|
||||
write(fd, self.buf, self.sz);
|
||||
close(fd);
|
||||
// Dump magiskinit as magisk
|
||||
int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755);
|
||||
write(fd, self.buf, self.sz);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void MagiskProxy::start() {
|
||||
// Mount rootfs as rw to do post-init rootfs patches
|
||||
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
|
||||
// Mount rootfs as rw to do post-init rootfs patches
|
||||
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
|
||||
|
||||
// Backup stuffs before removing them
|
||||
self = raw_data::read("/sbin/magisk");
|
||||
config = raw_data::read("/.backup/.magisk");
|
||||
char custom_rules_dir[64];
|
||||
custom_rules_dir[0] = '\0';
|
||||
xreadlink(TMP_RULESDIR, custom_rules_dir, sizeof(custom_rules_dir));
|
||||
// Backup stuffs before removing them
|
||||
self = raw_data::read("/sbin/magisk");
|
||||
config = raw_data::read("/.backup/.magisk");
|
||||
char custom_rules_dir[64];
|
||||
custom_rules_dir[0] = '\0';
|
||||
xreadlink(TMP_RULESDIR, custom_rules_dir, sizeof(custom_rules_dir));
|
||||
|
||||
unlink("/sbin/magisk");
|
||||
rm_rf("/.backup");
|
||||
unlink("/sbin/magisk");
|
||||
rm_rf("/.backup");
|
||||
|
||||
setup_tmp("/sbin");
|
||||
setup_tmp("/sbin");
|
||||
|
||||
// Create symlinks pointing back to /root
|
||||
recreate_sbin("/root", false);
|
||||
// Create symlinks pointing back to /root
|
||||
recreate_sbin("/root", false);
|
||||
|
||||
if (custom_rules_dir[0])
|
||||
xsymlink(custom_rules_dir, "/sbin/" RULESDIR);
|
||||
if (custom_rules_dir[0])
|
||||
xsymlink(custom_rules_dir, "/sbin/" RULESDIR);
|
||||
|
||||
// Tell magiskd to remount rootfs
|
||||
setenv("REMOUNT_ROOT", "1", 1);
|
||||
execv("/sbin/magisk", argv);
|
||||
// Tell magiskd to remount rootfs
|
||||
setenv("REMOUNT_ROOT", "1", 1);
|
||||
execv("/sbin/magisk", argv);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
using namespace std;
|
||||
|
||||
void fstab_entry::to_file(FILE *fp) {
|
||||
fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(),
|
||||
type.data(), mnt_flags.data(), fsmgr_flags.data());
|
||||
fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(),
|
||||
type.data(), mnt_flags.data(), fsmgr_flags.data());
|
||||
}
|
||||
|
||||
#define set_info(val) \
|
||||
@@ -22,193 +22,193 @@ entry.val = &line[val##0];
|
||||
extern uint32_t patch_verity(void *buf, uint32_t size);
|
||||
|
||||
void FirstStageInit::prepare() {
|
||||
if (cmd->force_normal_boot) {
|
||||
xmkdirs(FSR "/system/bin", 0755);
|
||||
rename("/init" /* magiskinit */, FSR "/system/bin/init");
|
||||
symlink("/system/bin/init", FSR "/init");
|
||||
rename("/.backup", FSR "/.backup");
|
||||
rename("/overlay.d", FSR "/overlay.d");
|
||||
xsymlink("/system/bin/init", "/init");
|
||||
if (cmd->force_normal_boot) {
|
||||
xmkdirs(FSR "/system/bin", 0755);
|
||||
rename("/init" /* magiskinit */, FSR "/system/bin/init");
|
||||
symlink("/system/bin/init", FSR "/init");
|
||||
rename("/.backup", FSR "/.backup");
|
||||
rename("/overlay.d", FSR "/overlay.d");
|
||||
xsymlink("/system/bin/init", "/init");
|
||||
|
||||
chdir(FSR);
|
||||
} else {
|
||||
xmkdir("/system", 0755);
|
||||
xmkdir("/system/bin", 0755);
|
||||
rename("/init" /* magiskinit */ , "/system/bin/init");
|
||||
rename("/.backup/init", "/init");
|
||||
}
|
||||
chdir(FSR);
|
||||
} else {
|
||||
xmkdir("/system", 0755);
|
||||
xmkdir("/system/bin", 0755);
|
||||
rename("/init" /* magiskinit */ , "/system/bin/init");
|
||||
rename("/.backup/init", "/init");
|
||||
}
|
||||
|
||||
// Try to load fstab from dt
|
||||
vector<fstab_entry> fstab;
|
||||
read_dt_fstab(fstab);
|
||||
// Try to load fstab from dt
|
||||
vector<fstab_entry> fstab;
|
||||
read_dt_fstab(fstab);
|
||||
|
||||
char fstab_file[128];
|
||||
fstab_file[0] = '\0';
|
||||
char fstab_file[128];
|
||||
fstab_file[0] = '\0';
|
||||
|
||||
// Find existing fstab file
|
||||
for (const char *hw : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
|
||||
if (hw[0] == '\0')
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Find existing fstab file
|
||||
for (const char *hw : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
|
||||
if (hw[0] == '\0')
|
||||
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()) {
|
||||
// fstab has to be somewhere in ramdisk
|
||||
if (fstab_file[0] == '\0') {
|
||||
LOGE("Cannot find fstab file in ramdisk!\n");
|
||||
return;
|
||||
}
|
||||
if (fstab.empty()) {
|
||||
// fstab has to be somewhere in ramdisk
|
||||
if (fstab_file[0] == '\0') {
|
||||
LOGE("Cannot find fstab file in ramdisk!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse and load fstab file
|
||||
file_readline(fstab_file, [&](string_view l) -> bool {
|
||||
if (l[0] == '#' || l.length() == 1)
|
||||
return true;
|
||||
char *line = (char *) l.data();
|
||||
// Parse and load fstab file
|
||||
file_readline(fstab_file, [&](string_view l) -> bool {
|
||||
if (l[0] == '#' || l.length() == 1)
|
||||
return true;
|
||||
char *line = (char *) l.data();
|
||||
|
||||
int dev0, dev1, mnt_point0, mnt_point1, type0, type1,
|
||||
mnt_flags0, mnt_flags1, fsmgr_flags0, fsmgr_flags1;
|
||||
int dev0, dev1, mnt_point0, mnt_point1, type0, type1,
|
||||
mnt_flags0, mnt_flags1, fsmgr_flags0, fsmgr_flags1;
|
||||
|
||||
sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n",
|
||||
&dev0, &dev1, &mnt_point0, &mnt_point1, &type0, &type1,
|
||||
&mnt_flags0, &mnt_flags1, &fsmgr_flags0, &fsmgr_flags1);
|
||||
sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n",
|
||||
&dev0, &dev1, &mnt_point0, &mnt_point1, &type0, &type1,
|
||||
&mnt_flags0, &mnt_flags1, &fsmgr_flags0, &fsmgr_flags1);
|
||||
|
||||
fstab_entry entry;
|
||||
fstab_entry entry;
|
||||
|
||||
set_info(dev);
|
||||
set_info(mnt_point);
|
||||
set_info(type);
|
||||
set_info(mnt_flags);
|
||||
set_info(fsmgr_flags);
|
||||
set_info(dev);
|
||||
set_info(mnt_point);
|
||||
set_info(type);
|
||||
set_info(mnt_flags);
|
||||
set_info(fsmgr_flags);
|
||||
|
||||
fstab.emplace_back(std::move(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";
|
||||
}
|
||||
}
|
||||
fstab.emplace_back(std::move(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
|
||||
if (fstab_file[0] == '\0') {
|
||||
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);
|
||||
}
|
||||
// Dump dt fstab to fstab file in rootfs
|
||||
if (fstab_file[0] == '\0') {
|
||||
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);
|
||||
}
|
||||
|
||||
// Patch init to force IsDtFstabCompatible() return false
|
||||
auto init = raw_data::mmap_rw("/init");
|
||||
init.patch({ make_pair("android,fstab", "xxx") });
|
||||
}
|
||||
// Patch init to force IsDtFstabCompatible() return false
|
||||
auto init = raw_data::mmap_rw("/init");
|
||||
init.patch({ make_pair("android,fstab", "xxx") });
|
||||
}
|
||||
|
||||
{
|
||||
LOGD("Write fstab file: %s\n", fstab_file);
|
||||
auto fp = xopen_file(fstab_file, "we");
|
||||
for (auto &entry : fstab) {
|
||||
// Redirect system mnt_point so init won't switch root in first stage init
|
||||
if (entry.mnt_point == "/system")
|
||||
entry.mnt_point = "/system_root";
|
||||
{
|
||||
LOGD("Write fstab file: %s\n", fstab_file);
|
||||
auto fp = xopen_file(fstab_file, "we");
|
||||
for (auto &entry : fstab) {
|
||||
// Redirect system mnt_point so init won't switch root in first stage init
|
||||
if (entry.mnt_point == "/system")
|
||||
entry.mnt_point = "/system_root";
|
||||
|
||||
// Force remove AVB for 2SI since it may bootloop some devices
|
||||
auto len = patch_verity(entry.fsmgr_flags.data(), entry.fsmgr_flags.length());
|
||||
entry.fsmgr_flags.resize(len);
|
||||
// Force remove AVB for 2SI since it may bootloop some devices
|
||||
auto len = patch_verity(entry.fsmgr_flags.data(), entry.fsmgr_flags.length());
|
||||
entry.fsmgr_flags.resize(len);
|
||||
|
||||
entry.to_file(fp.get());
|
||||
}
|
||||
}
|
||||
chmod(fstab_file, 0644);
|
||||
entry.to_file(fp.get());
|
||||
}
|
||||
}
|
||||
chmod(fstab_file, 0644);
|
||||
|
||||
chdir("/");
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
#define INIT_PATH "/system/bin/init"
|
||||
#define REDIR_PATH "/system/bin/am"
|
||||
|
||||
void SARInit::first_stage_prep() {
|
||||
int pid = getpid();
|
||||
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 = raw_data::read(src);
|
||||
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
|
||||
write(dest, init.buf, init.sz);
|
||||
fclone_attr(src, dest);
|
||||
close(dest);
|
||||
}
|
||||
// Patch init binary
|
||||
int src = xopen("/init", O_RDONLY);
|
||||
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
|
||||
{
|
||||
auto init = raw_data::read(src);
|
||||
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
|
||||
write(dest, init.buf, init.sz);
|
||||
fclone_attr(src, dest);
|
||||
close(dest);
|
||||
}
|
||||
|
||||
// Replace redirect init with magiskinit
|
||||
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
|
||||
write(dest, self.buf, self.sz);
|
||||
fclone_attr(src, dest);
|
||||
close(src);
|
||||
close(dest);
|
||||
// Replace redirect init with magiskinit
|
||||
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
|
||||
write(dest, self.buf, self.sz);
|
||||
fclone_attr(src, dest);
|
||||
close(src);
|
||||
close(dest);
|
||||
|
||||
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
|
||||
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
|
||||
xumount2("/dev", MNT_DETACH);
|
||||
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
|
||||
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
|
||||
xumount2("/dev", MNT_DETACH);
|
||||
|
||||
// Block SIGUSR1
|
||||
sigset_t block, old;
|
||||
sigemptyset(&block);
|
||||
sigaddset(&block, SIGUSR1);
|
||||
sigprocmask(SIG_BLOCK, &block, &old);
|
||||
// Block SIGUSR1
|
||||
sigset_t block, old;
|
||||
sigemptyset(&block);
|
||||
sigaddset(&block, SIGUSR1);
|
||||
sigprocmask(SIG_BLOCK, &block, &old);
|
||||
|
||||
if (int child = xfork(); child) {
|
||||
LOGD("init daemon [%d]\n", child);
|
||||
// Wait for children signal
|
||||
int sig;
|
||||
sigwait(&block, &sig);
|
||||
if (int child = xfork(); child) {
|
||||
LOGD("init daemon [%d]\n", child);
|
||||
// Wait for children signal
|
||||
int sig;
|
||||
sigwait(&block, &sig);
|
||||
|
||||
// Restore sigmask
|
||||
sigprocmask(SIG_SETMASK, &old, nullptr);
|
||||
} 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);
|
||||
// Restore sigmask
|
||||
sigprocmask(SIG_SETMASK, &old, nullptr);
|
||||
} 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
|
||||
kill(pid, SIGUSR1);
|
||||
// Resume parent
|
||||
kill(pid, SIGUSR1);
|
||||
|
||||
// Wait for second stage ack
|
||||
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
// Wait for second stage ack
|
||||
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
|
||||
// Write backup files
|
||||
char *tmp_dir = read_string(client);
|
||||
chdir(tmp_dir);
|
||||
free(tmp_dir);
|
||||
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
|
||||
char *tmp_dir = read_string(client);
|
||||
chdir(tmp_dir);
|
||||
free(tmp_dir);
|
||||
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!
|
||||
write(sockfd, &sockfd, sizeof(sockfd));
|
||||
close(client);
|
||||
close(sockfd);
|
||||
// Ack and bail out!
|
||||
write(sockfd, &sockfd, sizeof(sockfd));
|
||||
close(client);
|
||||
close(sockfd);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
247
native/jni/inject/hook.cpp
Normal file
247
native/jni/inject/hook.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include <xhook.h>
|
||||
#include <utils.hpp>
|
||||
#include <flags.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;
|
||||
|
||||
// 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;
|
||||
|
||||
namespace {
|
||||
|
||||
struct HookContext {
|
||||
int pid;
|
||||
bool unload;
|
||||
};
|
||||
|
||||
// JNI method declarations
|
||||
DCL_JNI_FUNC(nativeForkAndSpecialize)
|
||||
DCL_JNI_FUNC(nativeSpecializeAppProcess)
|
||||
DCL_JNI_FUNC(nativeForkSystemServer)
|
||||
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
// TODO: check if we need to do hiding
|
||||
// Demonstrate self unload in child process
|
||||
ctx->unload = true;
|
||||
|
||||
LOGD("hook: %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
LOGD("hook: %s\n", __FUNCTION__);
|
||||
|
||||
if (ctx->unload)
|
||||
self_unload();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
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) {
|
||||
LOGD("hook: %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void nativeSpecializeAppProcess_post(HookContext *ctx, JNIEnv *env, jclass clazz) {
|
||||
LOGD("hook: %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
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__);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
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);
|
||||
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();
|
||||
366
native/jni/inject/jni_hooks.hpp
Normal file
366
native/jni/inject/jni_hooks.hpp
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Original code: https://github.com/RikkaApps/Riru/blob/master/riru/src/main/cpp/jni_native_method.cpp
|
||||
* The code is modified and sublicensed to GPLv3 for incorporating into Magisk.
|
||||
*
|
||||
* Copyright (c) 2018-2021, RikkaW
|
||||
* Copyright (c) 2021, John 'topjohnwu' Wu
|
||||
*/
|
||||
|
||||
#define ENABLE_LEGACY_DP 0 // Nobody should use outdated developer preview...
|
||||
|
||||
// All possible missing arguments
|
||||
static union {
|
||||
struct {
|
||||
jintArray fds_to_ignore;
|
||||
jboolean is_child_zygote;
|
||||
jboolean is_top_app;
|
||||
jobjectArray pkg_data_info_list;
|
||||
jobjectArray whitelisted_data_info_list;
|
||||
jboolean mount_data_dirs;
|
||||
jboolean mount_storage_dirs;
|
||||
};
|
||||
size_t args_buf[8]; // Easy access to wipe all variables at once
|
||||
};
|
||||
|
||||
#define DCL_JNI(ret, name, sig, ...) \
|
||||
const static char name##_sig[] = sig; \
|
||||
static ret name(__VA_ARGS__)
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
#define pre_fork() \
|
||||
HookContext ctx{}; \
|
||||
memset(args_buf, 0, sizeof(args_buf)); \
|
||||
nativeForkAndSpecialize_pre(&ctx, env, clazz, uid, gid, gids, runtime_flags, \
|
||||
rlimits, mount_external, se_info, nice_name, fds_to_close, fds_to_ignore, 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)
|
||||
|
||||
#define orig_fork(ver, ...) \
|
||||
reinterpret_cast<decltype(&nativeForkAndSpecialize_##ver)> \
|
||||
(nativeForkAndSpecialize_orig->fnPtr)(__VA_ARGS__)
|
||||
|
||||
#define post_fork() \
|
||||
nativeForkAndSpecialize_post(&ctx, env, clazz); \
|
||||
return ctx.pid
|
||||
|
||||
#define DCL_FORK_AND_SPECIALIZE(ver, sig, ...) \
|
||||
DCL_JNI(jint, nativeForkAndSpecialize_##ver, sig, __VA_ARGS__)
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(m,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
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, jstring instruction_set, jstring app_data_dir) {
|
||||
pre_fork();
|
||||
orig_fork(m, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, nice_name, fds_to_close, instruction_set, app_data_dir);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(o,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
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, jstring instruction_set, jstring app_data_dir) {
|
||||
pre_fork();
|
||||
orig_fork(o, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, nice_name, fds_to_close, fds_to_ignore, instruction_set, app_data_dir);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(p,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
|
||||
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, jboolean is_child_zygote,
|
||||
jstring instruction_set, jstring app_data_dir) {
|
||||
pre_fork();
|
||||
orig_fork(p, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
|
||||
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(q_alt,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I",
|
||||
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, jboolean is_child_zygote,
|
||||
jstring instruction_set, jstring app_data_dir, jboolean is_top_app) {
|
||||
pre_fork();
|
||||
orig_fork(q_alt, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
|
||||
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir, is_top_app);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
#if ENABLE_LEGACY_DP
|
||||
DCL_FORK_AND_SPECIALIZE(r_dp2,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)I",
|
||||
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, jboolean is_child_zygote,
|
||||
jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list) {
|
||||
pre_fork();
|
||||
orig_fork(r_dp2, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
|
||||
nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set, app_data_dir,
|
||||
is_top_app, pkg_data_info_list);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(r_dp3,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;Z)I",
|
||||
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, jboolean is_child_zygote,
|
||||
jstring instruction_set, jstring app_data_dir, jboolean is_top_app, jobjectArray pkg_data_info_list,
|
||||
jboolean mount_storage_dirs) {
|
||||
pre_fork();
|
||||
orig_fork(r_dp3, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, nice_name, fds_to_close, fds_to_ignore, is_child_zygote, instruction_set,
|
||||
app_data_dir, is_top_app, pkg_data_info_list, mount_storage_dirs);
|
||||
post_fork();
|
||||
}
|
||||
#endif // ENABLE_LEGACY_DP
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(r,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I",
|
||||
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, 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) {
|
||||
pre_fork();
|
||||
orig_fork(r, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
|
||||
nice_name, fds_to_close, fds_to_ignore, 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);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(samsung_m,
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
|
||||
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
|
||||
jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir) {
|
||||
pre_fork();
|
||||
orig_fork(samsung_m, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, category, accessInfo, nice_name, fds_to_close, instruction_set, app_data_dir);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(samsung_n,
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;I)I",
|
||||
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
|
||||
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
|
||||
jstring nice_name, jintArray fds_to_close, jstring instruction_set, jstring app_data_dir, jint a1) {
|
||||
pre_fork();
|
||||
orig_fork(samsung_n, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, category, accessInfo, nice_name, fds_to_close, instruction_set, app_data_dir, a1);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(samsung_o,
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I",
|
||||
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
|
||||
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
|
||||
jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jstring instruction_set,
|
||||
jstring app_data_dir) {
|
||||
pre_fork();
|
||||
orig_fork(samsung_o, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, category, accessInfo, nice_name, fds_to_close, fds_to_ignore,
|
||||
instruction_set, app_data_dir);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
DCL_FORK_AND_SPECIALIZE(samsung_p,
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
|
||||
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
|
||||
jobjectArray rlimits, jint mount_external, jstring se_info, jint category, jint accessInfo,
|
||||
jstring nice_name, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote,
|
||||
jstring instruction_set, jstring app_data_dir) {
|
||||
pre_fork();
|
||||
orig_fork(samsung_p, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, category, accessInfo, nice_name, fds_to_close, fds_to_ignore, is_child_zygote,
|
||||
instruction_set, app_data_dir);
|
||||
post_fork();
|
||||
}
|
||||
|
||||
#define DEF_FORK(ver) { \
|
||||
"nativeForkAndSpecialize", \
|
||||
nativeForkAndSpecialize_##ver##_sig, \
|
||||
(void *) &nativeForkAndSpecialize_##ver \
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
#define pre_spec() \
|
||||
HookContext ctx{}; \
|
||||
memset(args_buf, 0, sizeof(args_buf)); \
|
||||
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)
|
||||
|
||||
#define orig_spec(ver, ...) \
|
||||
reinterpret_cast<decltype(&nativeSpecializeAppProcess_##ver)> \
|
||||
(nativeSpecializeAppProcess_orig->fnPtr)(__VA_ARGS__)
|
||||
|
||||
#define post_spec() \
|
||||
nativeSpecializeAppProcess_post(&ctx, env, clazz)
|
||||
|
||||
#define DCL_SPECIALIZE_APP(ver, sig, ...) \
|
||||
DCL_JNI(void, nativeSpecializeAppProcess_##ver, sig, __VA_ARGS__)
|
||||
|
||||
DCL_SPECIALIZE_APP(q,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
|
||||
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) {
|
||||
pre_spec();
|
||||
orig_spec(q, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
|
||||
nice_name, is_child_zygote, instruction_set, app_data_dir);
|
||||
post_spec();
|
||||
}
|
||||
|
||||
DCL_SPECIALIZE_APP(q_alt,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V",
|
||||
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) {
|
||||
pre_spec();
|
||||
orig_spec(q_alt, 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);
|
||||
post_spec();
|
||||
}
|
||||
|
||||
#if ENABLE_LEGACY_DP
|
||||
DCL_SPECIALIZE_APP(r_dp2,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)V",
|
||||
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) {
|
||||
pre_spec();
|
||||
orig_spec(r_dp2, 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);
|
||||
post_spec();
|
||||
}
|
||||
|
||||
DCL_SPECIALIZE_APP(r_dp3,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;Z)V",
|
||||
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, jboolean mount_storage_dirs) {
|
||||
pre_spec();
|
||||
orig_spec(r_dp3, 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,
|
||||
mount_storage_dirs);
|
||||
post_spec();
|
||||
}
|
||||
#endif // ENABLE_LEGACY_DP
|
||||
|
||||
DCL_SPECIALIZE_APP(r,
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
|
||||
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) {
|
||||
pre_spec();
|
||||
orig_spec(r, 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);
|
||||
post_spec();
|
||||
}
|
||||
|
||||
DCL_SPECIALIZE_APP(samsung_q,
|
||||
"(II[II[[IILjava/lang/String;IILjava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
|
||||
JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags,
|
||||
jobjectArray rlimits, jint mount_external, jstring se_info, jint space, jint accessInfo,
|
||||
jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) {
|
||||
pre_spec();
|
||||
orig_spec(samsung_q, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external,
|
||||
se_info, space, accessInfo, nice_name, is_child_zygote, instruction_set, app_data_dir);
|
||||
post_spec();
|
||||
}
|
||||
|
||||
#define DEF_SPEC(ver) { \
|
||||
"nativeSpecializeAppProcess", \
|
||||
nativeSpecializeAppProcess_##ver##_sig, \
|
||||
(void *) &nativeSpecializeAppProcess_##ver \
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
#define pre_server() \
|
||||
HookContext ctx{}; \
|
||||
memset(args_buf, 0, sizeof(args_buf)); \
|
||||
nativeForkSystemServer_pre(&ctx, env, clazz, uid, gid, gids, runtime_flags, \
|
||||
rlimits, permitted_capabilities, effective_capabilities)
|
||||
|
||||
#define orig_server(ver, ...) \
|
||||
reinterpret_cast<decltype(&nativeForkSystemServer_##ver)> \
|
||||
(nativeForkSystemServer_orig->fnPtr)(__VA_ARGS__)
|
||||
|
||||
#define post_server() \
|
||||
nativeForkSystemServer_post(&ctx, env, clazz); \
|
||||
return ctx.pid
|
||||
|
||||
#define DCL_FORK_SERVER(ver, sig, ...) \
|
||||
DCL_JNI(jint, nativeForkSystemServer_##ver, sig, __VA_ARGS__)
|
||||
|
||||
DCL_FORK_SERVER(m, "(II[II[[IJJ)I",
|
||||
JNIEnv *env, jclass clazz, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
|
||||
jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) {
|
||||
pre_server();
|
||||
orig_server(m, env, clazz, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
|
||||
effective_capabilities);
|
||||
post_server();
|
||||
}
|
||||
|
||||
DCL_FORK_SERVER(samsung_q, "(II[IIII[[IJJ)I",
|
||||
JNIEnv *env, jclass clazz, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
|
||||
jint space, jint accessInfo, jobjectArray rlimits, jlong permitted_capabilities,
|
||||
jlong effective_capabilities) {
|
||||
pre_server();
|
||||
orig_server(samsung_q, env, clazz, uid, gid, gids, runtime_flags, space, accessInfo, rlimits,
|
||||
permitted_capabilities, effective_capabilities);
|
||||
post_server();
|
||||
}
|
||||
|
||||
#define DEF_SERVER(ver) { \
|
||||
"nativeForkSystemServer", \
|
||||
nativeForkSystemServer_##ver##_sig, \
|
||||
(void *) &nativeForkSystemServer_##ver \
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const JNINativeMethod nativeForkAndSpecialize_methods[] = {
|
||||
DEF_FORK(m), DEF_FORK(o), DEF_FORK(p),
|
||||
DEF_FORK(q_alt), DEF_FORK(r),
|
||||
DEF_FORK(samsung_m), DEF_FORK(samsung_n),
|
||||
DEF_FORK(samsung_o), DEF_FORK(samsung_p),
|
||||
#if ENABLE_LEGACY_DP
|
||||
DEF_FORK(r_dp2), DEF_FORK(r_dp3)
|
||||
#endif
|
||||
};
|
||||
const int nativeForkAndSpecialize_methods_num = std::size(nativeForkAndSpecialize_methods);
|
||||
|
||||
const JNINativeMethod nativeSpecializeAppProcess_methods[] = {
|
||||
DEF_SPEC(q), DEF_SPEC(q_alt),
|
||||
DEF_SPEC(r), DEF_SPEC(samsung_q),
|
||||
#if ENABLE_LEGACY_DP
|
||||
DEF_SPEC(r_dp2), DEF_SPEC(r_dp3)
|
||||
#endif
|
||||
};
|
||||
const int nativeSpecializeAppProcess_methods_num = std::size(
|
||||
nativeSpecializeAppProcess_methods);
|
||||
|
||||
const JNINativeMethod nativeForkSystemServer_methods[] = {
|
||||
DEF_SERVER(m), DEF_SERVER(samsung_q)
|
||||
};
|
||||
const int nativeForkSystemServer_methods_num = std::size(nativeForkSystemServer_methods);
|
||||
|
||||
}
|
||||
241
native/jni/inject/ptrace.cpp
Normal file
241
native/jni/inject/ptrace.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Original code: https://github.com/Chainfire/injectvm-binderjack/blob/master/app/src/main/jni/libinject/inject.cpp
|
||||
* The code is heavily modified and sublicensed to GPLv3 for incorporating into Magisk.
|
||||
*
|
||||
* Copyright (c) 2015, Simone 'evilsocket' Margaritelli
|
||||
* Copyright (c) 2015-2019, Jorrit 'Chainfire' Jongma
|
||||
* Copyright (c) 2021, John 'topjohnwu' Wu
|
||||
*
|
||||
* See original LICENSE file from the original project for additional details:
|
||||
* https://github.com/Chainfire/injectvm-binderjack/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* The code in this file was originally planned to be used for some features,
|
||||
* but it turned out to be unsuitable for the task. However, this shall remain
|
||||
* in our arsenal in case it may be used in the future.
|
||||
*/
|
||||
|
||||
#include <elf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <utils.hpp>
|
||||
|
||||
#include "inject.hpp"
|
||||
#include "ptrace.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if defined(__arm__)
|
||||
#define CPSR_T_MASK (1u << 5)
|
||||
#define PARAMS_IN_REGS 4
|
||||
#elif defined(__aarch64__)
|
||||
#define CPSR_T_MASK (1u << 5)
|
||||
#define PARAMS_IN_REGS 8
|
||||
#define pt_regs user_pt_regs
|
||||
#define uregs regs
|
||||
#define ARM_pc pc
|
||||
#define ARM_sp sp
|
||||
#define ARM_cpsr pstate
|
||||
#define ARM_lr regs[30]
|
||||
#define ARM_r0 regs[0]
|
||||
#endif
|
||||
|
||||
bool _remote_read(int pid, uintptr_t addr, void *buf, size_t len) {
|
||||
for (size_t i = 0; i < len; i += sizeof(long)) {
|
||||
long data = xptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr + i));
|
||||
if (data < 0)
|
||||
return false;
|
||||
memcpy(static_cast<uint8_t *>(buf) + i, &data, std::min(len - i, sizeof(data)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _remote_write(int pid, uintptr_t addr, const void *buf, size_t len) {
|
||||
for (size_t i = 0; i < len; i += sizeof(long)) {
|
||||
long data = 0;
|
||||
memcpy(&data, static_cast<const uint8_t *>(buf) + i, std::min(len - i, sizeof(data)));
|
||||
if (xptrace(PTRACE_POKETEXT, pid, reinterpret_cast<void*>(addr + i), data) < 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get remote registers
|
||||
#define remote_getregs(regs) _remote_getregs(pid, regs)
|
||||
static void _remote_getregs(int pid, pt_regs *regs) {
|
||||
#if defined(__LP64__)
|
||||
uintptr_t regset = NT_PRSTATUS;
|
||||
iovec iov{};
|
||||
iov.iov_base = regs;
|
||||
iov.iov_len = sizeof(*regs);
|
||||
xptrace(PTRACE_GETREGSET, pid, reinterpret_cast<void*>(regset), &iov);
|
||||
#else
|
||||
xptrace(PTRACE_GETREGS, pid, nullptr, regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set remote registers
|
||||
#define remote_setregs(regs) _remote_setregs(pid, regs)
|
||||
static void _remote_setregs(int pid, pt_regs *regs) {
|
||||
#if defined(__LP64__)
|
||||
uintptr_t regset = NT_PRSTATUS;
|
||||
iovec iov{};
|
||||
iov.iov_base = regs;
|
||||
iov.iov_len = sizeof(*regs);
|
||||
xptrace(PTRACE_SETREGSET, pid, reinterpret_cast<void*>(regset), &iov);
|
||||
#else
|
||||
xptrace(PTRACE_SETREGS, pid, nullptr, regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t remote_call_abi(int pid, uintptr_t func_addr, int nargs, va_list va) {
|
||||
pt_regs regs, regs_bak;
|
||||
|
||||
// Get registers and save a backup
|
||||
remote_getregs(®s);
|
||||
memcpy(®s_bak, ®s, sizeof(regs));
|
||||
|
||||
// ABI dependent: Setup stack and registers to perform the call
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
// Fill R0-Rx with the first 4 (32-bit) or 8 (64-bit) parameters
|
||||
for (int i = 0; (i < nargs) && (i < PARAMS_IN_REGS); ++i) {
|
||||
regs.uregs[i] = va_arg(va, uintptr_t);
|
||||
}
|
||||
|
||||
// Push remaining parameters onto stack
|
||||
if (nargs > PARAMS_IN_REGS) {
|
||||
regs.ARM_sp -= sizeof(uintptr_t) * (nargs - PARAMS_IN_REGS);
|
||||
uintptr_t stack = regs.ARM_sp;
|
||||
for (int i = PARAMS_IN_REGS; i < nargs; ++i) {
|
||||
uintptr_t arg = va_arg(va, uintptr_t);
|
||||
remote_write(stack, &arg, sizeof(uintptr_t));
|
||||
stack += sizeof(uintptr_t);
|
||||
}
|
||||
}
|
||||
|
||||
// Set return address
|
||||
regs.ARM_lr = 0;
|
||||
|
||||
// Set function address to call
|
||||
regs.ARM_pc = func_addr;
|
||||
|
||||
// Setup the current processor status register
|
||||
if (regs.ARM_pc & 1u) {
|
||||
// thumb
|
||||
regs.ARM_pc &= (~1u);
|
||||
regs.ARM_cpsr |= CPSR_T_MASK;
|
||||
} else {
|
||||
// arm
|
||||
regs.ARM_cpsr &= ~CPSR_T_MASK;
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
// Push all params onto stack
|
||||
regs.esp -= sizeof(uintptr_t) * nargs;
|
||||
uintptr_t stack = regs.esp;
|
||||
for (int i = 0; i < nargs; ++i) {
|
||||
uintptr_t arg = va_arg(va, uintptr_t);
|
||||
remote_write(stack, &arg, sizeof(uintptr_t));
|
||||
stack += sizeof(uintptr_t);
|
||||
}
|
||||
|
||||
// Push return address onto stack
|
||||
uintptr_t ret_addr = 0;
|
||||
regs.esp -= sizeof(uintptr_t);
|
||||
remote_write(regs.esp, &ret_addr, sizeof(uintptr_t));
|
||||
|
||||
// Set function address to call
|
||||
regs.eip = func_addr;
|
||||
#elif defined(__x86_64__)
|
||||
// Align, rsp - 8 must be a multiple of 16 at function entry point
|
||||
uintptr_t space = sizeof(uintptr_t);
|
||||
if (nargs > 6)
|
||||
space += sizeof(uintptr_t) * (nargs - 6);
|
||||
while (((regs.rsp - space - 8) & 0xF) != 0)
|
||||
regs.rsp--;
|
||||
|
||||
// Fill [RDI, RSI, RDX, RCX, R8, R9] with the first 6 parameters
|
||||
for (int i = 0; (i < nargs) && (i < 6); ++i) {
|
||||
uintptr_t arg = va_arg(va, uintptr_t);
|
||||
switch (i) {
|
||||
case 0: regs.rdi = arg; break;
|
||||
case 1: regs.rsi = arg; break;
|
||||
case 2: regs.rdx = arg; break;
|
||||
case 3: regs.rcx = arg; break;
|
||||
case 4: regs.r8 = arg; break;
|
||||
case 5: regs.r9 = arg; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Push remaining parameters onto stack
|
||||
if (nargs > 6) {
|
||||
regs.rsp -= sizeof(uintptr_t) * (nargs - 6);
|
||||
uintptr_t stack = regs.rsp;
|
||||
for(int i = 6; i < nargs; ++i) {
|
||||
uintptr_t arg = va_arg(va, uintptr_t);
|
||||
remote_write(stack, &arg, sizeof(uintptr_t));
|
||||
stack += sizeof(uintptr_t);
|
||||
}
|
||||
}
|
||||
|
||||
// Push return address onto stack
|
||||
uintptr_t ret_addr = 0;
|
||||
regs.rsp -= sizeof(uintptr_t);
|
||||
remote_write(regs.rsp, &ret_addr, sizeof(uintptr_t));
|
||||
|
||||
// Set function address to call
|
||||
regs.rip = func_addr;
|
||||
|
||||
// may be needed
|
||||
regs.rax = 0;
|
||||
regs.orig_rax = 0;
|
||||
#else
|
||||
#error Unsupported ABI
|
||||
#endif
|
||||
|
||||
// Resume process to do the call
|
||||
remote_setregs(®s);
|
||||
xptrace(PTRACE_CONT, pid);
|
||||
|
||||
// Catch SIGSEGV caused by the 0 return address
|
||||
int status;
|
||||
while (waitpid(pid, &status, __WALL | __WNOTHREAD) == pid) {
|
||||
if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGSEGV))
|
||||
break;
|
||||
xptrace(PTRACE_CONT, pid);
|
||||
}
|
||||
|
||||
// Get registers again for return value
|
||||
remote_getregs(®s);
|
||||
|
||||
// Restore registers
|
||||
remote_setregs(®s_bak);
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
return regs.ARM_r0;
|
||||
#elif defined(__i386__)
|
||||
return regs.eax;
|
||||
#elif defined(__x86_64__)
|
||||
return regs.rax;
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t remote_call_vararg(int pid, uintptr_t addr, int nargs, ...) {
|
||||
char lib_name[4096];
|
||||
auto local = get_function_lib(addr, lib_name);
|
||||
if (local == 0)
|
||||
return 0;
|
||||
auto remote = get_remote_lib(pid, lib_name);
|
||||
if (remote == 0)
|
||||
return 0;
|
||||
addr = addr - local + remote;
|
||||
va_list va;
|
||||
va_start(va, nargs);
|
||||
auto result = remote_call_abi(pid, addr, nargs, va);
|
||||
va_end(va);
|
||||
return result;
|
||||
}
|
||||
27
native/jni/inject/ptrace.hpp
Normal file
27
native/jni/inject/ptrace.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Write bytes to the remote process at addr
|
||||
bool _remote_write(int pid, uintptr_t addr, const void *buf, size_t len);
|
||||
#define remote_write(...) _remote_write(pid, __VA_ARGS__)
|
||||
|
||||
// Read bytes from the remote process at addr
|
||||
bool _remote_read(int pid, uintptr_t addr, void *buf, size_t len);
|
||||
#define remote_read(...) _remote_read(pid, __VA_ARGS__)
|
||||
|
||||
// Call a remote function
|
||||
// Arguments are expected to be only integer-like or pointer types
|
||||
// as other more complex C ABIs are not implemented.
|
||||
uintptr_t remote_call_abi(int pid, uintptr_t func_addr, int nargs, va_list va);
|
||||
|
||||
// Find remote offset and invoke function
|
||||
uintptr_t remote_call_vararg(int pid, uintptr_t addr, int nargs, ...);
|
||||
|
||||
// C++ wrapper for auto argument counting and casting function pointers
|
||||
template<class FuncPtr, class ...Args>
|
||||
static uintptr_t _remote_call(int pid, FuncPtr sym, Args && ...args) {
|
||||
auto addr = reinterpret_cast<uintptr_t>(sym);
|
||||
return remote_call_vararg(pid, addr, sizeof...(args), std::forward<Args>(args)...);
|
||||
}
|
||||
#define remote_call(...) _remote_call(pid, __VA_ARGS__)
|
||||
101
native/jni/inject/utils.cpp
Normal file
101
native/jni/inject/utils.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <utils.hpp>
|
||||
|
||||
#include "inject.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
struct map_info {
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
int perms;
|
||||
char *path;
|
||||
|
||||
map_info() : start(0), end(0), perms(0), path(nullptr) {}
|
||||
|
||||
enum {
|
||||
EXEC = (1 << 0),
|
||||
WRITE = (1 << 1),
|
||||
READ = (1 << 2),
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
template<typename Func>
|
||||
static void parse_maps(int pid, Func fn) {
|
||||
char file[32];
|
||||
|
||||
// format: start-end perms offset dev inode path
|
||||
sprintf(file, "/proc/%d/maps", pid);
|
||||
file_readline(true, file, [=](string_view l) -> bool {
|
||||
char *pos = (char *) l.data();
|
||||
map_info info;
|
||||
|
||||
// Parse address hex strings
|
||||
info.start = strtoul(pos, &pos, 16);
|
||||
info.end = strtoul(++pos, &pos, 16);
|
||||
|
||||
// Parse permissions
|
||||
if (*(++pos) != '-')
|
||||
info.perms |= map_info::READ;
|
||||
if (*(++pos) != '-')
|
||||
info.perms |= map_info::WRITE;
|
||||
if (*(++pos) != '-')
|
||||
info.perms |= map_info::EXEC;
|
||||
pos += 3;
|
||||
|
||||
// Skip everything except path
|
||||
int path_off;
|
||||
sscanf(pos, "%*s %*s %*s %n%*s", &path_off);
|
||||
pos += path_off;
|
||||
info.path = pos;
|
||||
|
||||
return fn(info);
|
||||
});
|
||||
}
|
||||
|
||||
void unmap_all(const char *name) {
|
||||
vector<map_info> unmaps;
|
||||
parse_maps(getpid(), [=, &unmaps](map_info &info) -> bool {
|
||||
if (strcmp(info.path, name) == 0)
|
||||
unmaps.emplace_back(info);
|
||||
return true;
|
||||
});
|
||||
for (map_info &info : unmaps) {
|
||||
void *addr = reinterpret_cast<void *>(info.start);
|
||||
size_t size = info.end - info.start;
|
||||
munmap(addr, size);
|
||||
if (info.perms & map_info::READ) {
|
||||
// Make sure readable pages are still readable
|
||||
xmmap(addr, size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t get_function_lib(uintptr_t addr, char *lib) {
|
||||
uintptr_t base = 0;
|
||||
parse_maps(getpid(), [=, &base](map_info &info) -> bool {
|
||||
if (addr >= info.start && addr < info.end) {
|
||||
if (lib)
|
||||
strcpy(lib, info.path);
|
||||
base = info.start;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return base;
|
||||
}
|
||||
|
||||
uintptr_t get_remote_lib(int pid, const char *lib) {
|
||||
uintptr_t base = 0;
|
||||
parse_maps(pid, [=, &base](map_info &info) -> bool {
|
||||
if (strcmp(info.path, lib) == 0 && (info.perms & map_info::EXEC)) {
|
||||
base = info.start;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return base;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,35 +9,35 @@
|
||||
*****************/
|
||||
|
||||
struct mtk_hdr {
|
||||
uint32_t magic; /* MTK magic */
|
||||
uint32_t size; /* Size of the content */
|
||||
char name[32]; /* The type of the header */
|
||||
uint32_t magic; /* MTK magic */
|
||||
uint32_t size; /* Size of the content */
|
||||
char name[32]; /* The type of the header */
|
||||
|
||||
char padding[472]; /* Padding to 512 bytes */
|
||||
char padding[472]; /* Padding to 512 bytes */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dhtb_hdr {
|
||||
char magic[8]; /* DHTB magic */
|
||||
uint8_t checksum[40]; /* Payload SHA256, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
|
||||
uint32_t size; /* Payload size, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
|
||||
char magic[8]; /* DHTB magic */
|
||||
uint8_t checksum[40]; /* Payload SHA256, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
|
||||
uint32_t size; /* Payload size, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
|
||||
|
||||
char padding[460]; /* Padding to 512 bytes */
|
||||
char padding[460]; /* Padding to 512 bytes */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct blob_hdr {
|
||||
char secure_magic[20]; /* "-SIGNED-BY-SIGNBLOB-" */
|
||||
uint32_t datalen; /* 0x00000000 */
|
||||
uint32_t signature; /* 0x00000000 */
|
||||
char magic[16]; /* "MSM-RADIO-UPDATE" */
|
||||
uint32_t hdr_version; /* 0x00010000 */
|
||||
uint32_t hdr_size; /* Size of header */
|
||||
uint32_t part_offset; /* Same as size */
|
||||
uint32_t num_parts; /* Number of partitions */
|
||||
uint32_t unknown[7]; /* All 0x00000000 */
|
||||
char name[4]; /* Name of partition */
|
||||
uint32_t offset; /* offset in blob where this partition starts */
|
||||
uint32_t size; /* Size of data */
|
||||
uint32_t version; /* 0x00000001 */
|
||||
char secure_magic[20]; /* "-SIGNED-BY-SIGNBLOB-" */
|
||||
uint32_t datalen; /* 0x00000000 */
|
||||
uint32_t signature; /* 0x00000000 */
|
||||
char magic[16]; /* "MSM-RADIO-UPDATE" */
|
||||
uint32_t hdr_version; /* 0x00010000 */
|
||||
uint32_t hdr_size; /* Size of header */
|
||||
uint32_t part_offset; /* Same as size */
|
||||
uint32_t num_parts; /* Number of partitions */
|
||||
uint32_t unknown[7]; /* All 0x00000000 */
|
||||
char name[4]; /* Name of partition */
|
||||
uint32_t offset; /* offset in blob where this partition starts */
|
||||
uint32_t size; /* Size of data */
|
||||
uint32_t version; /* 0x00000001 */
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
@@ -78,54 +78,54 @@ struct blob_hdr {
|
||||
*/
|
||||
|
||||
struct boot_img_hdr_common {
|
||||
char magic[BOOT_MAGIC_SIZE];
|
||||
char magic[BOOT_MAGIC_SIZE];
|
||||
|
||||
uint32_t kernel_size; /* size in bytes */
|
||||
uint32_t kernel_addr; /* physical load addr */
|
||||
uint32_t kernel_size; /* size in bytes */
|
||||
uint32_t kernel_addr; /* physical load addr */
|
||||
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
uint32_t ramdisk_addr; /* physical load addr */
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
uint32_t ramdisk_addr; /* physical load addr */
|
||||
|
||||
uint32_t second_size; /* size in bytes */
|
||||
uint32_t second_addr; /* physical load addr */
|
||||
uint32_t second_size; /* size in bytes */
|
||||
uint32_t second_addr; /* physical load addr */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct boot_img_hdr_v0 : public boot_img_hdr_common {
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
|
||||
// In header v1, this field is used for header version
|
||||
// However, on some devices like Samsung, this field is used to store DTB
|
||||
// We treat this field differently based on its value
|
||||
union {
|
||||
uint32_t header_version; /* the version of the header */
|
||||
uint32_t extra_size; /* extra blob size in bytes */
|
||||
};
|
||||
// In header v1, this field is used for header version
|
||||
// However, on some devices like Samsung, this field is used to store DTB
|
||||
// We treat this field differently based on its value
|
||||
union {
|
||||
uint32_t header_version; /* the version of the header */
|
||||
uint32_t extra_size; /* extra blob size in bytes */
|
||||
};
|
||||
|
||||
// Operating system version and security patch level.
|
||||
// For version "A.B.C" and patch level "Y-M-D":
|
||||
// (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
|
||||
// os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
|
||||
uint32_t os_version;
|
||||
// Operating system version and security patch level.
|
||||
// For version "A.B.C" and patch level "Y-M-D":
|
||||
// (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
|
||||
// os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
|
||||
uint32_t os_version;
|
||||
|
||||
char name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||
char cmdline[BOOT_ARGS_SIZE];
|
||||
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
|
||||
char name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||
char cmdline[BOOT_ARGS_SIZE];
|
||||
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
|
||||
|
||||
// Supplemental command line data; kept here to maintain
|
||||
// binary compatibility with older versions of mkbootimg.
|
||||
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
|
||||
// Supplemental command line data; kept here to maintain
|
||||
// binary compatibility with older versions of mkbootimg.
|
||||
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
|
||||
uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */
|
||||
uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
|
||||
uint32_t header_size;
|
||||
uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO/ACPIO image */
|
||||
uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
|
||||
uint32_t header_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct boot_img_hdr_v2 : public boot_img_hdr_v1 {
|
||||
uint32_t dtb_size; /* size in bytes for DTB image */
|
||||
uint64_t dtb_addr; /* physical load address for DTB image */
|
||||
uint32_t dtb_size; /* size in bytes for DTB image */
|
||||
uint64_t dtb_addr; /* physical load address for DTB image */
|
||||
} __attribute__((packed));
|
||||
|
||||
// Default to hdr v2
|
||||
@@ -133,16 +133,16 @@ using boot_img_hdr = boot_img_hdr_v2;
|
||||
|
||||
// Special Samsung header
|
||||
struct boot_img_hdr_pxa : public boot_img_hdr_common {
|
||||
uint32_t extra_size; /* extra blob size in bytes */
|
||||
uint32_t unknown;
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t extra_size; /* extra blob size in bytes */
|
||||
uint32_t unknown;
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
|
||||
char name[24]; /* asciiz product name */
|
||||
char cmdline[BOOT_ARGS_SIZE];
|
||||
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
|
||||
char name[24]; /* asciiz product name */
|
||||
char cmdline[BOOT_ARGS_SIZE];
|
||||
char id[BOOT_ID_SIZE]; /* timestamp / checksum / sha1 / etc */
|
||||
|
||||
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
|
||||
char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* When the boot image header has a version of 3, the structure of the boot
|
||||
@@ -178,34 +178,34 @@ struct boot_img_hdr_pxa : public boot_img_hdr_common {
|
||||
*/
|
||||
|
||||
struct boot_img_hdr_v3 {
|
||||
uint8_t magic[BOOT_MAGIC_SIZE];
|
||||
uint8_t magic[BOOT_MAGIC_SIZE];
|
||||
|
||||
uint32_t kernel_size; /* size in bytes */
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
uint32_t os_version;
|
||||
uint32_t header_size;
|
||||
uint32_t reserved[4];
|
||||
uint32_t kernel_size; /* size in bytes */
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
uint32_t os_version;
|
||||
uint32_t header_size;
|
||||
uint32_t reserved[4];
|
||||
|
||||
uint32_t header_version;
|
||||
uint32_t header_version;
|
||||
|
||||
char cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
|
||||
char cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct boot_img_hdr_vnd_v3 {
|
||||
// Must be VENDOR_BOOT_MAGIC.
|
||||
uint8_t magic[BOOT_MAGIC_SIZE];
|
||||
// Version of the vendor boot image header.
|
||||
uint32_t header_version;
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t kernel_addr; /* physical load addr */
|
||||
uint32_t ramdisk_addr; /* physical load addr */
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
char cmdline[VENDOR_BOOT_ARGS_SIZE];
|
||||
uint32_t tags_addr; /* physical addr for kernel tags (if required) */
|
||||
char name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||
uint32_t header_size;
|
||||
uint32_t dtb_size; /* size in bytes for DTB image */
|
||||
uint64_t dtb_addr; /* physical load address for DTB image */
|
||||
// Must be VENDOR_BOOT_MAGIC.
|
||||
uint8_t magic[BOOT_MAGIC_SIZE];
|
||||
// Version of the vendor boot image header.
|
||||
uint32_t header_version;
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t kernel_addr; /* physical load addr */
|
||||
uint32_t ramdisk_addr; /* physical load addr */
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
char cmdline[VENDOR_BOOT_ARGS_SIZE];
|
||||
uint32_t tags_addr; /* physical addr for kernel tags (if required) */
|
||||
char name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||
uint32_t header_size;
|
||||
uint32_t dtb_size; /* size in bytes for DTB image */
|
||||
uint64_t dtb_addr; /* physical load address for DTB image */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*******************************
|
||||
@@ -219,51 +219,51 @@ virtual type name() { return 0; }
|
||||
|
||||
struct dyn_img_hdr {
|
||||
|
||||
// Standard entries
|
||||
decl_var(kernel_size, 32)
|
||||
decl_var(ramdisk_size, 32)
|
||||
decl_var(second_size, 32)
|
||||
decl_var(page_size, 32)
|
||||
decl_val(header_version, uint32_t)
|
||||
decl_var(extra_size, 32)
|
||||
decl_var(os_version, 32)
|
||||
decl_val(name, char *)
|
||||
decl_val(cmdline, char *)
|
||||
decl_val(id, char *)
|
||||
decl_val(extra_cmdline, char *)
|
||||
// Standard entries
|
||||
decl_var(kernel_size, 32)
|
||||
decl_var(ramdisk_size, 32)
|
||||
decl_var(second_size, 32)
|
||||
decl_var(page_size, 32)
|
||||
decl_val(header_version, uint32_t)
|
||||
decl_var(extra_size, 32)
|
||||
decl_var(os_version, 32)
|
||||
decl_val(name, char *)
|
||||
decl_val(cmdline, char *)
|
||||
decl_val(id, char *)
|
||||
decl_val(extra_cmdline, char *)
|
||||
|
||||
// v1/v2 specific
|
||||
decl_var(recovery_dtbo_size, 32)
|
||||
decl_var(recovery_dtbo_offset, 64)
|
||||
decl_var(header_size, 32)
|
||||
decl_var(dtb_size, 32)
|
||||
// v1/v2 specific
|
||||
decl_var(recovery_dtbo_size, 32)
|
||||
decl_var(recovery_dtbo_offset, 64)
|
||||
decl_var(header_size, 32)
|
||||
decl_var(dtb_size, 32)
|
||||
|
||||
virtual ~dyn_img_hdr() {
|
||||
free(raw);
|
||||
}
|
||||
virtual ~dyn_img_hdr() {
|
||||
free(raw);
|
||||
}
|
||||
|
||||
virtual size_t hdr_size() = 0;
|
||||
virtual size_t hdr_space() { return page_size(); }
|
||||
virtual size_t hdr_size() = 0;
|
||||
virtual size_t hdr_space() { return page_size(); }
|
||||
|
||||
const void *raw_hdr() const { return raw; }
|
||||
void print();
|
||||
void dump_hdr_file();
|
||||
void load_hdr_file();
|
||||
const void *raw_hdr() const { return raw; }
|
||||
void print();
|
||||
void dump_hdr_file();
|
||||
void load_hdr_file();
|
||||
|
||||
protected:
|
||||
union {
|
||||
// Main header could be either AOSP or PXA
|
||||
boot_img_hdr_v2 *v2_hdr; /* AOSP v2 header */
|
||||
boot_img_hdr_v3 *v3_hdr; /* AOSP v3 header */
|
||||
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
|
||||
boot_img_hdr_vnd_v3 *vnd; /* AOSP vendor v3 header */
|
||||
void *raw; /* Raw pointer */
|
||||
};
|
||||
union {
|
||||
// Main header could be either AOSP or PXA
|
||||
boot_img_hdr_v2 *v2_hdr; /* AOSP v2 header */
|
||||
boot_img_hdr_v3 *v3_hdr; /* AOSP v3 header */
|
||||
boot_img_hdr_pxa *hdr_pxa; /* Samsung PXA header */
|
||||
boot_img_hdr_vnd_v3 *vnd; /* AOSP vendor v3 header */
|
||||
void *raw; /* Raw pointer */
|
||||
};
|
||||
|
||||
private:
|
||||
// Junk for references
|
||||
static uint32_t j32;
|
||||
static uint64_t j64;
|
||||
// Junk for references
|
||||
static uint32_t j32;
|
||||
static uint64_t j64;
|
||||
};
|
||||
|
||||
#undef decl_var
|
||||
@@ -273,8 +273,8 @@ private:
|
||||
protected: name() = default; \
|
||||
public: \
|
||||
name(void *ptr) { \
|
||||
raw = xmalloc(sizeof(hdr)); \
|
||||
memcpy(raw, ptr, sizeof(hdr)); \
|
||||
raw = xmalloc(sizeof(hdr)); \
|
||||
memcpy(raw, ptr, sizeof(hdr)); \
|
||||
} \
|
||||
size_t hdr_size() override { return sizeof(hdr); }
|
||||
|
||||
@@ -285,93 +285,93 @@ decltype(std::declval<dyn_img_hdr>().name()) name() override { return hdr_name->
|
||||
#define impl_val(name) __impl_val(name, v2_hdr)
|
||||
|
||||
struct dyn_img_common : public dyn_img_hdr {
|
||||
impl_val(kernel_size)
|
||||
impl_val(ramdisk_size)
|
||||
impl_val(second_size)
|
||||
impl_val(kernel_size)
|
||||
impl_val(ramdisk_size)
|
||||
impl_val(second_size)
|
||||
};
|
||||
|
||||
struct dyn_img_v0 : public dyn_img_common {
|
||||
impl_cls(v0)
|
||||
impl_cls(v0)
|
||||
|
||||
impl_val(page_size)
|
||||
impl_val(extra_size)
|
||||
impl_val(os_version)
|
||||
impl_val(name)
|
||||
impl_val(cmdline)
|
||||
impl_val(id)
|
||||
impl_val(extra_cmdline)
|
||||
impl_val(page_size)
|
||||
impl_val(extra_size)
|
||||
impl_val(os_version)
|
||||
impl_val(name)
|
||||
impl_val(cmdline)
|
||||
impl_val(id)
|
||||
impl_val(extra_cmdline)
|
||||
};
|
||||
|
||||
struct dyn_img_v1 : public dyn_img_v0 {
|
||||
impl_cls(v1)
|
||||
impl_cls(v1)
|
||||
|
||||
impl_val(header_version)
|
||||
impl_val(recovery_dtbo_size)
|
||||
impl_val(recovery_dtbo_offset)
|
||||
impl_val(header_size)
|
||||
impl_val(header_version)
|
||||
impl_val(recovery_dtbo_size)
|
||||
impl_val(recovery_dtbo_offset)
|
||||
impl_val(header_size)
|
||||
|
||||
uint32_t &extra_size() override { return dyn_img_hdr::extra_size(); }
|
||||
uint32_t &extra_size() override { return dyn_img_hdr::extra_size(); }
|
||||
};
|
||||
|
||||
struct dyn_img_v2 : public dyn_img_v1 {
|
||||
impl_cls(v2)
|
||||
impl_cls(v2)
|
||||
|
||||
impl_val(dtb_size)
|
||||
impl_val(dtb_size)
|
||||
};
|
||||
|
||||
#undef impl_val
|
||||
#define impl_val(name) __impl_val(name, hdr_pxa)
|
||||
|
||||
struct dyn_img_pxa : public dyn_img_common {
|
||||
impl_cls(pxa)
|
||||
impl_cls(pxa)
|
||||
|
||||
impl_val(extra_size)
|
||||
impl_val(page_size)
|
||||
impl_val(name)
|
||||
impl_val(cmdline)
|
||||
impl_val(id)
|
||||
impl_val(extra_cmdline)
|
||||
impl_val(extra_size)
|
||||
impl_val(page_size)
|
||||
impl_val(name)
|
||||
impl_val(cmdline)
|
||||
impl_val(id)
|
||||
impl_val(extra_cmdline)
|
||||
};
|
||||
|
||||
#undef impl_val
|
||||
#define impl_val(name) __impl_val(name, v3_hdr)
|
||||
|
||||
struct dyn_img_v3 : public dyn_img_hdr {
|
||||
impl_cls(v3)
|
||||
impl_cls(v3)
|
||||
|
||||
impl_val(kernel_size)
|
||||
impl_val(ramdisk_size)
|
||||
impl_val(os_version)
|
||||
impl_val(header_size)
|
||||
impl_val(header_version)
|
||||
impl_val(cmdline)
|
||||
impl_val(kernel_size)
|
||||
impl_val(ramdisk_size)
|
||||
impl_val(os_version)
|
||||
impl_val(header_size)
|
||||
impl_val(header_version)
|
||||
impl_val(cmdline)
|
||||
|
||||
// Make API compatible
|
||||
uint32_t &page_size() override { page_sz = 4096; return page_sz; }
|
||||
char *extra_cmdline() override { return &v3_hdr->cmdline[BOOT_ARGS_SIZE]; }
|
||||
// Make API compatible
|
||||
uint32_t &page_size() override { page_sz = 4096; return page_sz; }
|
||||
char *extra_cmdline() override { return &v3_hdr->cmdline[BOOT_ARGS_SIZE]; }
|
||||
|
||||
private:
|
||||
uint32_t page_sz;
|
||||
uint32_t page_sz;
|
||||
};
|
||||
|
||||
#undef impl_val
|
||||
#define impl_val(name) __impl_val(name, vnd)
|
||||
|
||||
struct dyn_img_vnd_v3 : public dyn_img_hdr {
|
||||
impl_cls(vnd_v3)
|
||||
impl_cls(vnd_v3)
|
||||
|
||||
impl_val(header_version)
|
||||
impl_val(page_size)
|
||||
impl_val(ramdisk_size)
|
||||
impl_val(cmdline)
|
||||
impl_val(name)
|
||||
impl_val(header_size)
|
||||
impl_val(dtb_size)
|
||||
impl_val(header_version)
|
||||
impl_val(page_size)
|
||||
impl_val(ramdisk_size)
|
||||
impl_val(cmdline)
|
||||
impl_val(name)
|
||||
impl_val(header_size)
|
||||
impl_val(dtb_size)
|
||||
|
||||
size_t hdr_space() override { auto sz = page_size(); return do_align(hdr_size(), sz); }
|
||||
size_t hdr_space() override { auto sz = page_size(); return do_align(hdr_size(), sz); }
|
||||
|
||||
// Make API compatible
|
||||
char *extra_cmdline() override { return &vnd->cmdline[BOOT_ARGS_SIZE]; }
|
||||
// Make API compatible
|
||||
char *extra_cmdline() override { return &vnd->cmdline[BOOT_ARGS_SIZE]; }
|
||||
};
|
||||
|
||||
#undef __impl_cls
|
||||
@@ -395,48 +395,48 @@ struct dyn_img_vnd_v3 : public dyn_img_hdr {
|
||||
#define ACCLAIM_FLAG (1 << 9)
|
||||
|
||||
struct boot_img {
|
||||
// Memory map of the whole image
|
||||
uint8_t *map_addr;
|
||||
size_t map_size;
|
||||
// Memory map of the whole image
|
||||
uint8_t *map_addr;
|
||||
size_t map_size;
|
||||
|
||||
// Android image header
|
||||
dyn_img_hdr *hdr;
|
||||
// Android image header
|
||||
dyn_img_hdr *hdr;
|
||||
|
||||
// Flags to indicate the state of current boot image
|
||||
uint16_t flags = 0;
|
||||
// Flags to indicate the state of current boot image
|
||||
uint16_t flags = 0;
|
||||
|
||||
// The format of kernel, ramdisk and extra
|
||||
format_t k_fmt = UNKNOWN;
|
||||
format_t r_fmt = UNKNOWN;
|
||||
format_t e_fmt = UNKNOWN;
|
||||
// The format of kernel, ramdisk and extra
|
||||
format_t k_fmt = UNKNOWN;
|
||||
format_t r_fmt = UNKNOWN;
|
||||
format_t e_fmt = UNKNOWN;
|
||||
|
||||
/***************************************************
|
||||
* Following pointers points within the mmap region
|
||||
***************************************************/
|
||||
/***************************************************
|
||||
* Following pointers points within the mmap region
|
||||
***************************************************/
|
||||
|
||||
// MTK headers
|
||||
mtk_hdr *k_hdr;
|
||||
mtk_hdr *r_hdr;
|
||||
// MTK headers
|
||||
mtk_hdr *k_hdr;
|
||||
mtk_hdr *r_hdr;
|
||||
|
||||
// Pointer to dtb that is embedded in kernel
|
||||
uint8_t *kernel_dtb;
|
||||
uint32_t kernel_dt_size = 0;
|
||||
// Pointer to dtb that is embedded in kernel
|
||||
uint8_t *kernel_dtb;
|
||||
uint32_t kernel_dt_size = 0;
|
||||
|
||||
// Pointer to end of image
|
||||
uint8_t *tail;
|
||||
size_t tail_size = 0;
|
||||
// Pointer to end of image
|
||||
uint8_t *tail;
|
||||
size_t tail_size = 0;
|
||||
|
||||
// Pointers to blocks defined in header
|
||||
uint8_t *hdr_addr;
|
||||
uint8_t *kernel;
|
||||
uint8_t *ramdisk;
|
||||
uint8_t *second;
|
||||
uint8_t *extra;
|
||||
uint8_t *recovery_dtbo;
|
||||
uint8_t *dtb;
|
||||
// Pointers to blocks defined in header
|
||||
uint8_t *hdr_addr;
|
||||
uint8_t *kernel;
|
||||
uint8_t *ramdisk;
|
||||
uint8_t *second;
|
||||
uint8_t *extra;
|
||||
uint8_t *recovery_dtbo;
|
||||
uint8_t *dtb;
|
||||
|
||||
boot_img(const char *);
|
||||
~boot_img();
|
||||
boot_img(const char *);
|
||||
~boot_img();
|
||||
|
||||
void parse_image(uint8_t *addr, format_t type);
|
||||
void parse_image(uint8_t *addr, format_t type);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,437 +18,437 @@ constexpr int MAX_DEPTH = 32;
|
||||
static bitset<MAX_DEPTH> depth_set;
|
||||
|
||||
static void pretty_node(int depth) {
|
||||
if (depth == 0)
|
||||
return;
|
||||
if (depth == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < depth - 1; ++i)
|
||||
printf(depth_set[i] ? "│ " : " ");
|
||||
for (int i = 0; i < depth - 1; ++i)
|
||||
printf(depth_set[i] ? "│ " : " ");
|
||||
|
||||
printf(depth_set[depth - 1] ? "├── " : "└── ");
|
||||
printf(depth_set[depth - 1] ? "├── " : "└── ");
|
||||
}
|
||||
|
||||
static void pretty_prop(int depth) {
|
||||
for (int i = 0; i < depth; ++i)
|
||||
printf(depth_set[i] ? "│ " : " ");
|
||||
for (int i = 0; i < depth; ++i)
|
||||
printf(depth_set[i] ? "│ " : " ");
|
||||
|
||||
printf(depth_set[depth] ? "│ " : " ");
|
||||
printf(depth_set[depth] ? "│ " : " ");
|
||||
}
|
||||
|
||||
static void print_node(const void *fdt, int node = 0, int depth = 0) {
|
||||
// Print node itself
|
||||
pretty_node(depth);
|
||||
printf("#%d: %s\n", node, fdt_get_name(fdt, node, nullptr));
|
||||
// Print node itself
|
||||
pretty_node(depth);
|
||||
printf("#%d: %s\n", node, fdt_get_name(fdt, node, nullptr));
|
||||
|
||||
// Print properties
|
||||
depth_set[depth] = fdt_first_subnode(fdt, node) >= 0;
|
||||
int prop;
|
||||
fdt_for_each_property_offset(prop, fdt, node) {
|
||||
pretty_prop(depth);
|
||||
int size;
|
||||
const char *name;
|
||||
auto value = static_cast<const char *>(fdt_getprop_by_offset(fdt, prop, &name, &size));
|
||||
// Print properties
|
||||
depth_set[depth] = fdt_first_subnode(fdt, node) >= 0;
|
||||
int prop;
|
||||
fdt_for_each_property_offset(prop, fdt, node) {
|
||||
pretty_prop(depth);
|
||||
int size;
|
||||
const char *name;
|
||||
auto value = static_cast<const char *>(fdt_getprop_by_offset(fdt, prop, &name, &size));
|
||||
|
||||
bool is_str = !(size > 1 && value[0] == 0);
|
||||
if (is_str) {
|
||||
// Scan through value to see if printable
|
||||
for (int i = 0; i < size; ++i) {
|
||||
char c = value[i];
|
||||
if (i == size - 1) {
|
||||
// Make sure null terminate
|
||||
is_str = c == '\0';
|
||||
} else if ((c > 0 && c < 32) || c >= 127) {
|
||||
is_str = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool is_str = !(size > 1 && value[0] == 0);
|
||||
if (is_str) {
|
||||
// Scan through value to see if printable
|
||||
for (int i = 0; i < size; ++i) {
|
||||
char c = value[i];
|
||||
if (i == size - 1) {
|
||||
// Make sure null terminate
|
||||
is_str = c == '\0';
|
||||
} else if ((c > 0 && c < 32) || c >= 127) {
|
||||
is_str = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_str) {
|
||||
printf("[%s]: [%s]\n", name, value);
|
||||
} else {
|
||||
printf("[%s]: <bytes>(%d)\n", name, size);
|
||||
}
|
||||
}
|
||||
if (is_str) {
|
||||
printf("[%s]: [%s]\n", name, value);
|
||||
} else {
|
||||
printf("[%s]: <bytes>(%d)\n", name, size);
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive
|
||||
if (depth_set[depth]) {
|
||||
int child;
|
||||
int prev = -1;
|
||||
fdt_for_each_subnode(child, fdt, node) {
|
||||
if (prev >= 0)
|
||||
print_node(fdt, prev, depth + 1);
|
||||
prev = child;
|
||||
}
|
||||
depth_set[depth] = false;
|
||||
print_node(fdt, prev, depth + 1);
|
||||
}
|
||||
// Recursive
|
||||
if (depth_set[depth]) {
|
||||
int child;
|
||||
int prev = -1;
|
||||
fdt_for_each_subnode(child, fdt, node) {
|
||||
if (prev >= 0)
|
||||
print_node(fdt, prev, depth + 1);
|
||||
prev = child;
|
||||
}
|
||||
depth_set[depth] = false;
|
||||
print_node(fdt, prev, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int find_fstab(const void *fdt, int node = 0) {
|
||||
if (fdt_get_name(fdt, node, nullptr) == "fstab"sv)
|
||||
return node;
|
||||
int child;
|
||||
fdt_for_each_subnode(child, fdt, node) {
|
||||
int fstab = find_fstab(fdt, child);
|
||||
if (fstab >= 0)
|
||||
return fstab;
|
||||
}
|
||||
return -1;
|
||||
if (fdt_get_name(fdt, node, nullptr) == "fstab"sv)
|
||||
return node;
|
||||
int child;
|
||||
fdt_for_each_subnode(child, fdt, node) {
|
||||
int fstab = find_fstab(fdt, child);
|
||||
if (fstab >= 0)
|
||||
return fstab;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void dtb_print(const char *file, bool fstab) {
|
||||
size_t size;
|
||||
uint8_t *dtb;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
mmap_ro(file, dtb, size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||
auto fdt = dtb + i;
|
||||
if (fstab) {
|
||||
int node = find_fstab(fdt);
|
||||
if (node >= 0) {
|
||||
fprintf(stderr, "Found fstab in dtb.%04d\n", dtb_num);
|
||||
print_node(fdt, node);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Printing dtb.%04d\n", dtb_num);
|
||||
print_node(fdt);
|
||||
}
|
||||
++dtb_num;
|
||||
i += fdt_totalsize(fdt) - 1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
munmap(dtb, size);
|
||||
size_t size;
|
||||
uint8_t *dtb;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
mmap_ro(file, dtb, size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||
auto fdt = dtb + i;
|
||||
if (fstab) {
|
||||
int node = find_fstab(fdt);
|
||||
if (node >= 0) {
|
||||
fprintf(stderr, "Found fstab in dtb.%04d\n", dtb_num);
|
||||
print_node(fdt, node);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Printing dtb.%04d\n", dtb_num);
|
||||
print_node(fdt);
|
||||
}
|
||||
++dtb_num;
|
||||
i += fdt_totalsize(fdt) - 1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
munmap(dtb, size);
|
||||
}
|
||||
|
||||
static bool dtb_patch(const char *file) {
|
||||
bool keepverity = check_env("KEEPVERITY");
|
||||
bool patched = false;
|
||||
size_t size;
|
||||
uint8_t *dtb;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
mmap_rw(file, dtb, size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||
auto fdt = dtb + i;
|
||||
fprintf(stderr, "Loading dtb.%04d\n", dtb_num);
|
||||
if (int fstab = find_fstab(fdt); fstab >= 0) {
|
||||
int node;
|
||||
fdt_for_each_subnode(node, fdt, fstab) {
|
||||
const char *name = fdt_get_name(fdt, node, nullptr);
|
||||
fprintf(stderr, "Found fstab entry [%s]\n", name);
|
||||
if (!keepverity) {
|
||||
int len;
|
||||
auto value = fdt_getprop(fdt, node, "fsmgr_flags", &len);
|
||||
patched |= patch_verity(const_cast<void *>(value), len) != len;
|
||||
}
|
||||
}
|
||||
}
|
||||
++dtb_num;
|
||||
i += fdt_totalsize(fdt) - 1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
munmap(dtb, size);
|
||||
return patched;
|
||||
bool keepverity = check_env("KEEPVERITY");
|
||||
bool patched = false;
|
||||
size_t size;
|
||||
uint8_t *dtb;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
mmap_rw(file, dtb, size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||
auto fdt = dtb + i;
|
||||
fprintf(stderr, "Loading dtb.%04d\n", dtb_num);
|
||||
if (int fstab = find_fstab(fdt); fstab >= 0) {
|
||||
int node;
|
||||
fdt_for_each_subnode(node, fdt, fstab) {
|
||||
const char *name = fdt_get_name(fdt, node, nullptr);
|
||||
fprintf(stderr, "Found fstab entry [%s]\n", name);
|
||||
if (!keepverity) {
|
||||
int len;
|
||||
auto value = fdt_getprop(fdt, node, "fsmgr_flags", &len);
|
||||
patched |= patch_verity(const_cast<void *>(value), len) != len;
|
||||
}
|
||||
}
|
||||
}
|
||||
++dtb_num;
|
||||
i += fdt_totalsize(fdt) - 1;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
munmap(dtb, size);
|
||||
return patched;
|
||||
}
|
||||
|
||||
int dtb_commands(int argc, char *argv[]) {
|
||||
char *dtb = argv[0];
|
||||
++argv;
|
||||
--argc;
|
||||
char *dtb = argv[0];
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
if (argv[0] == "print"sv) {
|
||||
dtb_print(dtb, argc > 1 && argv[1] == "-f"sv);
|
||||
return 0;
|
||||
} else if (argv[0] == "patch"sv) {
|
||||
if (!dtb_patch(dtb))
|
||||
exit(1);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
if (argv[0] == "print"sv) {
|
||||
dtb_print(dtb, argc > 1 && argv[1] == "-f"sv);
|
||||
return 0;
|
||||
} else if (argv[0] == "patch"sv) {
|
||||
if (!dtb_patch(dtb))
|
||||
exit(1);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Unused, but keep these precious code as they took TONs of effort to write
|
||||
// Unused, but keep these precious code as they took TONs of effort to write
|
||||
|
||||
struct fdt_blob {
|
||||
void *fdt;
|
||||
uint32_t offset;
|
||||
uint32_t len;
|
||||
};
|
||||
struct fdt_blob {
|
||||
void *fdt;
|
||||
uint32_t offset;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
template <class Iter>
|
||||
class fdt_map_iter {
|
||||
public:
|
||||
typedef decltype(std::declval<typename Iter::value_type::second_type>().fdt) value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
template <class Iter>
|
||||
class fdt_map_iter {
|
||||
public:
|
||||
typedef decltype(std::declval<typename Iter::value_type::second_type>().fdt) value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
|
||||
explicit fdt_map_iter(Iter j) : i(j) {}
|
||||
fdt_map_iter& operator++() { ++i; return *this; }
|
||||
fdt_map_iter operator++(int) { auto tmp = *this; ++(*this); return tmp; }
|
||||
fdt_map_iter& operator--() { --i; return *this; }
|
||||
fdt_map_iter operator--(int) { auto tmp = *this; --(*this); return tmp; }
|
||||
bool operator==(fdt_map_iter j) const { return i == j.i; }
|
||||
bool operator!=(fdt_map_iter j) const { return !(*this == j); }
|
||||
reference operator*() { return i->second.fdt; }
|
||||
pointer operator->() { return &i->second.fdt; }
|
||||
private:
|
||||
Iter i;
|
||||
};
|
||||
explicit fdt_map_iter(Iter j) : i(j) {}
|
||||
fdt_map_iter& operator++() { ++i; return *this; }
|
||||
fdt_map_iter operator++(int) { auto tmp = *this; ++(*this); return tmp; }
|
||||
fdt_map_iter& operator--() { --i; return *this; }
|
||||
fdt_map_iter operator--(int) { auto tmp = *this; --(*this); return tmp; }
|
||||
bool operator==(fdt_map_iter j) const { return i == j.i; }
|
||||
bool operator!=(fdt_map_iter j) const { return !(*this == j); }
|
||||
reference operator*() { return i->second.fdt; }
|
||||
pointer operator->() { return &i->second.fdt; }
|
||||
private:
|
||||
Iter i;
|
||||
};
|
||||
|
||||
template<class Iter>
|
||||
inline fdt_map_iter<Iter> make_iter(Iter j) { return fdt_map_iter<Iter>(j); }
|
||||
template<class Iter>
|
||||
inline fdt_map_iter<Iter> make_iter(Iter j) { return fdt_map_iter<Iter>(j); }
|
||||
|
||||
template <typename Iter>
|
||||
static bool fdt_patch(Iter first, Iter last) {
|
||||
bool keepverity = check_env("KEEPVERITY");
|
||||
bool redirect = check_env("TWOSTAGEINIT");
|
||||
bool modified = false;
|
||||
template <typename Iter>
|
||||
static bool fdt_patch(Iter first, Iter last) {
|
||||
bool keepverity = check_env("KEEPVERITY");
|
||||
bool redirect = check_env("TWOSTAGEINIT");
|
||||
bool modified = false;
|
||||
|
||||
int idx = 0;
|
||||
for (auto it = first; it != last; ++it) {
|
||||
++idx;
|
||||
auto fdt = *it;
|
||||
int fstab = find_fstab(fdt);
|
||||
if (fstab < 0)
|
||||
continue;
|
||||
fprintf(stderr, "Found fstab in dtb.%04d\n", idx - 1);
|
||||
int block;
|
||||
fdt_for_each_subnode(block, fdt, fstab) {
|
||||
const char *name = fdt_get_name(fdt, block, nullptr);
|
||||
fprintf(stderr, "Found entry [%s] in fstab\n", name);
|
||||
if (!keepverity) {
|
||||
int size;
|
||||
auto value = fdt_getprop(fdt, block, "fsmgr_flags", &size);
|
||||
char *copy = static_cast<char *>(memcpy(malloc(size), value, size));
|
||||
if (patch_verity(copy, size) != size) {
|
||||
modified = true;
|
||||
fdt_setprop_string(fdt, block, "fsmgr_flags", copy);
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
if (redirect && name == "system"sv) {
|
||||
modified = true;
|
||||
fprintf(stderr, "Changing mnt_point to /system_root\n");
|
||||
fdt_setprop_string(fdt, block, "mnt_point", "/system_root");
|
||||
}
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
int idx = 0;
|
||||
for (auto it = first; it != last; ++it) {
|
||||
++idx;
|
||||
auto fdt = *it;
|
||||
int fstab = find_fstab(fdt);
|
||||
if (fstab < 0)
|
||||
continue;
|
||||
fprintf(stderr, "Found fstab in dtb.%04d\n", idx - 1);
|
||||
int block;
|
||||
fdt_for_each_subnode(block, fdt, fstab) {
|
||||
const char *name = fdt_get_name(fdt, block, nullptr);
|
||||
fprintf(stderr, "Found entry [%s] in fstab\n", name);
|
||||
if (!keepverity) {
|
||||
int size;
|
||||
auto value = fdt_getprop(fdt, block, "fsmgr_flags", &size);
|
||||
char *copy = static_cast<char *>(memcpy(malloc(size), value, size));
|
||||
if (patch_verity(copy, size) != size) {
|
||||
modified = true;
|
||||
fdt_setprop_string(fdt, block, "fsmgr_flags", copy);
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
if (redirect && name == "system"sv) {
|
||||
modified = true;
|
||||
fprintf(stderr, "Changing mnt_point to /system_root\n");
|
||||
fdt_setprop_string(fdt, block, "mnt_point", "/system_root");
|
||||
}
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
#define MAX_FDT_GROWTH 256
|
||||
|
||||
template <class Table, class Header>
|
||||
static int dt_table_patch(const Header *hdr, const char *out) {
|
||||
map<uint32_t, fdt_blob> dtb_map;
|
||||
auto buf = reinterpret_cast<const uint8_t *>(hdr);
|
||||
auto tables = reinterpret_cast<const Table *>(hdr + 1);
|
||||
template <class Table, class Header>
|
||||
static int dt_table_patch(const Header *hdr, const char *out) {
|
||||
map<uint32_t, fdt_blob> dtb_map;
|
||||
auto buf = reinterpret_cast<const uint8_t *>(hdr);
|
||||
auto tables = reinterpret_cast<const Table *>(hdr + 1);
|
||||
|
||||
constexpr bool is_dt_table = std::is_same_v<Header, dt_table_header>;
|
||||
constexpr bool is_dt_table = std::is_same_v<Header, dt_table_header>;
|
||||
|
||||
using endian_conv = uint32_t (*)(uint32_t);
|
||||
endian_conv be_to_le;
|
||||
endian_conv le_to_be;
|
||||
if constexpr (is_dt_table) {
|
||||
be_to_le = fdt32_to_cpu;
|
||||
le_to_be = cpu_to_fdt32;
|
||||
} else {
|
||||
be_to_le = le_to_be = [](uint32_t x) -> auto { return x; };
|
||||
}
|
||||
using endian_conv = uint32_t (*)(uint32_t);
|
||||
endian_conv be_to_le;
|
||||
endian_conv le_to_be;
|
||||
if constexpr (is_dt_table) {
|
||||
be_to_le = fdt32_to_cpu;
|
||||
le_to_be = cpu_to_fdt32;
|
||||
} else {
|
||||
be_to_le = le_to_be = [](uint32_t x) -> auto { return x; };
|
||||
}
|
||||
|
||||
// Collect all dtbs
|
||||
auto num_dtb = be_to_le(hdr->num_dtbs);
|
||||
for (int i = 0; i < num_dtb; ++i) {
|
||||
auto offset = be_to_le(tables[i].offset);
|
||||
if (dtb_map.count(offset) == 0) {
|
||||
auto blob = buf + offset;
|
||||
uint32_t size = fdt_totalsize(blob);
|
||||
auto fdt = xmalloc(size + MAX_FDT_GROWTH);
|
||||
memcpy(fdt, blob, size);
|
||||
fdt_open_into(fdt, fdt, size + MAX_FDT_GROWTH);
|
||||
dtb_map[offset] = { fdt, offset };
|
||||
}
|
||||
}
|
||||
if (dtb_map.empty())
|
||||
return 1;
|
||||
// Collect all dtbs
|
||||
auto num_dtb = be_to_le(hdr->num_dtbs);
|
||||
for (int i = 0; i < num_dtb; ++i) {
|
||||
auto offset = be_to_le(tables[i].offset);
|
||||
if (dtb_map.count(offset) == 0) {
|
||||
auto blob = buf + offset;
|
||||
uint32_t size = fdt_totalsize(blob);
|
||||
auto fdt = xmalloc(size + MAX_FDT_GROWTH);
|
||||
memcpy(fdt, blob, size);
|
||||
fdt_open_into(fdt, fdt, size + MAX_FDT_GROWTH);
|
||||
dtb_map[offset] = { fdt, offset };
|
||||
}
|
||||
}
|
||||
if (dtb_map.empty())
|
||||
return 1;
|
||||
|
||||
// Patch fdt
|
||||
if (!fdt_patch(make_iter(dtb_map.begin()), make_iter(dtb_map.end())))
|
||||
return 1;
|
||||
// Patch fdt
|
||||
if (!fdt_patch(make_iter(dtb_map.begin()), make_iter(dtb_map.end())))
|
||||
return 1;
|
||||
|
||||
unlink(out);
|
||||
int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
|
||||
unlink(out);
|
||||
int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
|
||||
|
||||
uint32_t total_size = 0;
|
||||
uint32_t total_size = 0;
|
||||
|
||||
// Copy headers and tables
|
||||
total_size += xwrite(fd, buf, dtb_map.begin()->first);
|
||||
// Copy headers and tables
|
||||
total_size += xwrite(fd, buf, dtb_map.begin()->first);
|
||||
|
||||
// mmap rw to patch table values retroactively
|
||||
auto mmap_sz = lseek(fd, 0, SEEK_CUR);
|
||||
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
// mmap rw to patch table values retroactively
|
||||
auto mmap_sz = lseek(fd, 0, SEEK_CUR);
|
||||
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
// Guess alignment using gcd
|
||||
uint32_t align = 1;
|
||||
if constexpr (!is_dt_table) {
|
||||
auto it = dtb_map.begin();
|
||||
align = (it++)->first;
|
||||
for (; it != dtb_map.end(); ++it)
|
||||
align = binary_gcd(align, it->first);
|
||||
}
|
||||
// Guess alignment using gcd
|
||||
uint32_t align = 1;
|
||||
if constexpr (!is_dt_table) {
|
||||
auto it = dtb_map.begin();
|
||||
align = (it++)->first;
|
||||
for (; it != dtb_map.end(); ++it)
|
||||
align = binary_gcd(align, it->first);
|
||||
}
|
||||
|
||||
// Write dtbs
|
||||
for (auto &val : dtb_map) {
|
||||
val.second.offset = lseek(fd, 0, SEEK_CUR);
|
||||
auto fdt = val.second.fdt;
|
||||
fdt_pack(fdt);
|
||||
auto size = fdt_totalsize(fdt);
|
||||
total_size += xwrite(fd, fdt, size);
|
||||
val.second.len = do_align(size, align);
|
||||
write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), align));
|
||||
// total_size += align_off(lseek(fd, 0, SEEK_CUR), align); /* Not needed */
|
||||
free(fdt);
|
||||
}
|
||||
// Write dtbs
|
||||
for (auto &val : dtb_map) {
|
||||
val.second.offset = lseek(fd, 0, SEEK_CUR);
|
||||
auto fdt = val.second.fdt;
|
||||
fdt_pack(fdt);
|
||||
auto size = fdt_totalsize(fdt);
|
||||
total_size += xwrite(fd, fdt, size);
|
||||
val.second.len = do_align(size, align);
|
||||
write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), align));
|
||||
// total_size += align_off(lseek(fd, 0, SEEK_CUR), align); /* Not needed */
|
||||
free(fdt);
|
||||
}
|
||||
|
||||
// Patch headers
|
||||
if constexpr (is_dt_table) {
|
||||
auto hdr_rw = reinterpret_cast<Header *>(addr);
|
||||
hdr_rw->total_size = le_to_be(total_size);
|
||||
}
|
||||
auto tables_rw = reinterpret_cast<Table *>(addr + sizeof(Header));
|
||||
for (int i = 0; i < num_dtb; ++i) {
|
||||
auto &blob = dtb_map[be_to_le(tables_rw[i].offset)];
|
||||
tables_rw[i].offset = le_to_be(blob.offset);
|
||||
tables_rw[i].len = le_to_be(blob.len);
|
||||
}
|
||||
// Patch headers
|
||||
if constexpr (is_dt_table) {
|
||||
auto hdr_rw = reinterpret_cast<Header *>(addr);
|
||||
hdr_rw->total_size = le_to_be(total_size);
|
||||
}
|
||||
auto tables_rw = reinterpret_cast<Table *>(addr + sizeof(Header));
|
||||
for (int i = 0; i < num_dtb; ++i) {
|
||||
auto &blob = dtb_map[be_to_le(tables_rw[i].offset)];
|
||||
tables_rw[i].offset = le_to_be(blob.offset);
|
||||
tables_rw[i].len = le_to_be(blob.len);
|
||||
}
|
||||
|
||||
munmap(addr, mmap_sz);
|
||||
close(fd);
|
||||
munmap(addr, mmap_sz);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) {
|
||||
vector<uint8_t *> fdt_list;
|
||||
vector<uint32_t> padding_list;
|
||||
for (int i = 0; i < dtb_sz; ++i) {
|
||||
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||
auto len = fdt_totalsize(dtb + i);
|
||||
auto fdt = static_cast<uint8_t *>(xmalloc(len + MAX_FDT_GROWTH));
|
||||
memcpy(fdt, dtb + i, len);
|
||||
fdt_pack(fdt);
|
||||
uint32_t padding = len - fdt_totalsize(fdt);
|
||||
padding_list.push_back(padding);
|
||||
fdt_open_into(fdt, fdt, len + MAX_FDT_GROWTH);
|
||||
fdt_list.push_back(fdt);
|
||||
i += len - 1;
|
||||
}
|
||||
}
|
||||
static int blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) {
|
||||
vector<uint8_t *> fdt_list;
|
||||
vector<uint32_t> padding_list;
|
||||
for (int i = 0; i < dtb_sz; ++i) {
|
||||
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
|
||||
auto len = fdt_totalsize(dtb + i);
|
||||
auto fdt = static_cast<uint8_t *>(xmalloc(len + MAX_FDT_GROWTH));
|
||||
memcpy(fdt, dtb + i, len);
|
||||
fdt_pack(fdt);
|
||||
uint32_t padding = len - fdt_totalsize(fdt);
|
||||
padding_list.push_back(padding);
|
||||
fdt_open_into(fdt, fdt, len + MAX_FDT_GROWTH);
|
||||
fdt_list.push_back(fdt);
|
||||
i += len - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fdt_patch(fdt_list.begin(), fdt_list.end()))
|
||||
return 1;
|
||||
if (!fdt_patch(fdt_list.begin(), fdt_list.end()))
|
||||
return 1;
|
||||
|
||||
unlink(out);
|
||||
int fd = xopen(out, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
|
||||
unlink(out);
|
||||
int fd = xopen(out, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
|
||||
|
||||
for (int i = 0; i < fdt_list.size(); ++i) {
|
||||
auto fdt = fdt_list[i];
|
||||
fdt_pack(fdt);
|
||||
// Only add padding back if it is anything meaningful
|
||||
if (padding_list[i] > 4) {
|
||||
auto len = fdt_totalsize(fdt);
|
||||
fdt_set_totalsize(fdt, len + padding_list[i]);
|
||||
}
|
||||
xwrite(fd, fdt, fdt_totalsize(fdt));
|
||||
free(fdt);
|
||||
}
|
||||
close(fd);
|
||||
for (int i = 0; i < fdt_list.size(); ++i) {
|
||||
auto fdt = fdt_list[i];
|
||||
fdt_pack(fdt);
|
||||
// Only add padding back if it is anything meaningful
|
||||
if (padding_list[i] > 4) {
|
||||
auto len = fdt_totalsize(fdt);
|
||||
fdt_set_totalsize(fdt, len + padding_list[i]);
|
||||
}
|
||||
xwrite(fd, fdt, fdt_totalsize(fdt));
|
||||
free(fdt);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MATCH(s) (memcmp(dtb, s, sizeof(s) - 1) == 0)
|
||||
|
||||
[[maybe_unused]] static int dtb_patch(const char *in, const char *out) {
|
||||
if (!out)
|
||||
out = in;
|
||||
size_t dtb_sz ;
|
||||
uint8_t *dtb;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", in);
|
||||
mmap_ro(in, dtb, dtb_sz);
|
||||
run_finally f([&]{ munmap(dtb, dtb_sz); });
|
||||
[[maybe_unused]] static int dtb_patch(const char *in, const char *out) {
|
||||
if (!out)
|
||||
out = in;
|
||||
size_t dtb_sz ;
|
||||
uint8_t *dtb;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", in);
|
||||
mmap_ro(in, dtb, dtb_sz);
|
||||
run_finally f([&]{ munmap(dtb, dtb_sz); });
|
||||
|
||||
if (MATCH(QCDT_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<qcdt_hdr*>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "QCDT v1\n");
|
||||
return dt_table_patch<qctable_v1>(hdr, out);
|
||||
case 2:
|
||||
fprintf(stderr, "QCDT v2\n");
|
||||
return dt_table_patch<qctable_v2>(hdr, out);
|
||||
case 3:
|
||||
fprintf(stderr, "QCDT v3\n");
|
||||
return dt_table_patch<qctable_v3>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(DTBH_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<dtbh_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 2:
|
||||
fprintf(stderr, "DTBH v2\n");
|
||||
return dt_table_patch<bhtable_v2>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(PXADT_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<pxadt_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "PXA-DT v1\n");
|
||||
return dt_table_patch<pxatable_v1>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(PXA19xx_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<pxa19xx_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "PXA-19xx v1\n");
|
||||
return dt_table_patch<pxatable_v1>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(SPRD_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<sprd_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "SPRD v1\n");
|
||||
return dt_table_patch<sprdtable_v1>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(DT_TABLE_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<dt_table_header *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 0:
|
||||
fprintf(stderr, "DT_TABLE v0\n");
|
||||
return dt_table_patch<dt_table_entry>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return blob_patch(dtb, dtb_sz, out);
|
||||
}
|
||||
}
|
||||
if (MATCH(QCDT_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<qcdt_hdr*>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "QCDT v1\n");
|
||||
return dt_table_patch<qctable_v1>(hdr, out);
|
||||
case 2:
|
||||
fprintf(stderr, "QCDT v2\n");
|
||||
return dt_table_patch<qctable_v2>(hdr, out);
|
||||
case 3:
|
||||
fprintf(stderr, "QCDT v3\n");
|
||||
return dt_table_patch<qctable_v3>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(DTBH_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<dtbh_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 2:
|
||||
fprintf(stderr, "DTBH v2\n");
|
||||
return dt_table_patch<bhtable_v2>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(PXADT_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<pxadt_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "PXA-DT v1\n");
|
||||
return dt_table_patch<pxatable_v1>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(PXA19xx_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<pxa19xx_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "PXA-19xx v1\n");
|
||||
return dt_table_patch<pxatable_v1>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(SPRD_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<sprd_hdr *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 1:
|
||||
fprintf(stderr, "SPRD v1\n");
|
||||
return dt_table_patch<sprdtable_v1>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else if (MATCH(DT_TABLE_MAGIC)) {
|
||||
auto hdr = reinterpret_cast<dt_table_header *>(dtb);
|
||||
switch (hdr->version) {
|
||||
case 0:
|
||||
fprintf(stderr, "DT_TABLE v0\n");
|
||||
return dt_table_patch<dt_table_entry>(hdr, out);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return blob_patch(dtb, dtb_sz, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,94 +11,94 @@
|
||||
#define SPRD_MAGIC "SPRD"
|
||||
|
||||
struct qcdt_hdr {
|
||||
char magic[4]; /* "QCDT" */
|
||||
uint32_t version; /* QCDT version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
char magic[4]; /* "QCDT" */
|
||||
uint32_t version; /* QCDT version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct qctable_v1 {
|
||||
uint32_t cpu_info[3]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in QCDT */
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t cpu_info[3]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in QCDT */
|
||||
uint32_t len; /* DTB size */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct qctable_v2 {
|
||||
uint32_t cpu_info[4]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in QCDT */
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t cpu_info[4]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in QCDT */
|
||||
uint32_t len; /* DTB size */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct qctable_v3 {
|
||||
uint32_t cpu_info[8]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in QCDT */
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t cpu_info[8]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in QCDT */
|
||||
uint32_t len; /* DTB size */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dtbh_hdr {
|
||||
char magic[4]; /* "DTBH" */
|
||||
uint32_t version; /* DTBH version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
char magic[4]; /* "DTBH" */
|
||||
uint32_t version; /* DTBH version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bhtable_v2 {
|
||||
uint32_t cpu_info[5]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in DTBH */
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t space; /* 0x00000020 */
|
||||
uint32_t cpu_info[5]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in DTBH */
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t space; /* 0x00000020 */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct pxadt_hdr {
|
||||
char magic[6]; /* "PXA-DT" */
|
||||
uint32_t version; /* PXA-* version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
char magic[6]; /* "PXA-DT" */
|
||||
uint32_t version; /* PXA-* version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct pxa19xx_hdr {
|
||||
char magic[8]; /* "PXA-19xx" */
|
||||
uint32_t version; /* PXA-* version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
char magic[8]; /* "PXA-19xx" */
|
||||
uint32_t version; /* PXA-* version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct pxatable_v1 {
|
||||
uint32_t cpu_info[2]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in PXA-* */
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t cpu_info[2]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in PXA-* */
|
||||
uint32_t len; /* DTB size */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sprd_hdr {
|
||||
char magic[4]; /* "SPRD" */
|
||||
uint32_t version; /* SPRD version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
char magic[4]; /* "SPRD" */
|
||||
uint32_t version; /* SPRD version */
|
||||
uint32_t num_dtbs; /* Number of DTBs */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sprdtable_v1 {
|
||||
uint32_t cpu_info[3]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in SPRD */
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t cpu_info[3]; /* Some CPU info */
|
||||
uint32_t offset; /* DTB offset in SPRD */
|
||||
uint32_t len; /* DTB size */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* AOSP DTB/DTBO partition layout */
|
||||
|
||||
struct dt_table_header {
|
||||
uint32_t magic; /* DT_TABLE_MAGIC */
|
||||
uint32_t total_size; /* includes dt_table_header + all dt_table_entry */
|
||||
uint32_t header_size; /* sizeof(dt_table_header) */
|
||||
uint32_t magic; /* DT_TABLE_MAGIC */
|
||||
uint32_t total_size; /* includes dt_table_header + all dt_table_entry */
|
||||
uint32_t header_size; /* sizeof(dt_table_header) */
|
||||
|
||||
uint32_t dt_entry_size; /* sizeof(dt_table_entry) */
|
||||
uint32_t num_dtbs; /* number of dt_table_entry */
|
||||
uint32_t dt_entries_offset; /* offset to the first dt_table_entry */
|
||||
uint32_t dt_entry_size; /* sizeof(dt_table_entry) */
|
||||
uint32_t num_dtbs; /* number of dt_table_entry */
|
||||
uint32_t dt_entries_offset; /* offset to the first dt_table_entry */
|
||||
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t version; /* DTBO image version */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t version; /* DTBO image version */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dt_table_entry {
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t offset;
|
||||
uint32_t len; /* DTB size */
|
||||
uint32_t offset;
|
||||
|
||||
uint32_t id;
|
||||
uint32_t rev;
|
||||
uint32_t flags;
|
||||
uint32_t id;
|
||||
uint32_t rev;
|
||||
uint32_t flags;
|
||||
|
||||
uint32_t custom[3];
|
||||
uint32_t custom[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
@@ -8,15 +8,15 @@ Fmt2Ext fmt2ext;
|
||||
|
||||
class FormatInit {
|
||||
public:
|
||||
FormatInit() {
|
||||
name2fmt["gzip"] = GZIP;
|
||||
name2fmt["xz"] = XZ;
|
||||
name2fmt["lzma"] = LZMA;
|
||||
name2fmt["bzip2"] = BZIP2;
|
||||
name2fmt["lz4"] = LZ4;
|
||||
name2fmt["lz4_legacy"] = LZ4_LEGACY;
|
||||
name2fmt["lz4_lg"] = LZ4_LG;
|
||||
}
|
||||
FormatInit() {
|
||||
name2fmt["gzip"] = GZIP;
|
||||
name2fmt["xz"] = XZ;
|
||||
name2fmt["lzma"] = LZMA;
|
||||
name2fmt["bzip2"] = BZIP2;
|
||||
name2fmt["lz4"] = LZ4;
|
||||
name2fmt["lz4_legacy"] = LZ4_LEGACY;
|
||||
name2fmt["lz4_lg"] = LZ4_LG;
|
||||
}
|
||||
};
|
||||
|
||||
static FormatInit init;
|
||||
@@ -24,82 +24,82 @@ static FormatInit init;
|
||||
#define MATCH(s) (len >= (sizeof(s) - 1) && memcmp(buf, s, sizeof(s) - 1) == 0)
|
||||
|
||||
format_t check_fmt(const void *buf, size_t len) {
|
||||
if (MATCH(CHROMEOS_MAGIC)) {
|
||||
return CHROMEOS;
|
||||
} else if (MATCH(BOOT_MAGIC)) {
|
||||
return AOSP;
|
||||
} else if (MATCH(VENDOR_BOOT_MAGIC)) {
|
||||
return AOSP_VENDOR;
|
||||
} else if (MATCH(GZIP1_MAGIC) || MATCH(GZIP2_MAGIC)) {
|
||||
return GZIP;
|
||||
} else if (MATCH(LZOP_MAGIC)) {
|
||||
return LZOP;
|
||||
} else if (MATCH(XZ_MAGIC)) {
|
||||
return XZ;
|
||||
} else if (len >= 13 && memcmp(buf, "\x5d\x00\x00", 3) == 0
|
||||
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
|
||||
return LZMA;
|
||||
} else if (MATCH(BZIP_MAGIC)) {
|
||||
return BZIP2;
|
||||
} else if (MATCH(LZ41_MAGIC) || MATCH(LZ42_MAGIC)) {
|
||||
return LZ4;
|
||||
} else if (MATCH(LZ4_LEG_MAGIC)) {
|
||||
return LZ4_LEGACY;
|
||||
} else if (MATCH(MTK_MAGIC)) {
|
||||
return MTK;
|
||||
} else if (MATCH(DTB_MAGIC)) {
|
||||
return DTB;
|
||||
} else if (MATCH(DHTB_MAGIC)) {
|
||||
return DHTB;
|
||||
} else if (MATCH(TEGRABLOB_MAGIC)) {
|
||||
return BLOB;
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
if (MATCH(CHROMEOS_MAGIC)) {
|
||||
return CHROMEOS;
|
||||
} else if (MATCH(BOOT_MAGIC)) {
|
||||
return AOSP;
|
||||
} else if (MATCH(VENDOR_BOOT_MAGIC)) {
|
||||
return AOSP_VENDOR;
|
||||
} else if (MATCH(GZIP1_MAGIC) || MATCH(GZIP2_MAGIC)) {
|
||||
return GZIP;
|
||||
} else if (MATCH(LZOP_MAGIC)) {
|
||||
return LZOP;
|
||||
} else if (MATCH(XZ_MAGIC)) {
|
||||
return XZ;
|
||||
} else if (len >= 13 && memcmp(buf, "\x5d\x00\x00", 3) == 0
|
||||
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
|
||||
return LZMA;
|
||||
} else if (MATCH(BZIP_MAGIC)) {
|
||||
return BZIP2;
|
||||
} else if (MATCH(LZ41_MAGIC) || MATCH(LZ42_MAGIC)) {
|
||||
return LZ4;
|
||||
} else if (MATCH(LZ4_LEG_MAGIC)) {
|
||||
return LZ4_LEGACY;
|
||||
} else if (MATCH(MTK_MAGIC)) {
|
||||
return MTK;
|
||||
} else if (MATCH(DTB_MAGIC)) {
|
||||
return DTB;
|
||||
} else if (MATCH(DHTB_MAGIC)) {
|
||||
return DHTB;
|
||||
} else if (MATCH(TEGRABLOB_MAGIC)) {
|
||||
return BLOB;
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
const char *Fmt2Name::operator[](format_t fmt) {
|
||||
switch (fmt) {
|
||||
case GZIP:
|
||||
return "gzip";
|
||||
case LZOP:
|
||||
return "lzop";
|
||||
case XZ:
|
||||
return "xz";
|
||||
case LZMA:
|
||||
return "lzma";
|
||||
case BZIP2:
|
||||
return "bzip2";
|
||||
case LZ4:
|
||||
return "lz4";
|
||||
case LZ4_LEGACY:
|
||||
return "lz4_legacy";
|
||||
case LZ4_LG:
|
||||
return "lz4_lg";
|
||||
case DTB:
|
||||
return "dtb";
|
||||
default:
|
||||
return "raw";
|
||||
}
|
||||
switch (fmt) {
|
||||
case GZIP:
|
||||
return "gzip";
|
||||
case LZOP:
|
||||
return "lzop";
|
||||
case XZ:
|
||||
return "xz";
|
||||
case LZMA:
|
||||
return "lzma";
|
||||
case BZIP2:
|
||||
return "bzip2";
|
||||
case LZ4:
|
||||
return "lz4";
|
||||
case LZ4_LEGACY:
|
||||
return "lz4_legacy";
|
||||
case LZ4_LG:
|
||||
return "lz4_lg";
|
||||
case DTB:
|
||||
return "dtb";
|
||||
default:
|
||||
return "raw";
|
||||
}
|
||||
}
|
||||
|
||||
const char *Fmt2Ext::operator[](format_t fmt) {
|
||||
switch (fmt) {
|
||||
case GZIP:
|
||||
return ".gz";
|
||||
case LZOP:
|
||||
return ".lzo";
|
||||
case XZ:
|
||||
return ".xz";
|
||||
case LZMA:
|
||||
return ".lzma";
|
||||
case BZIP2:
|
||||
return ".bz2";
|
||||
case LZ4:
|
||||
case LZ4_LEGACY:
|
||||
case LZ4_LG:
|
||||
return ".lz4";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
switch (fmt) {
|
||||
case GZIP:
|
||||
return ".gz";
|
||||
case LZOP:
|
||||
return ".lzo";
|
||||
case XZ:
|
||||
return ".xz";
|
||||
case LZMA:
|
||||
return ".lzma";
|
||||
case BZIP2:
|
||||
return ".bz2";
|
||||
case LZ4:
|
||||
case LZ4_LEGACY:
|
||||
case LZ4_LG:
|
||||
return ".lz4";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,26 +4,26 @@
|
||||
#include <string_view>
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN,
|
||||
UNKNOWN,
|
||||
/* Boot formats */
|
||||
CHROMEOS,
|
||||
AOSP,
|
||||
AOSP_VENDOR,
|
||||
DHTB,
|
||||
BLOB,
|
||||
CHROMEOS,
|
||||
AOSP,
|
||||
AOSP_VENDOR,
|
||||
DHTB,
|
||||
BLOB,
|
||||
/* Compression formats */
|
||||
GZIP,
|
||||
XZ,
|
||||
LZMA,
|
||||
BZIP2,
|
||||
LZ4,
|
||||
LZ4_LEGACY,
|
||||
LZ4_LG,
|
||||
GZIP,
|
||||
XZ,
|
||||
LZMA,
|
||||
BZIP2,
|
||||
LZ4,
|
||||
LZ4_LEGACY,
|
||||
LZ4_LG,
|
||||
/* Unsupported compression */
|
||||
LZOP,
|
||||
LZOP,
|
||||
/* Misc */
|
||||
MTK,
|
||||
DTB,
|
||||
MTK,
|
||||
DTB,
|
||||
} format_t;
|
||||
|
||||
#define COMPRESSED(fmt) ((fmt) >= GZIP && (fmt) < LZOP)
|
||||
@@ -57,12 +57,12 @@ typedef enum {
|
||||
|
||||
class Fmt2Name {
|
||||
public:
|
||||
const char *operator[](format_t fmt);
|
||||
const char *operator[](format_t fmt);
|
||||
};
|
||||
|
||||
class Fmt2Ext {
|
||||
public:
|
||||
const char *operator[](format_t fmt);
|
||||
const char *operator[](format_t fmt);
|
||||
};
|
||||
|
||||
format_t check_fmt(const void *buf, size_t len);
|
||||
|
||||
@@ -8,36 +8,36 @@
|
||||
#include "magiskboot.hpp"
|
||||
|
||||
static void hex2byte(uint8_t *hex, uint8_t *str) {
|
||||
char high, low;
|
||||
for (int i = 0, length = strlen((char *) hex); i < length; i += 2) {
|
||||
high = toupper(hex[i]) - '0';
|
||||
low = toupper(hex[i + 1]) - '0';
|
||||
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
|
||||
}
|
||||
char high, low;
|
||||
for (int i = 0, length = strlen((char *) hex); i < length; i += 2) {
|
||||
high = toupper(hex[i]) - '0';
|
||||
low = toupper(hex[i + 1]) - '0';
|
||||
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
|
||||
}
|
||||
}
|
||||
|
||||
int hexpatch(const char *image, const char *from, const char *to) {
|
||||
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
|
||||
int patched = 1;
|
||||
size_t filesize;
|
||||
uint8_t *file, *pattern, *patch;
|
||||
mmap_rw(image, file, filesize);
|
||||
pattern = (uint8_t *) xmalloc(patternsize);
|
||||
patch = (uint8_t *) xmalloc(patchsize);
|
||||
hex2byte((uint8_t *) from, pattern);
|
||||
hex2byte((uint8_t *) to, patch);
|
||||
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
|
||||
if (memcmp(file + i, pattern, patternsize) == 0) {
|
||||
fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to);
|
||||
memset(file + i, 0, patternsize);
|
||||
memcpy(file + i, patch, patchsize);
|
||||
i += patternsize - 1;
|
||||
patched = 0;
|
||||
}
|
||||
}
|
||||
munmap(file, filesize);
|
||||
free(pattern);
|
||||
free(patch);
|
||||
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
|
||||
int patched = 1;
|
||||
size_t filesize;
|
||||
uint8_t *file, *pattern, *patch;
|
||||
mmap_rw(image, file, filesize);
|
||||
pattern = (uint8_t *) xmalloc(patternsize);
|
||||
patch = (uint8_t *) xmalloc(patchsize);
|
||||
hex2byte((uint8_t *) from, pattern);
|
||||
hex2byte((uint8_t *) to, patch);
|
||||
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
|
||||
if (memcmp(file + i, pattern, patternsize) == 0) {
|
||||
fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to);
|
||||
memset(file + i, 0, patternsize);
|
||||
memcpy(file + i, patch, patchsize);
|
||||
i += patternsize - 1;
|
||||
patched = 0;
|
||||
}
|
||||
}
|
||||
munmap(file, filesize);
|
||||
free(pattern);
|
||||
free(patch);
|
||||
|
||||
return patched;
|
||||
return patched;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
using namespace std;
|
||||
|
||||
static void usage(char *arg0) {
|
||||
fprintf(stderr,
|
||||
fprintf(stderr,
|
||||
R"EOF(MagiskBoot - Boot Image Modification Tool
|
||||
|
||||
Usage: %s <action> [args...]
|
||||
@@ -96,100 +96,100 @@ Supported actions:
|
||||
<infile>/[outfile] can be '-' to be STDIN/STDOUT
|
||||
Supported methods: )EOF", arg0);
|
||||
|
||||
for (auto &it : name2fmt)
|
||||
fprintf(stderr, "%s ", it.first.data());
|
||||
for (auto &it : name2fmt)
|
||||
fprintf(stderr, "%s ", it.first.data());
|
||||
|
||||
fprintf(stderr, R"EOF(
|
||||
fprintf(stderr, R"EOF(
|
||||
|
||||
decompress <infile> [outfile]
|
||||
Detect method and decompress <infile>, optionally to [outfile]
|
||||
<infile>/[outfile] can be '-' to be STDIN/STDOUT
|
||||
Supported methods: )EOF");
|
||||
|
||||
for (auto &it : name2fmt)
|
||||
fprintf(stderr, "%s ", it.first.data());
|
||||
for (auto &it : name2fmt)
|
||||
fprintf(stderr, "%s ", it.first.data());
|
||||
|
||||
fprintf(stderr, "\n\n");
|
||||
exit(1);
|
||||
fprintf(stderr, "\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
cmdline_logging();
|
||||
umask(0);
|
||||
cmdline_logging();
|
||||
umask(0);
|
||||
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
// Skip '--' for backwards compatibility
|
||||
string_view action(argv[1]);
|
||||
if (str_starts(action, "--"))
|
||||
action = argv[1] + 2;
|
||||
// Skip '--' for backwards compatibility
|
||||
string_view action(argv[1]);
|
||||
if (str_starts(action, "--"))
|
||||
action = argv[1] + 2;
|
||||
|
||||
if (action == "cleanup") {
|
||||
fprintf(stderr, "Cleaning up...\n");
|
||||
unlink(HEADER_FILE);
|
||||
unlink(KERNEL_FILE);
|
||||
unlink(RAMDISK_FILE);
|
||||
unlink(SECOND_FILE);
|
||||
unlink(KER_DTB_FILE);
|
||||
unlink(EXTRA_FILE);
|
||||
unlink(RECV_DTBO_FILE);
|
||||
unlink(DTB_FILE);
|
||||
} else if (argc > 2 && action == "sha1") {
|
||||
uint8_t sha1[SHA_DIGEST_SIZE];
|
||||
void *buf;
|
||||
size_t size;
|
||||
mmap_ro(argv[2], buf, size);
|
||||
SHA_hash(buf, size, sha1);
|
||||
for (uint8_t i : sha1)
|
||||
printf("%02x", i);
|
||||
printf("\n");
|
||||
munmap(buf, size);
|
||||
} else if (argc > 2 && action == "split") {
|
||||
return split_image_dtb(argv[2]);
|
||||
} else if (argc > 2 && action == "unpack") {
|
||||
int idx = 2;
|
||||
bool nodecomp = false;
|
||||
bool hdr = false;
|
||||
for (;;) {
|
||||
if (idx >= argc)
|
||||
usage(argv[0]);
|
||||
if (argv[idx][0] != '-')
|
||||
break;
|
||||
for (char *flag = &argv[idx][1]; *flag; ++flag) {
|
||||
if (*flag == 'n')
|
||||
nodecomp = true;
|
||||
else if (*flag == 'h')
|
||||
hdr = true;
|
||||
else
|
||||
usage(argv[0]);
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
return unpack(argv[idx], nodecomp, hdr);
|
||||
} else if (argc > 2 && action == "repack") {
|
||||
if (argv[2] == "-n"sv) {
|
||||
if (argc == 3)
|
||||
usage(argv[0]);
|
||||
repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true);
|
||||
} else {
|
||||
repack(argv[2], argv[3] ? argv[3] : NEW_BOOT);
|
||||
}
|
||||
} else if (argc > 2 && action == "decompress") {
|
||||
decompress(argv[2], argv[3]);
|
||||
} else if (argc > 2 && str_starts(action, "compress")) {
|
||||
compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]);
|
||||
} else if (argc > 4 && action == "hexpatch") {
|
||||
return hexpatch(argv[2], argv[3], argv[4]);
|
||||
} else if (argc > 2 && action == "cpio"sv) {
|
||||
if (cpio_commands(argc - 2, argv + 2))
|
||||
usage(argv[0]);
|
||||
} else if (argc > 3 && action == "dtb") {
|
||||
if (dtb_commands(argc - 2, argv + 2))
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
if (action == "cleanup") {
|
||||
fprintf(stderr, "Cleaning up...\n");
|
||||
unlink(HEADER_FILE);
|
||||
unlink(KERNEL_FILE);
|
||||
unlink(RAMDISK_FILE);
|
||||
unlink(SECOND_FILE);
|
||||
unlink(KER_DTB_FILE);
|
||||
unlink(EXTRA_FILE);
|
||||
unlink(RECV_DTBO_FILE);
|
||||
unlink(DTB_FILE);
|
||||
} else if (argc > 2 && action == "sha1") {
|
||||
uint8_t sha1[SHA_DIGEST_SIZE];
|
||||
void *buf;
|
||||
size_t size;
|
||||
mmap_ro(argv[2], buf, size);
|
||||
SHA_hash(buf, size, sha1);
|
||||
for (uint8_t i : sha1)
|
||||
printf("%02x", i);
|
||||
printf("\n");
|
||||
munmap(buf, size);
|
||||
} else if (argc > 2 && action == "split") {
|
||||
return split_image_dtb(argv[2]);
|
||||
} else if (argc > 2 && action == "unpack") {
|
||||
int idx = 2;
|
||||
bool nodecomp = false;
|
||||
bool hdr = false;
|
||||
for (;;) {
|
||||
if (idx >= argc)
|
||||
usage(argv[0]);
|
||||
if (argv[idx][0] != '-')
|
||||
break;
|
||||
for (char *flag = &argv[idx][1]; *flag; ++flag) {
|
||||
if (*flag == 'n')
|
||||
nodecomp = true;
|
||||
else if (*flag == 'h')
|
||||
hdr = true;
|
||||
else
|
||||
usage(argv[0]);
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
return unpack(argv[idx], nodecomp, hdr);
|
||||
} else if (argc > 2 && action == "repack") {
|
||||
if (argv[2] == "-n"sv) {
|
||||
if (argc == 3)
|
||||
usage(argv[0]);
|
||||
repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true);
|
||||
} else {
|
||||
repack(argv[2], argv[3] ? argv[3] : NEW_BOOT);
|
||||
}
|
||||
} else if (argc > 2 && action == "decompress") {
|
||||
decompress(argv[2], argv[3]);
|
||||
} else if (argc > 2 && str_starts(action, "compress")) {
|
||||
compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]);
|
||||
} else if (argc > 4 && action == "hexpatch") {
|
||||
return hexpatch(argv[2], argv[3], argv[4]);
|
||||
} else if (argc > 2 && action == "cpio"sv) {
|
||||
if (cpio_commands(argc - 2, argv + 2))
|
||||
usage(argv[0]);
|
||||
} else if (argc > 3 && action == "dtb") {
|
||||
if (dtb_commands(argc - 2, argv + 2))
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,56 +8,56 @@
|
||||
#define MATCH(p) else if (strncmp(s + skip, p, sizeof(p) - 1) == 0) skip += (sizeof(p) - 1)
|
||||
|
||||
static int check_verity_pattern(const char *s) {
|
||||
int skip = s[0] == ',';
|
||||
int skip = s[0] == ',';
|
||||
|
||||
if (0) {}
|
||||
MATCH("verifyatboot");
|
||||
MATCH("verify");
|
||||
MATCH("avb_keys");
|
||||
MATCH("avb");
|
||||
MATCH("support_scfs");
|
||||
MATCH("fsverity");
|
||||
else return -1;
|
||||
if (0) {}
|
||||
MATCH("verifyatboot");
|
||||
MATCH("verify");
|
||||
MATCH("avb_keys");
|
||||
MATCH("avb");
|
||||
MATCH("support_scfs");
|
||||
MATCH("fsverity");
|
||||
else return -1;
|
||||
|
||||
if (s[skip] == '=') {
|
||||
while (s[skip] != '\0' && s[skip] != ' ' && s[skip] != '\n' && s[skip] != ',')
|
||||
++skip;
|
||||
}
|
||||
return skip;
|
||||
if (s[skip] == '=') {
|
||||
while (s[skip] != '\0' && s[skip] != ' ' && s[skip] != '\n' && s[skip] != ',')
|
||||
++skip;
|
||||
}
|
||||
return skip;
|
||||
}
|
||||
|
||||
#undef MATCH
|
||||
#define MATCH(p) else if (strncmp(s, p, sizeof(p) - 1) == 0) return (sizeof(p) - 1)
|
||||
|
||||
static int check_encryption_pattern(const char *s) {
|
||||
if (0) {}
|
||||
MATCH("forceencrypt");
|
||||
MATCH("forcefdeorfbe");
|
||||
MATCH("fileencryption");
|
||||
else return -1;
|
||||
if (0) {}
|
||||
MATCH("forceencrypt");
|
||||
MATCH("forcefdeorfbe");
|
||||
MATCH("fileencryption");
|
||||
else return -1;
|
||||
}
|
||||
|
||||
static uint32_t remove_pattern(void *buf, uint32_t size, int(*pattern_skip)(const char *)) {
|
||||
auto src = static_cast<char *>(buf);
|
||||
int orig_sz = size;
|
||||
int write = 0;
|
||||
for (int read = 0; read < orig_sz;) {
|
||||
if (int skip = pattern_skip(src + read); skip > 0) {
|
||||
fprintf(stderr, "Remove pattern [%.*s]\n", skip, src + read);
|
||||
size -= skip;
|
||||
read += skip;
|
||||
} else {
|
||||
src[write++] = src[read++];
|
||||
}
|
||||
}
|
||||
memset(src + write, 0, orig_sz - write);
|
||||
return size;
|
||||
auto src = static_cast<char *>(buf);
|
||||
int orig_sz = size;
|
||||
int write = 0;
|
||||
for (int read = 0; read < orig_sz;) {
|
||||
if (int skip = pattern_skip(src + read); skip > 0) {
|
||||
fprintf(stderr, "Remove pattern [%.*s]\n", skip, src + read);
|
||||
size -= skip;
|
||||
read += skip;
|
||||
} else {
|
||||
src[write++] = src[read++];
|
||||
}
|
||||
}
|
||||
memset(src + write, 0, orig_sz - write);
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t patch_verity(void *buf, uint32_t size) {
|
||||
return remove_pattern(buf, size, check_verity_pattern);
|
||||
return remove_pattern(buf, size, check_verity_pattern);
|
||||
}
|
||||
|
||||
uint32_t patch_encryption(void *buf, uint32_t size) {
|
||||
return remove_pattern(buf, size, check_encryption_pattern);
|
||||
return remove_pattern(buf, size, check_encryption_pattern);
|
||||
}
|
||||
|
||||
@@ -13,60 +13,60 @@ using namespace std;
|
||||
constexpr char RAMDISK_XZ[] = "ramdisk.cpio.xz";
|
||||
|
||||
static const char *UNSUPPORT_LIST[] =
|
||||
{ "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc",
|
||||
"boot/sbin/launch_daemonsu.sh" };
|
||||
{ "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc",
|
||||
"boot/sbin/launch_daemonsu.sh" };
|
||||
|
||||
static const char *MAGISK_LIST[] =
|
||||
{ ".backup/.magisk", "init.magisk.rc",
|
||||
"overlay/init.magisk.rc" };
|
||||
{ ".backup/.magisk", "init.magisk.rc",
|
||||
"overlay/init.magisk.rc" };
|
||||
|
||||
class magisk_cpio : public cpio_rw {
|
||||
public:
|
||||
magisk_cpio() = default;
|
||||
explicit magisk_cpio(const char *filename) : cpio_rw(filename) {}
|
||||
void patch();
|
||||
int test();
|
||||
char *sha1();
|
||||
void restore();
|
||||
void backup(const char *orig);
|
||||
void compress();
|
||||
void decompress();
|
||||
magisk_cpio() = default;
|
||||
explicit magisk_cpio(const char *filename) : cpio_rw(filename) {}
|
||||
void patch();
|
||||
int test();
|
||||
char *sha1();
|
||||
void restore();
|
||||
void backup(const char *orig);
|
||||
void compress();
|
||||
void decompress();
|
||||
};
|
||||
|
||||
bool check_env(const char *name) {
|
||||
const char *val = getenv(name);
|
||||
return val ? strcmp(val, "true") == 0 : false;
|
||||
const char *val = getenv(name);
|
||||
return val ? strcmp(val, "true") == 0 : false;
|
||||
}
|
||||
|
||||
void magisk_cpio::patch() {
|
||||
bool keepverity = check_env("KEEPVERITY");
|
||||
bool keepforceencrypt = check_env("KEEPFORCEENCRYPT");
|
||||
fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n",
|
||||
keepverity ? "true" : "false", keepforceencrypt ? "true" : "false");
|
||||
bool keepverity = check_env("KEEPVERITY");
|
||||
bool keepforceencrypt = check_env("KEEPFORCEENCRYPT");
|
||||
fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n",
|
||||
keepverity ? "true" : "false", keepforceencrypt ? "true" : "false");
|
||||
|
||||
for (auto it = entries.begin(); it != entries.end();) {
|
||||
auto cur = it++;
|
||||
bool fstab = (!keepverity || !keepforceencrypt) &&
|
||||
S_ISREG(cur->second->mode) &&
|
||||
!str_starts(cur->first, ".backup") &&
|
||||
!str_contains(cur->first, "twrp") &&
|
||||
!str_contains(cur->first, "recovery") &&
|
||||
str_contains(cur->first, "fstab");
|
||||
if (!keepverity) {
|
||||
if (fstab) {
|
||||
fprintf(stderr, "Found fstab file [%s]\n", cur->first.data());
|
||||
cur->second->filesize = patch_verity(cur->second->data, cur->second->filesize);
|
||||
} else if (cur->first == "verity_key") {
|
||||
rm(cur);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!keepforceencrypt) {
|
||||
if (fstab) {
|
||||
cur->second->filesize = patch_encryption(cur->second->data, cur->second->filesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto it = entries.begin(); it != entries.end();) {
|
||||
auto cur = it++;
|
||||
bool fstab = (!keepverity || !keepforceencrypt) &&
|
||||
S_ISREG(cur->second->mode) &&
|
||||
!str_starts(cur->first, ".backup") &&
|
||||
!str_contains(cur->first, "twrp") &&
|
||||
!str_contains(cur->first, "recovery") &&
|
||||
str_contains(cur->first, "fstab");
|
||||
if (!keepverity) {
|
||||
if (fstab) {
|
||||
fprintf(stderr, "Found fstab file [%s]\n", cur->first.data());
|
||||
cur->second->filesize = patch_verity(cur->second->data, cur->second->filesize);
|
||||
} else if (cur->first == "verity_key") {
|
||||
rm(cur);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!keepforceencrypt) {
|
||||
if (fstab) {
|
||||
cur->second->filesize = patch_encryption(cur->second->data, cur->second->filesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define STOCK_BOOT 0
|
||||
@@ -76,274 +76,274 @@ void magisk_cpio::patch() {
|
||||
#define TWO_STAGE_INIT (1 << 3)
|
||||
|
||||
int magisk_cpio::test() {
|
||||
for (auto file : UNSUPPORT_LIST)
|
||||
if (exists(file))
|
||||
return UNSUPPORTED_CPIO;
|
||||
for (auto file : UNSUPPORT_LIST)
|
||||
if (exists(file))
|
||||
return UNSUPPORTED_CPIO;
|
||||
|
||||
int flags = STOCK_BOOT;
|
||||
int flags = STOCK_BOOT;
|
||||
|
||||
if (exists(RAMDISK_XZ)) {
|
||||
flags |= COMPRESSED_CPIO | MAGISK_PATCHED;
|
||||
decompress();
|
||||
}
|
||||
if (exists(RAMDISK_XZ)) {
|
||||
flags |= COMPRESSED_CPIO | MAGISK_PATCHED;
|
||||
decompress();
|
||||
}
|
||||
|
||||
if (exists("apex") || exists("first_stage_ramdisk"))
|
||||
flags |= TWO_STAGE_INIT;
|
||||
if (exists("apex") || exists("first_stage_ramdisk"))
|
||||
flags |= TWO_STAGE_INIT;
|
||||
|
||||
for (auto file : MAGISK_LIST) {
|
||||
if (exists(file)) {
|
||||
flags |= MAGISK_PATCHED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (auto file : MAGISK_LIST) {
|
||||
if (exists(file)) {
|
||||
flags |= MAGISK_PATCHED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
return flags;
|
||||
}
|
||||
|
||||
#define for_each_line(line, buf, size) \
|
||||
for (line = (char *) buf; line < (char *) buf + size && line[0]; line = strchr(line + 1, '\n') + 1)
|
||||
|
||||
char *magisk_cpio::sha1() {
|
||||
decompress();
|
||||
char sha1[41];
|
||||
char *line;
|
||||
for (auto &e : entries) {
|
||||
if (e.first == "init.magisk.rc" || e.first == "overlay/init.magisk.rc") {
|
||||
for_each_line(line, e.second->data, e.second->filesize) {
|
||||
if (strncmp(line, "#STOCKSHA1=", 11) == 0) {
|
||||
strncpy(sha1, line + 12, 40);
|
||||
sha1[40] = '\0';
|
||||
return strdup(sha1);
|
||||
}
|
||||
}
|
||||
} else if (e.first == ".backup/.magisk") {
|
||||
for_each_line(line, e.second->data, e.second->filesize) {
|
||||
if (strncmp(line, "SHA1=", 5) == 0) {
|
||||
strncpy(sha1, line + 5, 40);
|
||||
sha1[40] = '\0';
|
||||
return strdup(sha1);
|
||||
}
|
||||
}
|
||||
} else if (e.first == ".backup/.sha1") {
|
||||
return (char *) e.second->data;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
decompress();
|
||||
char sha1[41];
|
||||
char *line;
|
||||
for (auto &e : entries) {
|
||||
if (e.first == "init.magisk.rc" || e.first == "overlay/init.magisk.rc") {
|
||||
for_each_line(line, e.second->data, e.second->filesize) {
|
||||
if (strncmp(line, "#STOCKSHA1=", 11) == 0) {
|
||||
strncpy(sha1, line + 12, 40);
|
||||
sha1[40] = '\0';
|
||||
return strdup(sha1);
|
||||
}
|
||||
}
|
||||
} else if (e.first == ".backup/.magisk") {
|
||||
for_each_line(line, e.second->data, e.second->filesize) {
|
||||
if (strncmp(line, "SHA1=", 5) == 0) {
|
||||
strncpy(sha1, line + 5, 40);
|
||||
sha1[40] = '\0';
|
||||
return strdup(sha1);
|
||||
}
|
||||
}
|
||||
} else if (e.first == ".backup/.sha1") {
|
||||
return (char *) e.second->data;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#define for_each_str(str, buf, size) \
|
||||
for (str = (char *) buf; str < (char *) buf + size; str = str += strlen(str) + 1)
|
||||
|
||||
void magisk_cpio::restore() {
|
||||
decompress();
|
||||
decompress();
|
||||
|
||||
if (auto it = entries.find(".backup/.rmlist"); it != entries.end()) {
|
||||
char *file;
|
||||
for_each_str(file, it->second->data, it->second->filesize)
|
||||
rm(file, false);
|
||||
rm(it);
|
||||
}
|
||||
if (auto it = entries.find(".backup/.rmlist"); it != entries.end()) {
|
||||
char *file;
|
||||
for_each_str(file, it->second->data, it->second->filesize)
|
||||
rm(file, false);
|
||||
rm(it);
|
||||
}
|
||||
|
||||
for (auto it = entries.begin(); it != entries.end();) {
|
||||
auto cur = it++;
|
||||
if (str_starts(cur->first, ".backup")) {
|
||||
if (cur->first.length() == 7 || cur->first.substr(8) == ".magisk") {
|
||||
rm(cur);
|
||||
} else {
|
||||
mv(cur, &cur->first[8]);
|
||||
}
|
||||
} else if (str_starts(cur->first, "magisk") ||
|
||||
cur->first == "overlay/init.magisk.rc" ||
|
||||
cur->first == "sbin/magic_mask.sh" ||
|
||||
cur->first == "init.magisk.rc") {
|
||||
// Some known stuff we can remove
|
||||
rm(cur);
|
||||
}
|
||||
}
|
||||
for (auto it = entries.begin(); it != entries.end();) {
|
||||
auto cur = it++;
|
||||
if (str_starts(cur->first, ".backup")) {
|
||||
if (cur->first.length() == 7 || cur->first.substr(8) == ".magisk") {
|
||||
rm(cur);
|
||||
} else {
|
||||
mv(cur, &cur->first[8]);
|
||||
}
|
||||
} else if (str_starts(cur->first, "magisk") ||
|
||||
cur->first == "overlay/init.magisk.rc" ||
|
||||
cur->first == "sbin/magic_mask.sh" ||
|
||||
cur->first == "init.magisk.rc") {
|
||||
// Some known stuff we can remove
|
||||
rm(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void magisk_cpio::backup(const char *orig) {
|
||||
if (access(orig, R_OK))
|
||||
return;
|
||||
entry_map bkup_entries;
|
||||
string remv;
|
||||
if (access(orig, R_OK))
|
||||
return;
|
||||
entry_map bkup_entries;
|
||||
string remv;
|
||||
|
||||
auto b = new cpio_entry(".backup", S_IFDIR);
|
||||
bkup_entries[b->filename].reset(b);
|
||||
auto b = new cpio_entry(".backup", S_IFDIR);
|
||||
bkup_entries[b->filename].reset(b);
|
||||
|
||||
magisk_cpio o(orig);
|
||||
magisk_cpio o(orig);
|
||||
|
||||
// Remove possible backups in original ramdisk
|
||||
o.rm(".backup", true);
|
||||
rm(".backup", true);
|
||||
// Remove possible backups in original ramdisk
|
||||
o.rm(".backup", true);
|
||||
rm(".backup", true);
|
||||
|
||||
auto lhs = o.entries.begin();
|
||||
auto rhs = entries.begin();
|
||||
auto lhs = o.entries.begin();
|
||||
auto rhs = entries.begin();
|
||||
|
||||
while (lhs != o.entries.end() || rhs != entries.end()) {
|
||||
int res;
|
||||
bool backup = false;
|
||||
if (lhs != o.entries.end() && rhs != entries.end()) {
|
||||
res = lhs->first.compare(rhs->first);
|
||||
} else if (lhs == o.entries.end()) {
|
||||
res = 1;
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
while (lhs != o.entries.end() || rhs != entries.end()) {
|
||||
int res;
|
||||
bool backup = false;
|
||||
if (lhs != o.entries.end() && rhs != entries.end()) {
|
||||
res = lhs->first.compare(rhs->first);
|
||||
} else if (lhs == o.entries.end()) {
|
||||
res = 1;
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
// Something is missing in new ramdisk, backup!
|
||||
backup = true;
|
||||
fprintf(stderr, "Backup missing entry: ");
|
||||
} else if (res == 0) {
|
||||
if (lhs->second->filesize != rhs->second->filesize ||
|
||||
memcmp(lhs->second->data, rhs->second->data, lhs->second->filesize) != 0) {
|
||||
// Not the same!
|
||||
backup = true;
|
||||
fprintf(stderr, "Backup mismatch entry: ");
|
||||
}
|
||||
} else {
|
||||
// Something new in ramdisk
|
||||
remv += rhs->first;
|
||||
remv += (char) '\0';
|
||||
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", rhs->first.data());
|
||||
}
|
||||
if (backup) {
|
||||
string back_name(".backup/");
|
||||
back_name += lhs->first;
|
||||
fprintf(stderr, "[%s] -> [%s]\n", lhs->first.data(), back_name.data());
|
||||
auto ex = static_cast<cpio_entry*>(lhs->second.release());
|
||||
ex->filename = back_name;
|
||||
bkup_entries[ex->filename].reset(ex);
|
||||
}
|
||||
if (res < 0) {
|
||||
// Something is missing in new ramdisk, backup!
|
||||
backup = true;
|
||||
fprintf(stderr, "Backup missing entry: ");
|
||||
} else if (res == 0) {
|
||||
if (lhs->second->filesize != rhs->second->filesize ||
|
||||
memcmp(lhs->second->data, rhs->second->data, lhs->second->filesize) != 0) {
|
||||
// Not the same!
|
||||
backup = true;
|
||||
fprintf(stderr, "Backup mismatch entry: ");
|
||||
}
|
||||
} else {
|
||||
// Something new in ramdisk
|
||||
remv += rhs->first;
|
||||
remv += (char) '\0';
|
||||
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", rhs->first.data());
|
||||
}
|
||||
if (backup) {
|
||||
string back_name(".backup/");
|
||||
back_name += lhs->first;
|
||||
fprintf(stderr, "[%s] -> [%s]\n", lhs->first.data(), back_name.data());
|
||||
auto ex = static_cast<cpio_entry*>(lhs->second.release());
|
||||
ex->filename = back_name;
|
||||
bkup_entries[ex->filename].reset(ex);
|
||||
}
|
||||
|
||||
// Increment positions
|
||||
if (res < 0) {
|
||||
++lhs;
|
||||
} else if (res == 0) {
|
||||
++lhs; ++rhs;
|
||||
} else {
|
||||
++rhs;
|
||||
}
|
||||
}
|
||||
// Increment positions
|
||||
if (res < 0) {
|
||||
++lhs;
|
||||
} else if (res == 0) {
|
||||
++lhs; ++rhs;
|
||||
} else {
|
||||
++rhs;
|
||||
}
|
||||
}
|
||||
|
||||
if (!remv.empty()) {
|
||||
auto rmlist = new cpio_entry(".backup/.rmlist", S_IFREG);
|
||||
rmlist->filesize = remv.length();
|
||||
rmlist->data = xmalloc(remv.length());
|
||||
memcpy(rmlist->data, remv.data(), remv.length());
|
||||
bkup_entries[rmlist->filename].reset(rmlist);
|
||||
}
|
||||
if (!remv.empty()) {
|
||||
auto rmlist = new cpio_entry(".backup/.rmlist", S_IFREG);
|
||||
rmlist->filesize = remv.length();
|
||||
rmlist->data = xmalloc(remv.length());
|
||||
memcpy(rmlist->data, remv.data(), remv.length());
|
||||
bkup_entries[rmlist->filename].reset(rmlist);
|
||||
}
|
||||
|
||||
if (bkup_entries.size() > 1)
|
||||
entries.merge(bkup_entries);
|
||||
if (bkup_entries.size() > 1)
|
||||
entries.merge(bkup_entries);
|
||||
}
|
||||
|
||||
void magisk_cpio::compress() {
|
||||
if (exists(RAMDISK_XZ))
|
||||
return;
|
||||
fprintf(stderr, "Compressing cpio -> [%s]\n", RAMDISK_XZ);
|
||||
auto init = entries.extract("init");
|
||||
if (exists(RAMDISK_XZ))
|
||||
return;
|
||||
fprintf(stderr, "Compressing cpio -> [%s]\n", RAMDISK_XZ);
|
||||
auto init = entries.extract("init");
|
||||
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
auto strm = make_stream_fp(get_encoder(XZ, make_unique<byte_stream>(data, len)));
|
||||
dump(strm.release());
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
auto strm = make_stream_fp(get_encoder(XZ, make_unique<byte_stream>(data, len)));
|
||||
dump(strm.release());
|
||||
|
||||
entries.clear();
|
||||
entries.insert(std::move(init));
|
||||
auto xz = new cpio_entry(RAMDISK_XZ, S_IFREG);
|
||||
xz->data = data;
|
||||
xz->filesize = len;
|
||||
insert(xz);
|
||||
entries.clear();
|
||||
entries.insert(std::move(init));
|
||||
auto xz = new cpio_entry(RAMDISK_XZ, S_IFREG);
|
||||
xz->data = data;
|
||||
xz->filesize = len;
|
||||
insert(xz);
|
||||
}
|
||||
|
||||
void magisk_cpio::decompress() {
|
||||
auto it = entries.find(RAMDISK_XZ);
|
||||
if (it == entries.end())
|
||||
return;
|
||||
fprintf(stderr, "Decompressing cpio [%s]\n", RAMDISK_XZ);
|
||||
auto it = entries.find(RAMDISK_XZ);
|
||||
if (it == entries.end())
|
||||
return;
|
||||
fprintf(stderr, "Decompressing cpio [%s]\n", RAMDISK_XZ);
|
||||
|
||||
char *data;
|
||||
size_t len;
|
||||
{
|
||||
auto strm = get_decoder(XZ, make_unique<byte_stream>(data, len));
|
||||
strm->write(it->second->data, it->second->filesize);
|
||||
}
|
||||
char *data;
|
||||
size_t len;
|
||||
{
|
||||
auto strm = get_decoder(XZ, make_unique<byte_stream>(data, len));
|
||||
strm->write(it->second->data, it->second->filesize);
|
||||
}
|
||||
|
||||
entries.erase(it);
|
||||
load_cpio(data, len);
|
||||
free(data);
|
||||
entries.erase(it);
|
||||
load_cpio(data, len);
|
||||
free(data);
|
||||
}
|
||||
|
||||
int cpio_commands(int argc, char *argv[]) {
|
||||
char *incpio = argv[0];
|
||||
++argv;
|
||||
--argc;
|
||||
char *incpio = argv[0];
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
magisk_cpio cpio;
|
||||
if (access(incpio, R_OK) == 0)
|
||||
cpio.load_cpio(incpio);
|
||||
magisk_cpio cpio;
|
||||
if (access(incpio, R_OK) == 0)
|
||||
cpio.load_cpio(incpio);
|
||||
|
||||
int cmdc;
|
||||
char *cmdv[6];
|
||||
int cmdc;
|
||||
char *cmdv[6];
|
||||
|
||||
while (argc) {
|
||||
// Clean up
|
||||
cmdc = 0;
|
||||
memset(cmdv, NULL, sizeof(cmdv));
|
||||
while (argc) {
|
||||
// Clean up
|
||||
cmdc = 0;
|
||||
memset(cmdv, NULL, sizeof(cmdv));
|
||||
|
||||
// Split the commands
|
||||
for (char *tok = strtok(argv[0], " "); tok; tok = strtok(nullptr, " "))
|
||||
cmdv[cmdc++] = tok;
|
||||
// Split the commands
|
||||
for (char *tok = strtok(argv[0], " "); tok; tok = strtok(nullptr, " "))
|
||||
cmdv[cmdc++] = tok;
|
||||
|
||||
if (cmdc == 0)
|
||||
continue;
|
||||
if (cmdc == 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(cmdv[0], "test") == 0) {
|
||||
exit(cpio.test());
|
||||
} else if (strcmp(cmdv[0], "restore") == 0) {
|
||||
cpio.restore();
|
||||
} else if (strcmp(cmdv[0], "sha1") == 0) {
|
||||
char *sha1 = cpio.sha1();
|
||||
if (sha1) printf("%s\n", sha1);
|
||||
return 0;
|
||||
} else if (strcmp(cmdv[0], "compress") == 0){
|
||||
cpio.compress();
|
||||
} else if (strcmp(cmdv[0], "decompress") == 0){
|
||||
cpio.decompress();
|
||||
} else if (strcmp(cmdv[0], "patch") == 0) {
|
||||
cpio.patch();
|
||||
} else if (cmdc == 2 && strcmp(cmdv[0], "exists") == 0) {
|
||||
exit(!cpio.exists(cmdv[1]));
|
||||
} else if (cmdc == 2 && strcmp(cmdv[0], "backup") == 0) {
|
||||
cpio.backup(cmdv[1]);
|
||||
} else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {
|
||||
bool r = cmdc > 2 && strcmp(cmdv[1], "-r") == 0;
|
||||
cpio.rm(cmdv[1 + r], r);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) {
|
||||
cpio.mv(cmdv[1], cmdv[2]);
|
||||
} else if (strcmp(cmdv[0], "extract") == 0) {
|
||||
if (cmdc == 3) {
|
||||
return !cpio.extract(cmdv[1], cmdv[2]);
|
||||
} else {
|
||||
cpio.extract();
|
||||
return 0;
|
||||
}
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) {
|
||||
cpio.mkdir(strtoul(cmdv[1], nullptr, 8), cmdv[2]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) {
|
||||
cpio.ln(cmdv[1], cmdv[2]);
|
||||
} else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) {
|
||||
cpio.add(strtoul(cmdv[1], nullptr, 8), cmdv[2], cmdv[3]);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(cmdv[0], "test") == 0) {
|
||||
exit(cpio.test());
|
||||
} else if (strcmp(cmdv[0], "restore") == 0) {
|
||||
cpio.restore();
|
||||
} else if (strcmp(cmdv[0], "sha1") == 0) {
|
||||
char *sha1 = cpio.sha1();
|
||||
if (sha1) printf("%s\n", sha1);
|
||||
return 0;
|
||||
} else if (strcmp(cmdv[0], "compress") == 0){
|
||||
cpio.compress();
|
||||
} else if (strcmp(cmdv[0], "decompress") == 0){
|
||||
cpio.decompress();
|
||||
} else if (strcmp(cmdv[0], "patch") == 0) {
|
||||
cpio.patch();
|
||||
} else if (cmdc == 2 && strcmp(cmdv[0], "exists") == 0) {
|
||||
exit(!cpio.exists(cmdv[1]));
|
||||
} else if (cmdc == 2 && strcmp(cmdv[0], "backup") == 0) {
|
||||
cpio.backup(cmdv[1]);
|
||||
} else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {
|
||||
bool r = cmdc > 2 && strcmp(cmdv[1], "-r") == 0;
|
||||
cpio.rm(cmdv[1 + r], r);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) {
|
||||
cpio.mv(cmdv[1], cmdv[2]);
|
||||
} else if (strcmp(cmdv[0], "extract") == 0) {
|
||||
if (cmdc == 3) {
|
||||
return !cpio.extract(cmdv[1], cmdv[2]);
|
||||
} else {
|
||||
cpio.extract();
|
||||
return 0;
|
||||
}
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) {
|
||||
cpio.mkdir(strtoul(cmdv[1], nullptr, 8), cmdv[2]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) {
|
||||
cpio.ln(cmdv[1], cmdv[2]);
|
||||
} else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) {
|
||||
cpio.add(strtoul(cmdv[1], nullptr, 8), cmdv[2], cmdv[3]);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
cpio.dump(incpio);
|
||||
return 0;
|
||||
cpio.dump(incpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,123 +10,125 @@
|
||||
using namespace std;
|
||||
|
||||
static const char *prop_key[] =
|
||||
{ "ro.boot.vbmeta.device_state", "ro.boot.verifiedbootstate", "ro.boot.flash.locked",
|
||||
"ro.boot.veritymode", "ro.boot.warranty_bit", "ro.warranty_bit",
|
||||
"ro.debuggable", "ro.secure", "ro.build.type", "ro.build.tags",
|
||||
"ro.vendor.boot.warranty_bit", "ro.vendor.warranty_bit",
|
||||
"vendor.boot.vbmeta.device_state", nullptr };
|
||||
{ "ro.boot.vbmeta.device_state", "ro.boot.verifiedbootstate", "ro.boot.flash.locked",
|
||||
"ro.boot.veritymode", "ro.boot.warranty_bit", "ro.warranty_bit",
|
||||
"ro.debuggable", "ro.secure", "ro.build.type", "ro.build.tags",
|
||||
"ro.vendor.boot.warranty_bit", "ro.vendor.warranty_bit",
|
||||
"vendor.boot.vbmeta.device_state", nullptr };
|
||||
|
||||
static const char *prop_val[] =
|
||||
{ "locked", "green", "1",
|
||||
"enforcing", "0", "0",
|
||||
"0", "1", "user", "release-keys",
|
||||
"0", "0",
|
||||
"locked", nullptr };
|
||||
{ "locked", "green", "1",
|
||||
"enforcing", "0", "0",
|
||||
"0", "1", "user", "release-keys",
|
||||
"0", "0",
|
||||
"locked", nullptr };
|
||||
|
||||
static const char *late_prop_key[] =
|
||||
{ "vendor.boot.verifiedbootstate", nullptr };
|
||||
{ "vendor.boot.verifiedbootstate", nullptr };
|
||||
|
||||
static const char *late_prop_val[] =
|
||||
{ "green", nullptr };
|
||||
{ "green", nullptr };
|
||||
|
||||
void hide_sensitive_props() {
|
||||
LOGI("hide_policy: Hiding sensitive props\n");
|
||||
LOGI("hide: Hiding sensitive props\n");
|
||||
|
||||
for (int i = 0; prop_key[i]; ++i) {
|
||||
auto value = getprop(prop_key[i]);
|
||||
if (!value.empty() && value != prop_val[i])
|
||||
setprop(prop_key[i], prop_val[i], false);
|
||||
}
|
||||
for (int i = 0; prop_key[i]; ++i) {
|
||||
auto value = getprop(prop_key[i]);
|
||||
if (!value.empty() && value != prop_val[i])
|
||||
setprop(prop_key[i], prop_val[i], false);
|
||||
}
|
||||
|
||||
// Hide that we booted from recovery when magisk is in recovery mode
|
||||
auto bootmode = getprop("ro.bootmode");
|
||||
if (!bootmode.empty() && str_contains(bootmode, "recovery"))
|
||||
setprop("ro.bootmode", "unknown", false);
|
||||
bootmode = getprop("ro.boot.mode");
|
||||
if (!bootmode.empty() && str_contains(bootmode, "recovery"))
|
||||
setprop("ro.boot.mode", "unknown", false);
|
||||
bootmode = getprop("vendor.boot.mode");
|
||||
if (!bootmode.empty() && str_contains(bootmode, "recovery"))
|
||||
setprop("vendor.boot.mode", "unknown", false);
|
||||
// Hide that we booted from recovery when magisk is in recovery mode
|
||||
auto bootmode = getprop("ro.bootmode");
|
||||
if (!bootmode.empty() && str_contains(bootmode, "recovery"))
|
||||
setprop("ro.bootmode", "unknown", false);
|
||||
bootmode = getprop("ro.boot.mode");
|
||||
if (!bootmode.empty() && str_contains(bootmode, "recovery"))
|
||||
setprop("ro.boot.mode", "unknown", false);
|
||||
bootmode = getprop("vendor.boot.mode");
|
||||
if (!bootmode.empty() && str_contains(bootmode, "recovery"))
|
||||
setprop("vendor.boot.mode", "unknown", false);
|
||||
|
||||
// Xiaomi cross region flash
|
||||
auto hwc = getprop("ro.boot.hwc");
|
||||
if (!hwc.empty() && str_contains(hwc, "CN"))
|
||||
setprop("ro.boot.hwc", "GLOBAL", false);
|
||||
auto hwcountry = getprop("ro.boot.hwcountry");
|
||||
if (!hwcountry.empty() && str_contains(hwcountry, "China"))
|
||||
setprop("ro.boot.hwcountry", "GLOBAL", false);
|
||||
// Xiaomi cross region flash
|
||||
auto hwc = getprop("ro.boot.hwc");
|
||||
if (!hwc.empty() && str_contains(hwc, "CN"))
|
||||
setprop("ro.boot.hwc", "GLOBAL", false);
|
||||
auto hwcountry = getprop("ro.boot.hwcountry");
|
||||
if (!hwcountry.empty() && str_contains(hwcountry, "China"))
|
||||
setprop("ro.boot.hwcountry", "GLOBAL", false);
|
||||
|
||||
auto selinux = getprop("ro.build.selinux");
|
||||
if (!selinux.empty())
|
||||
delprop("ro.build.selinux");
|
||||
auto selinux = getprop("ro.build.selinux");
|
||||
if (!selinux.empty())
|
||||
delprop("ro.build.selinux");
|
||||
}
|
||||
|
||||
void hide_late_sensitive_props() {
|
||||
LOGI("hide_policy: Hiding sensitive props (late)\n");
|
||||
LOGI("hide: Hiding sensitive props (late)\n");
|
||||
|
||||
for (int i = 0; late_prop_key[i]; ++i) {
|
||||
auto value = getprop(late_prop_key[i]);
|
||||
if (!value.empty() && value != late_prop_val[i])
|
||||
setprop(late_prop_key[i], late_prop_val[i], false);
|
||||
}
|
||||
for (int i = 0; late_prop_key[i]; ++i) {
|
||||
auto value = getprop(late_prop_key[i]);
|
||||
if (!value.empty() && value != late_prop_val[i])
|
||||
setprop(late_prop_key[i], late_prop_val[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
static void lazy_unmount(const char* mountpoint) {
|
||||
if (umount2(mountpoint, MNT_DETACH) != -1)
|
||||
LOGD("hide_policy: Unmounted (%s)\n", mountpoint);
|
||||
if (umount2(mountpoint, MNT_DETACH) != -1)
|
||||
LOGD("hide: Unmounted (%s)\n", mountpoint);
|
||||
}
|
||||
|
||||
#if ENABLE_PTRACE_MONITOR
|
||||
void hide_daemon(int pid) {
|
||||
if (fork_dont_care() == 0) {
|
||||
hide_unmount(pid);
|
||||
// Send resume signal
|
||||
kill(pid, SIGCONT);
|
||||
_exit(0);
|
||||
}
|
||||
if (fork_dont_care() == 0) {
|
||||
hide_unmount(pid);
|
||||
// Send resume signal
|
||||
kill(pid, SIGCONT);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define TMPFS_MNT(dir) (mentry->mnt_type == "tmpfs"sv && \
|
||||
strncmp(mentry->mnt_dir, "/" #dir, sizeof("/" #dir) - 1) == 0)
|
||||
|
||||
void hide_unmount(int pid) {
|
||||
if (switch_mnt_ns(pid))
|
||||
return;
|
||||
if (pid > 0 && switch_mnt_ns(pid))
|
||||
return;
|
||||
|
||||
LOGD("hide_policy: handling PID=[%d]\n", pid);
|
||||
LOGD("hide: handling PID=[%d]\n", pid);
|
||||
|
||||
char val;
|
||||
int fd = xopen(SELINUX_ENFORCE, O_RDONLY);
|
||||
xxread(fd, &val, sizeof(val));
|
||||
close(fd);
|
||||
// Permissive
|
||||
if (val == '0') {
|
||||
chmod(SELINUX_ENFORCE, 0640);
|
||||
chmod(SELINUX_POLICY, 0440);
|
||||
}
|
||||
char val;
|
||||
int fd = xopen(SELINUX_ENFORCE, O_RDONLY);
|
||||
xxread(fd, &val, sizeof(val));
|
||||
close(fd);
|
||||
// Permissive
|
||||
if (val == '0') {
|
||||
chmod(SELINUX_ENFORCE, 0640);
|
||||
chmod(SELINUX_POLICY, 0440);
|
||||
}
|
||||
|
||||
vector<string> targets;
|
||||
vector<string> targets;
|
||||
|
||||
// Unmount dummy skeletons and /sbin links
|
||||
targets.push_back(MAGISKTMP);
|
||||
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
|
||||
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext))
|
||||
targets.emplace_back(mentry->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
// Unmount dummy skeletons and /sbin links
|
||||
targets.push_back(MAGISKTMP);
|
||||
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
|
||||
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext))
|
||||
targets.emplace_back(mentry->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
|
||||
for (auto &s : reversed(targets))
|
||||
lazy_unmount(s.data());
|
||||
targets.clear();
|
||||
for (auto &s : reversed(targets))
|
||||
lazy_unmount(s.data());
|
||||
targets.clear();
|
||||
|
||||
// Unmount all Magisk created mounts
|
||||
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
|
||||
if (strstr(mentry->mnt_fsname, BLOCKDIR))
|
||||
targets.emplace_back(mentry->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
// Unmount all Magisk created mounts
|
||||
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
|
||||
if (strstr(mentry->mnt_fsname, BLOCKDIR))
|
||||
targets.emplace_back(mentry->mnt_dir);
|
||||
return true;
|
||||
});
|
||||
|
||||
for (auto &s : reversed(targets))
|
||||
lazy_unmount(s.data());
|
||||
for (auto &s : reversed(targets))
|
||||
lazy_unmount(s.data());
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user