Commit 40c64d50 authored by topjohnwu's avatar topjohnwu

Merge branch 'master' into feature/redesign

parents 89b1fa34 15bd2da8
...@@ -74,7 +74,7 @@ dependencies { ...@@ -74,7 +74,7 @@ dependencies {
implementation "${bindingAdapter}:${vBAdapt}" implementation "${bindingAdapter}:${vBAdapt}"
implementation "${bindingAdapter}-recyclerview:${vBAdapt}" implementation "${bindingAdapter}-recyclerview:${vBAdapt}"
def vMarkwon = '4.1.2' def vMarkwon = '4.2.0'
implementation "io.noties.markwon:core:${vMarkwon}" implementation "io.noties.markwon:core:${vMarkwon}"
implementation "io.noties.markwon:html:${vMarkwon}" implementation "io.noties.markwon:html:${vMarkwon}"
implementation "io.noties.markwon:image:${vMarkwon}" implementation "io.noties.markwon:image:${vMarkwon}"
...@@ -99,7 +99,7 @@ dependencies { ...@@ -99,7 +99,7 @@ dependencies {
implementation "com.squareup.okhttp3:okhttp:${vOkHttp}" implementation "com.squareup.okhttp3:okhttp:${vOkHttp}"
implementation "com.squareup.okhttp3:logging-interceptor:${vOkHttp}" implementation "com.squareup.okhttp3:logging-interceptor:${vOkHttp}"
def vMoshi = '1.9.1' def vMoshi = '1.9.2'
implementation "com.squareup.moshi:moshi:${vMoshi}" implementation "com.squareup.moshi:moshi:${vMoshi}"
def vKotshi = '2.0.2' def vKotshi = '2.0.2'
...@@ -111,7 +111,7 @@ dependencies { ...@@ -111,7 +111,7 @@ dependencies {
replacedBy('com.github.topjohnwu:room-runtime') replacedBy('com.github.topjohnwu:room-runtime')
} }
} }
def vRoom = '2.2.1' def vRoom = '2.2.2'
implementation "com.github.topjohnwu:room-runtime:${vRoom}" implementation "com.github.topjohnwu:room-runtime:${vRoom}"
implementation "androidx.room:room-rxjava2:${vRoom}" implementation "androidx.room:room-rxjava2:${vRoom}"
kapt "androidx.room:room-compiler:${vRoom}" kapt "androidx.room:room-compiler:${vRoom}"
...@@ -125,13 +125,12 @@ dependencies { ...@@ -125,13 +125,12 @@ dependencies {
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03'
implementation 'androidx.browser:browser:1.0.0' implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01' implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.fragment:fragment-ktx:1.2.0-rc02' implementation 'androidx.fragment:fragment-ktx:1.2.0-rc03'
implementation 'androidx.work:work-runtime:2.2.0' implementation 'androidx.work:work-runtime:2.2.0'
implementation 'androidx.transition:transition:1.2.0' implementation 'androidx.transition:transition:1.3.0-rc02'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.biometric:biometric:1.0.0' implementation 'com.google.android.material:material:1.2.0-alpha01'
implementation 'com.google.android.material:material:1.1.0-beta01'
implementation 'com.karumi:dexter:6.0.0' implementation 'com.karumi:dexter:6.0.0'
} }
...@@ -54,6 +54,7 @@ object Config : PreferenceModel, DBConfig { ...@@ -54,6 +54,7 @@ object Config : PreferenceModel, DBConfig {
const val REDESIGN = "redesign" const val REDESIGN = "redesign"
const val SAFETY = "safety_notice" const val SAFETY = "safety_notice"
const val THEME_ORDINAL = "theme_ordinal" const val THEME_ORDINAL = "theme_ordinal"
const val BOOT_ID = "boot_id"
// system state // system state
const val MAGISKHIDE = "magiskhide" const val MAGISKHIDE = "magiskhide"
...@@ -111,6 +112,8 @@ object Config : PreferenceModel, DBConfig { ...@@ -111,6 +112,8 @@ object Config : PreferenceModel, DBConfig {
} }
else Value.DEFAULT_CHANNEL else Value.DEFAULT_CHANNEL
var bootId by preference(Key.BOOT_ID, "")
var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS) var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS)
var repoOrder by preference(Key.REPO_ORDER, Value.ORDER_DATE) var repoOrder by preference(Key.REPO_ORDER, Value.ORDER_DATE)
......
...@@ -24,9 +24,6 @@ import com.topjohnwu.magisk.ui.flash.FlashActivity ...@@ -24,9 +24,6 @@ import com.topjohnwu.magisk.ui.flash.FlashActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.magisk.utils.refreshLocale import com.topjohnwu.magisk.utils.refreshLocale
import com.topjohnwu.magisk.utils.updateConfig import com.topjohnwu.magisk.utils.updateConfig
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.magisk.utils.defaultLocale
import java.util.*
import com.topjohnwu.magisk.redesign.MainActivity as RedesignActivity import com.topjohnwu.magisk.redesign.MainActivity as RedesignActivity
fun AssetManager.addAssetPath(path: String) { fun AssetManager.addAssetPath(path: String) {
......
...@@ -8,6 +8,8 @@ import com.topjohnwu.magisk.utils.CachedValue ...@@ -8,6 +8,8 @@ import com.topjohnwu.magisk.utils.CachedValue
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import java.io.FileInputStream
import java.io.IOException
val isRunningAsStub get() = Info.stub != null val isRunningAsStub get() = Info.stub != null
...@@ -36,6 +38,22 @@ object Info { ...@@ -36,6 +38,22 @@ object Info {
} }
} }
val isNewReboot by lazy {
try {
FileInputStream("/proc/sys/kernel/random/boot_id").bufferedReader().use {
val id = it.readLine()
if (id != Config.bootId) {
Config.bootId = id
true
} else {
false
}
}
} catch (e: IOException) {
false
}
}
private fun loadState() = runCatching { private fun loadState() = runCatching {
val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0] val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0]
val code = ShellUtils.fastCmd("magisk -V").toInt() val code = ShellUtils.fastCmd("magisk -V").toInt()
......
...@@ -3,8 +3,8 @@ package com.topjohnwu.magisk.data.database ...@@ -3,8 +3,8 @@ package com.topjohnwu.magisk.data.database
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.data.database.magiskdb.Delete
import com.topjohnwu.magisk.data.database.magiskdb.BaseDao import com.topjohnwu.magisk.data.database.magiskdb.BaseDao
import com.topjohnwu.magisk.data.database.magiskdb.Delete
import com.topjohnwu.magisk.data.database.magiskdb.Replace import com.topjohnwu.magisk.data.database.magiskdb.Replace
import com.topjohnwu.magisk.data.database.magiskdb.Select import com.topjohnwu.magisk.data.database.magiskdb.Select
import com.topjohnwu.magisk.extensions.now import com.topjohnwu.magisk.extensions.now
......
package com.topjohnwu.magisk.data.database package com.topjohnwu.magisk.data.database
import com.topjohnwu.magisk.data.database.magiskdb.Delete
import com.topjohnwu.magisk.data.database.magiskdb.BaseDao import com.topjohnwu.magisk.data.database.magiskdb.BaseDao
import com.topjohnwu.magisk.data.database.magiskdb.Delete
import com.topjohnwu.magisk.data.database.magiskdb.Replace import com.topjohnwu.magisk.data.database.magiskdb.Replace
import com.topjohnwu.magisk.data.database.magiskdb.Select import com.topjohnwu.magisk.data.database.magiskdb.Select
......
package com.topjohnwu.magisk.data.database package com.topjohnwu.magisk.data.database
import com.topjohnwu.magisk.data.database.magiskdb.Delete
import com.topjohnwu.magisk.data.database.magiskdb.BaseDao import com.topjohnwu.magisk.data.database.magiskdb.BaseDao
import com.topjohnwu.magisk.data.database.magiskdb.Delete
import com.topjohnwu.magisk.data.database.magiskdb.Replace import com.topjohnwu.magisk.data.database.magiskdb.Replace
import com.topjohnwu.magisk.data.database.magiskdb.Select import com.topjohnwu.magisk.data.database.magiskdb.Select
......
...@@ -33,8 +33,8 @@ import com.topjohnwu.magisk.FileProvider ...@@ -33,8 +33,8 @@ import com.topjohnwu.magisk.FileProvider
import com.topjohnwu.magisk.utils.DynamicClassLoader import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.currentLocale import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
......
package com.topjohnwu.magisk.extensions package com.topjohnwu.magisk.extensions
import android.os.Build import android.os.Build
import androidx.core.net.toFile
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.io.InputStream import java.io.InputStream
......
...@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.model.download ...@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.model.download
import android.app.Activity import android.app.Activity
import android.app.Notification import android.app.Notification
import android.content.Intent import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
......
...@@ -13,17 +13,21 @@ class Module(path: String) : BaseModule() { ...@@ -13,17 +13,21 @@ class Module(path: String) : BaseModule() {
override var versionCode: Int = -1 override var versionCode: Int = -1
override var description: String = "" override var description: String = ""
private val removeFile: SuFile = SuFile(path, "remove") private val removeFile = SuFile(path, "remove")
private val disableFile: SuFile = SuFile(path, "disable") private val disableFile = SuFile(path, "disable")
private val updateFile: SuFile = SuFile(path, "update") private val updateFile = SuFile(path, "update")
private val ruleFile = SuFile(path, "sepolicy.rule")
val updated: Boolean = updateFile.exists() val updated: Boolean = updateFile.exists()
var enable: Boolean = !disableFile.exists() var enable: Boolean = !disableFile.exists()
set(enable) { set(enable) {
val dir = "$PERSIST/$id"
field = if (enable) { field = if (enable) {
Shell.su("mkdir -p $dir", "cp -af $ruleFile $dir").submit()
disableFile.delete() disableFile.delete()
} else { } else {
Shell.su("rm -rf $dir").submit()
!disableFile.createNewFile() !disableFile.createNewFile()
} }
} }
...@@ -31,8 +35,10 @@ class Module(path: String) : BaseModule() { ...@@ -31,8 +35,10 @@ class Module(path: String) : BaseModule() {
var remove: Boolean = removeFile.exists() var remove: Boolean = removeFile.exists()
set(remove) { set(remove) {
field = if (remove) { field = if (remove) {
Shell.su("rm -rf $PERSIST/$id").submit()
removeFile.createNewFile() removeFile.createNewFile()
} else { } else {
Shell.su("cp -af $ruleFile $PERSIST/$id").submit()
!removeFile.delete() !removeFile.delete()
} }
} }
...@@ -54,6 +60,8 @@ class Module(path: String) : BaseModule() { ...@@ -54,6 +60,8 @@ class Module(path: String) : BaseModule() {
companion object { companion object {
private const val PERSIST = "/sbin/.magisk/mirror/persist/magisk"
@WorkerThread @WorkerThread
fun loadModules(): List<Module> { fun loadModules(): List<Module> {
val moduleList = mutableListOf<Module>() val moduleList = mutableListOf<Module>()
......
...@@ -287,8 +287,10 @@ abstract class MagiskInstaller { ...@@ -287,8 +287,10 @@ abstract class MagiskInstaller {
protected fun flashBoot(): Boolean { protected fun flashBoot(): Boolean {
if (!"direct_install $installDir $srcBoot".sh().isSuccess) if (!"direct_install $installDir $srcBoot".sh().isSuccess)
return false return false
if (!Info.keepVerity) arrayOf(
"patch_dtbo_image".sh() "(KEEPVERITY=${Info.keepVerity} patch_dtb_partitions)",
"run_migrations"
).sh()
return true return true
} }
......
...@@ -3,18 +3,16 @@ package com.topjohnwu.magisk.ui ...@@ -3,18 +3,16 @@ package com.topjohnwu.magisk.ui
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AlertDialog
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.magisk.wrap import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
open class SplashActivity : Activity() { open class SplashActivity : Activity() {
...@@ -41,6 +39,10 @@ open class SplashActivity : Activity() { ...@@ -41,6 +39,10 @@ open class SplashActivity : Activity() {
} }
} }
Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
// Set default configs // Set default configs
Config.initialize() Config.initialize()
...@@ -53,9 +55,13 @@ open class SplashActivity : Activity() { ...@@ -53,9 +55,13 @@ open class SplashActivity : Activity() {
// Setup shortcuts // Setup shortcuts
Shortcuts.setup(this) Shortcuts.setup(this)
Shell.su("mm_patch_dtbo").submit { if (Info.isNewReboot) {
val shell = Shell.newInstance()
shell.newJob().add("mm_patch_dtb").submit {
if (it.isSuccess) if (it.isSuccess)
Notifications.dtboPatched(this) Notifications.dtboPatched(this)
shell.close()
}
} }
DONE = true DONE = true
......
...@@ -2,12 +2,10 @@ package com.topjohnwu.magisk.utils ...@@ -2,12 +2,10 @@ package com.topjohnwu.magisk.utils
import android.content.Context import android.content.Context
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.rawResource import com.topjohnwu.magisk.extensions.rawResource
import com.topjohnwu.magisk.wrap import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.io.SuFile
class RootInit : Shell.Initializer() { class RootInit : Shell.Initializer() {
...@@ -17,9 +15,6 @@ class RootInit : Shell.Initializer() { ...@@ -17,9 +15,6 @@ class RootInit : Shell.Initializer() {
} }
fun init(context: Context, shell: Shell): Boolean { fun init(context: Context, shell: Shell): Boolean {
// Invalidate env state if shell is recreated
Info.envRef.invalidate()
val job = shell.newJob() val job = shell.newJob()
if (shell.isRoot) { if (shell.isRoot) {
job.add(context.rawResource(R.raw.util_functions)) job.add(context.rawResource(R.raw.util_functions))
...@@ -29,15 +24,12 @@ class RootInit : Shell.Initializer() { ...@@ -29,15 +24,12 @@ class RootInit : Shell.Initializer() {
job.add(context.rawResource(R.raw.nonroot_utils)) job.add(context.rawResource(R.raw.nonroot_utils))
} }
job.add("mount_partitions", job.add(
"mount_partitions",
"get_flags", "get_flags",
"run_migrations", "run_migrations",
"export BOOTMODE=true") "export BOOTMODE=true"
.exec() ).exec()
Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
return true return true
} }
......
This diff was suppressed by a .gitattributes entry.
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
android:layout_gravity="bottom|center_horizontal" android:layout_gravity="bottom|center_horizontal"
android:layout_margin="@dimen/fab_padding" android:layout_margin="@dimen/fab_padding"
android:onClick="@{() -> viewModel.fabPressed()}" android:onClick="@{() -> viewModel.fabPressed()}"
android:focusable="true"
android:clickable="true"
app:fabSize="normal" app:fabSize="normal"
app:layout_behavior="com.google.android.material.floatingactionbutton.FloatingActionButton$Behavior" app:layout_behavior="com.google.android.material.floatingactionbutton.FloatingActionButton$Behavior"
app:srcCompat="@drawable/ic_add" /> app:srcCompat="@drawable/ic_add" />
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
</data> </data>
<TextView <TextView
android:focusable="true"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="monospace" android:fontFamily="monospace"
......
...@@ -94,6 +94,8 @@ ...@@ -94,6 +94,8 @@
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/hide_app_checkbox" android:id="@+id/hide_app_checkbox"
android:focusable="true"
android:clickable="true"
style="@style/Widget.Icon" style="@style/Widget.Icon"
isChecked="@{item.isHiddenState}" isChecked="@{item.isHiddenState}"
android:onClick="@{() -> item.toggle()}" android:onClick="@{() -> item.toggle()}"
......
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/hide_process_icon" android:id="@+id/hide_process_icon"
android:focusable="true"
android:clickable="true"
style="@style/Widget.Icon" style="@style/Widget.Icon"
isChecked="@{item.isHidden}" isChecked="@{item.isHidden}"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
......
...@@ -106,6 +106,8 @@ ...@@ -106,6 +106,8 @@
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/checkbox" android:id="@+id/checkbox"
android:focusable="true"
android:clickable="true"
style="@style/Widget.Icon" style="@style/Widget.Icon"
isChecked="@{item.isChecked}" isChecked="@{item.isChecked}"
android:layout_marginEnd="@dimen/margin_generic" android:layout_marginEnd="@dimen/margin_generic"
...@@ -127,6 +129,8 @@ ...@@ -127,6 +129,8 @@
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/delete" android:id="@+id/delete"
android:focusable="true"
android:clickable="true"
style="@style/Widget.Icon" style="@style/Widget.Icon"
srcCompat="@{item.isDeletable ? R.drawable.ic_undelete : R.drawable.ic_delete}" srcCompat="@{item.isDeletable ? R.drawable.ic_undelete : R.drawable.ic_delete}"
android:onClick="@{() -> item.toggleDelete()}" android:onClick="@{() -> item.toggleDelete()}"
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
items="@{item.items}" items="@{item.items}"
scrollPosition="@={viewModel.scrollPosition}" scrollPosition="@={viewModel.scrollPosition}"
scrollPositionSmooth="@{true}" scrollPositionSmooth="@{true}"
android:focusable="true"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
...@@ -39,6 +40,8 @@ ...@@ -39,6 +40,8 @@
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
hide="@{viewModel.scrollPosition == item.items.size - 1 || item.items.size == 0}" hide="@{viewModel.scrollPosition == item.items.size - 1 || item.items.size == 0}"
android:focusable="true"
android:clickable="true"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
......
...@@ -105,6 +105,8 @@ ...@@ -105,6 +105,8 @@
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/download" android:id="@+id/download"
android:focusable="true"
android:clickable="true"
style="@style/Widget.Icon" style="@style/Widget.Icon"
isEnabled="@{viewModel.isConnected}" isEnabled="@{viewModel.isConnected}"
android:alpha="@{viewModel.isConnected ? 1f : .2f}" android:alpha="@{viewModel.isConnected ? 1f : .2f}"
......
# v7.4.0 # v7.5.0
- Hide Magisk Manager with stub APKs on Android 9.0+. Not all devices will be supported, please refer to Magisk v20.1 release notes. - Support new communication method (ContentProvider)
- Allow customizing app name when hiding Magisk Manager - Fix several issues with hidden stub APK
- Generate random keys to sign the hidden Magisk Manager to prevent signature detections - Support using BiometricPrompt (face unlock)
- Fix fingerprint UI infinite loop
mount_partitions() { mount_partitions() {
[ "`getprop ro.build.ab_update`" = "true" ] && SLOT=`getprop ro.boot.slot_suffix` [ "`getprop ro.build.ab_update`" = "true" ] && SLOT=`getprop ro.boot.slot_suffix`
[ "`getprop ro.build.system_root_image`" = "true" ] && SYSTEM_ROOT=true || SYSTEM_ROOT=false # Check whether non rootfs root dir exists
grep ' / ' /proc/mounts | grep -qv 'rootfs' && SYSTEM_ROOT=true || SYSTEM_ROOT=false
} }
get_flags() { get_flags() {
......
...@@ -17,16 +17,6 @@ fix_env() { ...@@ -17,16 +17,6 @@ fix_env() {
cd / cd /
} }
run_migrations() {
# Move the stock backups
if [ -f /data/magisk/stock_boot* ]; then
mv /data/magisk/stock_boot* /data 2>/dev/null
fi
if [ -f /data/adb/magisk/stock_boot* ]; then
mv /data/adb/magisk/stock_boot* /data 2>/dev/null
fi
}
direct_install() { direct_install() {
rm -rf $MAGISKBIN/* 2>/dev/null rm -rf $MAGISKBIN/* 2>/dev/null
mkdir -p $MAGISKBIN 2>/dev/null mkdir -p $MAGISKBIN 2>/dev/null
...@@ -43,30 +33,43 @@ direct_install() { ...@@ -43,30 +33,43 @@ direct_install() {
return 0 return 0
} }
mm_patch_dtbo() { mm_patch_dtb() {
$KEEPVERITY && return 1 || patch_dtbo_image local result=1
local PATCHED=$TMPDIR/dt.patched
for name in dtb dtbo; do
local IMAGE=`find_block $name$SLOT`
if [ ! -z $IMAGE ]; then
if $MAGISKBIN/magiskboot dtb $IMAGE patch $PATCHED; then
result=0
if [ ! -z $SHA1 ]; then
# Backup stuffs
mkdir /data/magisk_backup_${SHA1} 2>/dev/null
cat $IMAGE | gzip -9 > /data/magisk_backup_${SHA1}/${name}.img.gz
fi
cat $PATCHED /dev/zero > $IMAGE
rm -f $PATCHED
fi
fi
done
return $result
} }
restore_imgs() { restore_imgs() {
local SHA1=`grep_prop SHA1 /sbin/.magisk/config`
[ -z $SHA1 ] && local SHA1=`cat /.backup/.sha1`
[ -z $SHA1 ] && return 1 [ -z $SHA1 ] && return 1
local STOCKBOOT=/data/stock_boot_${SHA1}.img.gz local BACKUPDIR=/data/magisk_backup_$SHA1
local STOCKDTBO=/data/stock_dtbo.img.gz [ -d $BACKUPDIR ] || return 1
[ -f $STOCKBOOT ] || return 1
get_flags get_flags
find_boot_image find_boot_image
find_dtbo_image
if [ -f $STOCKDTBO -a -b "$DTBOIMAGE" ]; then for name in dtb dtbo; do
flash_image $STOCKDTBO $DTBOIMAGE [ -f $BACKUPDIR/${name}.img.gz ] || continue
fi local IMAGE=`find_block $name$SLOT`
if [ -f $STOCKBOOT -a -b "$BOOTIMAGE" ]; then [ -z $IMAGE ] && continue
flash_image $STOCKBOOT $BOOTIMAGE flash_image $BACKUPDIR/${name}.img.gz $IMAGE
return 0 done
fi [ -f $BACKUPDIR/boot.img.gz ] || return 1
return 1 flash_image $BACKUPDIR/boot.img.gz $BOOTIMAGE
} }
post_ota() { post_ota() {
...@@ -119,3 +122,5 @@ force_pm_install() { ...@@ -119,3 +122,5 @@ force_pm_install() {
[ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 1 [ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 1
return $res return $res
} }
SHA1=`grep_prop SHA1 /sbin/.magisk/config`
...@@ -80,10 +80,10 @@ ...@@ -80,10 +80,10 @@
<string name="direct_install">Instal·lació directa (Recomanat)</string> <string name="direct_install">Instal·lació directa (Recomanat)</string>
<string name="install_inactive_slot">Instal·la a la ranura inactiva (Després d\'una OTA)</string> <string name="install_inactive_slot">Instal·la a la ranura inactiva (Després d\'una OTA)</string>
<string name="install_inactive_slot_msg">El teu dispositiu serà FORÇAT a arrancar en l\'actual ranura inactiva després del reinici!\nUtilitza aquesta opció NOMÉS quan l\'OTA s\'hagi fet.\nContinuar?</string> <string name="install_inactive_slot_msg">El teu dispositiu serà FORÇAT a arrancar en l\'actual ranura inactiva després del reinici!\nUtilitza aquesta opció NOMÉS quan l\'OTA s\'hagi fet.\nContinuar?</string>
<string name="select_method">Sel·lecciona un mètode</string> <string name="select_method">Selecciona un mètode</string>
<string name="setup_title">Instal·lació addicional</string> <string name="setup_title">Instal·lació addicional</string>
<string name="select_patch_file">Sel·lecciona i arranja un arxiu</string> <string name="select_patch_file">Selecciona i arranja un arxiu</string>
<string name="patch_file_msg">Sel·lecciona una imatge crua (*.img) o un ODIN tarfile (*.tar)</string> <string name="patch_file_msg">Selecciona una imatge crua (*.img) o un ODIN tarfile (*.tar)</string>
<string name="reboot_delay_toast">Reinici en 5 segons…</string> <string name="reboot_delay_toast">Reinici en 5 segons…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
...@@ -94,7 +94,6 @@ ...@@ -94,7 +94,6 @@
<string name="settings_reboot_toast">Reinicia per aplicar els canvis</string> <string name="settings_reboot_toast">Reinicia per aplicar els canvis</string>
<string name="release_notes">Notes de llançament</string> <string name="release_notes">Notes de llançament</string>
<string name="repo_cache_cleared">Memòria cau del repositori netejada</string> <string name="repo_cache_cleared">Memòria cau del repositori netejada</string>
<string name="dtbo_patched_title">S\'ha arranjat DTBO</string> <string name="dtbo_patched_title">S\'ha arranjat DTBO</string>
<string name="dtbo_patched_reboot">Magisk Manager ha arranjat dtbo.img. Si us plau, reinicia el telèfon.</string> <string name="dtbo_patched_reboot">Magisk Manager ha arranjat dtbo.img. Si us plau, reinicia el telèfon.</string>
<string name="flashing">Arranjament…</string> <string name="flashing">Arranjament…</string>
...@@ -110,18 +109,19 @@ ...@@ -110,18 +109,19 @@
<string name="restore_done">Restauració feta!</string> <string name="restore_done">Restauració feta!</string>
<string name="restore_fail">La còpia de seguretat de Stock no existeix!</string> <string name="restore_fail">La còpia de seguretat de Stock no existeix!</string>
<string name="proprietary_title">Baixar codi propietari</string> <string name="proprietary_title">Baixar codi propietari</string>
<string name="proprietary_notice">Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nPot permetre que Magisk Manager baixi una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet?</string> <string name="proprietary_notice">Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nVot permetre que Magisk Manager baixi una extensió que conté el GoogleApiClient per poder fer la comprovació de SafetyNet?</string>
<string name="setup_fail">Instal·lació fallida.</string> <string name="setup_fail">Instal·lació fallida.</string>
<string name="env_fix_title">Es requereix instal·lació addicional</string> <string name="env_fix_title">Es requereix instal·lació addicional</string>
<string name="env_fix_msg">El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es baixarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instalació ara?</string> <string name="env_fix_msg">El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es baixarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instal·lació ara?</string>
<string name="setup_msg">S\'està executant la configuració de l\'entorn…</string> <string name="setup_msg">S\'està executant la configuració de l\'entorn…</string>
<string name="authenticate">Autenticar</string>
<!--Settings Activity --> <!--Settings Activity -->
<string name="settings_general_category">General</string> <string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Tema fosc</string> <string name="settings_dark_theme_title">Tema fosc</string>
<string name="settings_dark_theme_summary">Habilitar el tema fosc</string> <string name="settings_dark_theme_summary">Habilitar el tema fosc</string>
<string name="settings_download_path_title">Directori de baixades</string> <string name="settings_download_path_title">Directori de baixades</string>
<string name="settings_download_path_message">Els arxius es desaràn a %1$s</string> <string name="settings_download_path_message">Els arxius es desaran a %1$s</string>
<string name="settings_clear_cache_title">Netejar memòria cau del repositori</string> <string name="settings_clear_cache_title">Netejar memòria cau del repositori</string>
<string name="settings_clear_cache_summary">Neteja l\'informació en memòria cau per als repositoris en línia, força a l\'aplicació a actualitzar-se en línia.</string> <string name="settings_clear_cache_summary">Neteja l\'informació en memòria cau per als repositoris en línia, força a l\'aplicació a actualitzar-se en línia.</string>
<string name="settings_hide_manager_title">Amagar Magisk Manager</string> <string name="settings_hide_manager_title">Amagar Magisk Manager</string>
...@@ -139,7 +139,7 @@ ...@@ -139,7 +139,7 @@
<string name="settings_update_custom">Personalitzat</string> <string name="settings_update_custom">Personalitzat</string>
<string name="settings_update_custom_msg">Inserta una URL personalitzada</string> <string name="settings_update_custom_msg">Inserta una URL personalitzada</string>
<string name="settings_core_only_title">Mode nucli de Magisk</string> <string name="settings_core_only_title">Mode nucli de Magisk</string>
<string name="settings_core_only_summary">Habilitar només les funcions principals, no es carregaran tots els mòduls. MagiskSU y MagiskHide seguirán habilitats</string> <string name="settings_core_only_summary">Habilitar només les funcions principals, no es carregaran tots els mòduls. MagiskSU y MagiskHide seguiran habilitats</string>
<string name="settings_magiskhide_summary">Amagar Magisk de varies deteccions</string> <string name="settings_magiskhide_summary">Amagar Magisk de varies deteccions</string>
<string name="settings_hosts_title">Systemless Hosts</string> <string name="settings_hosts_title">Systemless Hosts</string>
<string name="settings_hosts_summary">Suport per aplicacions tipus Adblock fora de la partició del sistema</string> <string name="settings_hosts_summary">Suport per aplicacions tipus Adblock fora de la partició del sistema</string>
...@@ -148,7 +148,7 @@ ...@@ -148,7 +148,7 @@
<string name="settings_app_name">Escriu el nom desitjat per l\'App</string> <string name="settings_app_name">Escriu el nom desitjat per l\'App</string>
<string name="settings_app_name_hint">Nou nom</string> <string name="settings_app_name_hint">Nou nom</string>
<string name="settings_app_name_helper">Es refarà l\'App amb aquest nom</string> <string name="settings_app_name_helper">Es refarà l\'App amb aquest nom</string>
<string name="settings_app_name_error">Format invàl·lid</string> <string name="settings_app_name_error">Format invàlid</string>
<string name="settings_su_app_adb">Aplicacions y ADB</string> <string name="settings_su_app_adb">Aplicacions y ADB</string>
<string name="settings_su_app">Només aplicacions</string> <string name="settings_su_app">Només aplicacions</string>
<string name="settings_su_adb">Només ADB</string> <string name="settings_su_adb">Només ADB</string>
...@@ -166,6 +166,9 @@ ...@@ -166,6 +166,9 @@
<string name="request_timeout_summary">%1$d segons</string> <string name="request_timeout_summary">%1$d segons</string>
<string name="settings_su_reauth_title">Demanar després d\'una actualització</string> <string name="settings_su_reauth_title">Demanar després d\'una actualització</string>
<string name="settings_su_reauth_summary">Demanar permisos de superusuari novament si una aplicació és actualitzada o reinstal·lada</string> <string name="settings_su_reauth_summary">Demanar permisos de superusuari novament si una aplicació és actualitzada o reinstal·lada</string>
<string name="settings_su_biometric_title">Activar autenticació biomètrica</string>
<string name="settings_su_biometric_summary">Utilitza l\'autenticació biomètrica per permetre solicituds de superusuari</string>
<string name="no_biometric">El dispositiu no suporta o no té establerta configuració biomètrica</string>
<string name="multiuser_mode">Mode Multiusuari</string> <string name="multiuser_mode">Mode Multiusuari</string>
<string name="settings_owner_only">Només Administrador del Dispositiu</string> <string name="settings_owner_only">Només Administrador del Dispositiu</string>
...@@ -182,7 +185,7 @@ ...@@ -182,7 +185,7 @@
<string name="global_summary">Totes les sessions d\'arrel utilitzen el suport Namespace Global</string> <string name="global_summary">Totes les sessions d\'arrel utilitzen el suport Namespace Global</string>
<string name="requester_summary">Les sessions d\'arrel heretaran les peticiones Namespace</string> <string name="requester_summary">Les sessions d\'arrel heretaran les peticiones Namespace</string>
<string name="isolate_summary">Totes les sessions d\'arrel tindran la seva pròpia Namespace</string> <string name="isolate_summary">Totes les sessions d\'arrel tindran la seva pròpia Namespace</string>
<string name="settings_download_path_error">Error al crear la carpeta. El directori ha de ser accesible desde el directori arrel i no pot ser un arxiu.</string> <string name="settings_download_path_error">Error al crear la carpeta. El directori ha de ser accessible des de el directori arrel i no pot ser un arxiu.</string>
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">Petició de superusuari</string> <string name="su_request_title">Petició de superusuari</string>
...@@ -216,6 +219,6 @@ ...@@ -216,6 +219,6 @@
<string name="command">Ordre: %1$s</string> <string name="command">Ordre: %1$s</string>
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">Mostra apps del sistema</string> <string name="show_system_app">Mostra Apps del sistema</string>
</resources> </resources>
This diff is collapsed.
This diff is collapsed.
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
<string name="settings">Ayarlar</string> <string name="settings">Ayarlar</string>
<string name="install">Yükle</string> <string name="install">Yükle</string>
<string name="unsupport_magisk_title">Desteklenmeyen Magisk Sürümü</string> <string name="unsupport_magisk_title">Desteklenmeyen Magisk Sürümü</string>
<string name="unsupport_magisk_msg">Magisk Manager\'ın bu sürümü, %1$s daha düşük Magisk versiyonlarını desteklememektedir.\n\nUygulama hiçbir Magisk kurulu değil gibi davranacak, lütfen en kısa zamanda Magisk\'i yükseltin.</string>
<!--Status Fragment--> <!--Status Fragment-->
<string name="magisk_version_error">Magisk yüklü değil</string> <string name="magisk_version_error">Magisk yüklü değil</string>
...@@ -94,7 +95,6 @@ ...@@ -94,7 +95,6 @@
<string name="settings_reboot_toast">Ayarları uygulamak için yeniden başlatın</string> <string name="settings_reboot_toast">Ayarları uygulamak için yeniden başlatın</string>
<string name="release_notes">Sürüm notları</string> <string name="release_notes">Sürüm notları</string>
<string name="repo_cache_cleared">Repo önbelleği temizlendi</string> <string name="repo_cache_cleared">Repo önbelleği temizlendi</string>
<string name="dtbo_patched_title">DTBO yamalandı!</string> <string name="dtbo_patched_title">DTBO yamalandı!</string>
<string name="dtbo_patched_reboot">Magisk Manager dtbo.img\'yi yamaladı, lütfen yeniden başlatın</string> <string name="dtbo_patched_reboot">Magisk Manager dtbo.img\'yi yamaladı, lütfen yeniden başlatın</string>
<string name="flashing">Yükleniyor</string> <string name="flashing">Yükleniyor</string>
...@@ -115,6 +115,7 @@ ...@@ -115,6 +115,7 @@
<string name="env_fix_title">Ek Kurulum Gerekli</string> <string name="env_fix_title">Ek Kurulum Gerekli</string>
<string name="env_fix_msg">Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz?</string> <string name="env_fix_msg">Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz?</string>
<string name="setup_msg">Ortam kurulumu çalışıyor…</string> <string name="setup_msg">Ortam kurulumu çalışıyor…</string>
<string name="authenticate">Kimlik doğrulaması</string>
<!--Settings Activity --> <!--Settings Activity -->
<string name="settings_general_category">Genel</string> <string name="settings_general_category">Genel</string>
...@@ -166,6 +167,9 @@ ...@@ -166,6 +167,9 @@
<string name="request_timeout_summary">%1$d saniye</string> <string name="request_timeout_summary">%1$d saniye</string>
<string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrula</string> <string name="settings_su_reauth_title">Yükseltmeden sonra yeniden kimlik doğrula</string>
<string name="settings_su_reauth_summary">Uygulama yükseltmeleri sonrasında yetkili kullanıcı izinlerini yeniden doğrula</string> <string name="settings_su_reauth_summary">Uygulama yükseltmeleri sonrasında yetkili kullanıcı izinlerini yeniden doğrula</string>
<string name="settings_su_biometric_title">Biyometrik Kimlik Doğrulamayı Etkinleştir</string>
<string name="settings_su_biometric_summary">Superuser isteklerine izin vermek için biyometrik kimlik doğrulamayı kullanın</string>
<string name="no_biometric">Desteklenmeyen cihaz veya biyometrik ayar etkinleştirilmemiş</string>
<string name="multiuser_mode">Çok Kullanıcılı Mod</string> <string name="multiuser_mode">Çok Kullanıcılı Mod</string>
<string name="settings_owner_only">Yalnızca Cihaz Sahibi</string> <string name="settings_owner_only">Yalnızca Cihaz Sahibi</string>
......
...@@ -167,7 +167,7 @@ ...@@ -167,7 +167,7 @@
<string name="request_timeout_summary">%1$d 秒</string> <string name="request_timeout_summary">%1$d 秒</string>
<string name="settings_su_reauth_title">更新後重新驗證</string> <string name="settings_su_reauth_title">更新後重新驗證</string>
<string name="settings_su_reauth_summary">應用程式更新後,重新驗證超級使用者的請求</string> <string name="settings_su_reauth_summary">應用程式更新後,重新驗證超級使用者的請求</string>
<string name="settings_su_biometric_title">啟用生物特徵驗證</string>
<string name="multiuser_mode">多重使用者模式</string> <string name="multiuser_mode">多重使用者模式</string>
<string name="settings_owner_only">僅限裝置擁有者</string> <string name="settings_owner_only">僅限裝置擁有者</string>
<string name="settings_owner_manage">由裝置擁有者管理</string> <string name="settings_owner_manage">由裝置擁有者管理</string>
......
...@@ -7,7 +7,7 @@ if (configPath.exists()) ...@@ -7,7 +7,7 @@ if (configPath.exists())
configPath.withInputStream { is -> props.load(is) } configPath.withInputStream { is -> props.load(is) }
buildscript { buildscript {
ext.vKotlin = '1.3.60' ext.vKotlin = '1.3.61'
repositories { repositories {
google() google()
...@@ -16,7 +16,7 @@ buildscript { ...@@ -16,7 +16,7 @@ buildscript {
maven { url 'https://kotlin.bintray.com/kotlinx' } maven { url 'https://kotlin.bintray.com/kotlinx' }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.2' classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${vKotlin}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${vKotlin}"
......
# Magisk Documentation # Magisk Documentation
(Updated on 2019.9.19) (Updated on 2020.1.2)
- [Installation](install.md) - [Installation](install.md)
- [Tutorials](tutorials.md) - [Tutorials](tutorials.md)
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
The following sections are for developers The following sections are for developers
- [Magisk Details](details.md)
- [Magisk Tools](tools.md)
- [Developer Guides](guides.md) - [Developer Guides](guides.md)
- [Magisk Tools](tools.md)
- [Internal Details](details.md)
- [Deployment](deploy.md) - [Deployment](deploy.md)
# Magisk Details # Internal Details
## File Structure ## File Structure
### Paths in "sbin tmpfs overlay" ### Paths in "sbin tmpfs overlay"
One of Magisk's breakthrough designs is sbin tmpfs overlay. It is required to support system-as-root devices, and also is the key to hiding Magisk from detection. All Magisk binaries, applets, mirrors, and other trivial stuffs are all located in the `tmpfs` mounted on `/sbin`. MagiskHide can just simply unmount `/sbin` and the bind mounts to hide all modifications easily. One of Magisk's breakthrough designs is sbin tmpfs overlay. It is required to support system-as-root devices, and also is the key to hiding Magisk from detection. All Magisk binaries, applets, mirrors, and other trivial stuffs are all located in the `tmpfs` mounted on `/sbin`. MagiskHide can just simply unmount `/sbin` and the bind mounts to hide all modifications easily.
......
This diff is collapsed.
...@@ -25,9 +25,11 @@ The concept of `magiskboot` is to make boot image modification simpler. For unpa ...@@ -25,9 +25,11 @@ The concept of `magiskboot` is to make boot image modification simpler. For unpa
Usage: magiskboot <action> [args...] Usage: magiskboot <action> [args...]
Supported actions: Supported actions:
unpack [-h] <bootimg> unpack [-n] [-h] <bootimg>
Unpack <bootimg> to, if available, kernel, kernel_dtb, ramdisk.cpio, Unpack <bootimg> to, if available, kernel, kernel_dtb, ramdisk.cpio,
second, dtb, extra, and recovery_dtbo into current directory. second, dtb, extra, and recovery_dtbo into current directory.
If '-n' is provided, it will not attempt to decompress kernel or
ramdisk.cpio from their original formats.
If '-h' is provided, it will dump header info to 'header', If '-h' is provided, it will dump header info to 'header',
which will be parsed when repacking. which will be parsed when repacking.
Return values: Return values:
...@@ -45,7 +47,7 @@ Supported actions: ...@@ -45,7 +47,7 @@ Supported actions:
cpio <incpio> [commands...] cpio <incpio> [commands...]
Do cpio commands to <incpio> (modifications are done directly) Do cpio commands to <incpio> (modifications are done directly)
Each command is a single argument, use quotes if necessary Each command is a single argument, add quotes for each command
Supported commands: Supported commands:
exists ENTRY exists ENTRY
Return 0 if ENTRY exists, else return 1 Return 0 if ENTRY exists, else return 1
...@@ -65,8 +67,9 @@ Supported actions: ...@@ -65,8 +67,9 @@ Supported actions:
Test the current cpio's patch status Test the current cpio's patch status
Return values: Return values:
0:stock 1:Magisk 2:unsupported (phh, SuperSU, Xposed) 0:stock 1:Magisk 2:unsupported (phh, SuperSU, Xposed)
patch KEEPVERITY KEEPFORCEENCRYPT patch
Ramdisk patches. KEEP**** are boolean values Apply ramdisk patches. Configure settings with env variables:
KEEPVERITY KEEPFORCEENCRYPT
backup ORIG backup ORIG
Create ramdisk backups from ORIG Create ramdisk backups from ORIG
restore restore
...@@ -74,17 +77,25 @@ Supported actions: ...@@ -74,17 +77,25 @@ Supported actions:
sha1 sha1
Print stock boot SHA1 if previously backed up in ramdisk Print stock boot SHA1 if previously backed up in ramdisk
dtb-<cmd> <dtb> dtb <input> <action> [args...]
Do dtb related cmds to <dtb> (modifications are done directly) Do dtb related actions to <input>
Supported commands: Supported actions:
dump print [-f]
Dump all contents from dtb for debugging Print all contents of dtb for debugging
test Specify [-f] to only print fstab nodes
Check if fstab has verity/avb flags patch [OUT]
Return values:
0:flag exists 1:no flags
patch
Search for fstab and remove verity/avb Search for fstab and remove verity/avb
If [OUT] is not specified, it will directly output to <input>
Configure with env variables: KEEPVERITY TWOSTAGEINIT
split <input>
Split image.*-dtb into kernel + kernel_dtb
sha1 <file>
Print the SHA1 checksum for <file>
cleanup
Cleanup the current working directory
compress[=method] <infile> [outfile] compress[=method] <infile> [outfile]
Compress <infile> with [method] (default: gzip), optionally to [outfile] Compress <infile> with [method] (default: gzip), optionally to [outfile]
...@@ -95,12 +106,6 @@ Supported actions: ...@@ -95,12 +106,6 @@ Supported actions:
Detect method and decompress <infile>, optionally to [outfile] Detect method and decompress <infile>, optionally to [outfile]
<infile>/[outfile] can be '-' to be STDIN/STDOUT <infile>/[outfile] can be '-' to be STDIN/STDOUT
Supported methods: bzip2 gzip lz4 lz4_legacy lzma xz Supported methods: bzip2 gzip lz4 lz4_legacy lzma xz
sha1 <file>
Print the SHA1 checksum for <file>
cleanup
Cleanup the current working directory
``` ```
### magiskinit ### magiskinit
...@@ -119,20 +124,22 @@ Usage: magiskpolicy [--options...] [policy statements...] ...@@ -119,20 +124,22 @@ Usage: magiskpolicy [--options...] [policy statements...]
Options: Options:
--help show help message for policy statements --help show help message for policy statements
--load FILE load policies from FILE --load FILE load policies from FILE
--load-split load from preloaded sepolicy or compile --load-split load from precompiled sepolicy or compile
split policies split policies
--compile-split compile split cil policies --compile-split compile split cil policies
--save FILE save policies to FILE --save FILE save policies to FILE
--live directly apply sepolicy live --live directly apply sepolicy live
--magisk inject built-in rules for a minimal --magisk inject built-in rules for a minimal
Magisk selinux environment Magisk selinux environment
--apply FILE apply rules from FILE, read and parsed
line by line as policy statements
If neither --load or --compile-split is specified, it will load If neither --load or --compile-split is specified, it will load
from current live policies (/sys/fs/selinux/policy) from current live policies (/sys/fs/selinux/policy)
One policy statement should be treated as one parameter; One policy statement should be treated as one parameter;
this means a full policy statement should be enclosed in quotes; this means a full policy statement should be enclosed in quotes.
multiple policy statements can be provided in a single command Multiple policy statements can be provided in a single command.
The statements has a format of "<rule_name> [args...]" The statements has a format of "<rule_name> [args...]"
Multiple types and permissions can be grouped into collections Multiple types and permissions can be grouped into collections
...@@ -173,10 +180,10 @@ Notes: ...@@ -173,10 +180,10 @@ Notes:
Example: allow { s1 s2 } { t1 t2 } class * Example: allow { s1 s2 } { t1 t2 } class *
Will be expanded to: Will be expanded to:
allow s1 t1 class { all permissions } allow s1 t1 class { all-permissions }
allow s1 t2 class { all permissions } allow s1 t2 class { all-permissions }
allow s2 t1 class { all permissions } allow s2 t1 class { all-permissions }
allow s2 t2 class { all permissions } allow s2 t2 class { all-permissions }
``` ```
...@@ -202,7 +209,6 @@ Advanced Options (Internal APIs): ...@@ -202,7 +209,6 @@ Advanced Options (Internal APIs):
--clone-attr SRC DEST clone permission, owner, and selinux context --clone-attr SRC DEST clone permission, owner, and selinux context
--clone SRC DEST clone SRC to DEST --clone SRC DEST clone SRC to DEST
--sqlite SQL exec SQL commands to Magisk database --sqlite SQL exec SQL commands to Magisk database
--use-broadcast use broadcast for su logging and notify
Supported init triggers: Supported init triggers:
post-fs-data, service, boot-complete post-fs-data, service, boot-complete
...@@ -269,5 +275,4 @@ Actions: ...@@ -269,5 +275,4 @@ Actions:
ls Print the current hide list ls Print the current hide list
exec CMDs... Execute commands in isolated mount exec CMDs... Execute commands in isolated mount
namespace and do all hide unmounts namespace and do all hide unmounts
test Run process monitor test
``` ```
...@@ -73,6 +73,7 @@ LOCAL_SRC_FILES := \ ...@@ -73,6 +73,7 @@ LOCAL_SRC_FILES := \
magiskpolicy/magiskpolicy.cpp \ magiskpolicy/magiskpolicy.cpp \
magiskpolicy/rules.cpp \ magiskpolicy/rules.cpp \
magiskpolicy/policydb.cpp \ magiskpolicy/policydb.cpp \
magiskpolicy/statement.cpp \
magiskpolicy/sepolicy.c magiskpolicy/sepolicy.c
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=magiskpolicy_main LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=magiskpolicy_main
...@@ -97,7 +98,6 @@ ifdef BB_INIT ...@@ -97,7 +98,6 @@ ifdef BB_INIT
LOCAL_STATIC_LIBRARIES := libsepol libxz libutils LOCAL_STATIC_LIBRARIES := libsepol libxz libutils
LOCAL_C_INCLUDES := \ LOCAL_C_INCLUDES := \
jni/include \ jni/include \
jni/magiskpolicy \
$(EXT_PATH)/include \ $(EXT_PATH)/include \
out \ out \
out/$(TARGET_ARCH_ABI) \ out/$(TARGET_ARCH_ABI) \
...@@ -106,13 +106,14 @@ LOCAL_C_INCLUDES := \ ...@@ -106,13 +106,14 @@ LOCAL_C_INCLUDES := \
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
init/init.cpp \ init/init.cpp \
init/early_mount.cpp \ init/mount.cpp \
init/rootdir.cpp \ init/rootdir.cpp \
init/getinfo.cpp \ init/getinfo.cpp \
magiskpolicy/api.cpp \ magiskpolicy/api.cpp \
magiskpolicy/magiskpolicy.cpp \ magiskpolicy/magiskpolicy.cpp \
magiskpolicy/rules.cpp \ magiskpolicy/rules.cpp \
magiskpolicy/policydb.cpp \ magiskpolicy/policydb.cpp \
magiskpolicy/statement.cpp \
magiskpolicy/sepolicy.c magiskpolicy/sepolicy.c
LOCAL_LDFLAGS := -static LOCAL_LDFLAGS := -static
......
...@@ -131,7 +131,7 @@ void node_entry::create_module_tree(const char *module) { ...@@ -131,7 +131,7 @@ void node_entry::create_module_tree(const char *module) {
auto full_path = get_path(); auto full_path = get_path();
snprintf(buf, PATH_MAX, "%s/%s%s", MODULEROOT, module, full_path.c_str()); snprintf(buf, PATH_MAX, "%s/%s%s", MODULEROOT, module, full_path.c_str());
unique_ptr<DIR, decltype(&closedir)> dir(xopendir(buf), closedir); auto dir = xopen_dir(buf);
if (!dir) if (!dir)
return; return;
...@@ -148,7 +148,7 @@ void node_entry::create_module_tree(const char *module) { ...@@ -148,7 +148,7 @@ void node_entry::create_module_tree(const char *module) {
return; return;
} }
for (struct dirent *entry; (entry = xreaddir(dir.get()));) { for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_name == "."sv || entry->d_name == ".."sv) if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue; continue;
// Create new node // Create new node
...@@ -207,22 +207,18 @@ void node_entry::create_module_tree(const char *module) { ...@@ -207,22 +207,18 @@ void node_entry::create_module_tree(const char *module) {
} }
void node_entry::clone_skeleton() { void node_entry::clone_skeleton() {
DIR *dir;
struct dirent *entry;
// Clone the structure // Clone the structure
auto full_path = get_path(); auto full_path = get_path();
snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path.c_str()); snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path.data());
if (!(dir = xopendir(buf))) if (auto dir = xopen_dir(buf); dir) {
return; for (dirent *entry; (entry = xreaddir(dir.get()));) {
while ((entry = xreaddir(dir))) {
if (entry->d_name == "."sv || entry->d_name == ".."sv) if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue; continue;
// Create dummy node // Create dummy node
auto dummy = new node_entry(entry->d_name, entry->d_type, IS_DUMMY); auto dummy = new node_entry(entry->d_name, entry->d_type, IS_DUMMY);
insert(dummy); insert(dummy);
} }
closedir(dir); } else { return; }
if (status & IS_SKEL) { if (status & IS_SKEL) {
file_attr attr; file_attr attr;
...@@ -321,13 +317,15 @@ static int bind_mount(const char *from, const char *to, bool log) { ...@@ -321,13 +317,15 @@ static int bind_mount(const char *from, const char *to, bool log) {
static bool magisk_env() { static bool magisk_env() {
LOGI("* Initializing Magisk environment\n"); LOGI("* Initializing Magisk environment\n");
string pkg;
check_manager(&pkg);
char install_dir[128];
sprintf(install_dir, "%s/0/%s/install", APP_DATA_DIR, pkg.data());
// Alternative binaries paths // Alternative binaries paths
constexpr const char *alt_bin[] = { const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", install_dir };
"/cache/data_adb/magisk", "/data/magisk", for (auto alt : alt_bin) {
"/data/data/com.topjohnwu.magisk/install",
"/data/user_de/0/com.topjohnwu.magisk/install"
};
for (auto &alt : alt_bin) {
struct stat st; struct stat st;
if (lstat(alt, &st) != -1) { if (lstat(alt, &st) != -1) {
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
...@@ -415,15 +413,9 @@ static bool magisk_env() { ...@@ -415,15 +413,9 @@ static bool magisk_env() {
} }
static void prepare_modules() { static void prepare_modules() {
const char *legacy_imgs[] = {SECURE_DIR "/magisk.img", SECURE_DIR "/magisk_merge.img"}; // Upgrade modules
for (auto img : legacy_imgs) { if (auto dir = open_dir(MODULEUPGRADE); dir) {
if (access(img, F_OK) == 0) for (dirent *entry; (entry = xreaddir(dir.get()));) {
migrate_img(img);
}
DIR *dir;
struct dirent *entry;
if ((dir = opendir(MODULEUPGRADE))) {
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) { if (entry->d_type == DT_DIR) {
if (entry->d_name == "."sv || entry->d_name == ".."sv) if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue; continue;
...@@ -436,7 +428,6 @@ static void prepare_modules() { ...@@ -436,7 +428,6 @@ static void prepare_modules() {
rename(buf2, buf); rename(buf2, buf);
} }
} }
closedir(dir);
rm_rf(MODULEUPGRADE); rm_rf(MODULEUPGRADE);
} }
bind_mount(MIRRDIR MODULEROOT, MODULEMNT, false); bind_mount(MIRRDIR MODULEROOT, MODULEMNT, false);
...@@ -458,51 +449,48 @@ static void reboot() { ...@@ -458,51 +449,48 @@ static void reboot() {
void remove_modules() { void remove_modules() {
LOGI("* Remove all modules and reboot"); LOGI("* Remove all modules and reboot");
chdir(MODULEROOT); auto dir = xopen_dir(MODULEROOT);
rm_rf("lost+found"); int dfd = dirfd(dir.get());
DIR *dir = xopendir("."); for (dirent *entry; (entry = xreaddir(dir.get()));) {
struct dirent *entry;
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) { if (entry->d_type == DT_DIR) {
if (entry->d_name == "."sv || entry->d_name == ".."sv || entry->d_name == ".core"sv) if (entry->d_name == "."sv || entry->d_name == ".."sv || entry->d_name == ".core"sv)
continue; continue;
chdir(entry->d_name);
close(creat("remove", 0644)); int modfd = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
chdir(".."); close(xopenat(modfd, "remove", O_RDONLY | O_CREAT | O_CLOEXEC));
close(modfd);
} }
} }
closedir(dir);
chdir("/");
reboot(); reboot();
} }
static void collect_modules() { static void collect_modules() {
chdir(MODULEROOT); auto dir = xopen_dir(MODULEROOT);
rm_rf("lost+found"); int dfd = dirfd(dir.get());
DIR *dir = xopendir("."); for (dirent *entry; (entry = xreaddir(dir.get()));) {
struct dirent *entry;
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) { if (entry->d_type == DT_DIR) {
if (entry->d_name == "."sv || entry->d_name == ".."sv || entry->d_name == ".core"sv) if (entry->d_name == "."sv || entry->d_name == ".."sv || entry->d_name == ".core"sv)
continue; continue;
chdir(entry->d_name);
if (access("remove", F_OK) == 0) { int modfd = xopenat(dfd, entry->d_name, O_RDONLY);
chdir(".."); run_finally f([=]{ close(modfd); });
if (faccessat(modfd, "remove", F_OK, 0) == 0) {
LOGI("%s: remove\n", entry->d_name); LOGI("%s: remove\n", entry->d_name);
sprintf(buf, "%s/uninstall.sh", entry->d_name); fd_pathat(modfd, "uninstall.sh", buf, sizeof(buf));
if (access(buf, F_OK) == 0) if (access(buf, F_OK) == 0)
exec_script(buf); exec_script(buf);
rm_rf(entry->d_name); frm_rf(modfd);
unlinkat(dfd, entry->d_name, AT_REMOVEDIR);
continue; continue;
} }
unlink("update");
if (access("disable", F_OK)) unlinkat(modfd, "update", 0);
if (faccessat(modfd, "disable", F_OK, 0) != 0)
module_list.emplace_back(entry->d_name); module_list.emplace_back(entry->d_name);
chdir("..");
} }
} }
closedir(dir);
chdir("/");
} }
static bool load_modules(node_entry *root) { static bool load_modules(node_entry *root) {
...@@ -510,36 +498,47 @@ static bool load_modules(node_entry *root) { ...@@ -510,36 +498,47 @@ static bool load_modules(node_entry *root) {
bool has_modules = false; bool has_modules = false;
for (const auto &m : module_list) { for (const auto &m : module_list) {
const auto module = m.c_str(); const auto module = m.data();
char *name = buf + snprintf(buf, sizeof(buf), MODULEROOT "/%s/", module);
// Read props // Read props
snprintf(buf, PATH_MAX, "%s/%s/system.prop", MODULEROOT, module); strcpy(name, "system.prop");
if (access(buf, F_OK) == 0) { if (access(buf, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module); LOGI("%s: loading [system.prop]\n", module);
load_prop_file(buf, false); load_prop_file(buf, false);
} }
// Copy sepolicy rules
strcpy(name, "sepolicy.rule");
if (access(MIRRDIR "/persist", F_OK) == 0 && access(buf, F_OK) == 0) {
char *p = buf2 + snprintf(buf2, sizeof(buf2), MIRRDIR "/persist/magisk/%s", module);
xmkdirs(buf2, 0755);
strcpy(p, "/sepolicy.rule");
cp_afc(buf, buf2);
}
// Check whether skip mounting // Check whether skip mounting
snprintf(buf, PATH_MAX, "%s/%s/skip_mount", MODULEROOT, module); strcpy(name, "skip_mount");
if (access(buf, F_OK) == 0) if (access(buf, F_OK) == 0)
continue; continue;
// Double check whether the system folder exists // Double check whether the system folder exists
snprintf(buf, PATH_MAX, "%s/%s/system", MODULEROOT, module); strcpy(name, "system");
if (access(buf, F_OK) == -1) if (access(buf, F_OK) != 0)
continue; continue;
// Construct structure // Construct structure
has_modules = true; has_modules = true;
LOGI("%s: constructing magic mount structure\n", module); LOGI("%s: constructing magic mount structure\n", module);
// If /system/vendor exists in module, create a link outside // If /system/vendor exists in module, create a link outside
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MODULEROOT, module); strcpy(name, "system/vendor");
if (node_entry::vendor_root && access(buf, F_OK) == 0) { if (node_entry::vendor_root && access(buf, F_OK) == 0) {
snprintf(buf2, PATH_MAX, "%s/%s/vendor", MODULEROOT, module); snprintf(buf2, sizeof(buf2), "%s/%s/vendor", MODULEROOT, module);
unlink(buf2); unlink(buf2);
xsymlink("./system/vendor", buf2); xsymlink("./system/vendor", buf2);
} }
// If /system/product exists in module, create a link outside // If /system/product exists in module, create a link outside
snprintf(buf, PATH_MAX, "%s/%s/system/product", MODULEROOT, module); strcpy(name, "system/product");
if (node_entry::product_root && access(buf, F_OK) == 0) { if (node_entry::product_root && access(buf, F_OK) == 0) {
snprintf(buf2, PATH_MAX, "%s/%s/product", MODULEROOT, module); snprintf(buf2, sizeof(buf2), "%s/%s/product", MODULEROOT, module);
unlink(buf2); unlink(buf2);
xsymlink("./system/product", buf2); xsymlink("./system/product", buf2);
} }
...@@ -575,15 +574,14 @@ static bool check_data() { ...@@ -575,15 +574,14 @@ static bool check_data() {
} }
void unlock_blocks() { void unlock_blocks() {
DIR *dir;
struct dirent *entry;
int fd, dev, OFF = 0; int fd, dev, OFF = 0;
if (!(dir = xopendir("/dev/block"))) auto dir = xopen_dir("/dev/block");
if (!dir)
return; return;
dev = dirfd(dir); dev = dirfd(dir.get());
while((entry = readdir(dir))) { for (dirent *entry; (entry = readdir(dir.get()));) {
if (entry->d_type == DT_BLK) { if (entry->d_type == DT_BLK) {
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0) if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
continue; continue;
...@@ -592,7 +590,6 @@ void unlock_blocks() { ...@@ -592,7 +590,6 @@ void unlock_blocks() {
close(fd); close(fd);
} }
} }
closedir(dir);
} }
static bool log_dump = false; static bool log_dump = false;
...@@ -664,22 +661,6 @@ void post_fs_data(int client) { ...@@ -664,22 +661,6 @@ void post_fs_data(int client) {
unblock_boot_process(); unblock_boot_process();
} }
#if 0
// Increment boot count
int boot_count = 0;
FILE *cf = fopen(BOOTCOUNT, "r");
if (cf) {
fscanf(cf, "%d", &boot_count);
fclose(cf);
}
boot_count++;
if (boot_count > 2)
creat(DISABLEFILE, 0644);
cf = xfopen(BOOTCOUNT, "w");
fprintf(cf, "%d", boot_count);
fclose(cf);
#endif
if (!magisk_env()) { if (!magisk_env()) {
LOGE("* Magisk environment setup incomplete, abort\n"); LOGE("* Magisk environment setup incomplete, abort\n");
unblock_boot_process(); unblock_boot_process();
...@@ -760,7 +741,6 @@ void late_start(int client) { ...@@ -760,7 +741,6 @@ void late_start(int client) {
auto_start_magiskhide(); auto_start_magiskhide();
// Run scripts after full patch, most reliable way to run scripts
LOGI("* Running service.d scripts\n"); LOGI("* Running service.d scripts\n");
exec_common_script("service"); exec_common_script("service");
...@@ -791,11 +771,9 @@ void boot_complete(int client) { ...@@ -791,11 +771,9 @@ void boot_complete(int client) {
rename(MANAGERAPK, "/data/magisk.apk"); rename(MANAGERAPK, "/data/magisk.apk");
install_apk("/data/magisk.apk"); install_apk("/data/magisk.apk");
} else { } else {
// Check whether we have a valid manager installed // Check whether we have manager installed
db_strings str; if (!check_manager()) {
get_db_strings(str, SU_MANAGER); // Install stub
if (validate_manager(str[SU_MANAGER], 0, nullptr)) {
// There is no manager installed, install the stub
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk"); exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk");
install_apk("/data/magisk.apk"); install_apk("/data/magisk.apk");
} }
......
...@@ -118,10 +118,10 @@ static void main_daemon() { ...@@ -118,10 +118,10 @@ static void main_daemon() {
// Unmount pre-init patches // Unmount pre-init patches
if (access(ROOTMNT, F_OK) == 0) { if (access(ROOTMNT, F_OK) == 0) {
file_readline(ROOTMNT, [](auto line) -> bool { file_readline(true, ROOTMNT, [](auto line) -> bool {
umount2(line.data(), MNT_DETACH); umount2(line.data(), MNT_DETACH);
return true; return true;
}, true); });
} }
LOGI(SHOW_VER(Magisk) " daemon started\n"); LOGI(SHOW_VER(Magisk) " daemon started\n");
......
...@@ -246,28 +246,41 @@ int get_uid_policy(su_access &su, int uid) { ...@@ -246,28 +246,41 @@ int get_uid_policy(su_access &su, int uid) {
return 0; return 0;
} }
int validate_manager(string &alt_pkg, int userid, struct stat *st) { 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;
}
bool validate_manager(string &pkg, int userid, struct stat *st) {
struct stat tmp_st; struct stat tmp_st;
if (st == nullptr) if (st == nullptr)
st = &tmp_st; st = &tmp_st;
// Prefer DE storage // Prefer DE storage
char app_path[128]; char app_path[128];
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, alt_pkg.empty() ? "xxx" : alt_pkg.data()); sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, pkg.data());
if (stat(app_path, st)) { if (pkg.empty() || stat(app_path, st)) {
// Check the official package name // Check the official package name
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid); sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid);
if (stat(app_path, st)) { if (stat(app_path, st)) {
LOGE("su: cannot find manager"); LOGE("su: cannot find manager");
memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));
alt_pkg.clear(); pkg.clear();
return 1; return false;
} else { } else {
// Switch to official package if exists // Switch to official package if exists
alt_pkg = JAVA_PACKAGE_NAME; pkg = JAVA_PACKAGE_NAME;
} }
} }
return 0; return true;
} }
void exec_sql(int client) { void exec_sql(int client) {
......
...@@ -26,37 +26,36 @@ void exec_script(const char *script) { ...@@ -26,37 +26,36 @@ void exec_script(const char *script) {
void exec_common_script(const char *stage) { void exec_common_script(const char *stage) {
char path[4096]; char path[4096];
DIR *dir; char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage);
struct dirent *entry; auto dir = xopen_dir(path);
sprintf(path, SECURE_DIR "/%s.d", stage); if (!dir)
if (!(dir = xopendir(path)))
return; return;
chdir(path);
bool pfs = strcmp(stage, "post-fs-data") == 0; int dfd = dirfd(dir.get());
while ((entry = xreaddir(dir))) { bool pfs = stage == "post-fs-data"sv;
*(name++) = '/';
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_type == DT_REG) { if (entry->d_type == DT_REG) {
if (access(entry->d_name, X_OK) == -1) if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
continue; continue;
LOGI("%s.d: exec [%s]\n", stage, entry->d_name); LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
strcpy(name, entry->d_name);
exec_t exec { exec_t exec {
.pre_exec = set_path, .pre_exec = set_path,
.fork = pfs ? fork_no_zombie : fork_dont_care .fork = pfs ? fork_no_zombie : fork_dont_care
}; };
if (pfs) if (pfs)
exec_command_sync(exec, "/system/bin/sh", entry->d_name); exec_command_sync(exec, "/system/bin/sh", path);
else else
exec_command(exec, "/system/bin/sh", entry->d_name); exec_command(exec, "/system/bin/sh", path);
} }
} }
closedir(dir);
chdir("/");
} }
void exec_module_script(const char *stage, const vector<string> &module_list) { void exec_module_script(const char *stage, const vector<string> &module_list) {
char path[4096]; char path[4096];
bool pfs = strcmp(stage, "post-fs-data") == 0; bool pfs = stage == "post-fs-data"sv;
for (auto &m : module_list) { for (auto &m : module_list) {
const char* module = m.c_str(); const char* module = m.c_str();
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage); sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
...@@ -74,33 +73,6 @@ void exec_module_script(const char *stage, const vector<string> &module_list) { ...@@ -74,33 +73,6 @@ void exec_module_script(const char *stage, const vector<string> &module_list) {
} }
} }
constexpr char migrate_script[] =
"MODULEROOT=" MODULEROOT R"EOF(
IMG=%s
MNT=/dev/img_mnt
e2fsck -yf $IMG
mkdir -p $MNT
for num in 0 1 2 3 4 5 6 7; do
losetup /dev/block/loop${num} $IMG || continue
mount -t ext4 /dev/block/loop${num} $MNT
rm -rf $MNT/lost+found $MNT/.core
magisk --clone $MNT $MODULEROOT
umount $MNT
rm -rf $MNT
losetup -d /dev/block/loop${num}
break
done
rm -rf $IMG
)EOF";
void migrate_img(const char *img) {
LOGI("* Migrating %s\n", img);
exec_t exec { .pre_exec = set_path };
char cmds[sizeof(migrate_script) + 128];
sprintf(cmds, migrate_script, img);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
}
constexpr char install_script[] = R"EOF( constexpr char install_script[] = R"EOF(
APK=%s APK=%s
log -t Magisk "apk_install: $APK" log -t Magisk "apk_install: $APK"
......
...@@ -68,7 +68,6 @@ void remove_modules(); ...@@ -68,7 +68,6 @@ void remove_modules();
void exec_script(const char *script); void exec_script(const char *script);
void exec_common_script(const char *stage); void exec_common_script(const char *stage);
void exec_module_script(const char *stage, const std::vector<std::string> &module_list); void exec_module_script(const char *stage, const std::vector<std::string> &module_list);
void migrate_img(const char *img);
void install_apk(const char *apk); void install_apk(const char *apk);
/************** /**************
......
...@@ -155,7 +155,8 @@ typedef std::function<bool(db_row&)> db_row_cb; ...@@ -155,7 +155,8 @@ typedef std::function<bool(db_row&)> db_row_cb;
int get_db_settings(db_settings &cfg, int key = -1); int get_db_settings(db_settings &cfg, int key = -1);
int get_db_strings(db_strings &str, int key = -1); int get_db_strings(db_strings &str, int key = -1);
int get_uid_policy(su_access &su, int uid); int get_uid_policy(su_access &su, int uid);
int validate_manager(std::string &alt_pkg, int userid, struct stat *st); bool check_manager(std::string *pkg = nullptr);
bool validate_manager(std::string &pkg, int userid, struct stat *st);
void exec_sql(int client); void exec_sql(int client);
char *db_exec(const char *sql); char *db_exec(const char *sql);
char *db_exec(const char *sql, const db_row_cb &fn); char *db_exec(const char *sql, const db_row_cb &fn);
......
/* magiskpolicy.h - Public API for policy patching
*/
#pragma once #pragma once
#include <stdlib.h> #include <stdlib.h>
...@@ -35,3 +32,8 @@ int sepol_exists(const char *source); ...@@ -35,3 +32,8 @@ int sepol_exists(const char *source);
// Built in rules // Built in rules
void sepol_magisk_rules(); void sepol_magisk_rules();
// Statement parsing
void parse_statement(const char *statement);
void load_rule_file(const char *file);
void statement_help();
...@@ -112,7 +112,7 @@ void load_kernel_info(cmdline *cmd) { ...@@ -112,7 +112,7 @@ void load_kernel_info(cmdline *cmd) {
cmd->slot[0] = '_'; cmd->slot[0] = '_';
strcpy(cmd->slot + 1, value); strcpy(cmd->slot + 1, value);
} else if (key == "skip_initramfs") { } else if (key == "skip_initramfs") {
cmd->system_as_root = true; cmd->skip_initramfs = true;
} else if (key == "androidboot.force_normal_boot") { } else if (key == "androidboot.force_normal_boot") {
cmd->force_normal_boot = value[0] == '1'; cmd->force_normal_boot = value[0] == '1';
} else if (key == "androidboot.android_dt_dir") { } else if (key == "androidboot.android_dt_dir") {
...@@ -143,13 +143,13 @@ void load_kernel_info(cmdline *cmd) { ...@@ -143,13 +143,13 @@ void load_kernel_info(cmdline *cmd) {
if (recovery_mode) { if (recovery_mode) {
LOGD("Running in recovery mode, waiting for key...\n"); LOGD("Running in recovery mode, waiting for key...\n");
cmd->system_as_root = !check_key_combo(); cmd->skip_initramfs = !check_key_combo();
} }
if (cmd->dt_dir[0] == '\0') if (cmd->dt_dir[0] == '\0')
strcpy(cmd->dt_dir, DEFAULT_DT_DIR); strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
LOGD("system_as_root=[%d]\n", cmd->system_as_root); LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs);
LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot); LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot);
LOGD("slot=[%s]\n", cmd->slot); LOGD("slot=[%s]\n", cmd->slot);
LOGD("dt_dir=[%s]\n", cmd->dt_dir); LOGD("dt_dir=[%s]\n", cmd->dt_dir);
......
...@@ -147,11 +147,11 @@ class TestInit : public BaseInit { ...@@ -147,11 +147,11 @@ class TestInit : public BaseInit {
public: public:
TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
void start() override { void start() override {
// Write init tests here // Place init tests here
} }
}; };
static void setup_test(const char *dir) { [[maybe_unused]] static int test_main(int argc, char *argv[]) {
// Log to console // Log to console
cmdline_logging(); cmdline_logging();
log_cb.ex = nop_ex; log_cb.ex = nop_ex;
...@@ -167,13 +167,21 @@ static void setup_test(const char *dir) { ...@@ -167,13 +167,21 @@ static void setup_test(const char *dir) {
mounts.emplace_back(me->mnt_dir); mounts.emplace_back(me->mnt_dir);
return true; return true;
}); });
for (auto m = mounts.rbegin(); m != mounts.rend(); ++m) for (auto &m : reversed(mounts))
xumount(m->data()); xumount(m.data());
// chroot jail // chroot jail
chdir(dir); chdir(dirname(argv[0]));
chroot("."); chroot(".");
chdir("/"); chdir("/");
cmdline cmd{};
load_kernel_info(&cmd);
auto init = make_unique<TestInit>(argv, &cmd);
init->start();
return 1;
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
...@@ -184,44 +192,34 @@ int main(int argc, char *argv[]) { ...@@ -184,44 +192,34 @@ int main(int argc, char *argv[]) {
return (*init_applet_main[i])(argc, argv); return (*init_applet_main[i])(argc, argv);
} }
if (argc > 1 && strcmp(argv[1], "-x") == 0) { #ifdef MAGISK_DEBUG
if (strcmp(argv[2], "magisk") == 0) 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); return dump_magisk(argv[3], 0755);
else if (strcmp(argv[2], "manager") == 0) else if (argv[2] == "manager"sv)
return dump_manager(argv[3], 0644); return dump_manager(argv[3], 0644);
} }
if (argc > 1 && argv[1] == "selinux_setup"sv) {
auto init = make_unique<SecondStageInit>(argv);
init->start();
}
#ifdef MAGISK_DEBUG
bool run_test = getenv("INIT_TEST") != nullptr;
#else
constexpr bool run_test = false;
#endif
if (run_test) {
setup_test(dirname(argv[0]));
} else {
if (getpid() != 1) if (getpid() != 1)
return 1; return 1;
setup_klog(); setup_klog();
}
unique_ptr<BaseInit> init;
cmdline cmd{}; cmdline cmd{};
if (argc > 1 && argv[1] == "selinux_setup"sv) {
init = make_unique<SecondStageInit>(argv);
} else {
// This will also mount /sys and /proc
load_kernel_info(&cmd); load_kernel_info(&cmd);
unique_ptr<BaseInit> init; if (cmd.force_normal_boot) {
if (run_test) {
init = make_unique<TestInit>(argv, &cmd);
} else if (cmd.force_normal_boot) {
init = make_unique<ABFirstStageInit>(argv, &cmd); init = make_unique<ABFirstStageInit>(argv, &cmd);
} else if (cmd.system_as_root) { } else if (cmd.skip_initramfs) {
if (access("/overlay", F_OK) == 0) /* Compatible mode */
init = make_unique<SARCompatInit>(argv, &cmd);
else
init = make_unique<SARInit>(argv, &cmd); init = make_unique<SARInit>(argv, &cmd);
} else { } else {
decompress_ramdisk(); decompress_ramdisk();
...@@ -232,6 +230,7 @@ int main(int argc, char *argv[]) { ...@@ -232,6 +230,7 @@ int main(int argc, char *argv[]) {
else else
init = make_unique<RootFSInit>(argv, &cmd); init = make_unique<RootFSInit>(argv, &cmd);
} }
}
// Run the main routine // Run the main routine
init->start(); init->start();
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <vector> #include <vector>
#include <magisk.h>
struct cmdline { struct cmdline {
bool system_as_root; bool skip_initramfs;
bool force_normal_boot; bool force_normal_boot;
char slot[3]; char slot[3];
char dt_dir[128]; char dt_dir[128];
...@@ -45,7 +47,7 @@ protected: ...@@ -45,7 +47,7 @@ protected:
virtual void cleanup(); virtual void cleanup();
public: public:
BaseInit(char *argv[], cmdline *cmd) : BaseInit(char *argv[], cmdline *cmd) :
cmd(cmd), argv(argv), mount_list{"/sys", "/proc", "/dev"} {} cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {}
virtual ~BaseInit() = default; virtual ~BaseInit() = default;
virtual void start() = 0; virtual void start() = 0;
}; };
...@@ -53,28 +55,14 @@ public: ...@@ -53,28 +55,14 @@ public:
class MagiskInit : public BaseInit { class MagiskInit : public BaseInit {
protected: protected:
raw_data self; raw_data self;
const char *persist_dir;
virtual void early_mount() = 0; virtual void early_mount() = 0;
bool read_dt_fstab(const char *name, char *partname, char *fstype);
bool patch_sepolicy(const char *file = "/sepolicy"); bool patch_sepolicy(const char *file = "/sepolicy");
public: public:
MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
}; };
class RootFSBase : public MagiskInit {
protected:
int root = -1;
virtual void setup_rootfs();
public:
RootFSBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {};
void start() override {
early_mount();
setup_rootfs();
exec_init();
}
};
class SARBase : public MagiskInit { class SARBase : public MagiskInit {
protected: protected:
raw_data config; raw_data config;
...@@ -83,7 +71,9 @@ protected: ...@@ -83,7 +71,9 @@ protected:
void backup_files(); void backup_files();
void patch_rootdir(); void patch_rootdir();
public: public:
SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}; SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
persist_dir = MIRRDIR "/persist/magisk";
}
void start() override { void start() override {
early_mount(); early_mount();
patch_rootdir(); patch_rootdir();
...@@ -96,7 +86,7 @@ public: ...@@ -96,7 +86,7 @@ public:
* *************/ * *************/
class ABFirstStageInit : public BaseInit { class ABFirstStageInit : public BaseInit {
protected: private:
void prepare(); void prepare();
public: public:
ABFirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; ABFirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
...@@ -107,7 +97,7 @@ public: ...@@ -107,7 +97,7 @@ public:
}; };
class AFirstStageInit : public BaseInit { class AFirstStageInit : public BaseInit {
protected: private:
void prepare(); void prepare();
public: public:
AFirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; AFirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
...@@ -140,26 +130,26 @@ public: ...@@ -140,26 +130,26 @@ public:
* Initramfs * Initramfs
* **********/ * **********/
class RootFSInit : public RootFSBase { class RootFSInit : public MagiskInit {
private:
int root = -1;
void setup_rootfs();
protected: protected:
void early_mount() override; void early_mount() override;
public: public:
RootFSInit(char *argv[], cmdline *cmd) : RootFSBase(argv, cmd) {}; RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
}; persist_dir = "/dev/.magisk/mirror/persist/magisk";
}
/* ****************
* Compat-mode SAR
* ****************/
class SARCompatInit : public RootFSBase { void start() override {
protected: early_mount();
void early_mount() override; setup_rootfs();
void setup_rootfs() override; exec_init();
public: }
SARCompatInit(char *argv[], cmdline *cmd) : RootFSBase(argv, cmd) {};
}; };
void load_kernel_info(cmdline *cmd); void load_kernel_info(cmdline *cmd);
int dump_magisk(const char *path, mode_t mode); int dump_magisk(const char *path, mode_t mode);
int magisk_proxy_main(int argc, char *argv[]); int magisk_proxy_main(int argc, char *argv[]);
void setup_klog(); void setup_klog();
void mount_sbin();
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utils.h> #include <utils.h>
#include <logging.h> #include <logging.h>
#include <selinux.h> #include <selinux.h>
#include <magisk.h>
#include "init.h" #include "init.h"
...@@ -20,13 +21,17 @@ struct devinfo { ...@@ -20,13 +21,17 @@ struct devinfo {
static vector<devinfo> dev_list; static vector<devinfo> dev_list;
static char partname[32];
static char fstype[32];
static char block_dev[64];
static void parse_device(devinfo *dev, const char *uevent) { static void parse_device(devinfo *dev, const char *uevent) {
dev->partname[0] = '\0'; dev->partname[0] = '\0';
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool { parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
if (key == "MAJOR") if (key == "MAJOR")
dev->major = atoi(value.data()); dev->major = parse_int(value.data());
else if (key == "MINOR") else if (key == "MINOR")
dev->minor = atoi(value.data()); dev->minor = parse_int(value.data());
else if (key == "DEVNAME") else if (key == "DEVNAME")
strcpy(dev->devname, value.data()); strcpy(dev->devname, value.data());
else if (key == "PARTNAME") else if (key == "PARTNAME")
...@@ -38,35 +43,33 @@ static void parse_device(devinfo *dev, const char *uevent) { ...@@ -38,35 +43,33 @@ static void parse_device(devinfo *dev, const char *uevent) {
static void collect_devices() { static void collect_devices() {
char path[128]; char path[128];
struct dirent *entry; devinfo dev{};
devinfo dev; if (auto dir = xopen_dir("/sys/dev/block"); dir) {
DIR *dir = xopendir("/sys/dev/block"); for (dirent *entry; (entry = readdir(dir.get()));) {
if (dir == nullptr)
return;
while ((entry = readdir(dir))) {
if (entry->d_name == "."sv || entry->d_name == ".."sv) if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue; continue;
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name); sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
parse_device(&dev, path); parse_device(&dev, path);
dev_list.push_back(dev); dev_list.push_back(dev);
} }
closedir(dir); }
} }
static dev_t setup_block(const char *partname, char *block_dev = nullptr) { static int64_t setup_block(bool write_block = true) {
if (dev_list.empty()) if (dev_list.empty())
collect_devices(); collect_devices();
for (;;) { xmkdir("/dev", 0755);
xmkdir("/dev/block", 0755);
for (int tries = 0; tries < 3; ++tries) {
for (auto &dev : dev_list) { for (auto &dev : dev_list) {
if (strcasecmp(dev.partname, partname) == 0) { if (strcasecmp(dev.partname, partname) == 0) {
xmkdir("/dev", 0755); if (write_block) {
if (block_dev) {
sprintf(block_dev, "/dev/block/%s", dev.devname); sprintf(block_dev, "/dev/block/%s", dev.devname);
xmkdir("/dev/block", 0755);
} }
LOGD("Found %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor); LOGD("Found %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
dev_t rdev = makedev(dev.major, dev.minor); dev_t rdev = makedev(dev.major, dev.minor);
mknod(block_dev ? block_dev : "/dev/root", S_IFBLK | 0600, rdev); mknod(block_dev, S_IFBLK | 0600, rdev);
return rdev; return rdev;
} }
} }
...@@ -75,6 +78,9 @@ static dev_t setup_block(const char *partname, char *block_dev = nullptr) { ...@@ -75,6 +78,9 @@ static dev_t setup_block(const char *partname, char *block_dev = nullptr) {
dev_list.clear(); dev_list.clear();
collect_devices(); collect_devices();
} }
// The requested partname does not exist
return -1;
} }
static bool is_lnk(const char *name) { static bool is_lnk(const char *name) {
...@@ -84,15 +90,7 @@ static bool is_lnk(const char *name) { ...@@ -84,15 +90,7 @@ static bool is_lnk(const char *name) {
return S_ISLNK(st.st_mode); return S_ISLNK(st.st_mode);
} }
void BaseInit::cleanup() { static bool read_dt_fstab(cmdline *cmd, const char *name) {
// Unmount in reverse order
for (auto &p : reversed(mount_list)) {
LOGD("Unmount [%s]\n", p.data());
umount(p.data());
}
}
bool MagiskInit::read_dt_fstab(const char *name, char *partname, char *fstype) {
char path[128]; char path[128];
int fd; int fd;
sprintf(path, "%s/fstab/%s/dev", cmd->dt_dir, name); sprintf(path, "%s/fstab/%s/dev", cmd->dt_dir, name);
...@@ -112,18 +110,10 @@ bool MagiskInit::read_dt_fstab(const char *name, char *partname, char *fstype) { ...@@ -112,18 +110,10 @@ bool MagiskInit::read_dt_fstab(const char *name, char *partname, char *fstype) {
return false; return false;
} }
static char partname[32];
static char fstype[32];
static char block_dev[64];
#define link_root(name) \
if (is_lnk("/system_root" name)) \
cp_afc("/system_root" name, name)
#define mount_root(name) \ #define mount_root(name) \
if (!is_lnk("/" #name) && read_dt_fstab(#name, partname, fstype)) { \ if (!is_lnk("/" #name) && read_dt_fstab(cmd, #name)) { \
LOGD("Early mount " #name "\n"); \ LOGD("Early mount " #name "\n"); \
setup_block(partname, block_dev); \ setup_block(); \
xmkdir("/" #name, 0755); \ xmkdir("/" #name, 0755); \
xmount(block_dev, "/" #name, fstype, MS_RDONLY, nullptr); \ xmount(block_dev, "/" #name, fstype, MS_RDONLY, nullptr); \
mount_list.emplace_back("/" #name); \ mount_list.emplace_back("/" #name); \
...@@ -136,31 +126,14 @@ void RootFSInit::early_mount() { ...@@ -136,31 +126,14 @@ void RootFSInit::early_mount() {
root = xopen("/", O_RDONLY | O_CLOEXEC); root = xopen("/", O_RDONLY | O_CLOEXEC);
rename("/.backup/init", "/init"); rename("/.backup/init", "/init");
mount_root(system); // Mount sbin overlay for persist, but move it and add to cleanup list
mount_root(vendor); mount_sbin();
mount_root(product); xmount("/sbin", "/dev", nullptr, MS_MOVE, nullptr);
mount_root(odm); mount_list.emplace_back("/dev");
} mount_list.emplace_back("/dev/.magisk/mirror/persist");
mount_list.emplace_back("/dev/.magisk/mirror/cache");
void SARCompatInit::early_mount() {
full_read("/init", self.buf, self.sz);
LOGD("Cleaning rootfs\n"); mount_root(system);
root = xopen("/", O_RDONLY | O_CLOEXEC);
frm_rf(root, { ".backup", "overlay", "overlay.d", "proc", "sys" });
LOGD("Early mount system_root\n");
sprintf(partname, "system%s", cmd->slot);
setup_block(partname, block_dev);
xmkdir("/system_root", 0755);
if (xmount(block_dev, "/system_root", "ext4", MS_RDONLY, nullptr))
xmount(block_dev, "/system_root", "erofs", MS_RDONLY, nullptr);
xmkdir("/system", 0755);
xmount("/system_root/system", "/system", nullptr, MS_BIND, nullptr);
link_root("/vendor");
link_root("/product");
link_root("/odm");
mount_root(vendor); mount_root(vendor);
mount_root(product); mount_root(product);
mount_root(odm); mount_root(odm);
...@@ -203,6 +176,7 @@ void SARInit::early_mount() { ...@@ -203,6 +176,7 @@ void SARInit::early_mount() {
// Make dev writable // Make dev writable
xmkdir("/dev", 0755); xmkdir("/dev", 0755);
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755"); xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
mount_list.emplace_back("/dev");
backup_files(); backup_files();
...@@ -213,7 +187,19 @@ void SARInit::early_mount() { ...@@ -213,7 +187,19 @@ void SARInit::early_mount() {
LOGD("Early mount system_root\n"); LOGD("Early mount system_root\n");
sprintf(partname, "system%s", cmd->slot); sprintf(partname, "system%s", cmd->slot);
system_dev = setup_block(partname); strcpy(block_dev, "/dev/root");
auto dev = setup_block(false);
if (dev < 0) {
// Try NVIDIA naming scheme
strcpy(partname, "APP");
dev = setup_block();
if (dev < 0) {
// We don't really know what to do at this point...
LOGE("Cannot find root partition, abort\n");
exit(1);
}
}
system_dev = dev;
xmkdir("/system_root", 0755); xmkdir("/system_root", 0755);
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr)) if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr); xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
...@@ -245,3 +231,42 @@ void SecondStageInit::early_mount() { ...@@ -245,3 +231,42 @@ void SecondStageInit::early_mount() {
switch_root("/system_root"); switch_root("/system_root");
} }
void BaseInit::cleanup() {
// Unmount in reverse order
for (auto &p : reversed(mount_list)) {
if (xumount(p.data()) == 0)
LOGD("Unmount [%s]\n", p.data());
}
mount_list.clear();
mount_list.shrink_to_fit();
}
void mount_sbin() {
LOGD("Mount /sbin tmpfs overlay\n");
xmount("tmpfs", "/sbin", "tmpfs", 0, "mode=755");
xmkdir(MAGISKTMP, 0755);
xmkdir(MIRRDIR, 0);
xmkdir(BLOCKDIR, 0);
// Mount persist partition
strcpy(partname, "persist");
strcpy(block_dev, BLOCKDIR "/persist");
const char *mnt_point = MIRRDIR "/persist";
if (setup_block(false) < 0) {
// Fallback to cache
strcpy(partname, "cache");
strcpy(block_dev, BLOCKDIR "/cache");
if (setup_block(false) < 0) {
// Try NVIDIA's BS
strcpy(partname, "CAC");
if (setup_block(false) < 0)
return;
}
mnt_point = MIRRDIR "/cache";
xsymlink("./cache", MIRRDIR "/persist");
}
xmkdir(mnt_point, 0755);
xmount(block_dev, mnt_point, "ext4", 0, nullptr);
}
...@@ -24,7 +24,7 @@ static void patch_socket_name(const char *path) { ...@@ -24,7 +24,7 @@ static void patch_socket_name(const char *path) {
mmap_rw(path, buf, size); mmap_rw(path, buf, size);
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) { if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) {
gen_rand_str(buf + i, sizeof(MAIN_SOCKET)); gen_rand_str(buf + i, 16);
i += sizeof(MAIN_SOCKET); i += sizeof(MAIN_SOCKET);
} }
} }
...@@ -85,7 +85,7 @@ static void load_overlay_rc(int dirfd) { ...@@ -85,7 +85,7 @@ static void load_overlay_rc(int dirfd) {
rewinddir(dir); rewinddir(dir);
} }
void RootFSBase::setup_rootfs() { void RootFSInit::setup_rootfs() {
if (patch_sepolicy()) { if (patch_sepolicy()) {
char *addr; char *addr;
size_t size; size_t size;
...@@ -101,17 +101,8 @@ void RootFSBase::setup_rootfs() { ...@@ -101,17 +101,8 @@ void RootFSBase::setup_rootfs() {
munmap(addr, size); munmap(addr, size);
} }
// Handle legacy overlays
int fd = open("/overlay", O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
LOGD("Merge overlay folder\n");
mv_dir(fd, root);
close(fd);
rmdir("/overlay");
}
// Handle overlays // Handle overlays
fd = open("/overlay.d", O_RDONLY | O_CLOEXEC); int fd = open("/overlay.d", O_RDONLY | O_CLOEXEC);
if (fd >= 0) { if (fd >= 0) {
LOGD("Merge overlay.d\n"); LOGD("Merge overlay.d\n");
load_overlay_rc(fd); load_overlay_rc(fd);
...@@ -141,16 +132,6 @@ void RootFSBase::setup_rootfs() { ...@@ -141,16 +132,6 @@ void RootFSBase::setup_rootfs() {
close(fd); close(fd);
} }
void SARCompatInit::setup_rootfs() {
// Clone rootfs
LOGD("Clone root dir from system to rootfs\n");
int system_root = xopen("/system_root", O_RDONLY | O_CLOEXEC);
clone_dir(system_root, root, false);
close(system_root);
RootFSBase::setup_rootfs();
}
bool MagiskInit::patch_sepolicy(const char *file) { bool MagiskInit::patch_sepolicy(const char *file) {
bool patch_init = false; bool patch_init = false;
...@@ -174,7 +155,23 @@ bool MagiskInit::patch_sepolicy(const char *file) { ...@@ -174,7 +155,23 @@ bool MagiskInit::patch_sepolicy(const char *file) {
sepol_magisk_rules(); sepol_magisk_rules();
sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL); sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL);
// Custom rules
if (auto dir = xopen_dir(persist_dir); dir) {
char path[4096];
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue;
snprintf(path, sizeof(path), "%s/%s/sepolicy.rule", persist_dir, entry->d_name);
if (access(path, R_OK) == 0) {
LOGD("Loading custom sepolicy patch: %s\n", path);
load_rule_file(path);
}
}
}
dump_policydb(file); dump_policydb(file);
destroy_policydb();
// Remove OnePlus stupid debug sepolicy and use our own // Remove OnePlus stupid debug sepolicy and use our own
if (access("/sepolicy_debug", F_OK) == 0) { if (access("/sepolicy_debug", F_OK) == 0) {
...@@ -192,8 +189,7 @@ constexpr const char wrapper[] = ...@@ -192,8 +189,7 @@ constexpr const char wrapper[] =
; ;
static void sbin_overlay(const raw_data &self, const raw_data &config) { static void sbin_overlay(const raw_data &self, const raw_data &config) {
LOGD("Mount /sbin tmpfs overlay\n"); mount_sbin();
xmount("tmpfs", "/sbin", "tmpfs", 0, "mode=755");
// Dump binaries // Dump binaries
xmkdir(MAGISKTMP, 0755); xmkdir(MAGISKTMP, 0755);
...@@ -225,6 +221,48 @@ static void sbin_overlay(const raw_data &self, const raw_data &config) { ...@@ -225,6 +221,48 @@ static void sbin_overlay(const raw_data &self, const raw_data &config) {
xsymlink("./magiskinit", "/sbin/supolicy"); xsymlink("./magiskinit", "/sbin/supolicy");
} }
static void recreate_sbin(const char *mirror) {
int src = xopen(mirror, O_RDONLY | O_CLOEXEC);
int dest = xopen("/sbin", O_RDONLY | O_CLOEXEC);
DIR *fp = fdopendir(src);
char buf[256];
bool use_bind_mount = true;
for (dirent *entry; (entry = xreaddir(fp));) {
if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue;
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));
xsymlinkat(buf, dest, entry->d_name);
} else {
char sbin_path[256];
sprintf(buf, "%s/%s", mirror, entry->d_name);
sprintf(sbin_path, "/sbin/%s", entry->d_name);
if (use_bind_mount) {
// Create dummy
if (S_ISDIR(st.st_mode))
xmkdir(sbin_path, st.st_mode & 0777);
else
close(xopen(sbin_path, O_CREAT | O_WRONLY | O_CLOEXEC, st.st_mode & 0777));
if (xmount(buf, sbin_path, nullptr, MS_BIND, nullptr)) {
// Bind mount failed, fallback to symlink
remove(sbin_path);
use_bind_mount = false;
} else {
continue;
}
}
xsymlink(buf, sbin_path);
}
}
close(src);
close(dest);
}
#define ROOTMIR MIRRDIR "/system_root" #define ROOTMIR MIRRDIR "/system_root"
#define ROOTBLK BLOCKDIR "/system_root" #define ROOTBLK BLOCKDIR "/system_root"
#define MONOPOLICY "/sepolicy" #define MONOPOLICY "/sepolicy"
...@@ -260,47 +298,19 @@ void SARBase::patch_rootdir() { ...@@ -260,47 +298,19 @@ void SARBase::patch_rootdir() {
sbin_overlay(self, config); sbin_overlay(self, config);
// Mount system_root mirror // Mount system_root mirror
xmkdir(MIRRDIR, 0); xmkdir(ROOTMIR, 0755);
xmkdir(ROOTMIR, 0);
xmkdir(BLOCKDIR, 0);
mknod(ROOTBLK, S_IFBLK | 0600, system_dev); mknod(ROOTBLK, S_IFBLK | 0600, system_dev);
if (xmount(ROOTBLK, ROOTMIR, "ext4", MS_RDONLY, nullptr)) if (xmount(ROOTBLK, ROOTMIR, "ext4", MS_RDONLY, nullptr))
xmount(ROOTBLK, ROOTMIR, "erofs", MS_RDONLY, nullptr); xmount(ROOTBLK, ROOTMIR, "erofs", MS_RDONLY, nullptr);
// Recreate original sbin structure // Recreate original sbin structure
int src = xopen(ROOTMIR "/sbin", O_RDONLY | O_CLOEXEC); recreate_sbin(ROOTMIR "/sbin");
int dest = xopen("/sbin", O_RDONLY | O_CLOEXEC);
DIR *fp = fdopendir(src);
struct dirent *entry;
struct stat st;
char buf[256];
while ((entry = xreaddir(fp))) {
if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue;
fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
if (S_ISLNK(st.st_mode)) {
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
xsymlinkat(buf, dest, entry->d_name);
} else {
char spath[256];
sprintf(buf, "/sbin/%s", entry->d_name);
sprintf(spath, ROOTMIR "/sbin/%s", entry->d_name);
// Create dummy
if (S_ISDIR(st.st_mode))
xmkdir(buf, st.st_mode & 0777);
else
close(xopen(buf, O_CREAT | O_WRONLY | O_CLOEXEC, st.st_mode & 0777));
xmount(spath, buf, nullptr, MS_BIND, nullptr);
}
}
close(src);
close(dest);
// Patch init // Patch init
raw_data init; raw_data init;
file_attr attr; file_attr attr;
bool redirect = false; bool redirect = false;
src = xopen("/init", O_RDONLY | O_CLOEXEC); int src = xopen("/init", O_RDONLY | O_CLOEXEC);
fd_full_read(src, init.buf, init.sz); fd_full_read(src, init.buf, init.sz);
fgetattr(src, &attr); fgetattr(src, &attr);
close(src); close(src);
...@@ -320,7 +330,7 @@ void SARBase::patch_rootdir() { ...@@ -320,7 +330,7 @@ void SARBase::patch_rootdir() {
} }
} }
xmkdir(ROOTOVL, 0); xmkdir(ROOTOVL, 0);
dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC); int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC);
xwrite(dest, init.buf, init.sz); xwrite(dest, init.buf, init.sz);
fsetattr(dest, &attr); fsetattr(dest, &attr);
close(dest); close(dest);
...@@ -423,17 +433,16 @@ static void patch_fstab(const string &fstab) { ...@@ -423,17 +433,16 @@ static void patch_fstab(const string &fstab) {
#define FSR "/first_stage_ramdisk" #define FSR "/first_stage_ramdisk"
void ABFirstStageInit::prepare() { void ABFirstStageInit::prepare() {
DIR *dir = xopendir(FSR); auto dir = xopen_dir(FSR);
if (!dir) if (!dir)
return; return;
string fstab(FSR "/"); string fstab(FSR "/");
for (dirent *de; (de = readdir(dir));) { for (dirent *de; (de = xreaddir(dir.get()));) {
if (strstr(de->d_name, "fstab")) { if (strstr(de->d_name, "fstab")) {
fstab += de->d_name; fstab += de->d_name;
break; break;
} }
} }
closedir(dir);
if (fstab.length() == sizeof(FSR)) if (fstab.length() == sizeof(FSR))
return; return;
...@@ -450,14 +459,13 @@ void ABFirstStageInit::prepare() { ...@@ -450,14 +459,13 @@ void ABFirstStageInit::prepare() {
} }
void AFirstStageInit::prepare() { void AFirstStageInit::prepare() {
DIR *dir = xopendir("/"); auto dir = xopen_dir("/");
for (dirent *de; (de = readdir(dir));) { for (dirent *de; (de = xreaddir(dir.get()));) {
if (strstr(de->d_name, "fstab")) { if (strstr(de->d_name, "fstab")) {
patch_fstab(de->d_name); patch_fstab(de->d_name);
break; break;
} }
} }
closedir(dir);
// Move stuffs for next stage // Move stuffs for next stage
xmkdir("/system", 0755); xmkdir("/system", 0755);
...@@ -483,18 +491,7 @@ int magisk_proxy_main(int argc, char *argv[]) { ...@@ -483,18 +491,7 @@ int magisk_proxy_main(int argc, char *argv[]) {
sbin_overlay(self, config); sbin_overlay(self, config);
// Create symlinks pointing back to /root // Create symlinks pointing back to /root
char path[256]; recreate_sbin("/root");
int sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
DIR *dir = xopendir("/root");
struct dirent *entry;
while((entry = xreaddir(dir))) {
if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue;
sprintf(path, "/root/%s", entry->d_name);
xsymlinkat(path, sbin, entry->d_name);
}
close(sbin);
closedir(dir);
setenv("REMOUNT_ROOT", "1", 1); setenv("REMOUNT_ROOT", "1", 1);
execv("/sbin/magisk", argv); execv("/sbin/magisk", argv);
......
...@@ -22,14 +22,14 @@ uint32_t dyn_img_hdr::j32 = 0; ...@@ -22,14 +22,14 @@ uint32_t dyn_img_hdr::j32 = 0;
uint64_t dyn_img_hdr::j64 = 0; uint64_t dyn_img_hdr::j64 = 0;
static void decompress(format_t type, int fd, const void *in, size_t size) { static void decompress(format_t type, int fd, const void *in, size_t size) {
auto ptr = get_decoder(type, make_stream<fd_stream>(fd)); auto ptr = get_decoder(type, make_unique<fd_stream>(fd));
ptr->write(in, size); ptr->write(in, size);
} }
static off_t compress(format_t type, int fd, const void *in, size_t size) { static off_t compress(format_t type, int fd, const void *in, size_t size) {
auto prev = lseek(fd, 0, SEEK_CUR); auto prev = lseek(fd, 0, SEEK_CUR);
{ {
auto strm = get_encoder(type, make_stream<fd_stream>(fd)); auto strm = get_encoder(type, make_unique<fd_stream>(fd));
strm->write(in, size); strm->write(in, size);
} }
auto now = lseek(fd, 0, SEEK_CUR); auto now = lseek(fd, 0, SEEK_CUR);
...@@ -282,33 +282,61 @@ void boot_img::parse_image(uint8_t *addr) { ...@@ -282,33 +282,61 @@ void boot_img::parse_image(uint8_t *addr) {
fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt2name[r_fmt]); fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt2name[r_fmt]);
} }
void boot_img::find_kernel_dtb() { static int find_dtb_offset(uint8_t *buf, int sz) {
const int eof = static_cast<int>(hdr->kernel_size()); for (int off = 0; off < sz - (int) sizeof(fdt_header); ++off) {
for (int i = 0; i < eof - (int) sizeof(fdt_header); ++i) { auto fdt_hdr = reinterpret_cast<fdt_header *>(buf + off);
auto fdt_hdr = reinterpret_cast<fdt_header *>(kernel + i);
if (fdt32_to_cpu(fdt_hdr->magic) != FDT_MAGIC) if (fdt32_to_cpu(fdt_hdr->magic) != FDT_MAGIC)
continue; continue;
// Check that fdt_header.totalsize does not overflow kernel image size // Check that fdt_header.totalsize does not overflow kernel image size
uint32_t totalsize = fdt32_to_cpu(fdt_hdr->totalsize); uint32_t totalsize = fdt32_to_cpu(fdt_hdr->totalsize);
if (totalsize + i > eof) if (totalsize + off > sz)
continue; continue;
// Check that fdt_header.off_dt_struct does not overflow kernel image size // Check that fdt_header.off_dt_struct does not overflow kernel image size
uint32_t off_dt_struct = fdt32_to_cpu(fdt_hdr->off_dt_struct); uint32_t off_dt_struct = fdt32_to_cpu(fdt_hdr->off_dt_struct);
if (off_dt_struct + i > eof) if (off_dt_struct + off > sz)
continue; continue;
// Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE // Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE
auto fdt_node_hdr = reinterpret_cast<fdt_node_header *>(kernel + i + off_dt_struct); auto fdt_node_hdr = reinterpret_cast<fdt_node_header *>(buf + off + off_dt_struct);
if (fdt32_to_cpu(fdt_node_hdr->tag) != FDT_BEGIN_NODE) if (fdt32_to_cpu(fdt_node_hdr->tag) != FDT_BEGIN_NODE)
continue; continue;
kernel_dtb = kernel + i; return off;
kernel_dt_size = eof - i; }
hdr->kernel_size() = i; return -1;
}
void boot_img::find_kernel_dtb() {
if (int off = find_dtb_offset(kernel, hdr->kernel_size()); off > 0) {
kernel_dtb = kernel + off;
kernel_dt_size = hdr->kernel_size() - off;
hdr->kernel_size() = off;
fprintf(stderr, "KERNEL_DTB [%u]\n", kernel_dt_size); fprintf(stderr, "KERNEL_DTB [%u]\n", kernel_dt_size);
break; }
}
int split_image_dtb(const char *filename) {
uint8_t *buf;
size_t sz;
mmap_ro(filename, buf, sz);
run_finally f([=]{ munmap(buf, sz); });
if (int off = find_dtb_offset(buf, sz); off > 0) {
format_t fmt = check_fmt(buf, sz);
if (COMPRESSED(fmt)) {
int fd = creat(KERNEL_FILE, 0644);
decompress(fmt, fd, buf, off);
close(fd);
} else {
dump(buf, off, KERNEL_FILE);
}
dump(buf + off, sz - off, KER_DTB_FILE);
return 0;
} else {
fprintf(stderr, "Cannot find DTB in %s\n", filename);
return 1;
} }
} }
......
...@@ -57,7 +57,7 @@ protected: ...@@ -57,7 +57,7 @@ protected:
ENCODE ENCODE
} mode; } mode;
gz_strm(mode_t mode, sFILE &&fp) : cpr_stream(std::move(fp)), mode(mode) { gz_strm(mode_t mode, stream_ptr &&base) : cpr_stream(std::move(base)), mode(mode) {
switch(mode) { switch(mode) {
case DECODE: case DECODE:
inflateInit2(&strm, 15 | 16); inflateInit2(&strm, 15 | 16);
...@@ -99,12 +99,12 @@ private: ...@@ -99,12 +99,12 @@ private:
class gz_decoder : public gz_strm { class gz_decoder : public gz_strm {
public: public:
explicit gz_decoder(sFILE &&fp) : gz_strm(DECODE, std::move(fp)) {}; explicit gz_decoder(stream_ptr &&base) : gz_strm(DECODE, std::move(base)) {};
}; };
class gz_encoder : public gz_strm { class gz_encoder : public gz_strm {
public: public:
explicit gz_encoder(sFILE &&fp) : gz_strm(ENCODE, std::move(fp)) {}; explicit gz_encoder(stream_ptr &&base) : gz_strm(ENCODE, std::move(base)) {};
}; };
class bz_strm : public cpr_stream { class bz_strm : public cpr_stream {
...@@ -131,7 +131,7 @@ protected: ...@@ -131,7 +131,7 @@ protected:
ENCODE ENCODE
} mode; } mode;
bz_strm(mode_t mode, sFILE &&fp) : cpr_stream(std::move(fp)), mode(mode) { bz_strm(mode_t mode, stream_ptr &&base) : cpr_stream(std::move(base)), mode(mode) {
switch(mode) { switch(mode) {
case DECODE: case DECODE:
BZ2_bzDecompressInit(&strm, 0, 0); BZ2_bzDecompressInit(&strm, 0, 0);
...@@ -173,12 +173,12 @@ private: ...@@ -173,12 +173,12 @@ private:
class bz_decoder : public bz_strm { class bz_decoder : public bz_strm {
public: public:
explicit bz_decoder(sFILE &&fp) : bz_strm(DECODE, std::move(fp)) {}; explicit bz_decoder(stream_ptr &&base) : bz_strm(DECODE, std::move(base)) {};
}; };
class bz_encoder : public bz_strm { class bz_encoder : public bz_strm {
public: public:
explicit bz_encoder(sFILE &&fp) : bz_strm(ENCODE, std::move(fp)) {}; explicit bz_encoder(stream_ptr &&base) : bz_strm(ENCODE, std::move(base)) {};
}; };
class lzma_strm : public cpr_stream { class lzma_strm : public cpr_stream {
...@@ -199,8 +199,8 @@ protected: ...@@ -199,8 +199,8 @@ protected:
ENCODE_LZMA ENCODE_LZMA
} mode; } mode;
lzma_strm(mode_t mode, sFILE &&fp) lzma_strm(mode_t mode, stream_ptr &&base)
: cpr_stream(std::move(fp)), mode(mode), strm(LZMA_STREAM_INIT) { : cpr_stream(std::move(base)), mode(mode), strm(LZMA_STREAM_INIT) {
lzma_options_lzma opt; lzma_options_lzma opt;
// Initialize preset // Initialize preset
...@@ -247,22 +247,22 @@ private: ...@@ -247,22 +247,22 @@ private:
class lzma_decoder : public lzma_strm { class lzma_decoder : public lzma_strm {
public: public:
explicit lzma_decoder(sFILE &&fp) : lzma_strm(DECODE, std::move(fp)) {} explicit lzma_decoder(stream_ptr &&base) : lzma_strm(DECODE, std::move(base)) {}
}; };
class xz_encoder : public lzma_strm { class xz_encoder : public lzma_strm {
public: public:
explicit xz_encoder(sFILE &&fp) : lzma_strm(ENCODE_XZ, std::move(fp)) {} explicit xz_encoder(stream_ptr &&base) : lzma_strm(ENCODE_XZ, std::move(base)) {}
}; };
class lzma_encoder : public lzma_strm { class lzma_encoder : public lzma_strm {
public: public:
explicit lzma_encoder(sFILE &&fp) : lzma_strm(ENCODE_LZMA, std::move(fp)) {} explicit lzma_encoder(stream_ptr &&base) : lzma_strm(ENCODE_LZMA, std::move(base)) {}
}; };
class LZ4F_decoder : public cpr_stream { class LZ4F_decoder : public cpr_stream {
public: public:
explicit LZ4F_decoder(sFILE &&fp) : cpr_stream(std::move(fp)), outbuf(nullptr) { explicit LZ4F_decoder(stream_ptr &&base) : cpr_stream(std::move(base)), outbuf(nullptr) {
LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
} }
...@@ -317,8 +317,8 @@ private: ...@@ -317,8 +317,8 @@ private:
class LZ4F_encoder : public cpr_stream { class LZ4F_encoder : public cpr_stream {
public: public:
explicit LZ4F_encoder(sFILE &&fp) explicit LZ4F_encoder(stream_ptr &&base)
: cpr_stream(std::move(fp)), outbuf(nullptr), outCapacity(0) { : cpr_stream(std::move(base)), outbuf(nullptr), outCapacity(0) {
LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
} }
...@@ -378,8 +378,8 @@ private: ...@@ -378,8 +378,8 @@ private:
class LZ4_decoder : public cpr_stream { class LZ4_decoder : public cpr_stream {
public: public:
explicit LZ4_decoder(sFILE &&fp) explicit LZ4_decoder(stream_ptr &&base)
: cpr_stream(std::move(fp)), out_buf(new char[LZ4_UNCOMPRESSED]), : cpr_stream(std::move(base)), out_buf(new char[LZ4_UNCOMPRESSED]),
buffer(new char[LZ4_COMPRESSED]), init(false), block_sz(0), buf_off(0) {} buffer(new char[LZ4_COMPRESSED]), init(false), block_sz(0), buf_off(0) {}
~LZ4_decoder() override { ~LZ4_decoder() override {
...@@ -439,8 +439,8 @@ private: ...@@ -439,8 +439,8 @@ private:
class LZ4_encoder : public cpr_stream { class LZ4_encoder : public cpr_stream {
public: public:
explicit LZ4_encoder(sFILE &&fp) explicit LZ4_encoder(stream_ptr &&base)
: cpr_stream(std::move(fp)), outbuf(new char[LZ4_COMPRESSED]), buf(new char[LZ4_UNCOMPRESSED]), : cpr_stream(std::move(base)), outbuf(new char[LZ4_COMPRESSED]), buf(new char[LZ4_UNCOMPRESSED]),
init(false), buf_off(0), in_total(0) {} init(false), buf_off(0), in_total(0) {}
int write(const void *in, size_t size) override { int write(const void *in, size_t size) override {
...@@ -500,38 +500,38 @@ private: ...@@ -500,38 +500,38 @@ private:
unsigned in_total; unsigned in_total;
}; };
stream_ptr get_encoder(format_t type, sFILE &&fp) { stream_ptr get_encoder(format_t type, stream_ptr &&base) {
switch (type) { switch (type) {
case XZ: case XZ:
return make_unique<xz_encoder>(std::move(fp)); return make_unique<xz_encoder>(std::move(base));
case LZMA: case LZMA:
return make_unique<lzma_encoder>(std::move(fp)); return make_unique<lzma_encoder>(std::move(base));
case BZIP2: case BZIP2:
return make_unique<bz_encoder>(std::move(fp)); return make_unique<bz_encoder>(std::move(base));
case LZ4: case LZ4:
return make_unique<LZ4F_encoder>(std::move(fp)); return make_unique<LZ4F_encoder>(std::move(base));
case LZ4_LEGACY: case LZ4_LEGACY:
return make_unique<LZ4_encoder>(std::move(fp)); return make_unique<LZ4_encoder>(std::move(base));
case GZIP: case GZIP:
default: default:
return make_unique<gz_encoder>(std::move(fp)); return make_unique<gz_encoder>(std::move(base));
} }
} }
stream_ptr get_decoder(format_t type, sFILE &&fp) { stream_ptr get_decoder(format_t type, stream_ptr &&base) {
switch (type) { switch (type) {
case XZ: case XZ:
case LZMA: case LZMA:
return make_unique<lzma_decoder>(std::move(fp)); return make_unique<lzma_decoder>(std::move(base));
case BZIP2: case BZIP2:
return make_unique<bz_decoder>(std::move(fp)); return make_unique<bz_decoder>(std::move(base));
case LZ4: case LZ4:
return make_unique<LZ4F_decoder>(std::move(fp)); return make_unique<LZ4F_decoder>(std::move(base));
case LZ4_LEGACY: case LZ4_LEGACY:
return make_unique<LZ4_decoder>(std::move(fp)); return make_unique<LZ4_decoder>(std::move(base));
case GZIP: case GZIP:
default: default:
return make_unique<gz_decoder>(std::move(fp)); return make_unique<gz_decoder>(std::move(base));
} }
} }
...@@ -573,7 +573,7 @@ void decompress(char *infile, const char *outfile) { ...@@ -573,7 +573,7 @@ void decompress(char *infile, const char *outfile) {
} }
FILE *out_fp = outfile == "-"sv ? stdout : xfopen(outfile, "we"); FILE *out_fp = outfile == "-"sv ? stdout : xfopen(outfile, "we");
strm = get_decoder(type, make_sFILE(out_fp)); strm = get_decoder(type, make_unique<fp_stream>(out_fp));
if (ext) *ext = '.'; if (ext) *ext = '.';
} }
if (strm->write(buf, len) < 0) if (strm->write(buf, len) < 0)
...@@ -614,7 +614,7 @@ void compress(const char *method, const char *infile, const char *outfile) { ...@@ -614,7 +614,7 @@ void compress(const char *method, const char *infile, const char *outfile) {
out_fp = outfile == "-"sv ? stdout : xfopen(outfile, "we"); out_fp = outfile == "-"sv ? stdout : xfopen(outfile, "we");
} }
auto strm = get_encoder(it->second, make_sFILE(out_fp)); auto strm = get_encoder(it->second, make_unique<fp_stream>(out_fp));
char buf[4096]; char buf[4096];
size_t len; size_t len;
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
#include "format.h" #include "format.h"
stream_ptr get_encoder(format_t type, sFILE &&fp); stream_ptr get_encoder(format_t type, stream_ptr &&base);
stream_ptr get_decoder(format_t type, sFILE &&fp); stream_ptr get_decoder(format_t type, stream_ptr &&base);
void compress(const char *method, const char *infile, const char *outfile); void compress(const char *method, const char *infile, const char *outfile);
......
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <bitset>
#include <vector>
#include <map>
extern "C" { extern "C" {
#include <libfdt.h> #include <libfdt.h>
} }
#include <utils.h> #include <utils.h>
#include <bitset>
#include <vector>
#include <map>
#include "magiskboot.h" #include "magiskboot.h"
#include "dtb.h"
using namespace std; using namespace std;
#define DTB_MAGIC "\xd0\x0d\xfe\xed" struct fdt_blob {
#define QCDT_MAGIC "QCDT"
#define DTBH_MAGIC "DTBH"
#define PXADT_MAGIC "PXA-DT"
#define PXA19xx_MAGIC "PXA-19xx"
#define SPRD_MAGIC "SPRD"
struct qcdt_hdr {
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 */
} __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 */
} __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 */
} __attribute__((packed));
struct dtbh_hdr {
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 */
} __attribute__((packed));
struct pxadt_hdr {
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 */
} __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 */
} __attribute__((packed));
struct sprd_hdr {
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 */
} __attribute__((packed));
struct dtb_blob {
void *fdt; void *fdt;
uint32_t offset; uint32_t offset;
uint32_t len; uint32_t len;
...@@ -206,7 +133,7 @@ static void dtb_print(const char *file, bool fstab) { ...@@ -206,7 +133,7 @@ static void dtb_print(const char *file, bool fstab) {
// Loop through all the dtbs // Loop through all the dtbs
int dtb_num = 0; int dtb_num = 0;
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) { if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
auto fdt = dtb + i; auto fdt = dtb + i;
if (fstab) { if (fstab) {
int node = find_fstab(fdt); int node = find_fstab(fdt);
...@@ -266,19 +193,33 @@ static bool fdt_patch(Iter first, Iter last) { ...@@ -266,19 +193,33 @@ static bool fdt_patch(Iter first, Iter last) {
template <class Table, class Header> template <class Table, class Header>
static int dtb_patch(const Header *hdr, const char *in, const char *out) { static int dtb_patch(const Header *hdr, const char *in, const char *out) {
map<uint32_t, dtb_blob> dtb_map; map<uint32_t, fdt_blob> dtb_map;
auto buf = reinterpret_cast<const uint8_t *>(hdr); auto buf = reinterpret_cast<const uint8_t *>(hdr);
auto tables = reinterpret_cast<const Table *>(hdr + 1); auto tables = reinterpret_cast<const Table *>(hdr + 1);
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; };
}
// Collect all dtbs // Collect all dtbs
for (int i = 0; i < hdr->num_dtbs; ++i) { auto num_dtb = be_to_le(hdr->num_dtbs);
if (dtb_map.find(tables[i].offset) == dtb_map.end()) { for (int i = 0; i < num_dtb; ++i) {
auto blob = buf + tables[i].offset; auto offset = be_to_le(tables[i].offset);
int size = fdt_totalsize(blob); if (dtb_map.count(offset) == 0) {
auto blob = buf + offset;
uint32_t size = fdt_totalsize(blob);
auto fdt = xmalloc(size + 256); auto fdt = xmalloc(size + 256);
memcpy(fdt, blob, size); memcpy(fdt, blob, size);
fdt_open_into(fdt, fdt, size + 256); fdt_open_into(fdt, fdt, size + 256);
dtb_map[tables[i].offset] = { fdt, tables[i].offset }; dtb_map[offset] = { fdt, offset };
} }
} }
if (dtb_map.empty()) if (dtb_map.empty())
...@@ -292,18 +233,23 @@ static int dtb_patch(const Header *hdr, const char *in, const char *out) { ...@@ -292,18 +233,23 @@ static int dtb_patch(const Header *hdr, const char *in, const char *out) {
unlink(in); unlink(in);
int fd = xopen(out, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); int fd = xopen(out, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
uint32_t total_size = 0;
// Copy headers and tables // Copy headers and tables
xwrite(fd, buf, dtb_map.begin()->first); total_size += xwrite(fd, buf, dtb_map.begin()->first);
// mmap rw to patch table values retroactively // mmap rw to patch table values retroactively
auto mmap_sz = lseek(fd, 0, SEEK_CUR); auto mmap_sz = lseek(fd, 0, SEEK_CUR);
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// Guess page size using gcd // Guess alignment using gcd
uint32_t align = 1;
if constexpr (!is_dt_table) {
auto it = dtb_map.begin(); auto it = dtb_map.begin();
uint32_t page_size = (it++)->first; align = (it++)->first;
for (; it != dtb_map.end(); ++it) for (; it != dtb_map.end(); ++it)
page_size = binary_gcd(page_size, it->first); align = binary_gcd(align, it->first);
}
// Write dtbs // Write dtbs
for (auto &val : dtb_map) { for (auto &val : dtb_map) {
...@@ -311,18 +257,23 @@ static int dtb_patch(const Header *hdr, const char *in, const char *out) { ...@@ -311,18 +257,23 @@ static int dtb_patch(const Header *hdr, const char *in, const char *out) {
auto fdt = val.second.fdt; auto fdt = val.second.fdt;
fdt_pack(fdt); fdt_pack(fdt);
int size = fdt_totalsize(fdt); int size = fdt_totalsize(fdt);
xwrite(fd, fdt, size); total_size += xwrite(fd, fdt, size);
val.second.len = do_align(size, page_size); val.second.len = do_align(size, align);
write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), page_size)); 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); free(fdt);
} }
// Patch tables // 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)); auto tables_rw = reinterpret_cast<Table *>(addr + sizeof(Header));
for (int i = 0; i < hdr->num_dtbs; ++i) { for (int i = 0; i < num_dtb; ++i) {
auto &blob = dtb_map[tables_rw[i].offset]; auto &blob = dtb_map[be_to_le(tables_rw[i].offset)];
tables_rw[i].offset = blob.offset; tables_rw[i].offset = le_to_be(blob.offset);
tables_rw[i].len = blob.len; tables_rw[i].len = le_to_be(blob.len);
} }
munmap(addr, mmap_sz); munmap(addr, mmap_sz);
...@@ -393,10 +344,19 @@ static int dtb_patch(const char *in, const char *out) { ...@@ -393,10 +344,19 @@ static int dtb_patch(const char *in, const char *out) {
default: default:
return 1; 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 dtb_patch<dt_table_entry>(hdr, in, out);
default:
return 1;
}
} else { } else {
vector<uint8_t *> fdt_list; vector<uint8_t *> fdt_list;
for (int i = 0; i < dtb_sz; ++i) { for (int i = 0; i < dtb_sz; ++i) {
if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) { if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
int len = fdt_totalsize(dtb + i); int len = fdt_totalsize(dtb + i);
auto fdt = static_cast<uint8_t *>(xmalloc(len + 256)); auto fdt = static_cast<uint8_t *>(xmalloc(len + 256));
memcpy(fdt, dtb + i, len); memcpy(fdt, dtb + i, len);
......
#pragma once
#include <stdint.h>
#define FDT_MAGIC_STR "\xd0\x0d\xfe\xed"
#define DT_TABLE_MAGIC "\xd7\xb7\xab\x1e"
#define QCDT_MAGIC "QCDT"
#define DTBH_MAGIC "DTBH"
#define PXADT_MAGIC "PXA-DT"
#define PXA19xx_MAGIC "PXA-19xx"
#define SPRD_MAGIC "SPRD"
struct qcdt_hdr {
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 */
} __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 */
} __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 */
} __attribute__((packed));
struct dtbh_hdr {
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 */
} __attribute__((packed));
struct pxadt_hdr {
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 */
} __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 */
} __attribute__((packed));
struct sprd_hdr {
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 */
} __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 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 */
} __attribute__((packed));
struct dt_table_entry {
uint32_t len; /* DTB size */
uint32_t offset;
uint32_t id;
uint32_t rev;
uint32_t flags;
uint32_t custom[3];
} __attribute__((packed));
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
int unpack(const char *image, bool nodecomp = false, bool hdr = false); int unpack(const char *image, bool nodecomp = false, bool hdr = false);
void repack(const char* src_img, const char* out_img, bool nocomp = false); void repack(const char* src_img, const char* out_img, bool nocomp = false);
int split_image_dtb(const char *filename);
int hexpatch(const char *image, const char *from, const char *to); int hexpatch(const char *image, const char *from, const char *to);
int cpio_commands(int argc, char *argv[]); int cpio_commands(int argc, char *argv[]);
int dtb_commands(int argc, char *argv[]); int dtb_commands(int argc, char *argv[]);
......
...@@ -84,6 +84,15 @@ Supported actions: ...@@ -84,6 +84,15 @@ Supported actions:
If [OUT] is not specified, it will directly output to <input> If [OUT] is not specified, it will directly output to <input>
Configure with env variables: KEEPVERITY TWOSTAGEINIT Configure with env variables: KEEPVERITY TWOSTAGEINIT
split <input>
Split image.*-dtb into kernel + kernel_dtb
sha1 <file>
Print the SHA1 checksum for <file>
cleanup
Cleanup the current working directory
compress[=method] <infile> [outfile] compress[=method] <infile> [outfile]
Compress <infile> with [method] (default: gzip), optionally to [outfile] Compress <infile> with [method] (default: gzip), optionally to [outfile]
<infile>/[outfile] can be '-' to be STDIN/STDOUT <infile>/[outfile] can be '-' to be STDIN/STDOUT
...@@ -102,16 +111,7 @@ Supported actions: ...@@ -102,16 +111,7 @@ Supported actions:
for (auto &it : name2fmt) for (auto &it : name2fmt)
fprintf(stderr, "%s ", it.first.data()); fprintf(stderr, "%s ", it.first.data());
fprintf(stderr, R"EOF( fprintf(stderr, "\n\n");
sha1 <file>
Print the SHA1 checksum for <file>
cleanup
Cleanup the current working directory
)EOF");
exit(1); exit(1);
} }
...@@ -147,6 +147,8 @@ int main(int argc, char *argv[]) { ...@@ -147,6 +147,8 @@ int main(int argc, char *argv[]) {
printf("%02x", i); printf("%02x", i);
printf("\n"); printf("\n");
munmap(buf, size); munmap(buf, size);
} else if (argc > 2 && action == "split") {
return split_image_dtb(argv[2]);
} else if (argc > 2 && action == "unpack") { } else if (argc > 2 && action == "unpack") {
int idx = 2; int idx = 2;
bool nodecomp = false; bool nodecomp = false;
......
...@@ -5,54 +5,58 @@ ...@@ -5,54 +5,58 @@
#include "magiskboot.h" #include "magiskboot.h"
#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) { static int check_verity_pattern(const char *s) {
int skip = 0; int skip = s[0] == ',';
if (s[0] == ',') ++skip;
if (strncmp(s + skip, "verify", 6) == 0) if (0) {}
skip += 6; MATCH("verify");
else if (strncmp(s + skip, "avb", 3) == 0) MATCH("avb");
skip += 3; MATCH("support_scfs");
else else return -1;
return -1;
if (s[skip] == '=') { if (s[skip] == '=') {
while (s[skip] != '\0' && s[skip] != ' ' && s[skip] != '\n' && s[skip] != ',') ++skip; while (s[skip] != '\0' && s[skip] != ' ' && s[skip] != '\n' && s[skip] != ',')
++skip;
} }
return 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) { static int check_encryption_pattern(const char *s) {
static const char *encrypt_list[] = { "forceencrypt", "forcefdeorfbe" }; if (0) {}
for (auto enc : encrypt_list) { MATCH("forceencrypt");
int len = strlen(enc); MATCH("forcefdeorfbe");
if (strncmp(s, enc, len) == 0) MATCH("fileencryption");
return len; else return -1;
}
return -1;
} }
char *patch_verity(const void *buf, uint32_t &size, bool inplace) { char *patch_verity(const void *buf, uint32_t &size, bool inplace) {
auto src = static_cast<const char *>(buf); auto src = static_cast<const char *>(buf);
auto dest = (char *)(inplace ? buf : xmalloc(size));
int src_size = size; int src_size = size;
bool found = false; bool found = false;
auto patched = (char *)(inplace ? buf : xmalloc(size));
int write = 0; int write = 0;
for (int read = 0; read < src_size; ++read, ++write) { for (int read = 0; read < src_size;) {
if (int skip; (skip = check_verity_pattern(src + read)) > 0) { if (int skip; (skip = check_verity_pattern(src + read)) > 0) {
fprintf(stderr, "Found pattern [%.*s]\n", skip, src + read); fprintf(stderr, "Found pattern [%.*s]\n", skip, src + read);
size -= skip; size -= skip;
read += skip; read += skip;
found = true; found = true;
} else {
dest[write++] = src[read++];
} }
patched[write] = src[read];
} }
patched[write] = '\0'; dest[write] = '\0';
if (!found) { if (!found) {
if (!inplace) if (!inplace)
free(patched); free(dest);
return nullptr; return nullptr;
} }
return patched; return dest;
} }
void patch_encryption(void *buf, uint32_t &size) { void patch_encryption(void *buf, uint32_t &size) {
......
...@@ -47,8 +47,11 @@ void magisk_cpio::patch() { ...@@ -47,8 +47,11 @@ void magisk_cpio::patch() {
for (auto it = entries.begin(); it != entries.end();) { for (auto it = entries.begin(); it != entries.end();) {
auto cur = it++; auto cur = it++;
bool fstab = (!keepverity || !keepforceencrypt) && bool fstab = (!keepverity || !keepforceencrypt) &&
S_ISREG(cur->second->mode) &&
!str_starts(cur->first, ".backup") && !str_starts(cur->first, ".backup") &&
str_contains(cur->first, "fstab") && S_ISREG(cur->second->mode); !str_contains(cur->first, "twrp") &&
!str_contains(cur->first, "recovery") &&
str_contains(cur->first, "fstab");
if (!keepverity) { if (!keepverity) {
if (fstab) { if (fstab) {
fprintf(stderr, "Found fstab file [%s]\n", cur->first.data()); fprintf(stderr, "Found fstab file [%s]\n", cur->first.data());
...@@ -244,7 +247,7 @@ void magisk_cpio::compress() { ...@@ -244,7 +247,7 @@ void magisk_cpio::compress() {
uint8_t *data; uint8_t *data;
size_t len; size_t len;
auto strm = make_stream(get_encoder(XZ, make_stream<byte_stream>(data, len))); auto strm = make_stream_fp(get_encoder(XZ, make_unique<byte_stream>(data, len)));
dump(strm.release()); dump(strm.release());
entries.clear(); entries.clear();
...@@ -264,7 +267,7 @@ void magisk_cpio::decompress() { ...@@ -264,7 +267,7 @@ void magisk_cpio::decompress() {
char *data; char *data;
size_t len; size_t len;
{ {
auto strm = get_decoder(XZ, make_stream<byte_stream>(data, len)); auto strm = get_decoder(XZ, make_unique<byte_stream>(data, len));
strm->write(it->second->data, it->second->filesize); strm->write(it->second->data, it->second->filesize);
} }
......
...@@ -67,7 +67,7 @@ void hide_unmount(int pid) { ...@@ -67,7 +67,7 @@ void hide_unmount(int pid) {
// Unmount dummy skeletons and /sbin links // Unmount dummy skeletons and /sbin links
parse_mnt("/proc/self/mounts", [&](mntent *mentry) { parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(sbin)) if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(sbin) || TMPFS_MNT(product))
targets.emplace_back(mentry->mnt_dir); targets.emplace_back(mentry->mnt_dir);
return true; return true;
}); });
......
...@@ -183,7 +183,7 @@ bool init_list() { ...@@ -183,7 +183,7 @@ bool init_list() {
// Migrate old hide list into database // Migrate old hide list into database
if (access(LEGACY_LIST, R_OK) == 0) { if (access(LEGACY_LIST, R_OK) == 0) {
file_readline(LEGACY_LIST, [](string_view s) -> bool { file_readline(true, LEGACY_LIST, [](string_view s) -> bool {
add_list(s.data()); add_list(s.data());
return true; return true;
}); });
......
#include "magiskpolicy.h" #include <magiskpolicy.h>
#include "sepolicy.h" #include "sepolicy.h"
//#define vprint(fmt, ...) printf(fmt, __VA_ARGS__) //#define vprint(fmt, ...) printf(fmt, __VA_ARGS__)
......
This diff is collapsed.
...@@ -8,11 +8,12 @@ ...@@ -8,11 +8,12 @@
#include <utils.h> #include <utils.h>
#include <logging.h> #include <logging.h>
#include <stream.h> #include <stream.h>
#include <magiskpolicy.h>
#include "magiskpolicy.h"
#include "sepolicy.h" #include "sepolicy.h"
int load_policydb(const char *file) { int load_policydb(const char *file) {
LOGD("Load policy from: %s\n", file);
if (magisk_policydb) if (magisk_policydb)
destroy_policydb(); destroy_policydb();
...@@ -101,7 +102,7 @@ static void load_cil(struct cil_db *db, const char *file) { ...@@ -101,7 +102,7 @@ static void load_cil(struct cil_db *db, const char *file) {
size_t size; size_t size;
mmap_ro(file, addr, size); mmap_ro(file, addr, size);
cil_add_file(db, (char *) file, addr, size); cil_add_file(db, (char *) file, addr, size);
LOGD("cil_add[%s]\n", file); LOGD("cil_add [%s]\n", file);
munmap(addr, size); munmap(addr, size);
} }
...@@ -178,7 +179,7 @@ int dump_policydb(const char *file) { ...@@ -178,7 +179,7 @@ int dump_policydb(const char *file) {
size_t len; size_t len;
{ {
auto fp = make_stream<byte_stream>(data, len); auto fp = make_stream_fp<byte_stream>(data, len);
struct policy_file pf; struct policy_file pf;
policy_file_init(&pf); policy_file_init(&pf);
pf.type = PF_USE_STDIO; pf.type = PF_USE_STDIO;
......
#include <logging.h> #include <logging.h>
#include <flags.h> #include <flags.h>
#include <magiskpolicy.h>
#include "magiskpolicy.h"
#include "sepolicy.h" #include "sepolicy.h"
static void allowSuClient(const char *target) { static void allowSuClient(const char *target) {
......
#include <cstring>
#include <vector>
#include <string>
#include <magiskpolicy.h>
#include <logging.h>
#include <utils.h>
using namespace std;
static const char *type_msg_1 =
R"EOF(Type 1:
"<rule_name> source_type target_type class perm_set"
Rules: allow, deny, auditallow, dontaudit
)EOF";
static const char *type_msg_2 =
R"EOF(Type 2:
"<rule_name> source_type target_type class operation xperm_set"
Rules: allowxperm, auditallowxperm, dontauditxperm
* The only supported operation is ioctl
* The only supported xperm_set format is range ([low-high])
)EOF";
static const char *type_msg_3 =
R"EOF(Type 3:
"<rule_name> class"
Rules: create, permissive, enforcing
)EOF";
static const char *type_msg_4 =
R"EOF(Type 4:
"attradd class attribute"
)EOF";
static const char *type_msg_5 =
R"EOF(Type 5:
"<rule_name> source_type target_type class default_type"
Rules: type_transition, type_change, type_member
)EOF";
static const char *type_msg_6 =
R"EOF(Type 6:
"name_transition source_type target_type class default_type object_name"
)EOF";
void statement_help() {
fprintf(stderr,
R"EOF(One policy statement should be treated as one parameter;
this means a full policy statement should be enclosed in quotes.
Multiple policy statements can be provided in a single command.
The statements has a format of "<rule_name> [args...]"
Multiple types and permissions can be grouped into collections
wrapped in curly brackets.
'*' represents a collection containing all valid matches.
Supported policy statements:
%s
%s
%s
%s
%s
%s
Notes:
* Type 4 - 6 does not support collections
* Object classes cannot be collections
* source_type and target_type can also be attributes
Example: allow { s1 s2 } { t1 t2 } class *
Will be expanded to:
allow s1 t1 class { all-permissions }
allow s1 t2 class { all-permissions }
allow s2 t1 class { all-permissions }
allow s2 t2 class { all-permissions }
)EOF", type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5, type_msg_6);
exit(0);
}
static int parse_bracket(char *tok, char *&stmt, vector<const char *> &vec) {
if (tok == nullptr || tok[0] != '{') {
// Not in a bracket
vec.push_back(tok);
} else {
if (stmt)
stmt[-1] = ' ';
tok = strchr(tok, '{') + 1;
char *end = strchr(tok, '}');
if (end == nullptr) // Bracket not closed
return 1;
*end = '\0';
char *cur;
while ((cur = strtok_r(nullptr, " ", &tok)) != nullptr)
vec.push_back(cur);
stmt = end + 1;
}
return 0;
}
// Pattern 1: action { source } { target } class { permission }
static int parse_pattern_1(int action, const char *action_str, char *stmt) {
int (*action_func)(const char*, const char*, const char*, const char*);
switch (action) {
case 0:
action_func = sepol_allow;
break;
case 1:
action_func = sepol_deny;
break;
case 2:
action_func = sepol_auditallow;
break;
case 3:
action_func = sepol_dontaudit;
break;
default:
return 1;
}
int state = 0;
char *cur, *cls;
vector<const char*> source, target, permission;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
if (cur[0] == '*') cur = ALL;
vector<const char *> *vec;
switch (state) {
case 0:
vec = &source;
break;
case 1:
vec = &target;
break;
case 2:
vec = nullptr;
cls = cur;
break;
case 3:
vec = &permission;
break;
default:
return 1;
}
if (vec && parse_bracket(cur, stmt, *vec))
return 1;
++state;
}
if (state != 4 || source.empty() || target.empty() || permission.empty())
return 1;
for (auto src : source)
for (auto tgt : target)
for (auto perm : permission)
if (action_func(src, tgt, cls, perm))
LOGW("Error in: %s %s %s %s %s\n", action_str, src, tgt, cls, perm);
return 0;
}
// Pattern 2: action { source } { target } { class } ioctl range
static int parse_pattern_2(int action, const char *action_str, char *stmt) {
int (*action_func)(const char*, const char*, const char*, const char*);
switch (action) {
case 0:
action_func = sepol_allowxperm;
break;
case 1:
action_func = sepol_auditallowxperm;
break;
case 2:
action_func = sepol_dontauditxperm;
break;
default:
return 1;
}
int state = 0;
char *cur, *range;
vector<const char *> source, target, classes;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
if (cur[0] == '*') cur = ALL;
vector<const char *> *vec;
switch (state) {
case 0:
vec = &source;
break;
case 1:
vec = &target;
break;
case 2:
vec = &classes;
break;
case 3:
// Currently only support ioctl
if (strcmp(cur, "ioctl") != 0)
return 1;
vec = nullptr;
break;
case 4:
vec = nullptr;
range = cur;
break;
default:
return 1;
}
if (vec && parse_bracket(cur, stmt, *vec))
return 1;
++state;
}
if (state != 5 || source.empty() || target.empty() || classes.empty())
return 1;
for (auto src : source)
for (auto tgt : target)
for (auto cls : classes)
if (action_func(src, tgt, cls, range))
LOGW("Error in: %s %s %s %s %s\n", action_str, src, tgt, cls, range);
return 0;
}
// Pattern 3: action { type }
static int parse_pattern_3(int action, const char *action_str, char* stmt) {
int (*action_func)(const char*);
switch (action) {
case 0:
action_func = sepol_create;
break;
case 1:
action_func = sepol_permissive;
break;
case 2:
action_func = sepol_enforce;
break;
default:
return 1;
}
char *cur;
vector<const char *> domains;
while ((cur = strtok_r(nullptr, " {}", &stmt)) != nullptr) {
if (cur[0] == '*') cur = ALL;
domains.push_back(cur);
}
if (domains.empty())
return 1;
for (auto dom : domains)
if (action_func(dom))
LOGW("Error in: %s %s\n", action_str, dom);
return 0;
}
// Pattern 4: action { class } { attribute }
static int parse_pattern_4(int action, const char *action_str, char *stmt) {
int (*action_func)(const char*, const char*);
switch (action) {
case 0:
action_func = sepol_attradd;
break;
default:
return 1;
}
int state = 0;
char *cur;
vector<const char *> classes, attribute;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
if (cur[0] == '*') cur = ALL;
vector<const char *> *vec;
switch (state) {
case 0:
vec = &classes;
break;
case 1:
vec = &attribute;
break;
default:
return 1;
}
if (parse_bracket(cur, stmt, *vec))
return 1;
++state;
}
if (state != 2 || classes.empty() || attribute.empty())
return 1;
for (auto cls : classes)
for (auto attr : attribute)
if (action_func(cls, attr))
LOGW("Error in: %s %s %s\n", action_str, cls, attr);
return 0;
}
// Pattern 5: action source target class default
static int parse_pattern_5(int action, const char *action_str, char *stmt) {
int (*action_func)(const char*, const char*, const char*, const char*);
switch (action) {
case 0:
action_func = sepol_typetrans;
break;
case 1:
action_func = sepol_typechange;
break;
case 2:
action_func = sepol_typemember;
break;
default:
return 1;
}
int state = 0;
char *cur;
char *source, *target, *cls, *def;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
switch(state) {
case 0:
source = cur;
break;
case 1:
target = cur;
break;
case 2:
cls = cur;
break;
case 3:
def = cur;
break;
default:
return 1;
}
++state;
}
if (state < 4) return 1;
if (action_func(source, target, cls, def))
LOGW("Error in: %s %s %s %s %s\n", action_str, source, target, cls, def);
return 0;
}
// Pattern 6: action source target class default filename
static int parse_pattern_6(int action, const char *action_str, char *stmt) {
int state = 0;
char *cur;
char *source, *target, *cls, *def, *filename;
while ((cur = strtok_r(nullptr, " ", &stmt)) != nullptr) {
switch(state) {
case 0:
source = cur;
break;
case 1:
target = cur;
break;
case 2:
cls = cur;
break;
case 3:
def = cur;
break;
case 4:
filename = cur;
break;
default:
return 1;
}
++state;
}
if (state < 4) return 1;
if (sepol_nametrans(source, target, cls, def, filename))
LOGW("Error in: %s %s %s %s %s %s\n", action_str, source, target, cls, def, filename);
return 0;
}
#define add_action(name, type, num) \
else if (strcmp(name, action) == 0) { \
if (parse_pattern_##type(num, name, remain)) \
LOGW("Syntax error in '%s'\n\n%s\n", statement, type_msg_##type); \
}
void parse_statement(const char *statement) {
char *action, *remain;
// strtok will modify strings, duplicate the statement
string stmt(statement);
action = strtok_r(stmt.data(), " ", &remain);
if (remain == nullptr) {
LOGE("Syntax error in '%s'\n\n", statement);
return;
}
if (0) {}
add_action("allow", 1, 0)
add_action("deny", 1, 1)
add_action("auditallow", 1, 2)
add_action("dontaudit", 1, 3)
add_action("allowxperm", 2, 0)
add_action("auditallowxperm", 2, 1)
add_action("dontauditxperm", 2, 2)
add_action("create", 3, 0)
add_action("permissive", 3, 1)
add_action("enforce", 3, 2)
add_action("attradd", 4, 0)
add_action("type_transition", 5, 0)
add_action("type_change", 5, 1)
add_action("type_member", 5, 2)
add_action("name_transition", 6, 0)
else { LOGW("Unknown statement: '%s'\n\n", statement); }
}
void load_rule_file(const char *file) {
file_readline(true, file, [](string_view line) -> bool {
if (line.empty() || line[0] == '#')
return true;
parse_statement(line.data());
return true;
});
}
/* file.cpp - Contains all files related utilities
*/
#include <sys/sendfile.h> #include <sys/sendfile.h>
#include <sys/mman.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
...@@ -359,7 +355,7 @@ void write_zero(int fd, size_t size) { ...@@ -359,7 +355,7 @@ void write_zero(int fd, size_t size) {
} }
} }
void file_readline(const char *file, const function<bool (string_view)> &fn, bool trim) { void file_readline(bool trim, const char *file, const std::function<bool(std::string_view)> &fn) {
FILE *fp = xfopen(file, "re"); FILE *fp = xfopen(file, "re");
if (fp == nullptr) if (fp == nullptr)
return; return;
...@@ -384,7 +380,7 @@ void file_readline(const char *file, const function<bool (string_view)> &fn, boo ...@@ -384,7 +380,7 @@ void file_readline(const char *file, const function<bool (string_view)> &fn, boo
} }
void parse_prop_file(const char *file, const function<bool (string_view, string_view)> &fn) { void parse_prop_file(const char *file, const function<bool (string_view, string_view)> &fn) {
file_readline(file, [&](string_view line_view) -> bool { file_readline(true, file, [&](string_view line_view) -> bool {
char *line = (char *) line_view.data(); char *line = (char *) line_view.data();
if (line[0] == '#') if (line[0] == '#')
return true; return true;
...@@ -393,7 +389,7 @@ void parse_prop_file(const char *file, const function<bool (string_view, string_ ...@@ -393,7 +389,7 @@ void parse_prop_file(const char *file, const function<bool (string_view, string_
return true; return true;
*eql = '\0'; *eql = '\0';
return fn(line, eql + 1); return fn(line, eql + 1);
}, true); });
} }
void parse_mnt(const char *file, const function<bool (mntent*)> &fn) { void parse_mnt(const char *file, const function<bool (mntent*)> &fn) {
......
#pragma once #pragma once
#include <sys/mman.h>
#include <sys/stat.h>
#include <mntent.h> #include <mntent.h>
#include <functional> #include <functional>
#include <string_view> #include <string_view>
#include "xwrap.h"
#define do_align(p, a) (((p) + (a) - 1) / (a) * (a)) #define do_align(p, a) (((p) + (a) - 1) / (a) * (a))
#define align_off(p, a) (do_align(p, a) - (p)) #define align_off(p, a) (do_align(p, a) - (p))
using sFILE = std::unique_ptr<FILE, decltype(&fclose)>;
static inline sFILE make_sFILE(FILE *fp = nullptr) {
return sFILE(fp, fclose);
}
struct file_attr { struct file_attr {
struct stat st; struct stat st;
char con[128]; char con[128];
...@@ -36,12 +35,15 @@ void clone_attr(const char *source, const char *target); ...@@ -36,12 +35,15 @@ void clone_attr(const char *source, const char *target);
void fd_full_read(int fd, void **buf, size_t *size); void fd_full_read(int fd, void **buf, size_t *size);
void full_read(const char *filename, void **buf, size_t *size); void full_read(const char *filename, void **buf, size_t *size);
void write_zero(int fd, size_t size); void write_zero(int fd, size_t size);
void file_readline(bool trim, const char *file, const std::function<bool(std::string_view)> &fn);
void file_readline(const char *file, const std::function<bool (std::string_view)> &fn, bool trim = false); static inline void file_readline(const char *file,
void parse_prop_file(const char *file, const std::function const std::function<bool(std::string_view)> &fn) {
<bool(std::string_view, std::string_view)> &fn); file_readline(false, file, fn);
}
void parse_prop_file(const char *file,
const std::function<bool(std::string_view, std::string_view)> &fn);
void *__mmap(const char *filename, size_t *size, bool rw); void *__mmap(const char *filename, size_t *size, bool rw);
void frm_rf(int dirfd, std::initializer_list<const char *> excl = std::initializer_list<const char *>()); void frm_rf(int dirfd, std::initializer_list<const char *> excl = {});
void clone_dir(int src, int dest, bool overwrite = true); void clone_dir(int src, int dest, bool overwrite = true);
void parse_mnt(const char *file, const std::function<bool(mntent*)> &fn); void parse_mnt(const char *file, const std::function<bool(mntent*)> &fn);
...@@ -80,3 +82,22 @@ void mmap_rw(const char *filename, B &buf, L &sz) { ...@@ -80,3 +82,22 @@ void mmap_rw(const char *filename, B &buf, L &sz) {
buf = (B) __mmap(filename, &__sz, true); buf = (B) __mmap(filename, &__sz, true);
sz = __sz; sz = __sz;
} }
using sFILE = std::unique_ptr<FILE, decltype(&fclose)>;
using sDIR = std::unique_ptr<DIR, decltype(&closedir)>;
static inline sDIR open_dir(const char *path) {
return sDIR(opendir(path), closedir);
}
static inline sDIR xopen_dir(const char *path) {
return sDIR(xopendir(path), closedir);
}
static inline sFILE open_file(const char *path, const char *mode) {
return sFILE(fopen(path, mode), fclose);
}
static inline sFILE xopen_file(const char *path, const char *mode) {
return sFILE(xfopen(path, mode), fclose);
}
...@@ -5,17 +5,6 @@ ...@@ -5,17 +5,6 @@
#include "../files.h" #include "../files.h"
class stream;
using stream_ptr = std::unique_ptr<stream>;
sFILE make_stream(stream_ptr &&strm);
template <class T, class... Args>
sFILE make_stream(Args &&... args) {
return make_stream(stream_ptr(new T(std::forward<Args>(args)...)));
}
class stream { class stream {
public: public:
virtual int read(void *buf, size_t len); virtual int read(void *buf, size_t len);
...@@ -24,35 +13,22 @@ public: ...@@ -24,35 +13,22 @@ public:
virtual ~stream() = default; virtual ~stream() = default;
}; };
// Delegates all operations to the base FILE pointer using stream_ptr = std::unique_ptr<stream>;
// Delegates all operations to base stream
class filter_stream : public stream { class filter_stream : public stream {
public: public:
filter_stream(sFILE &&fp = make_sFILE()) : fp(std::move(fp)) {} filter_stream(stream_ptr &&base) : base(std::move(base)) {}
int read(void *buf, size_t len) override; int read(void *buf, size_t len) override;
int write(const void *buf, size_t len) override; int write(const void *buf, size_t len) override;
void set_base(sFILE &&f);
template <class T, class... Args >
void set_base(Args&&... args) {
set_base(make_stream<T>(std::forward<Args>(args)...));
}
protected:
sFILE fp;
};
// Handy interface for classes that need custom seek logic
class seekable_stream : public stream {
protected: protected:
size_t _pos = 0; stream_ptr base;
off_t seek_pos(off_t off, int whence);
virtual size_t end_pos() = 0;
}; };
// Byte stream that dynamically allocates memory // Byte stream that dynamically allocates memory
class byte_stream : public seekable_stream { class byte_stream : public stream {
public: public:
byte_stream(uint8_t *&buf, size_t &len); byte_stream(uint8_t *&buf, size_t &len);
template <class byte> template <class byte>
...@@ -64,10 +40,10 @@ public: ...@@ -64,10 +40,10 @@ public:
private: private:
uint8_t *&_buf; uint8_t *&_buf;
size_t &_len; size_t &_len;
size_t _pos = 0;
size_t _cap = 0; size_t _cap = 0;
void resize(size_t new_pos, bool zero = false); void resize(size_t new_pos, bool zero = false);
size_t end_pos() final { return _len; }
}; };
// File stream but does not close the file descriptor at any time // File stream but does not close the file descriptor at any time
...@@ -81,3 +57,28 @@ public: ...@@ -81,3 +57,28 @@ public:
private: private:
int fd; int fd;
}; };
/* ****************************************
* Bridge between stream class and C stdio
* ****************************************/
// sFILE -> stream_ptr
class fp_stream final : public stream {
public:
fp_stream(FILE *fp = nullptr) : fp(fp, fclose) {}
fp_stream(sFILE &&fp) : fp(std::move(fp)) {}
int read(void *buf, size_t len) override;
int write(const void *buf, size_t len) override;
off_t seek(off_t off, int whence) override;
private:
sFILE fp;
};
// stream_ptr -> sFILE
sFILE make_stream_fp(stream_ptr &&strm);
template <class T, class... Args>
sFILE make_stream_fp(Args &&... args) {
return make_stream_fp(stream_ptr(new T(std::forward<Args>(args)...)));
}
#pragma once #pragma once
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdio.h>
#include <dirent.h>
#include <pthread.h>
#include <poll.h>
#include <mntent.h>
#include "../missing.h" #include "../missing.h"
#include "../xwrap.h" #include "../xwrap.h"
#include "../files.h" #include "../files.h"
......
#pragma once #pragma once
#include <pthread.h>
#include <string> #include <string>
#include <functional> #include <functional>
#include <string_view> #include <string_view>
......
...@@ -55,10 +55,7 @@ static int __setcon(const char *ctx) { ...@@ -55,10 +55,7 @@ static int __setcon(const char *ctx) {
static int __getfilecon(const char *path, char **ctx) { static int __getfilecon(const char *path, char **ctx) {
char buf[1024]; char buf[1024];
int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
if (rc < 0) { if (rc >= 0)
errno = -rc;
return -1;
}
*ctx = strdup(buf); *ctx = strdup(buf);
return rc; return rc;
} }
...@@ -66,10 +63,7 @@ static int __getfilecon(const char *path, char **ctx) { ...@@ -66,10 +63,7 @@ static int __getfilecon(const char *path, char **ctx) {
static int __lgetfilecon(const char *path, char **ctx) { static int __lgetfilecon(const char *path, char **ctx) {
char buf[1024]; char buf[1024];
int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
if (rc < 0) { if (rc >= 0)
errno = -rc;
return -1;
}
*ctx = strdup(buf); *ctx = strdup(buf);
return rc; return rc;
} }
...@@ -77,39 +71,21 @@ static int __lgetfilecon(const char *path, char **ctx) { ...@@ -77,39 +71,21 @@ static int __lgetfilecon(const char *path, char **ctx) {
static int __fgetfilecon(int fd, char **ctx) { static int __fgetfilecon(int fd, char **ctx) {
char buf[1024]; char buf[1024];
int rc = syscall(__NR_fgetxattr, fd, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); int rc = syscall(__NR_fgetxattr, fd, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1);
if (rc < 0) { if (rc >= 0)
errno = -rc;
return -1;
}
*ctx = strdup(buf); *ctx = strdup(buf);
return rc; return rc;
} }
static int __setfilecon(const char *path, const char *ctx) { static int __setfilecon(const char *path, const char *ctx) {
int rc = syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); return syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
if (rc) {
errno = -rc;
return -1;
}
return 0;
} }
static int __lsetfilecon(const char *path, const char *ctx) { static int __lsetfilecon(const char *path, const char *ctx) {
int rc = syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); return syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
if (rc) {
errno = -rc;
return -1;
}
return 0;
} }
static int __fsetfilecon(int fd, const char *ctx) { static int __fsetfilecon(int fd, const char *ctx) {
int rc = syscall(__NR_fsetxattr, fd, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); return syscall(__NR_fsetxattr, fd, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0);
if (rc) {
errno = -rc;
return -1;
}
return 0;
} }
// Function pointers // Function pointers
...@@ -231,11 +207,10 @@ void restore_rootcon() { ...@@ -231,11 +207,10 @@ void restore_rootcon() {
setfilecon(MIRRDIR, ROOT_CON); setfilecon(MIRRDIR, ROOT_CON);
setfilecon(BLOCKDIR, ROOT_CON); setfilecon(BLOCKDIR, ROOT_CON);
struct dirent *entry; auto dir = xopen_dir("/sbin");
DIR *dir = xopendir("/sbin"); int dfd = dirfd(dir.get());
int dfd = dirfd(dir);
while ((entry = xreaddir(dir))) { for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_name == "."sv || entry->d_name == ".."sv) if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue; continue;
setfilecon_at(dfd, entry->d_name, ROOT_CON); setfilecon_at(dfd, entry->d_name, ROOT_CON);
...@@ -244,6 +219,4 @@ void restore_rootcon() { ...@@ -244,6 +219,4 @@ void restore_rootcon() {
setfilecon("/sbin/magisk.bin", MAGISK_CON); setfilecon("/sbin/magisk.bin", MAGISK_CON);
setfilecon("/sbin/magisk", MAGISK_CON); setfilecon("/sbin/magisk", MAGISK_CON);
setfilecon("/sbin/magiskinit", MAGISK_CON); setfilecon("/sbin/magiskinit", MAGISK_CON);
closedir(dir);
} }
...@@ -23,7 +23,7 @@ static int strm_close(void *v) { ...@@ -23,7 +23,7 @@ static int strm_close(void *v) {
return 0; return 0;
} }
sFILE make_stream(stream_ptr &&strm) { sFILE make_stream_fp(stream_ptr &&strm) {
sFILE fp(funopen(strm.release(), strm_read, strm_write, strm_seek, strm_close), fclose); sFILE fp(funopen(strm.release(), strm_read, strm_write, strm_seek, strm_close), fclose);
setbuf(fp.get(), nullptr); setbuf(fp.get(), nullptr);
return fp; return fp;
...@@ -44,29 +44,24 @@ off_t stream::seek(off_t off, int whence) { ...@@ -44,29 +44,24 @@ off_t stream::seek(off_t off, int whence) {
return -1; return -1;
} }
int filter_stream::read(void *buf, size_t len) { int fp_stream::read(void *buf, size_t len) {
return fread(buf, 1, len, fp.get()); return fread(buf, 1, len, fp.get());
} }
int filter_stream::write(const void *buf, size_t len) { int fp_stream::write(const void *buf, size_t len) {
return fwrite(buf, 1, len, fp.get()); return fwrite(buf, 1, len, fp.get());
} }
void filter_stream::set_base(sFILE &&f) { off_t fp_stream::seek(off_t off, int whence) {
fp = std::move(f); return fseek(fp.get(), off, whence);
} }
off_t seekable_stream::seek_pos(off_t off, int whence) { int filter_stream::read(void *buf, size_t len) {
switch (whence) { return base->read(buf, len);
case SEEK_CUR: }
return _pos + off;
case SEEK_END: int filter_stream::write(const void *buf, size_t len) {
return end_pos() + off; return base->write(buf, len);
case SEEK_SET:
return off;
default:
return -1;
}
} }
byte_stream::byte_stream(uint8_t *&buf, size_t &len) : _buf(buf), _len(len) { byte_stream::byte_stream(uint8_t *&buf, size_t &len) : _buf(buf), _len(len) {
...@@ -89,9 +84,20 @@ int byte_stream::write(const void *buf, size_t len) { ...@@ -89,9 +84,20 @@ int byte_stream::write(const void *buf, size_t len) {
} }
off_t byte_stream::seek(off_t off, int whence) { off_t byte_stream::seek(off_t off, int whence) {
off_t np = seek_pos(off, whence); off_t np;
if (np < 0) switch (whence) {
case SEEK_CUR:
np = _pos + off;
break;
case SEEK_END:
np = _len + off;
break;
case SEEK_SET:
np = off;
break;
default:
return -1; return -1;
}
resize(np, true); resize(np, true);
_pos = np; _pos = np;
return np; return np;
......
/* xwrap.cpp - wrappers around existing library functions.
*
* Functions with the x prefix are wrappers that either succeed or log the
* error message. They usually have the same arguments and return value
* as the function they wrap.
*
*/
#include <sched.h> #include <sched.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <pthread.h> #include <pthread.h>
#include <sys/socket.h> #include <sys/socket.h>
......
#pragma once #pragma once
#include <dirent.h>
#include <stdio.h>
#include <poll.h>
#include <fcntl.h>
FILE *xfopen(const char *pathname, const char *mode); FILE *xfopen(const char *pathname, const char *mode);
FILE *xfdopen(int fd, const char *mode); FILE *xfdopen(int fd, const char *mode);
int xopen(const char *pathname, int flags); int xopen(const char *pathname, int flags);
......
...@@ -70,9 +70,8 @@ main() { ...@@ -70,9 +70,8 @@ main() {
remove_system_su remove_system_su
find_manager_apk find_manager_apk
patch_boot_image install_magisk
cd /
# Cleanups # Cleanups
$BOOTMODE || recovery_cleanup $BOOTMODE || recovery_cleanup
rm -rf $TMPDIR rm -rf $TMPDIR
......
...@@ -13,20 +13,15 @@ ...@@ -13,20 +13,15 @@
# #
# File name Type Description # File name Type Description
# #
# boot_patch.sh script A script to patch boot. Expect path to boot image as parameter. # boot_patch.sh script A script to patch boot image for Magisk.
# (this file) The script will use binaries and files in its same directory # (this file) The script will use binaries and files in its same directory
# to complete the patching process # to complete the patching process
# util_functions.sh script A script which hosts all functions requires for this script # util_functions.sh script A script which hosts all functions required for this script
# to work properly # to work properly
# magiskinit binary The binary to replace /init, which has the magisk binary embedded # magiskinit binary The binary to replace /init; magisk binary embedded
# magiskboot binary A tool to unpack boot image, decompress ramdisk, extract ramdisk, # magiskboot binary A tool to manipulate boot images
# and patch the ramdisk for Magisk support # chromeos folder This folder includes all the utilities and keys to sign
# chromeos folder This folder should store all the utilities and keys to sign # (optional) chromeos boot images. Currently only used for Pixel C
# (optional) a chromeos device. Used for Pixel C
#
# If the script is not running as root, then the input boot image should be a stock image
# or have a backup included in ramdisk internally, since we cannot access the stock boot
# image placed under /data we've created when previously installed
# #
########################################################################################## ##########################################################################################
########################################################################################## ##########################################################################################
...@@ -104,10 +99,8 @@ fi ...@@ -104,10 +99,8 @@ fi
case $((STATUS & 3)) in case $((STATUS & 3)) in
0 ) # Stock boot 0 ) # Stock boot
ui_print "- Stock boot image detected" ui_print "- Stock boot image detected"
ui_print "- Backing up stock boot image"
SHA1=`./magiskboot sha1 "$BOOTIMAGE" 2>/dev/null` SHA1=`./magiskboot sha1 "$BOOTIMAGE" 2>/dev/null`
STOCKDUMP=stock_boot_${SHA1}.img.gz cat $BOOTIMAGE > stock_boot.img
./magiskboot compress "$BOOTIMAGE" $STOCKDUMP
cp -af ramdisk.cpio ramdisk.cpio.orig 2>/dev/null cp -af ramdisk.cpio ramdisk.cpio.orig 2>/dev/null
;; ;;
1 ) # Magisk patched 1 ) # Magisk patched
...@@ -158,7 +151,7 @@ rm -f ramdisk.cpio.orig config ...@@ -158,7 +151,7 @@ rm -f ramdisk.cpio.orig config
########################################################################################## ##########################################################################################
for dt in dtb kernel_dtb extra recovery_dtbo; do for dt in dtb kernel_dtb extra recovery_dtbo; do
[ -f $dt ] && ./magiskboot dtb $dt patch && ui_print "- Patching fstab in $dt" [ -f $dt ] && ./magiskboot dtb $dt patch && ui_print "- Patch fstab in $dt"
done done
if [ -f kernel ]; then if [ -f kernel ]; then
......
...@@ -53,7 +53,7 @@ ui_print "- Target image: $BOOTIMAGE" ...@@ -53,7 +53,7 @@ ui_print "- Target image: $BOOTIMAGE"
# Detect version and architecture # Detect version and architecture
api_level_arch_detect api_level_arch_detect
[ $API -lt 17 ] && abort "! Magisk is only for Android 4.2 and above" [ $API -lt 17 ] && abort "! Magisk only support Android 4.2 and above"
ui_print "- Device platform: $ARCH" ui_print "- Device platform: $ARCH"
...@@ -108,9 +108,8 @@ $BOOTMODE || recovery_actions ...@@ -108,9 +108,8 @@ $BOOTMODE || recovery_actions
# Boot/DTBO Patching # Boot/DTBO Patching
########################################################################################## ##########################################################################################
patch_boot_image install_magisk
cd /
# Cleanups # Cleanups
$BOOTMODE || recovery_cleanup $BOOTMODE || recovery_cleanup
rm -rf $TMPDIR rm -rf $TMPDIR
......
...@@ -15,6 +15,7 @@ TMPDIR=/dev/tmp ...@@ -15,6 +15,7 @@ TMPDIR=/dev/tmp
INSTALLER=$TMPDIR/install INSTALLER=$TMPDIR/install
CHROMEDIR=$INSTALLER/chromeos CHROMEDIR=$INSTALLER/chromeos
PERSISTDIR=/sbin/.magisk/mirror/persist
# Default permissions # Default permissions
umask 022 umask 022
...@@ -50,6 +51,7 @@ chmod -R 755 $MAGISKBIN ...@@ -50,6 +51,7 @@ chmod -R 755 $MAGISKBIN
check_data check_data
$DATA_DE || abort "! Cannot access /data, please uninstall with Magisk Manager" $DATA_DE || abort "! Cannot access /data, please uninstall with Magisk Manager"
$BOOTMODE || recovery_actions $BOOTMODE || recovery_actions
run_migrations
########################################################################################## ##########################################################################################
# Uninstall # Uninstall
...@@ -57,7 +59,6 @@ $BOOTMODE || recovery_actions ...@@ -57,7 +59,6 @@ $BOOTMODE || recovery_actions
get_flags get_flags
find_boot_image find_boot_image
find_dtbo_image
[ -e $BOOTIMAGE ] || abort "! Unable to detect boot image" [ -e $BOOTIMAGE ] || abort "! Unable to detect boot image"
ui_print "- Found target image: $BOOTIMAGE" ui_print "- Found target image: $BOOTIMAGE"
...@@ -96,16 +97,18 @@ case $((STATUS & 3)) in ...@@ -96,16 +97,18 @@ case $((STATUS & 3)) in
1 ) # Magisk patched 1 ) # Magisk patched
ui_print "- Magisk patched image detected" ui_print "- Magisk patched image detected"
# Find SHA1 of stock boot image # Find SHA1 of stock boot image
[ -z $SHA1 ] && SHA1=`./magiskboot cpio ramdisk.cpio sha1 2>/dev/null` SHA1=`./magiskboot cpio ramdisk.cpio sha1 2>/dev/null`
STOCKBOOT=/data/stock_boot_${SHA1}.img.gz BACKUPDIR=/data/magisk_backup_$SHA1
STOCKDTBO=/data/stock_dtbo.img.gz if [ -d $BACKUPDIR ]; then
if [ -f $STOCKBOOT ]; then
ui_print "- Restoring stock boot image" ui_print "- Restoring stock boot image"
flash_image $STOCKBOOT $BOOTIMAGE flash_image $BACKUPDIR/boot.img.gz $BOOTIMAGE
if [ -f $STOCKDTBO -a -b "$DTBOIMAGE" ]; then for name in dtb dtbo; do
ui_print "- Restoring stock dtbo image" [ -f $BACKUPDIR/${name}.img.gz ] || continue
flash_image $STOCKDTBO $DTBOIMAGE IMAGE=`find_block $name$SLOT`
fi [ -z $IMAGE ] && continue
ui_print "- Restoring stock $name image"
flash_image $BACKUPDIR/${name}.img.gz $IMAGE
done
else else
ui_print "! Boot image backup unavailable" ui_print "! Boot image backup unavailable"
ui_print "- Restoring ramdisk with internal backup" ui_print "- Restoring ramdisk with internal backup"
...@@ -128,9 +131,10 @@ case $((STATUS & 3)) in ...@@ -128,9 +131,10 @@ case $((STATUS & 3)) in
esac esac
ui_print "- Removing Magisk files" ui_print "- Removing Magisk files"
rm -rf /cache/*magisk* /cache/unblock /data/*magisk* /data/cache/*magisk* /data/property/*magisk* \ rm -rf \
/data/Magisk.apk /data/busybox /data/custom_ramdisk_patch.sh /data/adb/*magisk* \ /cache/*magisk* /cache/unblock /data/*magisk* /data/cache/*magisk* /data/property/*magisk* \
/data/adb/post-fs-data.d /data/adb/service.d /data/adb/modules* 2>/dev/null /data/Magisk.apk /data/busybox /data/custom_ramdisk_patch.sh /data/adb/*magisk* \
/data/adb/post-fs-data.d /data/adb/service.d /data/adb/modules* $PERSISTDIR/magisk 2>/dev/null
if [ -f /system/addon.d/99-magisk.sh ]; then if [ -f /system/addon.d/99-magisk.sh ]; then
mount -o rw,remount /system mount -o rw,remount /system
......
This diff is collapsed.
This diff is collapsed.
...@@ -34,7 +34,7 @@ repositories { ...@@ -34,7 +34,7 @@ repositories {
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
def bcVer = '1.63' def bcVer = '1.64'
api "org.bouncycastle:bcprov-jdk15on:${bcVer}" api "org.bouncycastle:bcprov-jdk15on:${bcVer}"
api "org.bouncycastle:bcpkix-jdk15on:${bcVer}" api "org.bouncycastle:bcpkix-jdk15on:${bcVer}"
} }
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment