Merge branch 'master' into feature/redesign

This commit is contained in:
topjohnwu 2020-01-02 14:52:50 +08:00
commit 40c64d50d5
82 changed files with 1960 additions and 1642 deletions

View File

@ -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 {
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 {
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 {
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'
} }

View File

@ -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 {
} }
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)

View File

@ -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) {

View File

@ -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 {
} }
} }
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()

View File

@ -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

View File

@ -1,7 +1,7 @@
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

View File

@ -1,7 +1,7 @@
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

View File

@ -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

View File

@ -1,7 +1,6 @@
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

View File

@ -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

View File

@ -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() {
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() {
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>()

View File

@ -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
} }

View File

@ -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() {
} }
} }
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() {
// Setup shortcuts // Setup shortcuts
Shortcuts.setup(this) Shortcuts.setup(this)
Shell.su("mm_patch_dtbo").submit { if (Info.isNewReboot) {
if (it.isSuccess) val shell = Shell.newInstance()
Notifications.dtboPatched(this) shell.newJob().add("mm_patch_dtb").submit {
if (it.isSuccess)
Notifications.dtboPatched(this)
shell.close()
}
} }
DONE = true DONE = true

View File

@ -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() {
} }
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() {
job.add(context.rawResource(R.raw.nonroot_utils)) job.add(context.rawResource(R.raw.nonroot_utils))
} }
job.add("mount_partitions", job.add(
"get_flags", "mount_partitions",
"run_migrations", "get_flags",
"export BOOTMODE=true") "run_migrations",
.exec() "export BOOTMODE=true"
).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
} }

View File

@ -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" />

View File

@ -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"

View File

@ -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()}"

View File

@ -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"

View File

@ -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 @@
<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()}"

View File

@ -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 @@
<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"

View File

@ -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}"

View File

@ -1,5 +1,4 @@
# 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

View File

@ -1,6 +1,7 @@
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() {

View File

@ -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() {
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() {
[ "$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`

View File

@ -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 @@
<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 @@
<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 @@
<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 @@
<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 @@
<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 @@
<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 @@
<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>

View File

@ -8,13 +8,14 @@
<string name="settings">Einstellungen</string> <string name="settings">Einstellungen</string>
<string name="install">Installieren</string> <string name="install">Installieren</string>
<string name="unsupport_magisk_title">Nicht unterstützte Magisk Version</string> <string name="unsupport_magisk_title">Nicht unterstützte Magisk Version</string>
<string name="unsupport_magisk_msg">Diese Version von Magisk Manager unterstützt keine Magisk-Versionen unter %1$s.\n\nDie App verhält sich so, als ob kein Magisk installiert ist. Bitte Magisk so schnell wie möglich aktualisieren.</string>
<!--Status Fragment--> <!--Status Fragment-->
<string name="magisk_version_error">Magisk ist nicht installiert</string> <string name="magisk_version_error">Magisk ist nicht installiert</string>
<string name="checking_for_updates">Suche nach Aktualisierungen…</string> <string name="checking_for_updates">Suche nach Aktualisierungen…</string>
<string name="invalid_update_channel">Ungültiger Aktualisierungskanal</string> <string name="invalid_update_channel">Ungültiger Aktualisierungskanal</string>
<string name="safetyNet_check_text">SafetyNet-Status abfragen</string> <string name="safetyNet_check_text">SafetyNet-Status abfragen</string>
<string name="checking_safetyNet_status">Prüfe SafetyNet-Status…</string> <string name="checking_safetyNet_status">SafetyNet-Status prüfen</string>
<string name="safetyNet_check_success">SafetyNet-Test erfolgreich</string> <string name="safetyNet_check_success">SafetyNet-Test erfolgreich</string>
<string name="safetyNet_api_error">SafetyNet API Fehler</string> <string name="safetyNet_api_error">SafetyNet API Fehler</string>
<string name="safetyNet_res_invalid">Die Antwort ist ungültig</string> <string name="safetyNet_res_invalid">Die Antwort ist ungültig</string>
@ -23,11 +24,12 @@
<string name="advanced_settings_title">Erweiterte Optionen</string> <string name="advanced_settings_title">Erweiterte Optionen</string>
<string name="keep_force_encryption">\"force encryption\" beibehalten</string> <string name="keep_force_encryption">\"force encryption\" beibehalten</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity beibehalten</string> <string name="keep_dm_verity">AVB 2.0/dm-verity beibehalten</string>
<string name="recovery_mode">Wiederherstellungsmodus</string>
<string name="current_installed">Installiert: %1$s</string> <string name="current_installed">Installiert: %1$s</string>
<string name="latest_version">Neueste: %1$s</string> <string name="latest_version">Neueste: %1$s</string>
<string name="uninstall">Deinstallieren</string> <string name="uninstall">Deinstallieren</string>
<string name="uninstall_magisk_title">Magisk deinstallieren</string> <string name="uninstall_magisk_title">Magisk deinstallieren</string>
<string name="uninstall_magisk_msg">Alle Module werden deaktiviert/entfernt. Root wird entfernt, und Ihre Daten werden möglicherweise verschlüsselt, wenn nicht bereits der Fall.</string> <string name="uninstall_magisk_msg">Alle Module werden deaktiviert/entfernt. Root wird entfernt, und deine Daten werden möglicherweise verschlüsselt, wenn es nicht bereits der Fall ist.</string>
<string name="update">aktualisieren</string> <string name="update">aktualisieren</string>
<string name="core_only_enabled">(Core only Modus aktiviert)</string> <string name="core_only_enabled">(Core only Modus aktiviert)</string>
@ -43,6 +45,7 @@
<string name="reboot_recovery">Neustart in das Recovery</string> <string name="reboot_recovery">Neustart in das Recovery</string>
<string name="reboot_bootloader">Neustart in den Bootloader</string> <string name="reboot_bootloader">Neustart in den Bootloader</string>
<string name="reboot_download">Neustart in den Download-Modus</string> <string name="reboot_download">Neustart in den Download-Modus</string>
<string name="reboot_edl">Neustart in den EDL-Modus</string>
<!--Repo Fragment--> <!--Repo Fragment-->
<string name="update_available">Aktualisierung verfügbar</string> <string name="update_available">Aktualisierung verfügbar</string>
@ -67,6 +70,8 @@
<string name="progress_channel">Fortschrittsbenachrichtigungen</string> <string name="progress_channel">Fortschrittsbenachrichtigungen</string>
<string name="download_complete">Download abgeschlossen</string> <string name="download_complete">Download abgeschlossen</string>
<string name="download_file_error">Fehler beim Herunterladen der Datei</string> <string name="download_file_error">Fehler beim Herunterladen der Datei</string>
<string name="download_open_parent">Im übergeordneten Ordner anzeigen</string>
<string name="download_open_self">Datei anzeigen</string>
<string name="magisk_update_title">Neues Magisk Update verfügbar!</string> <string name="magisk_update_title">Neues Magisk Update verfügbar!</string>
<string name="manager_update_title">Aktualisierung für Magisk Manager verfügbar!</string> <string name="manager_update_title">Aktualisierung für Magisk Manager verfügbar!</string>
@ -74,71 +79,77 @@
<string name="manager_download_install">Herunterladen und installieren</string> <string name="manager_download_install">Herunterladen und installieren</string>
<string name="download_zip_only">Nur Zip-Datei herunterladen</string> <string name="download_zip_only">Nur Zip-Datei herunterladen</string>
<string name="direct_install">Direkt installieren (empfohlen)</string> <string name="direct_install">Direkt installieren (empfohlen)</string>
<string name="install_inactive_slot">Installiere in inaktiven Slot (Nach OTA)</string> <string name="install_inactive_slot">In inaktiven Slot installieren (Nach OTA)</string>
<string name="install_inactive_slot_msg">Dein Gerät wird GEZWUNGEN in den aktuell inaktiven Slot zu starten, nachdem ein Neustart durchgeführt wurde!\nBenutze diese Option nur, nachdem das OTA beendet wurde.\nFortsetzen?</string> <string name="install_inactive_slot_msg">Dein Gerät wird GEZWUNGEN in den aktuell inaktiven Slot zu starten, nachdem ein Neustart durchgeführt wurde!\nBenutze diese Option nur, nachdem das OTA beendet wurde.\nFortsetzen?</string>
<string name="select_method">Methode auswählen</string> <string name="select_method">Methode auswählen</string>
<string name="setup_title">Zusätzliche Einrichtung</string> <string name="setup_title">Zusätzliche Einrichtung</string>
<string name="select_patch_file">Auswählen und Patchen einer Datei</string> <string name="select_patch_file">Auswählen und Patchen einer Datei</string>
<string name="patch_file_msg">Wählen Sie ein Rohabbild (*.img) oder eine ODIN-Tar-Datei (*.tar) aus.</string> <string name="patch_file_msg">Ein Rohabbild (*.img) oder eine ODIN-Tar-Datei (*.tar) auswählen.</string>
<string name="reboot_delay_toast">Neustart in 5 Sekunden…</string> <string name="reboot_delay_toast">Neustart in 5 Sekunden…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="repo_install_title">Installiere %1$s</string> <string name="repo_install_title">%1$s installieren</string>
<string name="repo_install_msg">Möchtest du %1$s installieren?</string> <string name="repo_install_msg">Möchtest du %1$s installieren?</string>
<string name="download">Herunterladen</string> <string name="download">Herunterladen</string>
<string name="reboot">Neustart</string> <string name="reboot">Neustart</string>
<string name="settings_reboot_toast">Neustarten, um die Änderungen zu übernehmen</string> <string name="settings_reboot_toast">Neustarten, um die Änderungen zu übernehmen</string>
<string name="release_notes">Versionshinweise</string> <string name="release_notes">Versionshinweise</string>
<string name="repo_cache_cleared">Repo-Cache geleert</string> <string name="repo_cache_cleared">Repo-Cache geleert</string>
<string name="dtbo_patched_title">DTBO wurde gepatched!</string> <string name="dtbo_patched_title">DTBO wurde gepatched!</string>
<string name="dtbo_patched_reboot">Magisk Manager hat dtbo.img gepatched, bitte neustarten</string> <string name="dtbo_patched_reboot">Magisk Manager hat dtbo.img gepatched, bitte neustarten</string>
<string name="flashing">Flashing</string> <string name="flashing">Flashing</string>
<string name="done">Erledigt!</string> <string name="done">Erledigt!</string>
<string name="failure">Fehler</string> <string name="failure">Fehler</string>
<string name="hide_manager_title">Verberge Magisk Manager…</string> <string name="hide_manager_title">Magisk Manager verbergen</string>
<string name="hide_manager_fail_toast">Verbergen von Magisk Manager fehlgeschlagen…</string> <string name="hide_manager_fail_toast">Magisk Manager verbergen ist fehlgeschlagen…</string>
<string name="open_link_failed_toast">Es wurde keine Anwendung gefunden, um diesen Link zu öffnen...</string> <string name="open_link_failed_toast">Es wurde keine App gefunden, um diesen Link zu öffnen…</string>
<string name="warning">Warnung</string> <string name="warning">Warnung</string>
<string name="complete_uninstall">Komplette Deinstallation</string> <string name="complete_uninstall">Komplette Deinstallation</string>
<string name="restore_img">Images wiederherstellen</string> <string name="restore_img">Images wiederherstellen</string>
<string name="restore_img_msg">Wiederherstellen...</string> <string name="restore_img_msg">Wiederherstellen</string>
<string name="restore_done">Wiederherstellung erfolgreich!</string> <string name="restore_done">Wiederherstellung erfolgreich!</string>
<string name="restore_fail">Kein Original Backup vorhanden!</string> <string name="restore_fail">Kein Original Backup vorhanden!</string>
<string name="proprietary_title">Lade proprietären Code herunter</string> <string name="proprietary_title">Lade proprietären Code herunter</string>
<string name="proprietary_notice">Magisk Manager ist FOSS und enthält keinen proprietären SafetyNet API Code von Google. Magisk Manager erlauben eine Erweiterung (enthält GoogleApiClient) für SafetyNet-Checks herunterzuladen?</string> <string name="proprietary_notice">Magisk Manager ist FOSS und enthält keinen proprietären SafetyNet API Code von Google. Magisk Manager erlauben eine Erweiterung (enthält GoogleApiClient) für SafetyNet-Checks herunterzuladen?</string>
<string name="setup_fail">Einrichtung fehlgeschlagen</string> <string name="setup_fail">Einrichtung fehlgeschlagen</string>
<string name="env_fix_title">Zusätzliche Einrichtung erforderlich</string> <string name="env_fix_title">Zusätzliche Einrichtung erforderlich</string>
<string name="env_fix_msg">Ihr Gerät benötigt zusätzliche Einrichtung, damit Magisk ordnungsgemäß funktioniert. Es wird eine Magisk-Installations-Zip wird heruntergeladen, fortfahren?</string> <string name="env_fix_msg">Dein Gerät benötigt eine zusätzliche Einrichtung, damit Magisk ordnungsgemäß funktioniert. Es wird eine Magisk-Installations-Zip heruntergeladen. Fortfahren?</string>
<string name="setup_msg">Umgebungseinrichtung läuft…</string> <string name="setup_msg">Umgebungseinrichtung läuft…</string>
<string name="authenticate">Authentifizieren</string>
<!--Settings Activity --> <!--Settings Activity -->
<string name="settings_general_category">Allgemein</string> <string name="settings_general_category">Allgemein</string>
<string name="settings_dark_theme_title">Dunkles Theme</string> <string name="settings_dark_theme_title">Dunkles Theme</string>
<string name="settings_dark_theme_summary">Dunkles Theme aktivieren</string> <string name="settings_dark_theme_summary">Dunkles Theme aktivieren</string>
<string name="settings_download_path_title">Download-Verzeichnis</string>
<string name="settings_download_path_message">Dateien werden in %1$s gespeichert</string>
<string name="settings_clear_cache_title">Repo-Cache leeren</string> <string name="settings_clear_cache_title">Repo-Cache leeren</string>
<string name="settings_clear_cache_summary">Löscht die zwischengespeicherten Informationen des Online-Repos. Erzwingt eine Aktualisierung</string> <string name="settings_clear_cache_summary">Löscht die zwischengespeicherten Informationen des Online-Repos. Erzwingt eine Aktualisierung</string>
<string name="settings_hide_manager_title">Magisk Manager verbergen</string> <string name="settings_hide_manager_title">Magisk Manager verbergen</string>
<string name="settings_hide_manager_summary">Magisk Manager mit zufälligem Paketnamen neu packen</string> <string name="settings_hide_manager_summary">Magisk Manager mit zufälligem Paketnamen neu packen</string>
<string name="settings_restore_manager_title">Magisk Manager wiederherstellen</string> <string name="settings_restore_manager_title">Magisk Manager wiederherstellen</string>
<string name="settings_restore_manager_summary">Stellt Magisk Manager mit ursprünglichem Paketnamen wieder her</string> <string name="settings_restore_manager_summary">Magisk Manager mit ursprünglichem Paketnamen wiederherstellen</string>
<string name="language">Sprache</string> <string name="language">Sprache</string>
<string name="system_default">(Systemstandard)</string> <string name="system_default">(Systemstandard)</string>
<string name="settings_update">Aktualisierungs-Einstellungen</string> <string name="settings_update">Aktualisierungs-Einstellungen</string>
<string name="settings_check_update_title">Prüfe nach Aktualisierungen</string> <string name="settings_check_update_title">Auf Aktualisierungen prüfen</string>
<string name="settings_check_update_summary">Prüfe regelmäßig im Hintergrund nach Aktualisierungen</string> <string name="settings_check_update_summary">Regelmäßig im Hintergrund auf Aktualisierungen prüfen</string>
<string name="settings_update_channel_title">Aktualisierungs-Kanal</string> <string name="settings_update_channel_title">Aktualisierungs-Kanal</string>
<string name="settings_update_stable">Stabil</string> <string name="settings_update_stable">Stabil</string>
<string name="settings_update_beta">Beta</string> <string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Benutzerdefiniert</string> <string name="settings_update_custom">Benutzerdefiniert</string>
<string name="settings_update_custom_msg">Gib eine benutzerdefinierte URL ein</string> <string name="settings_update_custom_msg">Eine benutzerdefinierte URL eingeben</string>
<string name="settings_core_only_title">Nur Kernfunktionen</string> <string name="settings_core_only_title">Nur Kernfunktionen</string>
<string name="settings_core_only_summary">Aktiviert lediglich die Kernfunktionen, Module werden nicht geladen. MagiskSU und Magisk Hide bleiben weiterhin aktiv</string> <string name="settings_core_only_summary">Aktiviert lediglich die Kernfunktionen, Module werden nicht geladen. MagiskSU und Magisk Hide bleiben weiterhin aktiv</string>
<string name="settings_magiskhide_summary">Versteckt Magisk vor diversen Entdeckungsmethoden</string> <string name="settings_magiskhide_summary">Versteckt Magisk vor diversen Entdeckungsmethoden</string>
<string name="settings_hosts_title">Systemlose Hosts-Datei</string> <string name="settings_hosts_title">Systemlose Hosts-Datei</string>
<string name="settings_hosts_summary">Systemlose Unterstützung für Werbeblocker</string> <string name="settings_hosts_summary">Systemlose Unterstützung für Werbeblocker</string>
<string name="settings_hosts_toast">systemless Hosts-Modul hinzugefügt</string> <string name="settings_hosts_toast">Systemless Hosts-Modul hinzugefügt</string>
<string name="settings_app_name">Den gewünschten App-Namen eingeben</string>
<string name="settings_app_name_hint">Neuer Name</string>
<string name="settings_app_name_helper">Die App wird unter diesem Namen neu gepackt</string>
<string name="settings_app_name_error">Ungültiges Format</string>
<string name="settings_su_app_adb">Apps und ADB</string> <string name="settings_su_app_adb">Apps und ADB</string>
<string name="settings_su_app">Nur Apps</string> <string name="settings_su_app">Nur Apps</string>
<string name="settings_su_adb">Nur ADB</string> <string name="settings_su_adb">Nur ADB</string>
@ -156,6 +167,9 @@
<string name="request_timeout_summary">%1$d Sekunden</string> <string name="request_timeout_summary">%1$d Sekunden</string>
<string name="settings_su_reauth_title">Nach Aktualisierung erneut authentifizieren</string> <string name="settings_su_reauth_title">Nach Aktualisierung erneut authentifizieren</string>
<string name="settings_su_reauth_summary">Superuser-Zugriff nach App-Aktualisierung erneut abfragen</string> <string name="settings_su_reauth_summary">Superuser-Zugriff nach App-Aktualisierung erneut abfragen</string>
<string name="settings_su_biometric_title">Biometrische Authentifizierung aktivieren</string>
<string name="settings_su_biometric_summary">Biometrische Authentifizierung verwenden, um Superuser-Anfragen zu ermöglichen</string>
<string name="no_biometric">Nicht unterstütztes Gerät oder keine biometrischen Einstellungen aktiviert</string>
<string name="multiuser_mode">Mehrbenutzermodus</string> <string name="multiuser_mode">Mehrbenutzermodus</string>
<string name="settings_owner_only">Nur der Gerätebesitzer</string> <string name="settings_owner_only">Nur der Gerätebesitzer</string>
@ -172,6 +186,7 @@
<string name="global_summary">Alle Root-Sitzungen benutzen den global angelegten Namespace</string> <string name="global_summary">Alle Root-Sitzungen benutzen den global angelegten Namespace</string>
<string name="requester_summary">Root-Sitzungen erben den Namespace des Abfragenden</string> <string name="requester_summary">Root-Sitzungen erben den Namespace des Abfragenden</string>
<string name="isolate_summary">Jede Root-Sitzung hat ihren isolierten Namespace</string> <string name="isolate_summary">Jede Root-Sitzung hat ihren isolierten Namespace</string>
<string name="settings_download_path_error">Fehler beim Erstellen eines Ordners. Er muss im Stammverzeichnis des Speichers zugänglich und darf keine Datei sein.</string>
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">Superuser-Anfrage</string> <string name="su_request_title">Superuser-Anfrage</string>
@ -187,7 +202,7 @@
<string name="sixtymin">60 Min.</string> <string name="sixtymin">60 Min.</string>
<string name="su_allow_toast">Superuser-Rechte für %1$s gewährt</string> <string name="su_allow_toast">Superuser-Rechte für %1$s gewährt</string>
<string name="su_deny_toast">Superuser-Rechte für %1$s verweigert</string> <string name="su_deny_toast">Superuser-Rechte für %1$s verweigert</string>
<string name="no_apps_found">Keine Applikationen gefunden</string> <string name="no_apps_found">Keine Apps gefunden</string>
<string name="su_snack_grant">Superuser-Rechte werden für %1$s gewährt</string> <string name="su_snack_grant">Superuser-Rechte werden für %1$s gewährt</string>
<string name="su_snack_deny">Superuser-Rechte werden für %1$s verweigert</string> <string name="su_snack_deny">Superuser-Rechte werden für %1$s verweigert</string>
<string name="su_snack_notif_on">Benachrichtigungen für %1$s sind aktiviert</string> <string name="su_snack_notif_on">Benachrichtigungen für %1$s sind aktiviert</string>
@ -205,6 +220,6 @@
<string name="command">Befehl: %1$s</string> <string name="command">Befehl: %1$s</string>
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">System Applikationen anzeigen</string> <string name="show_system_app">System-Apps anzeigen</string>
</resources> </resources>

View File

@ -3,216 +3,221 @@
<!--Welcome Activity--> <!--Welcome Activity-->
<string name="modules">Modules</string> <string name="modules">Modules</string>
<string name="downloads">Téléchargements</string> <string name="downloads">Téléchargements</string>
<string name="superuser">Superutilisateur</string> <string name="superuser">Superutilisateur</string>
<string name="log">Journal</string> <string name="log">Journal</string>
<string name="settings">Paramètres</string> <string name="settings">Paramètres</string>
<string name="install">Installer</string> <string name="install">Installer</string>
<string name="unsupport_magisk_title">Version de Magisk non prise en charge</string> <string name="unsupport_magisk_title">Version de Magisk non prise en charge</string>
<string name="unsupport_magisk_msg">Cette version de Magisk Manager ne prend pas en charge les versions de Magisk inférieures à %1$s.\n\nLapplication se comportera comme si Magisk nétait pas installé, veuillez mettre à jour Magisk dès que possible.</string>
<!--Status Fragment--> <!--Status Fragment-->
<string name="magisk_version_error">Magisk nest pas installé.</string> <string name="magisk_version_error">Magisk nest pas installé</string>
<string name="checking_for_updates">Vérification des mises à jour…</string> <string name="checking_for_updates">Vérification des mises à jour…</string>
<string name="invalid_update_channel">Canal de mise à jour invalide</string> <string name="invalid_update_channel">Canal de mise à jour invalide</string>
<string name="safetyNet_check_text">Appuyez pour lancer le contrôle SafetyNet.</string> <string name="safetyNet_check_text">Appuyez pour lancer le contrôle SafetyNet</string>
<string name="checking_safetyNet_status">Vérification de létat de SafetyNet…</string> <string name="checking_safetyNet_status">Vérification de létat de SafetyNet…</string>
<string name="safetyNet_check_success">Contrôle SafetyNet passé avec succès</string> <string name="safetyNet_check_success">Contrôle SafetyNet réussi</string>
<string name="safetyNet_api_error">Erreur de lAPI SafetyNet</string> <string name="safetyNet_api_error">Erreur de lAPI SafetyNet</string>
<string name="safetyNet_res_invalid">La réponse est incorrecte.</string> <string name="safetyNet_res_invalid">La réponse est incorrecte</string>
<string name="magisk_up_to_date">Magisk est à jour</string> <string name="magisk_up_to_date">Magisk est à jour</string>
<string name="manager_up_to_date">Magisk Manager est à jour</string> <string name="manager_up_to_date">Magisk Manager est à jour</string>
<string name="advanced_settings_title">Paramètres avancés</string> <string name="advanced_settings_title">Paramètres avancés</string>
<string name="keep_force_encryption">Conserver le chiffrement forcé</string> <string name="keep_force_encryption">Conserver le chiffrement forcé</string>
<string name="keep_dm_verity">Conserver AVB 2.0/dm-verity</string> <string name="keep_dm_verity">Conserver AVB 2.0/dm-verity</string>
<string name="recovery_mode">Mode Récupération</string> <string name="recovery_mode">Mode récupération</string>
<string name="current_installed">Version actuellement installée : %1$s</string> <string name="current_installed">Version actuellement installée : %1$s</string>
<string name="latest_version">Dernière version disponible : %1$s</string> <string name="latest_version">Dernière version disponible : %1$s</string>
<string name="uninstall">Désinstaller</string> <string name="uninstall">Désinstaller</string>
<string name="uninstall_magisk_title">Désinstaller Magisk</string> <string name="uninstall_magisk_title">Désinstaller Magisk</string>
<string name="uninstall_magisk_msg">Tous les modules seront désactivés ou supprimés. Les permissions de superutilisateur seront perdues et vos données seront potentiellement chiffrées si elles ne le sont pas déjà.</string> <string name="uninstall_magisk_msg">Tous les modules seront désactivés ou supprimés!\nLaccès superutiliateur sera perdu!\nVos données seront potentiellement chiffrées si elles ne le sont pas déjà.</string>
<string name="update">Mise à jour</string> <string name="update">Mise à jour</string>
<string name="core_only_enabled">(Mode « sans modules » activé)</string> <string name="core_only_enabled">(mode « sans modules » activé)</string>
<!--Module Fragment--> <!--Module Fragment-->
<string name="no_info_provided">(aucune information transmise)</string> <string name="no_info_provided">(aucune information transmise)</string>
<string name="no_modules_found">Aucun module trouvé.</string> <string name="no_modules_found">Aucun module trouvé</string>
<string name="update_file_created">Le module sera mis à jour au prochain redémarrage.</string> <string name="update_file_created">Le module sera mis à jour au prochain redémarrage!</string>
<string name="remove_file_created">Le module sera supprimé au prochain redémarrage.</string> <string name="remove_file_created">Le module sera supprimé au prochain redémarrage!</string>
<string name="remove_file_deleted">Le module ne sera pas supprimé au prochain redémarrage.</string> <string name="remove_file_deleted">Le module ne sera pas supprimé au prochain redémarrage!</string>
<string name="disable_file_created">Le module sera désactivé au prochain redémarrage.</string> <string name="disable_file_created">Le module sera désactivé au prochain redémarrage!</string>
<string name="disable_file_removed">Le module sera activé au prochain redémarrage.</string> <string name="disable_file_removed">Le module sera activé au prochain redémarrage!</string>
<string name="author">Créé par %1$s</string> <string name="author">Créé par %1$s</string>
<string name="reboot_recovery">Redémarrer en mode récupération</string> <string name="reboot_recovery">Redémarrer en mode récupération</string>
<string name="reboot_bootloader">Redémarrer en mode amorçage</string> <string name="reboot_bootloader">Redémarrer en mode amorçage</string>
<string name="reboot_download">Redémarrer en mode téléchargement</string> <string name="reboot_download">Redémarrer en mode téléchargement</string>
<string name="reboot_edl">Redémarrer en mode EDL</string> <string name="reboot_edl">Redémarrer en mode secours (EDL)</string>
<!--Repo Fragment--> <!--Repo Fragment-->
<string name="update_available">Mise à jour disponible</string> <string name="update_available">Mise à jour disponible</string>
<string name="installed">Installé</string> <string name="installed">Installé</string>
<string name="not_installed">Non installé</string> <string name="not_installed">Non installé</string>
<string name="updated_on">Mis à jour le : %1$s</string> <string name="updated_on">Mis à jour le : %1$s</string>
<string name="sorting_order">Mode de tri :</string> <string name="sorting_order">Mode de tri</string>
<string name="sort_by_name">par nom</string> <string name="sort_by_name">alphabétique</string>
<string name="sort_by_update">par date décroissante</string> <string name="sort_by_update">antichronologique</string>
<!--Log Fragment--> <!--Log Fragment-->
<string name="menuSaveLog">Enregistrer le journal</string> <string name="menuSaveLog">Enregistrer le journal</string>
<string name="menuReload">Actualiser</string> <string name="menuReload">Actualiser</string>
<string name="menuClearLog">Effacer le journal maintenant</string> <string name="menuClearLog">Effacer le journal maintenant</string>
<string name="logs_cleared">Journal effacé avec succès.</string> <string name="logs_cleared">Le journal a bien été effacé.</string>
<!--About Activity--> <!--About Activity-->
<string name="app_changelog">Journal</string> <string name="app_changelog">Journal des modifications</string>
<!-- System Components, Notifications --> <!-- System Components, Notifications -->
<string name="update_channel">Mises à jour de Magisk</string> <string name="update_channel">Mises à jour de Magisk</string>
<string name="progress_channel">Progression des notifications</string> <string name="progress_channel">Notifications de progression</string>
<string name="download_complete">Téléchargement terminé</string> <string name="download_complete">Téléchargement terminé</string>
<string name="download_file_error">Erreur de téléchargement du fichier</string> <string name="download_file_error">Erreur lors du téléchargement du fichier</string>
<string name="download_open_parent">Afficher dans le dossier parent</string> <string name="download_open_parent">Afficher le dossier parent</string>
<string name="download_open_self">Afficher fichier</string> <string name="download_open_self">Afficher le fichier</string>
<string name="magisk_update_title">Une mise à jour de Magisk est disponible!</string> <string name="magisk_update_title">Une mise à jour de Magisk est disponible!</string>
<string name="manager_update_title">Une mise à jour de Magisk Manager est disponible!</string> <string name="manager_update_title">Une mise à jour de Magisk Manager est disponible!</string>
<!-- Installation --> <!-- Installation -->
<string name="manager_download_install">Appuyez pour le télécharger et linstaller.</string> <string name="manager_download_install">Appuyez pour le télécharger et linstaller.</string>
<string name="download_zip_only">Télécharger le ZIP uniquement</string> <string name="download_zip_only">Télécharger le ZIP sans linstaller</string>
<string name="direct_install">Installation directe (recommandée)</string> <string name="direct_install">Installation directe (recommandée)</string>
<string name="install_inactive_slot">Installer dans lespace inactif (après mise à jour OTA)</string> <string name="install_inactive_slot">Installer dans lespace inactif (après mise à jour OTA)</string>
<string name="install_inactive_slot_msg">Votre appareil sera réamorcé à partir de lespace actuellement inactif après un redémarrage!\nNutilisez cette option quuniquement après que la mise à jour OTA ait été effectuée.\nVoulez-vous continuer?</string> <string name="install_inactive_slot_msg">Votre appareil sera obligatoirement réamorcé à partir de lespace (slot) actuellement inactif après son redémarrage!\nNutilisez cette option uniquement après que la mise à jour OTA a été effectuée.\nVoulezvous continuer?</string>
<string name="select_method">Sélectionnez la méthode</string> <string name="select_method">Sélectionnez la méthode</string>
<string name="setup_title">Installation additionnelle</string> <string name="setup_title">Configuration supplémentaire</string>
<string name="select_patch_file">Sélectionner et Patcher un Fichier</string> <string name="select_patch_file">Sélectionnez le fichier cible du correctif</string>
<string name="patch_file_msg">Sélectionnez une image brute (*.img) ou un fichier tar ODIN (*.tar)</string> <string name="patch_file_msg">Sélectionnez une image brute (*.img) ou une archive TAR ODIN (*.tar)</string>
<string name="reboot_delay_toast">Redémarrage dans 5 secondes…</string> <string name="reboot_delay_toast">Redémarrage dans 5 secondes…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="repo_install_title">Installer %1$s</string> <string name="repo_install_title">Installer %1$s</string>
<string name="repo_install_msg">Voulezvous installer %1$s maintenant?</string> <string name="repo_install_msg">Voulezvous installer %1$s maintenant?</string>
<string name="download">Télécharger</string> <string name="download">Télécharger</string>
<string name="reboot">Redémarrer</string> <string name="reboot">Redémarrer</string>
<string name="settings_reboot_toast">Redémarrer afin dappliquer les réglages.</string> <string name="settings_reboot_toast">Redémarrer afin dappliquer les paramètres</string>
<string name="release_notes">Notes de version</string> <string name="release_notes">Notes de version</string>
<string name="repo_cache_cleared">Cache du dépôt effacé</string> <string name="repo_cache_cleared">Cache du dépôt effacé</string>
<string name="dtbo_patched_title">Larborescence matérielle (DTBO) a été modifiée!</string>
<string name="dtbo_patched_title">DTBO a été modifié!</string> <string name="dtbo_patched_reboot">Magisk Manager a modifié le fichier dtbo.img. Veuillez redémarrer.</string>
<string name="dtbo_patched_reboot">Magisk Manager vient de modifier le fichier dtbo.img, veuillez redémarrer.</string> <string name="flashing">Écriture dans la mémoire Flash…</string>
<string name="flashing">Installation</string> <string name="done">Terminé!</string>
<string name="done">Terminé!</string> <string name="failure">Erreur</string>
<string name="failure">Échec</string> <string name="hide_manager_title">Masquer Magisk Manager…</string>
<string name="hide_manager_title">Masquer Magisk Manager…</string> <string name="hide_manager_fail_toast">Le masquage de Magisk Manager a échoué.</string>
<string name="hide_manager_fail_toast">Le masquage de Magisk Manager a échoué.</string> <string name="open_link_failed_toast">Aucune application permettant douvrir le lien na été trouvée</string>
<string name="open_link_failed_toast">Aucune application permettant douvrir le lien na été trouvée.</string>
<string name="warning">Avertissement</string> <string name="warning">Avertissement</string>
<string name="complete_uninstall">Désinstallation terminée</string> <string name="complete_uninstall">Désinstallation complète</string>
<string name="restore_img">Restauration des images</string> <string name="restore_img">Restauration des images</string>
<string name="restore_img_msg">Restauration…</string> <string name="restore_img_msg">Restauration…</string>
<string name="restore_done">Restauration terminée!</string> <string name="restore_done">Restauration terminée!</string>
<string name="restore_fail">La sauvegarde par défaut nexiste pas!</string> <string name="restore_fail">La sauvegarde par défaut nexiste pas!</string>
<string name="proprietary_title">Téléchargement de code propriétaire</string> <string name="proprietary_title">Téléchargement de code propriétaire</string>
<string name="proprietary_notice">Magisk Manager est un logiciel libre et ne contient pas le code propriétaire de lAPI SafetyNet de Google.Voulezvous autoriser Magisk Manager à télécharger une extension (contenant GoogleApiClient) pour les contrôles SafetyNet?</string> <string name="proprietary_notice">Magisk Manager est un logiciel libre et ne contient pas le code propriétaire de lAPI SafetyNet de Google. Autorisezvous Magisk Manager à télécharger une extension (contenant GoogleApiClient) pour les contrôles SafetyNet?</string>
<string name="setup_fail">Échec de linstallation</string> <string name="setup_fail">Échec de linstallation</string>
<string name="env_fix_title">Installation additionnelle requise</string> <string name="env_fix_title">Installation supplémentaire requise</string>
<string name="env_fix_msg">Votre appareil a besoin dune configuration supplémentaire pour que Magisk fonctionne correctement. Pour cela, il est nécessaire de télécharger un fichier ZIP dinstallation de Magisk. Voulezvous le faire maintenant?</string> <string name="env_fix_msg">Votre appareil a besoin dune installation supplémentaire afin que Magisk fonctionne correctement. Un fichier ZIP dinstallation pour Magisk devra être téléchargé. Voulezvous faire cette installation maintenant?</string>
<string name="setup_msg">Démarrer linstallation de lenvironnement…</string> <string name="setup_msg">Installation de lenvironnement en cours…</string>
<string name="authenticate">Authentification</string>
<!--Settings Activity --> <!--Settings Activity -->
<string name="settings_general_category">Général</string> <string name="settings_general_category">Général</string>
<string name="settings_dark_theme_title">Thème sombre</string> <string name="settings_dark_theme_title">Thème sombre</string>
<string name="settings_dark_theme_summary">Activer le thème sombre.</string> <string name="settings_dark_theme_summary">Activer le thème sombre</string>
<string name="settings_download_path_title">Emplacement téléchargement</string> <string name="settings_download_path_title">Répertoire de téléchargement</string>
<string name="settings_download_path_message">Les fichiers seront sauvegardés dans %1$s</string> <string name="settings_download_path_message">Les fichiers seront sauvegardés dans %1$s</string>
<string name="settings_clear_cache_title">Effacer le cache du dépôt</string> <string name="settings_clear_cache_title">Effacer le cache du dépôt</string>
<string name="settings_clear_cache_summary">Effacer les informations de cache pour les dépôts en ligne. Cela force lapplication à récupérer ses informations en ligne.</string> <string name="settings_clear_cache_summary">Effacer les informations en cache concerant les dépôts en ligne. Ceci force lapplication à télécharger des informations à jour.</string>
<string name="settings_hide_manager_title">Masquer Magisk Manager</string> <string name="settings_hide_manager_title">Masquer Magisk Manager</string>
<string name="settings_hide_manager_summary">Réempaqueter Magisk Manager avec un nom de paquet aléatoire.</string> <string name="settings_hide_manager_summary">Réempaqueter Magisk Manager avec des noms de paquet et dapplication aléatoires.</string>
<string name="settings_restore_manager_title">Restaurer Magisk Manager</string> <string name="settings_restore_manager_title">Restaurer Magisk Manager</string>
<string name="settings_restore_manager_summary">Restaurer Magisk Manager avec son nom de paquet dorigine</string> <string name="settings_restore_manager_summary">Restaurer Magisk Manager avec ses noms de paquet et dapplication dorigine</string>
<string name="language">Langue</string> <string name="language">Langue</string>
<string name="system_default">(système par défaut)</string> <string name="system_default">(langue par défaut du système)</string>
<string name="settings_update">Mise à jour des réglages</string> <string name="settings_update">Paramètres de mise à jour</string>
<string name="settings_check_update_title">Vérification des mises à jour</string> <string name="settings_check_update_title">Vérifier les mises à jour</string>
<string name="settings_check_update_summary">Vérifier périodiquement en tâche de fond lexistence dune mise à jour.</string> <string name="settings_check_update_summary">Vérifier périodiquement en tâche de fond lexistence dune mise à jour</string>
<string name="settings_update_channel_title">Canal de mise à jour</string> <string name="settings_update_channel_title">Canal de mise à jour</string>
<string name="settings_update_stable">Stable</string> <string name="settings_update_stable">Stable</string>
<string name="settings_update_beta">Bêta</string> <string name="settings_update_beta">Bêta</string>
<string name="settings_update_custom">Personnalisé</string> <string name="settings_update_custom">Personnalisé</string>
<string name="settings_update_custom_msg">Insérez une URL personnalisée</string> <string name="settings_update_custom_msg">Saisissez une URL personnalisée</string>
<string name="settings_core_only_title">Mode Magisk Core uniquement</string> <string name="settings_core_only_title">Mode « sans modules » uniquement</string>
<string name="settings_core_only_summary">Active uniquement les fonctionnalités de base. MagiskSU et MagiskHide resteront activés, mais aucun module ne sera chargé. </string> <string name="settings_core_only_summary">Activer uniquement les fonctionnalités de base. MagiskSU et MagiskHide resteront activés, mais aucun module ne sera chargé.</string>
<string name="settings_magiskhide_summary">Rendre Magisk invisible à diverses formes de détection.</string> <string name="settings_magiskhide_summary">Rendre Magisk invisible à diverses formes de détection.</string>
<string name="settings_hosts_title">Fichier hosts sans système</string> <string name="settings_hosts_title">Fichier hosts hors partition système</string>
<string name="settings_hosts_summary">Prise en charge du fichier hosts sans système pour les applications de type AdBlock.</string> <string name="settings_hosts_summary">Utilisation dun fichier hosts hors de la partition système pour les applications de blocage de publicité.</string>
<string name="settings_hosts_toast">Ajout dun module hosts sans système</string> <string name="settings_hosts_toast">Ajout dun module pour fichier hosts hors système</string>
<string name="settings_app_name">Taper le nom de l\'application désirée</string>
<string name="settings_app_name">Saisissez le nom de lapplication désiré</string>
<string name="settings_app_name_hint">Nouveau nom</string> <string name="settings_app_name_hint">Nouveau nom</string>
<string name="settings_app_name_helper">L\'application sera réempacter sous ce nom</string> <string name="settings_app_name_helper">Lapplication sera réempaquetée sous ce nom</string>
<string name="settings_app_name_error">Format invalide</string> <string name="settings_app_name_error">Format incorrect</string>
<string name="settings_su_app_adb">Applications et ADB</string> <string name="settings_su_app_adb">Applications et ADB</string>
<string name="settings_su_app">Applications uniquement</string> <string name="settings_su_app">Applications uniquement</string>
<string name="settings_su_adb">ADB uniquement</string> <string name="settings_su_adb">ADB uniquement</string>
<string name="settings_su_disable">Désactivé</string> <string name="settings_su_disable">Désactivé</string>
<string name="settings_su_request_10">10 secondes</string> <string name="settings_su_request_10">10 secondes</string>
<string name="settings_su_request_15">15 secondes</string> <string name="settings_su_request_15">15 secondes</string>
<string name="settings_su_request_20">20 secondes</string> <string name="settings_su_request_20">20 secondes</string>
<string name="settings_su_request_30">30 secondes</string> <string name="settings_su_request_30">30 secondes</string>
<string name="settings_su_request_45">45 secondes</string> <string name="settings_su_request_45">45 secondes</string>
<string name="settings_su_request_60">60 secondes</string> <string name="settings_su_request_60">60 secondes</string>
<string name="superuser_access">Accès superutilisateur</string> <string name="superuser_access">Accès superutilisateur</string>
<string name="auto_response">Réponse automatique</string> <string name="auto_response">Réponse automatique</string>
<string name="request_timeout">Délai dexpiration de la demande</string> <string name="request_timeout">Délai dexpiration de la demande</string>
<string name="superuser_notification">Notification superutilisateur</string> <string name="superuser_notification">Notification superutilisateur</string>
<string name="request_timeout_summary">%1$d secondes</string> <string name="request_timeout_summary">%1$d secondes</string>
<string name="settings_su_reauth_title">Authentifier à nouveau après la mise à niveau</string> <string name="settings_su_reauth_title">Sauthentifier à nouveau après la mise à niveau</string>
<string name="settings_su_reauth_summary">Authentifier à nouveau les autorisations superutilisateur après une mise à jour de lapplication</string> <string name="settings_su_reauth_summary">Redemander une authentification pour autoriser laccès en superutilisateur après une mise à jour de lapplication</string>
<string name="settings_su_biometric_title">Activer lauthentification biométrique</string>
<string name="settings_su_biometric_summary">Utiliser lauthentification biométrique pour autoriser les accès en superutilisateur</string>
<string name="no_biometric">Lappareil nest pas pris en charge ou alors aucun paramètre biométrique nest activé</string>
<string name="multiuser_mode">Mode multiutilisateur</string> <string name="multiuser_mode">Mode multiutilisateur</string>
<string name="settings_owner_only">Propriétaire de lappareil uniquement</string> <string name="settings_owner_only">Propriétaire de lappareil uniquement</string>
<string name="settings_owner_manage">Géré par le propriétaire de lappareil</string> <string name="settings_owner_manage">Géré par le propriétaire de lappareil</string>
<string name="settings_user_independent">Indépendant de lutilisateur</string> <string name="settings_user_independent">Indépendant de lutilisateur</string>
<string name="owner_only_summary">Seul le propriétaire a un accès superutilisateur.</string> <string name="owner_only_summary">Seul le propriétaire possède un accès superutilisateur.</string>
<string name="owner_manage_summary">Seul le propriétaire peut gérer laccès superutilisateur et recevoir les demandes de requêtes.</string> <string name="owner_manage_summary">Seul le propriétaire peut gérer laccès superutilisateur et recevoir les demandes daccès.</string>
<string name="user_indepenent_summary">Chaque utilisateur a ses propres règles superutilisateur séparées.</string> <string name="user_indepenent_summary">Chaque utilisateur a ses propres règles daccès superutilisateur séparées.</string>
<string name="mount_namespace_mode">Mode despace de noms du montage</string> <string name="mount_namespace_mode">Mode despace de noms du montage</string>
<string name="settings_ns_global">Espace de noms global</string> <string name="settings_ns_global">Espace de noms global</string>
<string name="settings_ns_requester">Hériter de lespace de noms</string> <string name="settings_ns_requester">Hériter de lespace de noms</string>
<string name="settings_ns_isolate">Espace de noms isolé</string> <string name="settings_ns_isolate">Espace de noms isolé</string>
<string name="global_summary">Toutes les sessions superutilisateur utilisent lespace de noms global du montage.</string> <string name="global_summary">Toutes les sessions superutilisateur utilisent lespace de noms global du montage.</string>
<string name="requester_summary">Les sessions superutilisateur hériteront de lespace de noms de leur demandeur.</string> <string name="requester_summary">Les sessions superutilisateur hériteront de lespace de noms de leur demandeur.</string>
<string name="isolate_summary">Chaque session superutilisateur aura son propre espace de noms isolé.</string> <string name="isolate_summary">Chaque session superutilisateur aura son propre espace de noms isolé.</string>
<string name="settings_download_path_error">Erreur lors de la création du dossier. Il doit être accessible depuis le répertoire racine du stockage et ne doit pas être un fichier.</string> <string name="settings_download_path_error">Erreur lors de la création du dossier. Ce dernier doit être accessible depuis le répertoire racine du stockage et ne doit pas être un fichier.</string>
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">Requête superutilisateur</string> <string name="su_request_title">Demande daccès superutilisateur</string>
<string name="deny">Refuser</string> <string name="deny">Refuser</string>
<string name="prompt">Demander</string> <string name="prompt">Demander</string>
<string name="grant">Accepter</string> <string name="grant">Accepter</string>
<string name="su_warning">Autoriser laccès complet à votre appareil.\nRefusez si vous nêtes pas sûr!</string> <string name="su_warning">Autoriser laccès complet à votre appareil.\nRefusez si vous nêtes pas sûr(e)!</string>
<string name="forever">Toujours</string> <string name="forever">Toujours</string>
<string name="once">Une fois</string> <string name="once">Une fois</string>
<string name="tenmin">10min</string> <string name="tenmin">10min</string>
<string name="twentymin">20min</string> <string name="twentymin">20min</string>
<string name="thirtymin">30min</string> <string name="thirtymin">30min</string>
<string name="sixtymin">60min</string> <string name="sixtymin">60min</string>
<string name="su_allow_toast">%1$s a obtenu les droits superutilisateur</string> <string name="su_allow_toast">%1$s a obtenu les droits de superutilisateur</string>
<string name="su_deny_toast">%1$s na pas obtenu les droits superutilisateur</string> <string name="su_deny_toast">%1$s sest vu refuser les droits de superutilisateur</string>
<string name="no_apps_found">Aucune application trouvée</string> <string name="no_apps_found">Aucune application trouvée</string>
<string name="su_snack_grant">Les droits superutilisateur de %1$s sont accordés</string> <string name="su_snack_grant">Les droits de superutilisateur sont accordés à %1$s</string>
<string name="su_snack_deny">Les droits superutilisateur de %1$s sont refusés</string> <string name="su_snack_deny">Les droits de superutilisateur sont refusés à %1$s</string>
<string name="su_snack_notif_on">Les notifications pour %1$s sont activées</string> <string name="su_snack_notif_on">Les notifications sont activées pour %1$s</string>
<string name="su_snack_notif_off">Les notifications pour %1$s sont désactivées</string> <string name="su_snack_notif_off">Les notifications sont désactivées pour %1$s</string>
<string name="su_snack_log_on">La journalisation pour %1$s est activée</string> <string name="su_snack_log_on">La journalisation est activée pour %1$s</string>
<string name="su_snack_log_off">La journalisation pour %1$s est désactivée</string> <string name="su_snack_log_off">La journalisation est désactivée pour %1$s</string>
<string name="su_revoke_title">Annuler ?</string> <string name="su_revoke_title">Révoquer?</string>
<string name="su_revoke_msg">Confirmezvous lannulation des droits pour %1$s?</string> <string name="su_revoke_msg">Confirmezvous la révocation des droits accordés à %1$s?</string>
<string name="toast">Toast</string> <string name="toast">Toast</string>
<string name="none">Aucun</string> <string name="none">Aucun</string>
<!--Superuser logs--> <!--Superuser logs-->
<string name="pid">PID : %1$d</string> <string name="pid">PID : %1$d</string>
<string name="target_uid">UID cible : %1$d</string> <string name="target_uid">UID cible : %1$d</string>
<string name="command">Commande : %1$s</string> <string name="command">Commande : %1$s</string>
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">Afficher les applications système</string> <string name="show_system_app">Afficher les applications système</string>

View File

@ -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,8 +95,7 @@
<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>
<string name="done">Tamamlandı!</string> <string name="done">Tamamlandı!</string>
@ -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 @@
<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>

View File

@ -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>

View File

@ -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 {
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}"

View File

@ -1,5 +1,5 @@
# 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 @@
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)

View File

@ -1,4 +1,4 @@
# 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.

View File

@ -1,9 +1,7 @@
# Developer Guides # Developer Guides
Please read through [Magisk Details](details.md) before reading the following guides. If you are developing a module, pay extra attention to the [Magic Mount](details.md#magic-mount) section.
## Magisk Modules ## Magisk Modules
A Magisk module is a folder placed in `/data/adb/modules` with a structure below: A Magisk module is a folder placed in `/data/adb/modules` with the structure below:
``` ```
/data/adb/modules /data/adb/modules
@ -14,40 +12,38 @@ A Magisk module is a folder placed in `/data/adb/modules` with a structure below
│ │ │ │
│ │ *** Module Identity *** │ │ *** Module Identity ***
│ │ │ │
│   ├── module.prop <--- This files stores the metadata of the module │   ├── module.prop <--- This file stores the metadata of the module
│ │ │ │
│ │ *** Status files *** │ │ *** Main Contents ***
│ │ │ │
│   ├── skip_mount <--- If exists, Magisk will NOT mount your files │   ├── system <--- This folder will be mounted if skip_mount does not exists
│   │   ├── ...
│   │   ├── ...
│   │   └── ...
│ │
│ │ *** Status Flags ***
│ │
│   ├── skip_mount <--- If exists, Magisk will NOT mount your system folder
│   ├── disable <--- If exists, the module will be disabled │   ├── disable <--- If exists, the module will be disabled
│   ├── remove <--- If exists, the module will be removed next reboot │   ├── remove <--- If exists, the module will be removed next reboot
│ │ │ │
│ │ *** Scripts *** │ │ *** Optional Files ***
│ │ │ │
│   ├── post-fs-data.sh <--- This script will be executed in post-fs-data │   ├── post-fs-data.sh <--- This script will be executed in post-fs-data
│   ├── service.sh <--- This script will be executed in late_start service │   ├── service.sh <--- This script will be executed in late_start service
| ├── uninstall.sh <--- This script will be executed when Magisk removes your module | ├── uninstall.sh <--- This script will be executed when Magisk removes your module
│ │ │   ├── system.prop <--- Properties in this file will be loaded as system properties by resetprop
│ │ *** Resetprop Files *** │   ├── sepolicy.rule <--- Additional custom sepolicy rules to be patched
│ │
│   ├── system.prop <--- This file will be loaded as system properties by resetprop
│ │
│ │ *** Module contents ***
│ │
│   ├── system <--- This folder will be Magic Mounted if skip_mount does not exists
│   │   ├── .
│   │   ├── .
│   │   └── .
│   │ │   │
│ │ *** Auto Generated by Magisk *** │ │ *** Auto Generated, DO NOT MANUALLY CREATE OR MODIFY ***
│   │ │   │
│   ├── vendor <--- A symlink to $MODID/system/vendor │   ├── vendor <--- A symlink to $MODID/system/vendor
│   ├── product <--- A symlink to $MODID/system/product │   ├── product <--- A symlink to $MODID/system/product
│ │ │ │
│ │ *** Others *** │ │ *** Any additional files / folders are allowed ***
│ │ │ │
│   ├── . <--- Any additional files / folders are allowed │   ├── ...
│   └── . │   └── ...
| |
├── another_module ├── another_module
│   ├── . │   ├── .
@ -55,9 +51,11 @@ A Magisk module is a folder placed in `/data/adb/modules` with a structure below
├── . ├── .
├── . ├── .
``` ```
As long as a folder follows the structure above, it will be recognized as a module.
Here is the **strict** format of `module.prop`:
#### module.prop
This is the **strict** format of `module.prop`
``` ```
id=<string> id=<string>
@ -71,27 +69,134 @@ description=<string>
ex: ✓ `a_module`, ✓ `a.module`, ✓ `module-101`, ✗ `a module`, ✗ `1_module`, ✗ `-a-module`<br> ex: ✓ `a_module`, ✓ `a.module`, ✓ `module-101`, ✗ `a module`, ✗ `1_module`, ✗ `-a-module`<br>
This is the **unique identifier** of your module. You should not change it once published. This is the **unique identifier** of your module. You should not change it once published.
- `versionCode` has to be an **integer**. This is used to compare versions - `versionCode` has to be an **integer**. This is used to compare versions
- Others that isn't mentioned above can be any **single line** string. - Others that weren't mentioned above can be any **single line** string.
#### Shell scripts (`*.sh`)
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script.
In all scripts of your module, please use `MODDIR=${0%/*}` to get your module's base directory path; do **NOT** hardcode your module path in scripts.
#### system.prop
This file follows the same format as `build.prop`. Each line comprises of `[key]=[value]`.
#### sepolicy.rule
If your module requires some additional sepolicy patches, please add those rules into this file. The module installer script and Magisk's daemon will make sure this file is copied to somewhere `magiskinit` can read pre-init to ensure these rules are injected properly.
Each line in this file will be treated as a policy statement. For more details how a policy statement is formated, please check [magiskpolicy](tools.md#magiskpolicy)'s documentation.
#### The `system` folder
All files you want Magisk to replace/inject for you should be placed in this folder. Please read through the [Magic Mount](details.md#magic-mount) section to understand how Magisk mount your files.
## Magisk Module Installer ## Magisk Module Installer
The official Magisk Module installer is hosted **[here](https://github.com/topjohnwu/magisk-module-installer)**.
That repo is a starting point for creating a Magisk module installer zip. Here are some details: A Magisk Module Installer is a Magisk Module packaged in a zip file that can be flashed in Magisk Manager or custom recoveries such as TWRP. An installer have the same file structure as a Magisk module (please check the previous section for more info). The simplest Magisk Module Installer is just a Magisk Module packed in a zip file, with addition to the following files:
- You will found out that `META-INF/com/google/android/update-binary` is a dummy file. If you are creating a module locally for personal usage or testing, download the latest installer [`module_installer.sh`](https://github.com/topjohnwu/Magisk/blob/master/scripts/module_installer.sh) and replace `update-binary` with the script - `update-binary`: Download the latest [module_installer.sh](https://github.com/topjohnwu/Magisk/blob/master/scripts/module_installer.sh) and rename/copy that script as `update-binary`
- The next thing to do is to modify `module.prop` to provide information about your module - `updater-script`: This file should only contain the string `#MAGISK`
- Finally, modify `install.sh` to fit your need. The script is heavily documented so you should know what to do.
- (Optional) If you want to run custom uninstallation logic when your module is removed, add a new file `uninstall.sh` to the root of the installer By default, `update-binary` will check/setup the environment, load utility functions, extract the module installer zip to where your module will be installed, and finally do some trivial tasks and cleanups, which should cover most simple modules' needs.
- **Windows users aware!!** The line endings of all text files should be in the **Unix format**. Please use advanced text editors like Sublime, Atom, Notepad++ etc. to edit **ALL** text files, **NEVER** use Windows Notepad.
```
module.zip
├── META-INF
│   └── com
│      └── google
│         └── android
│            ├── update-binary <--- The module_installer.sh you downloaded
│            └── updater-script <--- Should only contain the string "#MAGISK"
├── customize.sh <--- (Optional, more details later)
│ This script will be sourced by update-binary
├── ...
├── ... /* The rest of module's files */
|
```
#### Customization
If you need to customize the module installation process, optionally you can create a new script in the installer called `customize.sh`. This script will be *sourced* (not executed!) by `update-binary` after all files are extracted and default permissions and secontext are applied. This is very useful if your module includes different files based on ABI, or you need to set special permissions/secontext for some of your files (e.g. files in `/system/bin`).
If you need even more customization and prefer to do everything on your own, declare `SKIPUNZIP=1` in `customize.sh` to skip the extraction and applying default permissions/secontext steps. Be aware that by doing so, your `customize.sh` will then be responsible to install everything by itself.
#### `customize.sh` Environment
Magisk's internal busybox's path `$BBPATH` is added in the front of `PATH`. The following variables and shell functions are available for convenience:
##### Variables
- `MAGISK_VER` (string): the version string of current installed Magisk (e.g. `v20.0`)
- `MAGISK_VER_CODE` (int): the version code of current installed Magisk (e.g. `20000`)
- `BOOTMODE` (bool): `true` if the module is being installed in Magisk Manager
- `MODPATH` (path): the path where your module files should be installed
- `TMPDIR` (path): a place where you can temporarily store files
- `ZIPFILE` (path): your module's installation zip
- `ARCH` (string): the CPU architecture of the device. Value is either `arm`, `arm64`, `x86`, or `x64`
- `IS64BIT` (bool): `true` if `$ARCH` is either `arm64` or `x64`
- `API` (int): the API level (Android version) of the device (e.g. `21` for Android 5.0)
##### Functions
```
ui_print <msg>
print <msg> to console
Avoid using 'echo' as it will not display in custom recovery's console
abort <msg>
print error message <msg> to console and terminate installation
Avoid using 'exit' as it will skip the termination cleanup steps
set_perm <target> <owner> <group> <permission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
this function is a shorthand for the following commands:
chown owner.group target
chmod permission target
chcon context target
set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
for all files in <directory>, it will call:
set_perm file owner group filepermission context
for all directories in <directory> (including itself), it will call:
set_perm dir owner group dirpermission context
```
##### Easy Replace
You can declare a list of folders you want to directly replace in the variable name `REPLACE`. The module installer script will pickup this variable and create `.replace` files for you. An example declaration:
```
REPLACE="
/system/app/YouTube
/system/app/Bloatware
"
```
The list above will result in the following files being created: `$MODPATH/system/app/YouTube/.replace` and `$MODPATH/system/app/Bloatware/.replace`
#### Notes
- When your module is downloaded with Magisk Manager, `update-binary` will be **forcefully** replaced with the latest [`module_installer.sh`](https://github.com/topjohnwu/Magisk/blob/master/scripts/module_installer.sh) to ensure all installer uses up-to-date scripts. **DO NOT** try to add any custom logic in `update-binary` as it is pointless.
- Due to historical reasons, **DO NOT** add a file named `install.sh` in your module installer. That specific file was previously used and will be treated differently.
- **DO NOT** call `exit` at the end of `customize.sh`. The module installer would want to do finalizations.
## Submit Modules ## Submit Modules
You can submit a module to **Magisk-Module-Repo** so users can download your module directly in Magisk Manager. Before submitting, follow the instructions in the previous section to create a valid installer for your module. You can then create a request for submission via this link: [submission](https://github.com/Magisk-Modules-Repo/submission).
- When your module is downloaded with Magisk Manager, `META-INF/com/google/android/update-binary` will be **forcefully** replaced with the latest [`module_installer.sh`](https://github.com/topjohnwu/Magisk/blob/master/scripts/module_installer.sh) to make sure all installation uses the latest scripts. You can submit a module to **Magisk-Module-Repo** so users can download your module directly in Magisk Manager.
- Since `update-binary` will be replaced, this means that all modules in the repo are expected to follow how the installation framework works: the installation framework will load your `install.sh` script and run the corresponding callbacks.
- This also means that you should NOT add custom logic in `update-binary` as they will simply be ignored. - Follow the instructions in the previous section to create a valid installer for your module.
- Create `README.md` (filename should be exactly the same) containing all info for your module. If you are not familiar with the Markdown syntax, the [Markdown Cheat Sheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) will be handy.
- Create a repository with your personal GitHub account, and upload your module installer to the repo
- Create a request for submission via this link: [submission](https://github.com/Magisk-Modules-Repo/submission)
## Module Tricks
#### Remove Files
How to remove a file systemless-ly? To actually make the file *disappear* is complicated (possible, not worth the effort). Replacing it with a dummy file should be good enough! Create an empty file with the same name and place it in the same path within a module, it shall replace your target file with a dummy file.
#### Remove Folders
Same as mentioned above, actually making the folder *disappear* is not worth the effort. Replacing it with an empty folder should be good enough! A handy trick for module developers is to add the folder you want to remove into the `REPLACE` list within `customize.sh`. If your module doesn't provide a corresponding folder, it will create an empty folder, and automatically add `.replace` into the empty folder so the dummy folder will properly replace the one in `/system`.
## Boot Scripts ## Boot Scripts
In Magisk, you can run boot scripts in 2 different modes: **post-fs-data** and **late_start service** mode. In Magisk, you can run boot scripts in 2 different modes: **post-fs-data** and **late_start service** mode.
- post-fs-data mode - post-fs-data mode
@ -118,9 +223,10 @@ In Magisk, there are also 2 kinds of scripts: **general scripts** and **module s
- Will NOT be executed when **Core-Only** mode is enabled (all modules are disabled) - Will NOT be executed when **Core-Only** mode is enabled (all modules are disabled)
- Modules require boot scripts should **ONLY** use module scripts instead of general scripts - Modules require boot scripts should **ONLY** use module scripts instead of general scripts
Magisk's internal busybox's path `$BBPATH` is always prepended in `PATH`. This means all commands you call in scripts are always using busybox unless the applet is not included. This makes sure that your script always run in a predictable environment and always have the full suite of commands regardless of which Android version it is running on. Magisk's internal busybox's path `$BBPATH` is added in the front of `PATH`. This means all commands you call in scripts are always using busybox unless the applet is not included. This makes sure that your script always run in a predictable environment and always have the full suite of commands regardless of which Android version it is running on.
## Root Directory Overlay System ## Root Directory Overlay System
Since `/` is read-only in system-as-root devices, Magisk provides an overlay system, allowing developers to patch files / add new rc scripts. Additional files shall be placed in the `overlay.d` folder in the ramdisk, and they will have the following restrictions: Since `/` is read-only in system-as-root devices, Magisk provides an overlay system, allowing developers to patch files / add new rc scripts. Additional files shall be placed in the `overlay.d` folder in the ramdisk, and they will have the following restrictions:
- All `*.rc` files in `overlay.d` will be read and concatenated *AFTER* `init.rc` - All `*.rc` files in `overlay.d` will be read and concatenated *AFTER* `init.rc`
@ -130,9 +236,3 @@ e.g. you can replace `/res/random.png` by adding the file `overlay.d/res/random.
e.g. `overlay.d/new_file` will be ignored if `/new_file` does not exist e.g. `overlay.d/new_file` will be ignored if `/new_file` does not exist
- Additional files in `overlay.d/sbin` is allowed as they will be copied into Magisk's sbin overlay.<br> - Additional files in `overlay.d/sbin` is allowed as they will be copied into Magisk's sbin overlay.<br>
e.g. `overlay.d/sbin/libfoo.ko` will be copied to `/sbin/libfoo.ko`. e.g. `overlay.d/sbin/libfoo.ko` will be copied to `/sbin/libfoo.ko`.
## Remove Files
How to remove a file systemless-ly? To actually make the file *disappear* is complicated (possible, not worth the effort). Replacing it with a dummy file should be good enough! Create an empty file with the same name and place it in the same path within a module, it shall replace your target file with a dummy file.
## Remove Folders
Same as mentioned above, actually making the folder *disappear* is not worth the effort. Replacing it with an empty folder should be good enough! A handy trick for module developers is to add the folder you want to remove into the `REPLACE` list within `install.sh`. If your module doesn't provide a corresponding folder, it will create an empty folder, and automatically add `.replace` into the empty folder so the dummy folder will properly replace the one in `/system`.

View File

@ -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:
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:
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:
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:
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...]
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:
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):
--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:
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
``` ```

View File

@ -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
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 := \
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

View File

@ -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) {
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) {
} }
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); }
} } else { return; }
closedir(dir);
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) {
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() {
} }
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() {
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() {
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) {
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() {
} }
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() {
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) {
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) {
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) {
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");
} }

View File

@ -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");

View File

@ -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) {

View File

@ -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) {
} }
} }
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"

View File

@ -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);
/************** /**************

View File

@ -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);

View File

@ -1,6 +1,3 @@
/* 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);
// 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();

View File

@ -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) {
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);

View File

@ -75,12 +75,12 @@ static bool unxz(int fd, const uint8_t *buf, size_t size) {
xz_crc32_init(); xz_crc32_init();
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26); struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
struct xz_buf b = { struct xz_buf b = {
.in = buf, .in = buf,
.in_pos = 0, .in_pos = 0,
.in_size = size, .in_size = size,
.out = out, .out = out,
.out_pos = 0, .out_pos = 0,
.out_size = sizeof(out) .out_size = sizeof(out)
}; };
enum xz_ret ret; enum xz_ret ret;
do { do {
@ -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) {
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,53 +192,44 @@ 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) { if (getpid() != 1)
auto init = make_unique<SecondStageInit>(argv); return 1;
init->start(); setup_klog();
}
#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)
return 1;
setup_klog();
}
cmdline cmd{};
load_kernel_info(&cmd);
unique_ptr<BaseInit> init; unique_ptr<BaseInit> init;
if (run_test) { cmdline cmd{};
init = make_unique<TestInit>(argv, &cmd);
} else if (cmd.force_normal_boot) { if (argc > 1 && argv[1] == "selinux_setup"sv) {
init = make_unique<ABFirstStageInit>(argv, &cmd); init = make_unique<SecondStageInit>(argv);
} else if (cmd.system_as_root) {
if (access("/overlay", F_OK) == 0) /* Compatible mode */
init = make_unique<SARCompatInit>(argv, &cmd);
else
init = make_unique<SARInit>(argv, &cmd);
} else { } else {
decompress_ramdisk(); // This will also mount /sys and /proc
if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0) load_kernel_info(&cmd);
init = make_unique<RecoveryInit>(argv, &cmd);
else if (access("/apex", F_OK) == 0) if (cmd.force_normal_boot) {
init = make_unique<AFirstStageInit>(argv, &cmd); init = make_unique<ABFirstStageInit>(argv, &cmd);
else } else if (cmd.skip_initramfs) {
init = make_unique<RootFSInit>(argv, &cmd); init = make_unique<SARInit>(argv, &cmd);
} else {
decompress_ramdisk();
if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
init = make_unique<RecoveryInit>(argv, &cmd);
else if (access("/apex", F_OK) == 0)
init = make_unique<AFirstStageInit>(argv, &cmd);
else
init = make_unique<RootFSInit>(argv, &cmd);
}
} }
// Run the main routine // Run the main routine

View File

@ -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:
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:
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:
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:
* *************/ * *************/
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:
}; };
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:
* 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";
}
/* **************** void start() override {
* Compat-mode SAR early_mount();
* ****************/ setup_rootfs();
exec_init();
class SARCompatInit : public RootFSBase { }
protected:
void early_mount() override;
void setup_rootfs() override;
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();

View File

@ -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 {
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) {
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) if (entry->d_name == "."sv || entry->d_name == ".."sv)
return; continue;
while ((entry = readdir(dir))) { sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
if (entry->d_name == "."sv || entry->d_name == ".."sv) parse_device(&dev, path);
continue; dev_list.push_back(dev);
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name); }
parse_device(&dev, path);
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) {
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) {
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) {
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,36 +126,19 @@ 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 sbin overlay for persist, but move it and add to cleanup list
mount_sbin();
xmount("/sbin", "/dev", nullptr, MS_MOVE, nullptr);
mount_list.emplace_back("/dev");
mount_list.emplace_back("/dev/.magisk/mirror/persist");
mount_list.emplace_back("/dev/.magisk/mirror/cache");
mount_root(system); mount_root(system);
mount_root(vendor); mount_root(vendor);
mount_root(product); mount_root(product);
mount_root(odm); mount_root(odm);
} }
void SARCompatInit::early_mount() {
full_read("/init", self.buf, self.sz);
LOGD("Cleaning rootfs\n");
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(product);
mount_root(odm);
}
static void switch_root(const string &path) { static void switch_root(const string &path) {
LOGD("Switch root to %s\n", path.data()); LOGD("Switch root to %s\n", path.data());
vector<string> mounts; vector<string> mounts;
@ -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() {
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() {
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);
}

View File

@ -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) {
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() {
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() {
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) {
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[] =
; ;
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) {
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() {
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() {
} }
} }
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) {
#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() {
} }
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[]) {
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);

View File

@ -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) {
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;
} }
} }

View File

@ -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:
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:
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:
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:
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:
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:
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:
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:
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:
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) {
} }
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) {
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;

View File

@ -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);

View File

@ -1,93 +1,20 @@
#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) {
// 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) {
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) {
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
auto it = dtb_map.begin(); uint32_t align = 1;
uint32_t page_size = (it++)->first; if constexpr (!is_dt_table) {
for (; it != dtb_map.end(); ++it) auto it = dtb_map.begin();
page_size = binary_gcd(page_size, it->first); align = (it++)->first;
for (; it != dtb_map.end(); ++it)
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) {
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) {
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);

104
native/jni/magiskboot/dtb.h Normal file
View File

@ -0,0 +1,104 @@
#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));

View File

@ -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[]);

View File

@ -16,7 +16,7 @@ using namespace std;
static void usage(char *arg0) { static void usage(char *arg0) {
fprintf(stderr, fprintf(stderr,
FULL_VER(MagiskBoot) R"EOF( - Boot Image Modification Tool FULL_VER(MagiskBoot) R"EOF( - Boot Image Modification Tool
Usage: %s <action> [args...] Usage: %s <action> [args...]
@ -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:
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[]) {
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;

View File

@ -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) {

View File

@ -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() {
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() {
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);
} }

View File

@ -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;
}); });

View File

@ -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;
}); });

View File

@ -1,4 +1,5 @@
#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__)

View File

@ -1,459 +1,59 @@
/* magiskpolicy.cpp - Main function for policy patching
*
* Includes all the parsing logic for the policy statements
*/
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
#include <vector>
#include <string>
#include <logging.h> #include <logging.h>
#include <utils.h> #include <utils.h>
#include <flags.h> #include <flags.h>
#include <magiskpolicy.h>
#include "sepolicy.h" #include "sepolicy.h"
#include "magiskpolicy.h"
using namespace std; using namespace std::literals;
static const char *type_msg_1 =
"Type 1:\n"
"\"<rule_name> source_type target_type class perm_set\"\n"
"Rules: allow, deny, auditallow, dontaudit\n";
static const char *type_msg_2 =
"Type 2:\n"
"\"<rule_name> source_type target_type class operation xperm_set\"\n"
"Rules: allowxperm, auditallowxperm, dontauditxperm\n"
"* The only supported operation is ioctl\n"
"* The only supported xperm_set format is range ([low-high])\n";
static const char *type_msg_3 =
"Type 3:\n"
"\"<rule_name> class\"\n"
"Rules: create, permissive, enforcing\n";
static const char *type_msg_4 =
"Type 4:\n"
"\"attradd class attribute\"\n";
static const char *type_msg_5 =
"Type 5:\n"
"\"<rule_name> source_type target_type class default_type\"\n"
"Rules: type_transition, type_change, type_member\n";
static const char *type_msg_6 =
"Type 6:\n"
"\"name_transition source_type target_type class default_type object_name\"\n";
[[noreturn]] static void statements() {
fprintf(stderr,
"One policy statement should be treated as one parameter;\n"
"this means a full policy statement should be enclosed in quotes;\n"
"multiple policy statements can be provided in a single command\n"
"\n"
"The statements has a format of \"<rule_name> [args...]\"\n"
"Multiple types and permissions can be grouped into collections\n"
"wrapped in curly brackets.\n"
"'*' represents a collection containing all valid matches.\n"
"\n"
"Supported policy statements:\n"
"\n"
"%s\n"
"%s\n"
"%s\n"
"%s\n"
"%s\n"
"%s\n"
"Notes:\n"
"* Type 4 - 6 does not support collections\n"
"* Object classes cannot be collections\n"
"* source_type and target_type can also be attributes\n"
"\n"
"Example: allow { s1 s2 } { t1 t2 } class *\n"
"Will be expanded to:\n"
"\n"
"allow s1 t1 class { all permissions }\n"
"allow s1 t2 class { all permissions }\n"
"allow s2 t1 class { all permissions }\n"
"allow s2 t2 class { all permissions }\n"
"\n",
type_msg_1, type_msg_2, type_msg_3, type_msg_4, type_msg_5, type_msg_6);
exit(0);
}
[[noreturn]] static void usage(char *arg0) { [[noreturn]] static void usage(char *arg0) {
fprintf(stderr, fprintf(stderr,
FULL_VER(MagiskPolicy) "\n\n" FULL_VER(MagiskPolicy) R"EOF(
"Usage: %s [--options...] [policy statements...]\n"
"\n" Usage: %s [--options...] [policy statements...]
"Options:\n"
" --help show help message for policy statements\n" Options:
" --load FILE load policies from FILE\n" --help show help message for policy statements
" --load-split load from preloaded sepolicy or compile\n" --load FILE load policies from FILE
" split policies\n" --load-split load from precompiled sepolicy or compile
" --compile-split compile split cil policies\n" split policies
" --save FILE save policies to FILE\n" --compile-split compile split cil policies
" --live directly apply sepolicy live\n" --save FILE save policies to FILE
" --magisk inject built-in rules for a minimal\n" --live directly apply sepolicy live
" Magisk selinux environment\n" --magisk inject built-in rules for a minimal
"\n" Magisk selinux environment
"If neither --load or --compile-split is specified, it will load\n" --apply FILE apply rules from FILE, read and parsed
"from current live policies (" SELINUX_POLICY ")\n" line by line as policy statements
"\n",
arg0); If neither --load or --compile-split is specified, it will load
from current live policies (/sys/fs/selinux/policy)
)EOF", arg0);
exit(1); exit(1);
} }
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))
fprintf(stderr, "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))
fprintf(stderr, "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))
fprintf(stderr, "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))
fprintf(stderr, "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))
fprintf(stderr, "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))
fprintf(stderr, "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)) \
fprintf(stderr, "Syntax error in '%s'\n\n%s\n", orig.c_str(), type_msg_##type); \
}
static void parse_statement(char *statement) {
char *action, *remain;
// strtok will modify the origin string, duplicate the statement for error messages
string orig(statement);
action = strtok_r(statement, " ", &remain);
if (remain == nullptr) remain = &action[strlen(action)];
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 { fprintf(stderr, "Unknown statement: '%s'\n\n", orig.c_str()); }
}
int magiskpolicy_main(int argc, char *argv[]) { int magiskpolicy_main(int argc, char *argv[]) {
cmdline_logging(); cmdline_logging();
const char *outfile = nullptr; const char *out_file = nullptr;
bool magisk = false, live = false; const char *rule_file = nullptr;
bool magisk = false;
bool live = false;
if (argc < 2) usage(argv[0]); if (argc < 2) usage(argv[0]);
int i = 1; int i = 1;
for (; i < argc; ++i) { for (; i < argc; ++i) {
// Parse options // Parse options
if (argv[i][0] == '-' && argv[i][1] == '-') { if (argv[i][0] == '-' && argv[i][1] == '-') {
if (strcmp(argv[i] + 2, "live") == 0) auto option = argv[i] + 2;
if (option == "live"sv)
live = true; live = true;
else if (strcmp(argv[i] + 2, "magisk") == 0) else if (option == "magisk"sv)
magisk = true; magisk = true;
else if (strcmp(argv[i] + 2, "load") == 0) { else if (option == "load"sv) {
if (argv[i + 1] == nullptr) if (argv[i + 1] == nullptr)
usage(argv[0]); usage(argv[0]);
if (load_policydb(argv[i + 1])) { if (load_policydb(argv[i + 1])) {
@ -461,23 +61,28 @@ int magiskpolicy_main(int argc, char *argv[]) {
return 1; return 1;
} }
++i; ++i;
} else if (strcmp(argv[i] + 2, "load-split") == 0) { } else if (option == "load-split"sv) {
if (load_split_cil()) { if (load_split_cil()) {
fprintf(stderr, "Cannot load split cil\n"); fprintf(stderr, "Cannot load split cil\n");
return 1; return 1;
} }
} else if (strcmp(argv[i] + 2, "compile-split") == 0) { } else if (option == "compile-split"sv) {
if (compile_split_cil()) { if (compile_split_cil()) {
fprintf(stderr, "Cannot compile split cil\n"); fprintf(stderr, "Cannot compile split cil\n");
return 1; return 1;
} }
} else if (strcmp(argv[i] + 2, "save") == 0) { } else if (option == "save"sv) {
if (argv[i + 1] == nullptr) if (argv[i + 1] == nullptr)
usage(argv[0]); usage(argv[0]);
outfile = argv[i + 1]; out_file = argv[i + 1];
++i; ++i;
} else if (strcmp(argv[i] + 2, "help") == 0) { } else if (option == "apply"sv) {
statements(); if (argv[i + 1] == nullptr)
usage(argv[0]);
rule_file = argv[i + 1];
++i;
} else if (option == "help"sv) {
statement_help();
} else { } else {
usage(argv[0]); usage(argv[0]);
} }
@ -495,6 +100,9 @@ int magiskpolicy_main(int argc, char *argv[]) {
if (magisk) if (magisk)
sepol_magisk_rules(); sepol_magisk_rules();
if (rule_file)
load_rule_file(rule_file);
for (; i < argc; ++i) for (; i < argc; ++i)
parse_statement(argv[i]); parse_statement(argv[i]);
@ -503,8 +111,8 @@ int magiskpolicy_main(int argc, char *argv[]) {
return 1; return 1;
} }
if (outfile && dump_policydb(outfile)) { if (out_file && dump_policydb(out_file)) {
fprintf(stderr, "Cannot dump policy to %s\n", outfile); fprintf(stderr, "Cannot dump policy to %s\n", out_file);
return 1; return 1;
} }

View File

@ -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) {
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) {
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;

View File

@ -1,7 +1,7 @@
#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) {

View File

@ -0,0 +1,425 @@
#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;
});
}

View File

@ -1,8 +1,4 @@
/* 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) {
} }
} }
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
} }
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_
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) {

View File

@ -1,17 +1,16 @@
#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);
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) {
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);
}

View File

@ -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:
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: protected:
sFILE fp; stream_ptr base;
};
// Handy interface for classes that need custom seek logic
class seekable_stream : public stream {
protected:
size_t _pos = 0;
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:
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:
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)...)));
}

View File

@ -1,14 +1,5 @@
#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"

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <pthread.h>
#include <string> #include <string>
#include <functional> #include <functional>
#include <string_view> #include <string_view>

View File

@ -55,61 +55,37 @@ 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; *ctx = strdup(buf);
return -1;
}
*ctx = strdup(buf);
return rc; return rc;
} }
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; *ctx = strdup(buf);
return -1;
}
*ctx = strdup(buf);
return rc; return rc;
} }
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; *ctx = strdup(buf);
return -1;
}
*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() {
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() {
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);
} }

View File

@ -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) {
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) {
} }
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) {
return -1; case SEEK_CUR:
np = _pos + off;
break;
case SEEK_END:
np = _len + off;
break;
case SEEK_SET:
np = off;
break;
default:
return -1;
}
resize(np, true); resize(np, true);
_pos = np; _pos = np;
return np; return np;

View File

@ -1,17 +1,6 @@
/* 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>

View File

@ -1,5 +1,10 @@
#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);

View File

@ -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

View File

@ -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
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
########################################################################################## ##########################################################################################
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

View File

@ -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
# 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

View File

@ -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
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
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
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
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

View File

@ -1,12 +1,15 @@
#!/sbin/sh #!/sbin/sh
TMPDIR=/dev/tmp #################
MOUNTPATH=/dev/magisk_img # Initialization
#################
# Default permissions
umask 022 umask 022
# Initial cleanup # Global vars
TMPDIR=/dev/tmp
PERSISTDIR=/sbin/.magisk/mirror/persist
rm -rf $TMPDIR 2>/dev/null rm -rf $TMPDIR 2>/dev/null
mkdir -p $TMPDIR mkdir -p $TMPDIR
@ -14,20 +17,33 @@ mkdir -p $TMPDIR
ui_print() { echo "$1"; } ui_print() { echo "$1"; }
require_new_magisk() { require_new_magisk() {
ui_print "***********************************" ui_print "*******************************"
ui_print " Please install the latest Magisk! " ui_print " Please install Magisk v19.0+! "
ui_print "***********************************" ui_print "*******************************"
exit 1 exit 1
} }
imageless_magisk() { is_legacy_script() {
[ $MAGISK_VER_CODE -gt 18100 ] unzip -l "$ZIPFILE" install.sh | grep -q install.sh
return $? return $?
} }
########################################################################################## print_modname() {
local len
len=`echo -n $MODNAME | wc -c`
len=$((len + 2))
local pounds=`printf "%${len}s" | tr ' ' '*'`
ui_print "$pounds"
ui_print " $MODNAME "
ui_print "$pounds"
ui_print "*******************"
ui_print " Powered by Magisk "
ui_print "*******************"
}
##############
# Environment # Environment
########################################################################################## ##############
OUTFD=$2 OUTFD=$2
ZIPFILE=$3 ZIPFILE=$3
@ -35,12 +51,9 @@ ZIPFILE=$3
mount /data 2>/dev/null mount /data 2>/dev/null
# Load utility functions # Load utility functions
if [ -f /data/adb/magisk/util_functions.sh ]; then [ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
. /data/adb/magisk/util_functions.sh . /data/adb/magisk/util_functions.sh
NVBASE=/data/adb [ $MAGISK_VER_CODE -gt 18100 ] || require_new_magisk
else
require_new_magisk
fi
# Preperation for flashable zips # Preperation for flashable zips
setup_flashable setup_flashable
@ -54,98 +67,107 @@ api_level_arch_detect
# Setup busybox and binaries # Setup busybox and binaries
$BOOTMODE && boot_actions || recovery_actions $BOOTMODE && boot_actions || recovery_actions
########################################################################################## ##############
# Preparation # Preparation
########################################################################################## ##############
# Extract common files # Extract prop file
unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2 unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2
[ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!"
[ ! -f $TMPDIR/install.sh ] && abort "! Unable to extract zip file!"
# Load install script
. $TMPDIR/install.sh
if imageless_magisk; then
$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules
MODULEROOT=$NVBASE/$MODDIRNAME
else
$BOOTMODE && IMGNAME=magisk_merge.img || IMGNAME=magisk.img
IMG=$NVBASE/$IMGNAME
request_zip_size_check "$ZIPFILE"
mount_magisk_img
MODULEROOT=$MOUNTPATH
fi
$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules
MODULEROOT=$NVBASE/$MODDIRNAME
MODID=`grep_prop id $TMPDIR/module.prop` MODID=`grep_prop id $TMPDIR/module.prop`
MODPATH=$MODULEROOT/$MODID MODPATH=$MODULEROOT/$MODID
MODNAME=`grep_prop name $TMPDIR/module.prop`
print_modname
ui_print "******************************"
ui_print "Powered by Magisk (@topjohnwu)"
ui_print "******************************"
##########################################################################################
# Install
##########################################################################################
# Create mod paths # Create mod paths
rm -rf $MODPATH 2>/dev/null rm -rf $MODPATH 2>/dev/null
mkdir -p $MODPATH mkdir -p $MODPATH
on_install ##########
# Install
##########
# Remove placeholder if is_legacy_script; then
rm -f $MODPATH/system/placeholder 2>/dev/null unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2
# Custom uninstaller # Load install script
[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh . $TMPDIR/install.sh
# Auto Mount # Callbacks
if imageless_magisk; then print_modname
on_install
# Custom uninstaller
[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh
# Skip mount
$SKIPMOUNT && touch $MODPATH/skip_mount $SKIPMOUNT && touch $MODPATH/skip_mount
# prop file
$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
# Module info
cp -af $TMPDIR/module.prop $MODPATH/module.prop
# post-fs-data scripts
$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
# service scripts
$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
ui_print "- Setting permissions"
set_permissions
else else
$SKIPMOUNT || touch $MODPATH/auto_mount print_modname
fi
# prop files unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2
$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
# Module info if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then
cp -af $TMPDIR/module.prop $MODPATH/module.prop ui_print "- Extracting module files"
if $BOOTMODE; then unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2
# Update info for Magisk Manager
if imageless_magisk; then # Default permissions
mktouch $NVBASE/modules/$MODID/update set_perm_recursive $MODPATH 0 0 0755 0644
cp -af $TMPDIR/module.prop $NVBASE/modules/$MODID/module.prop
else
mktouch /sbin/.magisk/img/$MODID/update
cp -af $TMPDIR/module.prop /sbin/.magisk/img/$MODID/module.prop
fi fi
# Load customization script
[ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh
fi fi
# post-fs-data mode scripts
$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
# service mode scripts
$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
# Handle replace folders # Handle replace folders
for TARGET in $REPLACE; do for TARGET in $REPLACE; do
ui_print "- Replace target: $TARGET"
mktouch $MODPATH$TARGET/.replace mktouch $MODPATH$TARGET/.replace
done done
ui_print "- Setting permissions" if $BOOTMODE; then
set_permissions # Update info for Magisk Manager
mktouch $NVBASE/modules/$MODID/update
cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop
fi
########################################################################################## # Copy over custom sepolicy rules
if [ -f $MODPATH/sepolicy.rule -a -e $PERSISTDIR ]; then
ui_print "- Installing custom sepolicy patch"
PERSISTMOD=$PERSISTDIR/magisk/$MODID
mkdir -p $PERSISTMOD
cp -af $MODPATH/sepolicy.rule $PERSISTMOD/sepolicy.rule
fi
# Remove stuffs that don't belong to modules
rm -rf \
$MODPATH/system/placeholder $MODPATH/customize.sh \
$MODPATH/README.md $MODPATH/.git* 2>/dev/null
##############
# Finalizing # Finalizing
########################################################################################## ##############
cd / cd /
imageless_magisk || unmount_magisk_img
$BOOTMODE || recovery_cleanup $BOOTMODE || recovery_cleanup
rm -rf $TMPDIR $MOUNTPATH rm -rf $TMPDIR
ui_print "- Done" ui_print "- Done"
exit 0 exit 0

View File

@ -5,27 +5,8 @@
# #
######################################### #########################################
##########
# Presets
##########
#MAGISK_VERSION_STUB #MAGISK_VERSION_STUB
# Detect whether in boot mode
[ -z $BOOTMODE ] && BOOTMODE=false
$BOOTMODE || ps | grep zygote | grep -qv grep && BOOTMODE=true
$BOOTMODE || ps -A 2>/dev/null | grep zygote | grep -qv grep && BOOTMODE=true
# Presets
MAGISKTMP=/sbin/.magisk
NVBASE=/data/adb
[ -z $TMPDIR ] && TMPDIR=/dev/tmp
# Bootsigner related stuff
BOOTSIGNERCLASS=a.a
BOOTSIGNER="/system/bin/dalvikvm -Xnodex2oat -Xnoimage-dex2oat -cp \$APK \$BOOTSIGNERCLASS"
BOOTSIGNED=false
################### ###################
# Helper Functions # Helper Functions
################### ###################
@ -128,15 +109,15 @@ recovery_actions() {
} }
recovery_cleanup() { recovery_cleanup() {
ui_print "- Unmounting partitions"
umount -l /system 2>/dev/null
umount -l /system_root 2>/dev/null
umount -l /vendor 2>/dev/null
umount -l /dev/random 2>/dev/null
export PATH=$OLD_PATH export PATH=$OLD_PATH
[ -z $OLD_LD_LIB ] || export LD_LIBRARY_PATH=$OLD_LD_LIB [ -z $OLD_LD_LIB ] || export LD_LIBRARY_PATH=$OLD_LD_LIB
[ -z $OLD_LD_PRE ] || export LD_PRELOAD=$OLD_LD_PRE [ -z $OLD_LD_PRE ] || export LD_PRELOAD=$OLD_LD_PRE
[ -z $OLD_LD_CFG ] || export LD_CONFIG_FILE=$OLD_LD_CFG [ -z $OLD_LD_CFG ] || export LD_CONFIG_FILE=$OLD_LD_CFG
ui_print "- Unmounting partitions"
umount -l /system_root 2>/dev/null
umount -l /system 2>/dev/null
umount -l /vendor 2>/dev/null
umount -l /dev/random 2>/dev/null
} }
####################### #######################
@ -165,19 +146,29 @@ find_block() {
return 1 return 1
} }
mount_part() { # mount_name <partname> <mountpoint> <flag>
$BOOTMODE && return mount_name() {
local PART=$1 local PART=$1
local POINT=/${PART} local POINT=$2
local FLAG=$3
[ -L $POINT ] && rm -f $POINT [ -L $POINT ] && rm -f $POINT
mkdir $POINT 2>/dev/null mkdir -p $POINT 2>/dev/null
is_mounted $POINT && return is_mounted $POINT && return
ui_print "- Mounting $PART" ui_print "- Mounting $POINT"
mount -o ro $POINT 2>/dev/null # First try mounting with fstab
mount $FLAG $POINT 2>/dev/null
if ! is_mounted $POINT; then if ! is_mounted $POINT; then
local BLOCK=`find_block $PART$SLOT` local BLOCK=`find_block $PART`
mount -o ro $BLOCK $POINT mount $FLAG $BLOCK $POINT
fi fi
}
mount_ro_ensure() {
# We handle ro partitions only in recovery
$BOOTMODE && return
local PART=$1$SLOT
local POINT=/$1
mount_name $PART $POINT '-o ro'
is_mounted $POINT || abort "! Cannot mount $POINT" is_mounted $POINT || abort "! Cannot mount $POINT"
} }
@ -190,7 +181,8 @@ mount_partitions() {
fi fi
[ -z $SLOT ] || ui_print "- Current boot slot: $SLOT" [ -z $SLOT ] || ui_print "- Current boot slot: $SLOT"
mount_part system # Mount ro partitions
mount_ro_ensure system
if [ -f /system/init.rc ]; then if [ -f /system/init.rc ]; then
SYSTEM_ROOT=true SYSTEM_ROOT=true
[ -L /system_root ] && rm -f /system_root [ -L /system_root ] && rm -f /system_root
@ -201,8 +193,20 @@ mount_partitions() {
grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts \ grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts \
&& SYSTEM_ROOT=true || SYSTEM_ROOT=false && SYSTEM_ROOT=true || SYSTEM_ROOT=false
fi fi
[ -L /system/vendor ] && mount_part vendor [ -L /system/vendor ] && mount_ro_ensure vendor
$SYSTEM_ROOT && ui_print "- Device is system-as-root" $SYSTEM_ROOT && ui_print "- Device is system-as-root"
# Mount persist partition in recovery
if ! $BOOTMODE && [ ! -z $PERSISTDIR ]; then
# Try to mount persist
PERSISTDIR=/persist
mount_name persist /persist
if ! is_mounted /persist; then
# Fallback to cache
mount_name cache /cache
is_mounted /cache && PERSISTDIR=/cache || PERSISTDIR=
fi
fi
} }
get_flags() { get_flags() {
@ -272,30 +276,29 @@ flash_image() {
return 0 return 0
} }
find_dtbo_image() { patch_dtb_partitions() {
DTBOIMAGE=`find_block dtbo$SLOT` local result=1
} cd $MAGISKBIN
for name in dtb dtbo; do
patch_dtbo_image() { local IMAGE=`find_block $name$SLOT`
find_dtbo_image if [ ! -z $IMAGE ]; then
if [ ! -z $DTBOIMAGE ]; then ui_print "- $name image: $IMAGE"
ui_print "- DTBO image: $DTBOIMAGE" if ./magiskboot dtb $IMAGE patch dt.patched; then
local PATCHED=$TMPDIR/dtbo result=0
if $MAGISKBIN/magiskboot dtb $DTBOIMAGE patch $PATCHED; then ui_print "- Backing up stock $name image"
ui_print "- Backing up stock DTBO image" cat $IMAGE > stock_${name}.img
$MAGISKBIN/magiskboot compress $DTBOIMAGE $MAGISKBIN/stock_dtbo.img.gz ui_print "- Flashing patched $name"
ui_print "- Patching DTBO to remove avb-verity" cat dt.patched /dev/zero > $IMAGE
cat $PATCHED /dev/zero > $DTBOIMAGE rm -f dt.patched
rm -f $PATCHED fi
return 0
fi fi
fi done
return 1 cd /
return $result
} }
patch_boot_image() { # Common installation script for flash_script.sh and addon.d.sh
# Common installation script for flash_script.sh (updater-script) and addon.d.sh install_magisk() {
SOURCEDMODE=true
cd $MAGISKBIN cd $MAGISKBIN
eval $BOOTSIGNER -verify < $BOOTIMAGE && BOOTSIGNED=true eval $BOOTSIGNER -verify < $BOOTIMAGE && BOOTSIGNED=true
@ -304,6 +307,7 @@ patch_boot_image() {
$IS64BIT && mv -f magiskinit64 magiskinit 2>/dev/null || rm -f magiskinit64 $IS64BIT && mv -f magiskinit64 magiskinit 2>/dev/null || rm -f magiskinit64
# Source the boot patcher # Source the boot patcher
SOURCEDMODE=true
. ./boot_patch.sh "$BOOTIMAGE" . ./boot_patch.sh "$BOOTIMAGE"
ui_print "- Flashing new boot image" ui_print "- Flashing new boot image"
@ -318,18 +322,8 @@ patch_boot_image() {
./magiskboot cleanup ./magiskboot cleanup
rm -f new-boot.img rm -f new-boot.img
if [ -f stock_boot* ]; then patch_dtb_partitions
rm -f /data/stock_boot* 2>/dev/null run_migrations
$DATA && mv stock_boot* /data
fi
# Patch DTBO together with boot image
$KEEPVERITY || patch_dtbo_image
if [ -f stock_dtbo* ]; then
rm -f /data/stock_dtbo* 2>/dev/null
$DATA && mv stock_dtbo* /data
fi
} }
sign_chromeos() { sign_chromeos() {
@ -411,6 +405,41 @@ find_manager_apk() {
[ -f $APK ] || ui_print "! Unable to detect Magisk Manager APK for BootSigner" [ -f $APK ] || ui_print "! Unable to detect Magisk Manager APK for BootSigner"
} }
run_migrations() {
local LOCSHA1
local TARGET
# Legacy app installation
local BACKUP=/data/adb/magisk/stock_boot*.gz
if [ -f $BACKUP ]; then
cp $BACKUP /data
rm -f $BACKUP
fi
# Legacy backup
for gz in /data/stock_boot*.gz; do
[ -f $gz ] || break
LOCSHA1=`basename $gz | sed -e 's/stock_boot_//' -e 's/.img.gz//'`
[ -z $LOCSHA1 ] && break
mkdir /data/magisk_backup_${LOCSHA1} 2>/dev/null
mv $gz /data/magisk_backup_${LOCSHA1}/boot.img.gz
done
# Stock backups
LOCSHA1=$SHA1
for name in boot dtb dtbo; do
BACKUP=/data/adb/magisk/stock_${name}.img
[ -f $BACKUP ] || continue
if [ $name = 'boot' ]; then
LOCSHA1=`$MAGISKBIN/magiskboot sha1 $BACKUP`
mkdir /data/magisk_backup_${LOCSHA1} 2>/dev/null
fi
TARGET=/data/magisk_backup_${LOCSHA1}/${name}.img
cp $BACKUP $TARGET
rm -f $BACKUP
gzip -9f $TARGET
done
}
################# #################
# Module Related # Module Related
################# #################
@ -446,27 +475,24 @@ request_zip_size_check() {
reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'` reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'`
} }
##################################
# Backwards Compatibile Functions
##################################
get_outfd() { setup_flashable; }
mount_magisk_img() {
$BOOTMODE && MODULE_BASE=modules_update || MODULE_BASE=modules
MODULEPATH=$NVBASE/$MODULE_BASE
mkdir -p $MODULEPATH 2>/dev/null
ln -s $MODULEPATH $MOUNTPATH
}
unmount_magisk_img() {
rm -f $MOUNTPATH 2>/dev/null
}
boot_actions() { return; } boot_actions() { return; }
######## ##########
# Setup # Presets
######## ##########
# Detect whether in boot mode
[ -z $BOOTMODE ] && ps | grep zygote | grep -qv grep && BOOTMODE=true
[ -z $BOOTMODE ] && ps -A 2>/dev/null | grep zygote | grep -qv grep && BOOTMODE=true
[ -z $BOOTMODE ] && BOOTMODE=false
MAGISKTMP=/sbin/.magisk
NVBASE=/data/adb
[ -z $TMPDIR ] && TMPDIR=/dev/tmp
# Bootsigner related stuff
BOOTSIGNERCLASS=a.a
BOOTSIGNER="/system/bin/dalvikvm -Xnodex2oat -Xnoimage-dex2oat -cp \$APK \$BOOTSIGNERCLASS"
BOOTSIGNED=false
resolve_vars resolve_vars

View File

@ -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}"
} }

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="upgrade_msg">Mettre à jour vers la version complête de Magisk Manager pour finir l\'installation. Télécharger et installer?</string> <string name="upgrade_msg">Une mise à niveau de Magisk Manager en version complète est nécessaire afin de terminer linstallation. Souhaitezvous procéder à son téléchargement et son installation?</string>
<string name="no_internet_msg">Veuillez vous connecter à Internet! Une mise à niveau complête vers le Gestionnaire Magisk est requise.</string> <string name="no_internet_msg">Veuillez vous connecter à Internet! Une mise à niveau complète de Magisk Manager est requise.</string>
<string name="dling">Téléchargement en cours</string>
</resources> </resources>

View File

@ -1,4 +1,5 @@
<resources> <resources>
<string name="upgrade_msg">需要升級到完整版 Magisk Manager。是否下載並安裝</string> <string name="upgrade_msg">需要升級到完整版 Magisk Manager。是否下載並安裝</string>
<string name="no_internet_msg">請連上網路!升級到完整版 Magisk Manager 是必須的。</string> <string name="no_internet_msg">請連上網路!升級到完整版 Magisk Manager 是必須的。</string>
<string name="dling">下載中</string>
</resources> </resources>