Compare commits

...

32 Commits

Author SHA1 Message Date
topjohnwu
a27e30cf54 Update release notes 2021-01-17 06:08:15 -08:00
topjohnwu
79140c7636 Proper xxread and xwrite implementation 2021-01-17 01:42:45 -08:00
topjohnwu
1f4c595cd3 Revert to old su -c behavior 2021-01-16 23:59:31 -08:00
topjohnwu
b5b62e03af Fix copySepolicyRules logic 2021-01-16 21:45:45 -08:00
topjohnwu
67e2a4720e Fix xxread false negatives
Fix #3710
2021-01-16 21:43:53 -08:00
topjohnwu
f5c2d72429 Also log pid and tid 2021-01-16 16:10:47 -08:00
topjohnwu
2f5331ab48 Update README 2021-01-16 05:02:39 -08:00
topjohnwu
7f8257152f Add v21.3 release notes 2021-01-16 04:55:44 -08:00
topjohnwu
0cd80f2556 Update app changelog 2021-01-16 04:42:14 -08:00
rydwhelchel
1717387876 Grammatical changes to the install docs 2021-01-15 21:32:29 -08:00
Mspy1
109363ebf6 Fixed typo 2021-01-15 21:31:58 -08:00
LLZN
716c4fa386 new update values-cs
update czech strings.xml
2021-01-15 21:31:17 -08:00
Arbri çoçka
9a09b4eb20 fix strings-sq 2021-01-15 21:29:53 -08:00
Rikka
95a5b57265 Remove "Flashing" overlay
Fix #3579, fix #3250
2021-01-15 21:28:59 -08:00
topjohnwu
13fbf397d1 Isolated processes might still be hide-able 2021-01-15 20:22:49 -08:00
vvb2060
20be99ec8a Restore mistakenly deleted codes 2021-01-15 19:59:55 -08:00
topjohnwu
04c53c3578 Legacy SAR: use a simpler method to detect is_two_stage 2021-01-15 02:44:40 -08:00
topjohnwu
51bc27a869 Avoid F2FS like a plague 2021-01-15 02:24:11 -08:00
topjohnwu
71b083794c Maintain global mount list 2021-01-14 21:14:54 -08:00
topjohnwu
b100d0c503 Revert DTB fstab changes 2021-01-14 19:48:00 -08:00
topjohnwu
76061296c9 Let MagiskBoot handle dtb fstab patching 2021-01-14 06:20:12 -08:00
topjohnwu
bb303d2da1 Remove old unused code 2021-01-14 05:59:53 -08:00
topjohnwu
c91c070343 Re-enable DTB table rebuilding 2021-01-14 05:45:05 -08:00
topjohnwu
aec06a6f61 Get proper total image size 2021-01-14 03:55:27 -08:00
topjohnwu
e8ba671fc2 Guard all injection features behind a global flag 2021-01-13 20:07:23 -08:00
topjohnwu
1860e5d133 Dynamically find libselinux.so path 2021-01-13 19:41:57 -08:00
topjohnwu
f2cb3c38fe Update mmap implementation
Always map memory as writable, but private when read-only
2021-01-12 22:50:55 -08:00
topjohnwu
9a28dd4f6e Implement MagiskHide through code injection 2021-01-12 03:28:00 -08:00
topjohnwu
d2acd59ea8 Minor code refactoring 2021-01-12 00:07:48 -08:00
topjohnwu
79dfdb29e7 Minor tweaks for patching tar files 2021-01-11 19:47:36 -08:00
topjohnwu
eb21c8b42e Code cleanups 2021-01-11 02:19:10 -08:00
topjohnwu
541bb53553 Update links in README 2021-01-10 20:36:58 -08:00
61 changed files with 1069 additions and 929 deletions

View File

@@ -15,11 +15,11 @@ Here are some feature highlights:
## Downloads
[![](https://img.shields.io/badge/Magisk%20Manager-v8.0.4-green)](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.4/MagiskManager-v8.0.4.apk)
[![](https://img.shields.io/badge/Magisk%20Manager-v8.0.6-green)](https://github.com/topjohnwu/Magisk/releases/download/manager-v8.0.6/MagiskManager-v8.0.6.apk)
[![](https://img.shields.io/badge/Magisk%20Manager-Canary-red)](https://raw.githubusercontent.com/topjohnwu/magisk_files/canary/app-debug.apk)
<br>
[![](https://img.shields.io/badge/Magisk-v20.4-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v20.4)
[![](https://img.shields.io/badge/Magisk%20Beta-v21.2-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v21.2)
[![](https://img.shields.io/badge/Magisk-v21.3-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v21.3)
[![](https://img.shields.io/badge/Magisk%20Beta-v21.3-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v21.3)
## Useful Links

View File

@@ -41,6 +41,11 @@ abstract class BaseUIFragment<VM : BaseViewModel, Binding : ViewDataBinding> :
return binding.root
}
override fun onStart() {
super.onStart()
activity.supportActionBar?.subtitle = null
}
override fun onEventDispatched(event: ViewEvent) = when(event) {
is ContextExecutor -> event(requireContext())
is ActivityExecutor -> event(activity)

View File

@@ -191,9 +191,10 @@ abstract class MagiskInstallImpl : KoinComponent {
if (rawData.size < 256)
continue
// Patch flags to AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED
// Patch flags to AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED |
// AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED
console.add("-- Patching: vbmeta.img")
ByteBuffer.wrap(rawData).putInt(120, 2)
ByteBuffer.wrap(rawData).putInt(120, 3)
tarOut.putNextEntry(newEntry("vbmeta.img", rawData.size.toLong()))
tarOut.write(rawData)
} else {
@@ -204,7 +205,7 @@ abstract class MagiskInstallImpl : KoinComponent {
}
val boot = SuFile.open(installDir, "boot.img")
val recovery = SuFile.open(installDir, "recovery.img")
if (recovery.exists() && boot.exists()) {
if (Config.recovery && recovery.exists() && boot.exists()) {
// Install Magisk to recovery
srcBoot = recovery.path
// Repack boot image to prevent restore
@@ -360,9 +361,10 @@ abstract class MagiskInstallImpl : KoinComponent {
}
private fun copySepolicyRules(): Boolean {
if (Info.remote.magisk.versionCode >= 21100) return true
// Copy existing rules for migration
"copy_sepolicy_rules".sh()
if (Info.remote.magisk.versionCode >= 21100) {
// Copy existing rules for migration
"copy_sepolicy_rules".sh()
}
return true
}

View File

@@ -29,6 +29,6 @@ val viewModelModules = module {
viewModel { MainViewModel() }
// Legacy
viewModel { (args: FlashFragmentArgs) -> FlashViewModel(args, get()) }
viewModel { (args: FlashFragmentArgs) -> FlashViewModel(args) }
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
}

View File

@@ -32,6 +32,10 @@ class FlashFragment : BaseUIFragment<FlashViewModel, FragmentFlashMd2Binding>()
super.onStart()
setHasOptionsMenu(true)
activity.setTitle(R.string.flash_screen_title)
viewModel.subtitle.observe(this) {
activity.supportActionBar?.setSubtitle(it)
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {

View File

@@ -1,9 +1,10 @@
package com.topjohnwu.magisk.ui.flash
import android.content.res.Resources
import android.net.Uri
import android.view.MenuItem
import androidx.databinding.Bindable
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
@@ -26,17 +27,15 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class FlashViewModel(
args: FlashFragmentArgs,
private val resources: Resources
args: FlashFragmentArgs
) : BaseViewModel() {
@get:Bindable
var showReboot = Shell.rootAccess()
set(value) = set(value, field, { field = it }, BR.showReboot)
@get:Bindable
var behaviorText = resources.getString(R.string.flashing)
set(value) = set(value, field, { field = it }, BR.behaviorText)
private val _subtitle = MutableLiveData(R.string.flashing)
val subtitle get() = _subtitle as LiveData<Int>
val adapter = RvBindingAdapter<ConsoleItem>()
val items = diffListOf<ConsoleItem>()
@@ -91,9 +90,9 @@ class FlashViewModel(
private fun onResult(success: Boolean) {
state = if (success) State.LOADED else State.LOADING_FAILED
behaviorText = when {
success -> resources.getString(R.string.done)
else -> resources.getString(R.string.failure)
when {
success -> _subtitle.postValue(R.string.done)
else -> _subtitle.postValue(R.string.failure)
}
}

View File

@@ -312,7 +312,7 @@ object RequestTimeout : BaseSettingsItem.Selector() {
override var value = selected
set(value) = setV(value, field, { field = it }) {
Config.suDefaultTimeout = it
Config.suDefaultTimeout = entryValues[it].toInt()
}
private val selected: Int

View File

@@ -56,29 +56,6 @@
app:icon="@drawable/ic_restart"
app:iconTint="?colorOnPrimary" />
<com.google.android.material.card.MaterialCardView
style="@style/WidgetFoundation.Card.Elevated"
goneUnless="@{viewModel.loading}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:contentPadding="@dimen/l1">
<TextView
movieBehavior="@{viewModel.loading}"
movieBehaviorText="@{viewModel.behaviorText}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="monospace"
android:gravity="center"
android:textAppearance="@style/AppearanceFoundation.Body"
android:textColor="?colorOnSurface"
android:textStyle="bold"
tools:text="Flashing..." />
</com.google.android.material.card.MaterialCardView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@@ -1,14 +1,8 @@
## v8.0.5
## v8.0.7
- Fix sepolicy rule copying
- Fix sepolicy rule migration when upgrading
## v8.0.4
## v8.0.6
- A lot of stability changes and minor bug fixes
- Collect device properties, app logcat, and Magisk logs when saving logs in the logs menu
## v8.0.3
- Switch to the new Magisk Module Repo setup in preparation to allow 3rd party repos
- Add tapjacking protection on Superuser request dialog
- Stability changes and bug fixes
- Minor UI changes
- Update internal scripts

View File

@@ -1,169 +1,247 @@
<resources>
<!--Welcome Activity-->
<string name="modules">Moduly</string>
<string name="superuser">Superuser</string>
<string name="logs">Log</string>
<!--Sections-->
<string name="modules">Správce modulů</string>
<string name="superuser">SuperUser</string>
<string name="logs">Protokol</string>
<string name="settings">Nastavení</string>
<string name="refresh">Obnovit lokální data</string>
<string name="install">Instalovat</string>
<string name="unsupport_magisk_title">Nepodporovaná verze Magisk</string>
<string name="section_home">Domů</string>
<string name="section_theme">Téma</string>
<string name="safetynet">SafetyNet</string>
<!--Status Fragment-->
<string name="invalid_update_channel">Neplatný kanál aktualizace</string>
<string name="safetynet_api_error">Chyba SafetyNet API</string>
<string name="safetynet_res_invalid">Odpověď je neplatná.</string>
<string name="keep_force_encryption">Udržet "force encryption"</string>
<string name="keep_dm_verity">Udržet "AVB 2.0/dm-verity"</string>
<string name="uninstall_magisk_title">Odinstalovat Magisk</string>
<string name="uninstall_magisk_msg">Všechny moduly budou zakázány/odstraněny. Root bude odstraněn a pokud jsou data dešifrována, můžou být zašifrována.</string>
<string name="update">Aktualizovat</string>
<!--Module Fragment-->
<string name="no_info_provided">(Žádné informace)</string>
<string name="reboot_recovery">Restartovat do Recovery</string>
<string name="reboot_bootloader">Restartovat do Bootloaderu</string>
<string name="reboot_download">Restartovat do Download</string>
<!--Repo Fragment-->
<string name="update_available">Dostupná aktualizace</string>
<string name="home_installed_version">Nainstalováno</string>
<string name="sorting_order">Pořadí řazení</string>
<!--Log Fragment-->
<string name="menuSaveLog">Uložit log</string>
<string name="menuClearLog">Smazat log</string>
<string name="logs_cleared">Log byl smazán.</string>
<!--About Activity-->
<!--Home-->
<string name="no_connection">Žádné připojení</string>
<string name="app_changelog">Seznam změn</string>
<string name="manager">Správce</string>
<string name="loading">Načítání…</string>
<string name="update">Aktualizovat</string>
<string name="not_available">N/A</string>
<string name="hide">Skrýt</string>
<string name="status">Stav</string>
<string name="home_package">Balíček</string>
<!-- System Components, Notifications -->
<string name="update_channel">Aktualizace Magisk</string>
<string name="progress_channel">Oznámení o průběhu</string>
<string name="download_complete">Stahování dokončeno</string>
<string name="download_file_error">Chyba při stahování souboru</string>
<string name="magisk_update_title">Aktualizace Magisk je dostupná!</string>
<string name="manager_update_title">Aktualizace Magisk Manager je dostup!</string>
<string name="home_notice_content">Zkontrolujte, zda používáte Magisk Manager s otevřeným kódem. Správce z neznámého zdroje může provádět nebezpečné akce!</string>
<string name="home_support_title">Podpořte nás</string>
<string name="home_item_source">Zdroj</string>
<string name="home_support_content">Magisk je a vždy bude svobodný s otevřeným kódem. Můžete nám však zaslat malý dar jako poděkování.</string>
<string name="home_status_normal">Normální</string>
<string name="home_status_stub">Testovací</string>
<string name="home_installed_version">Nainstalova</string>
<string name="home_latest_version">Poslední</string>
<string name="invalid_update_channel">Neplatný kanál aktualizace</string>
<string name="uninstall_magisk_title">Odinstalovat Magisk</string>
<string name="uninstall_magisk_msg">Všechny moduly budou zakázány/odstraněny!\nROOT bude odstraněn!\nPokud jsou data dešifrována, můžou být zašifrována!</string>
<string name="home_check_safetynet">Zkontrolovat SafetyNet</string>
<!-- Installation -->
<string name="manager_download_install">Stiskněte pro stažení a instalaci.</string>
<string name="download_zip_only">Stáhnout pouze zip</string>
<!--Install-->
<string name="keep_force_encryption">Ponechat Force Encryption</string>
<string name="keep_dm_verity">Ponechat AVB 2.0/DM-Verity</string>
<string name="recovery_mode">Režim Recovery</string>
<string name="install_options_title">Možnosti</string>
<string name="install_method_title">Způsob</string>
<string name="install_next">Další</string>
<string name="install_start">Spustit</string>
<string name="manager_download_install">Stiskněte pro stažení a instalaci</string>
<string name="download_zip_only">Stáhnout pouze soubor ZIP</string>
<string name="direct_install">Přímá instalace (doporučeno)</string>
<string name="install_inactive_slot">Instalace do druhého slotu (po OTA)</string>
<string name="install_inactive_slot_msg">Vaše zařízení bude po restartu VYNUCENĚ spuštěno do aktuálního neaktivního slotu!\nTuto možnost použijte pouze po dokončení OTA.\nPokračovat?</string>
<string name="install_inactive_slot_msg">Vaše zařízení bude po restartu VYNUCENĚ spuštěno do aktuálního neaktivního slotu!\nTuto možnost použijte pouze po dokončení OTA.\nChcete pokračovat?</string>
<string name="setup_title">Další nastavení</string>
<string name="select_patch_file">Vybrat a opravit soubor</string>
<string name="patch_file_msg">Vyberte obraz raw (*.img) nebo soubor tar pro ODIN (*.tar)</string>
<string name="patch_file_msg">Vyberte soubor RAW (*.img) nebo soubor TAR pro ODIN (*.tar)</string>
<string name="reboot_delay_toast">Restartování za 5 sekund…</string>
<string name="flash_screen_title">Instalace</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">Instalovat %1$s</string>
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
<string name="download">Stáhnout</string>
<string name="reboot">Restartovat</string>
<string name="release_notes">Poznámky k vydání</string>
<string name="repo_cache_cleared">Mezipaměť smazána</string>
<!--Superuser-->
<string name="su_request_title">Požadavek SuperUser</string>
<string name="touch_filtered_warning">Protože aplikace zavírá požadavek SuperUser, Magisk nemůže ověřit Vaši odpověď</string>
<string name="deny">Zakázat</string>
<string name="prompt">Zeptat se</string>
<string name="grant">Povolit</string>
<string name="su_warning">Povolí plný přístup k Vašemu zařízení.\nZakažte, pokud si nejste jisti!</string>
<string name="forever">Trvale</string>
<string name="once">Jednou</string>
<string name="tenmin">10 minut</string>
<string name="twentymin">20 minut</string>
<string name="thirtymin">30 minut</string>
<string name="sixtymin">60 minut</string>
<string name="su_allow_toast">Pro %1$s bylo oprávnění SuperUser povoleno</string>
<string name="su_deny_toast">Pro %1$s bylo oprávnění SuperUser zakázáno</string>
<string name="su_snack_grant">SuperUser oprávnění pro %1$s je povoleno</string>
<string name="su_snack_deny">SuperUser oprávnění pro %1$s je zakázáno</string>
<string name="su_snack_notif_on">Oznámení pro %1$s jsou povolena</string>
<string name="su_snack_notif_off">Oznámení pro %1$s jsou zakázána</string>
<string name="su_snack_log_on">Protokolování %1$s je povoleno</string>
<string name="su_snack_log_off">Protokolování %1$s je zakázáno</string>
<string name="su_revoke_title">Smazat?</string>
<string name="su_revoke_msg">Chcete smazat protokol k oprávnění pro %1$s?</string>
<string name="toast">Text</string>
<string name="none">Žádné</string>
<string name="flashing">Instalová</string>
<string name="hide_manager_title">Skrytí Magisk Manageru…</string>
<string name="hide_manager_fail_toast">Skrytí Magisk Manageru selhalo.</string>
<string name="open_link_failed_toast">Nebyla nalezena žádná aplikace pro otevření odkazu.</string>
<string name="complete_uninstall">Dokončete odinstalaci</string>
<string name="restore_img">Obnovit obrazy</string>
<string name="restore_img_msg">Obnovování…</string>
<string name="restore_done">Obnovení bylo provedeno!</string>
<string name="restore_fail">Výchozí záloha neexistuje!</string>
<string name="proprietary_title">Stáhnout proprietární kód</string>
<string name="proprietary_notice">Magisk Manager je FOSS a neobsahuje proprietární kód SafetyNet API společnosti Google.\n\nChcete povolit aplikaci Magisk Manager stažení rozšíření (obsahuje GoogleApiClient) pro kontrolu SafetyNet?</string>
<string name="setup_fail">Nastavení selhalo.</string>
<string name="env_fix_title">Vyžaduje se další nastavení</string>
<string name="env_fix_msg">Vaše zařízení potřebuje další nastavení, aby Magisk fungoval správně. Stáhne se instalační zip Magisk, chcete pokračovat?</string>
<string name="setup_msg">Nastavení je spuštěno…</string>
<string name="superuser_toggle_notification">Oznáme</string>
<string name="superuser_toggle_revoke">Smazat</string>
<string name="superuser_policy_none">Žádná aplikace nepožádala o oprávnění SuperUser.</string>
<!--Settings Activity -->
<string name="settings_clear_cache_title">Smazat uchovanou mezipaměť</string>
<string name="settings_clear_cache_summary">Smaže informace online použití v mezipaměti, donutí aplikaci obnovit informace online.</string>
<!--Logs-->
<string name="log_data_none">Žádné protokoly. Vyzkoušejte nějakou aplikaci vyžadující oprávnění SuperUser.</string>
<string name="log_data_magisk_none">Protokoly Magisk jsou prázdné. To je zvláštní!</string>
<string name="menuSaveLog">Uložit protokol</string>
<string name="menuClearLog">Smazat protokol</string>
<string name="logs_cleared">Protokol byl smazán</string>
<string name="pid">PID:%1$d</string>
<string name="target_uid">Cílové UID: %1$d</string>
<!--SafetyNet-->
<string name="safetynet_api_error">Chyba SafetyNet API</string>
<string name="safetynet_res_invalid">Odpověď je neplatná</string>
<string name="safetynet_attest_success">Úspěšné!</string>
<string name="safetynet_attest_failure">Chyba ověření!</string>
<string name="safetynet_attest_loading">Čekejte…</string>
<string name="safetynet_attest_restart">Zkusit znovu</string>
<!--MagiskHide-->
<string name="show_system_app">Zobrazit systémové aplikace</string>
<string name="show_os_app">Zobrazit OS aplikace</string>
<string name="hide_filter_hint">Filtrovat podle názvu</string>
<string name="hide_scroll_up">Posunout nahoru</string>
<string name="hide_filters">Filtry</string>
<string name="hide_search">Vyhledávání</string>
<!--Module-->
<string name="no_info_provided">(žádné informace)</string>
<string name="reboot_userspace">Restartovat do UserSpace</string>
<string name="reboot_recovery">Restartovat do Recovery</string>
<string name="reboot_bootloader">Restartovat do Bootloader</string>
<string name="reboot_download">Restartovat do Download</string>
<string name="reboot_edl">Restartovat do EDL</string>
<string name="module_version_author">%1$s z %2$s</string>
<string name="module_section_pending">Aktualizace</string>
<string name="module_section_pending_action">Aktualizovat vše</string>
<string name="module_state_remove">Odstranit</string>
<string name="module_state_restore">Obnovit</string>
<string name="module_action_install_external">Instalace z úložiště</string>
<string name="update_available">Dostupná aktualizace</string>
<string name="module_installed">@string/home_installed_version</string>
<string name="module_section_online">Online</string>
<string name="sorting_order">Seřadit</string>
<!--Settings-->
<string name="settings_dark_mode_title">Režim motivu</string>
<string name="settings_dark_mode_message">Vyberte režim, který nejlépe vyhovuje Vašemu stylu!</string>
<string name="settings_dark_mode_light">Světlý</string>
<string name="settings_dark_mode_system">Podle systému</string>
<string name="settings_dark_mode_dark">Tmavý</string>
<string name="settings_download_path_title">Složka pro stahování</string>
<string name="settings_download_path_message">Soubory budou uloženy do %1$s.</string>
<string name="settings_clear_cache_title">Smazat mezipaměť</string>
<string name="settings_clear_cache_summary">Smažete online informace o použití z mezipaměti, a tím na aplikaci vynutíte obnovení online informací.</string>
<string name="settings_hide_manager_title">Skrýt Magisk Manager</string>
<string name="settings_hide_manager_summary">Nahradí Magisk Manager náhodným názvem balíčku.</string>
<string name="settings_hide_manager_summary">Nahradíte Magisk Manager náhodným názvem balíčku.</string>
<string name="settings_restore_manager_title">Obnovit Magisk Manager</string>
<string name="settings_restore_manager_summary">Obnoví Magisk Manager na původní název balíčku.</string>
<string name="settings_restore_manager_summary">Obnovíte Magisk Manager na původní název balíčku.</string>
<string name="language">Jazyk</string>
<string name="system_default">(Výchozí systémový)</string>
<string name="settings_check_update_title">Zkontrolovat aktualizace</string>
<string name="settings_check_update_summary">Pravidelně kontrolujte aktualizace na pozadí.</string>
<string name="system_default">(výchozí podle systému)</string>
<string name="settings_check_update_title">Automatické aktualizace</string>
<string name="settings_check_update_summary">Povolíte pravidelnou kontrolu aktualizace na pozadí.</string>
<string name="settings_update_channel_title">Kanál aktualizace</string>
<string name="settings_update_stable">Stabilní</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Vlastní</string>
<string name="settings_update_custom_msg">Vložte vlastní URL</string>
<string name="settings_magiskhide_summary">Skrýt Magisk z různých detekcí.</string>
<string name="settings_hosts_title">Nesystémoví hostitelé</string>
<string name="settings_hosts_summary">Podpora nesystémových hostitelů pro aplikace Adblock.</string>
<string name="settings_magiskhide_summary">Skryjete Magisk před různými detekcemi.</string>
<string name="settings_hosts_title">Nesystémový hostitel</string>
<string name="settings_hosts_summary">Přidáte modul pro podporu nesystémových hostitelů v aplikaci AdBlock.</string>
<string name="settings_hosts_toast">Přidán systémový modul hostitelů</string>
<string name="settings_app_name_hint">Nový název</string>
<string name="settings_app_name_helper">Název aplikace bude nahrazen tímto názvem.</string>
<string name="settings_app_name_error">Neplatný formát</string>
<string name="settings_su_app_adb">Aplikace a ADB</string>
<string name="settings_su_app">Pouze aplikace</string>
<string name="settings_su_adb">Pouze ADB</string>
<string name="settings_su_disable">Zakázáno</string>
<string name="settings_su_disable">Zakázat</string>
<string name="settings_su_request_10">10 sekund</string>
<string name="settings_su_request_15">15 sekund</string>
<string name="settings_su_request_20">20 sekund</string>
<string name="settings_su_request_30">30 sekund</string>
<string name="settings_su_request_45">45 sekund</string>
<string name="settings_su_request_60">60 sekund</string>
<string name="superuser_access">Přístup Superuser</string>
<string name="superuser_access">Přístup SuperUser</string>
<string name="auto_response">Automatická odezva</string>
<string name="request_timeout">Časový limit požadavku</string>
<string name="superuser_notification">Oznámení Superuser</string>
<string name="superuser_notification">Oznámení SuperUser</string>
<string name="settings_su_reauth_title">Opětovné ověření po aktualizaci</string>
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění Superuser po aktualizaci aplikace</string>
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění SuperUser po aktualizaci aplikace.</string>
<string name="settings_su_tapjack_title">Povolit ochranu před TapJack</string>
<string name="settings_su_tapjack_summary">Okno dialogu SuperUser nebude reagovat na kliknutí v případě, že je zavřené nebo překryté jiným oknem.</string>
<string name="settings_su_biometric_title">Povolit biometrické ověření</string>
<string name="settings_su_biometric_summary">Použijte biometrické ověření pro povolení požadavků SuperUser.</string>
<string name="no_biometric">Nepodporované zařízení nebo není biometrické ověření povolené</string>
<string name="settings_customization">Přizpůsobit</string>
<string name="setting_add_shortcut_summary">Přidejte odkaz na domovskou obrazovku v případě, že se po skrytí aplikace její název a ikona těžko rozpoznávají.</string>
<string name="settings_doh_title">DNS nebo HTTPS</string>
<string name="settings_doh_description">Řešení pro opravy DNS v některých zemích.</string>
<string name="multiuser_mode">Režim více uživatelů</string>
<string name="settings_owner_only">Pouze vlastník zařízení</string>
<string name="settings_owner_manage">Spravováno vlastníkem zařízení</string>
<string name="settings_user_independent">Nezávislý uživatel</string>
<string name="owner_only_summary">Pouze vlastník má root přístup.</string>
<string name="owner_manage_summary">Root přístup spravuje pouze vlastník a přijímá požadavky k přístupu.</string>
<string name="user_indepenent_summary">Každý uživatel má svá vlastní pravidla root.</string>
<string name="settings_owner_only">Vlastník zařízení</string>
<string name="settings_owner_manage">Správce zařízení</string>
<string name="settings_user_independent">Všichni uživatelé</string>
<string name="owner_only_summary">Pouze vlastník má přístup ROOT.</string>
<string name="owner_manage_summary">Přístup ROOT má správce zařízení, který přijímá požadavky k přístupu.</string>
<string name="user_indepenent_summary">Každý uživatel má svá vlastní pravidla přístupu ROOT.</string>
<string name="mount_namespace_mode">Režim připojení jmenného prostoru</string>
<string name="settings_ns_global">Globální jmenný prostor</string>
<string name="settings_ns_requester">Zděděný jmenný prostor</string>
<string name="settings_ns_requester">Odvozený jmenný prostor</string>
<string name="settings_ns_isolate">Izolovaný jmenný prostor</string>
<string name="global_summary">Všechny relace root používají globální připojení jmenného prostoru.</string>
<string name="requester_summary">Kořenové relace dědí jmenný prostor žadatele.</string>
<string name="isolate_summary">Každá relace root bude mít svůj vlastní izolovaný jmenný prostor.</string>
<string name="global_summary">Všechny relace ROOT používají globální jmenný prostor.</string>
<string name="requester_summary">Relace ROOT je odvozena od jmenného prostoru žadatele.</string>
<string name="isolate_summary">Každá relace ROOT má svůj vlastní izolovaný jmenný prostor.</string>
<!--Superuser-->
<string name="su_request_title">Požadavek Superuser</string>
<string name="deny">Zamítnout</string>
<string name="prompt">Dotaz</string>
<string name="grant">Povolit</string>
<string name="su_warning">Povolí plný přístup k vašemu zařízení.\nZamítněte, pokud si nejste jisti!</string>
<string name="forever">Navždy</string>
<string name="once">Jednou</string>
<string name="tenmin">10 minut</string>
<string name="twentymin">20 minut</string>
<string name="thirtymin">30 minut</string>
<string name="sixtymin">60 minut</string>
<string name="su_allow_toast">Pro %1$s bylo oprávnění Superuser povoleno</string>
<string name="su_deny_toast">Pro %1$s bylo oprávnění Superuser zamítnuto</string>
<string name="su_snack_grant">Superuser oprávnění pro %1$s je povoleno</string>
<string name="su_snack_deny">Superuser oprávnění pro %1$s je zamítnuto</string>
<string name="su_snack_notif_on">Oznámení pro %1$s jsou povolena</string>
<string name="su_snack_notif_off">Oznámení pro %1$s jsou zakázána</string>
<string name="su_snack_log_on">Logování %1$s je povoleno</string>
<string name="su_snack_log_off">Logování %1$s je zakázáno</string>
<string name="su_revoke_title">Smazat?</string>
<string name="su_revoke_msg">Smazat záznam ohledně oprávnění pro %1$s?</string>
<string name="toast">Informační text</string>
<string name="none">Žádný</string>
<!--Notifications-->
<string name="update_channel">Aktualizace Magisk</string>
<string name="progress_channel">Oznámení o průběhu</string>
<string name="download_complete">Stahování dokončeno</string>
<string name="download_file_error">Chyba při stahování souboru</string>
<string name="download_open_parent">Zobrazit výchozí složku</string>
<string name="download_open_self">Zobrazit soubor</string>
<string name="magisk_update_title">Aktualizace Magisk je dostupná!</string>
<string name="manager_update_title">Aktualizace Magisk Manager je dostupná!</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">Cílové UID: %1$d</string>
<!-- MagiskHide -->
<string name="show_system_app">Zobrazit systémové aplikace</string>
<!--Toasts, Dialogs-->
<string name="yes">ANO</string>
<string name="no">NE</string>
<string name="repo_install_title">Instalovat %1$s</string>
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
<string name="download">Stáhnout</string>
<string name="reboot">Restartovat</string>
<string name="release_notes">Poznámky k vydání</string>
<string name="repo_cache_cleared">Mezipaměť smazána</string>
<string name="flashing">Instalování…</string>
<string name="done">Hotovo!</string>
<string name="failure">Selhalo!</string>
<string name="hide_manager_title">Skrývání Magisk Manager…</string>
<string name="hide_manager_fail_toast">Skrývání Magisk Manager selhalo.</string>
<string name="restore_manager_fail_toast">Obnovení Magisk Manager selhalo.</string>
<string name="open_link_failed_toast">Nebyla nalezena žádná aplikace pro otevření odkazu.</string>
<string name="complete_uninstall">Odinstalovat</string>
<string name="restore_img">Obnovit obrazy</string>
<string name="restore_img_msg">Obnovování…</string>
<string name="restore_done">Obnovení bylo provedeno!</string>
<string name="restore_fail">Výchozí záloha neexistuje!</string>
<string name="proprietary_title">Stáhnout kód</string>
<string name="proprietary_notice">Magisk Manager je FOSS a neobsahuje kód SafetyNet API společnosti Google.\n\nChcete povolit aplikaci Magisk Manager stažení rozšíření (obsahuje GoogleApiClient) pro kontrolu SafetyNet?</string>
<string name="setup_fail">Nastavení selhalo</string>
<string name="env_fix_title">Vyžaduje se další nastavení</string>
<string name="env_fix_msg">Vaše zařízení potřebuje další nastavení, aby Magisk fungoval správně. Stáhne se instalační soubor (.zip) Magisk. Chcete pokračovat?</string>
<string name="setup_msg">Nastavení je spuštěno…</string>
<string name="authenticate">Ověřit</string>
<string name="unsupport_magisk_title">Nepodporovaná verze Magisk</string>
<string name="unsupport_magisk_msg">Tato verze Magisk Manager nepodporuje verzi Magisk nižší než %1$s.\n\nMůžete buď ručně aktualizovat Magisk, nebo nainstalovat starší verzi aplikace.</string>
<string name="external_rw_permission_denied">Udělte oprávnění pro povolení této funkce.</string>
<string name="add_shortcut_title">Přidat odkaz na domovskou obrazovku</string>
<string name="add_shortcut_msg">Po skrytí Magisk Manager se může jeho název a ikona těžko rozpoznat. Chcete přidat odkaz na domovskou obrazovku?</string>
<string name="app_not_found">Nelze nalézt žádnou aplikaci, která dokáže provést tuto akci.</string>
</resources>

View File

@@ -60,7 +60,7 @@
<string name="prompt">Pyet</string>
<string name="grant">Lejo</string>
<string name="su_warning">Jep akses të plotë në pajisjen tuaj. \n Moho nëse nuk je i sigurt!</string>
<string name="forever">Përgjithmonë</string>
<string name="forever">Gjithmonë</string>
<string name="once">Një herë</string>
<string name="tenmin">10 minuta</string>
<string name="twentymin">20 minuta</string>
@@ -77,6 +77,7 @@
<string name="su_revoke_title">Anulohet?</string>
<string name="su_revoke_msg">Konfirmo të heqësh të drejtat e %1$s?</string>
<string name="toast">dolli</string>
<string name="none">Asnjë</string>
<string name="superuser_toggle_notification">Njoftimet</string>
<string name="superuser_toggle_revoke">Anulo</string>
<string name="superuser_policy_none">Asnjë aplikacion nuk ka kërkuar ende leje për superpërdoruesin.</string>
@@ -156,6 +157,12 @@
<string name="settings_su_app">Vetëm aplikacionet</string>
<string name="settings_su_adb">Vetëm ADB</string>
<string name="settings_su_disable">Çaktivizuar</string>
<string name="settings_su_request_10">10 Sekonda</string>
<string name="settings_su_request_15">15 Sekonda</string>
<string name="settings_su_request_20">20 Sekonda</string>
<string name="settings_su_request_30">30 Sekonda</string>
<string name="settings_su_request_45">45 Sekonda</string>
<string name="settings_su_request_60">60 Sekonda</string>
<string name="superuser_access">Hyrja në superpërdorues</string>
<string name="auto_response">Përgjigje Automatike</string>
<string name="request_timeout">Koha e kërkesës</string>
@@ -207,7 +214,7 @@
<string name="failure">Dështoi!</string>
<string name="hide_manager_title">Fshehja e Magisk manager…</string>
<string name="hide_manager_fail_toast">Fsheh Menaxherin e Magisk dështoi</string>
<string name="restore_manager_fail_toast">Rikthe menaxherin e Magisk dështoi</string>
<string name="restore_manager_fail_toast">Rikthimi i menaxherin e Magisk dështoi</string>
<string name="open_link_failed_toast">Asnjë aplikacion nuk u gjet për të hapur lidhjen</string>
<string name="complete_uninstall">Çinstalimi i plotë</string>
<string name="restore_img">Rikthe Imazhet</string>

View File

@@ -132,7 +132,7 @@
<string name="settings_dark_mode_message">Stilinize en iyi uyan modu seçin!</string>
<string name="settings_dark_mode_light">Her Zaman Aydınlık</string>
<string name="settings_dark_mode_system">Sistemi Takip Et</string>
<string name="settings_dark_mode_dark">Her Zmana Karanlık</string>
<string name="settings_dark_mode_dark">Her Zaman Karanlık</string>
<string name="settings_download_path_title">İndirme dizini</string>
<string name="settings_download_path_message">Dosyalar %1$s konumuna kaydedilecek</string>
<string name="settings_clear_cache_title">Depo Önbelleğini Temizle</string>

View File

@@ -1,5 +1,4 @@
# Magisk Documentation
(Updated on 2020.11.13)
- [Installation Instructions](install.md)
- [Frequently Asked Questions](faq.md)

View File

@@ -1,5 +1,18 @@
# Magisk Manager Changelog
### v8.0.7
- Fix sepolicy rule migration when upgrading
### v8.0.6
- Minor UI changes
- Update internal scripts
### v8.0.5
- Fix sepolicy rule copying
### v8.0.4
- A lot of stability changes and minor bug fixes

View File

@@ -1,5 +1,16 @@
# Magisk Changelog
### v21.4
- [MagiskSU] Fix `su -c` behavior that broke many root apps
- [General] Properly handle read/write over sockets (the `broken pipe` issue)
### v21.3
- [MagiskInit] Avoid mounting `f2fs` userdata as it may result in kernel crashes. This shall fix a lot of bootloops
- [MagiskBoot] Fix a minor header checksum bug for `DHTB` header and ASUS `blob` image formats
- [MagiskHide] Allowing hiding isolated processes if the mount namespace is separated
### v21.2
- [MagiskInit] Detect 2SI after mounting `system_root` on legacy SAR devices

View File

@@ -17,7 +17,7 @@ Download and install the latest Magisk Manager. We use the app to gather some in
<p align="center"><img src="images/device_info.png" width="500"/></p>
Pay special attention to the **Ramdisk** info. If the result is **Yes**, congratulations, your device is perfect for installing Magisk! However, if the result is **No**, this means your device's boot partition does **NOT** include ramdisk, and unfortunately you would have to go through some hoops to make Magisk work properly.
Pay special attention to the **Ramdisk** info. If the result is **Yes**, congratulations, your device is perfect for installing Magisk! However, if the result is **No** this means your device's boot partition does **NOT** include ramdisk. This means you will have to go through some extra steps to make Magisk work properly.
> **If your device does not have boot ramdisk, read the [Magisk in Recovery](#magisk-in-recovery) section after installing. The information in that section is VERY important!**
@@ -27,15 +27,15 @@ If you are using a Huawei device and the **SAR** result is **Yes**, please check
Otherwise, continue to [Patching Images](#patching-images).
(P.S.1 If your device have boot ramdisk, you can also install with [Custom Recovery](#custom-recovery))<br>
(P.S.1 If your device has boot ramdisk, you can also install with [Custom Recovery](#custom-recovery))<br>
(P.S.2 If you are interested in how Android boots and how it affects Magisk, check out [this document](boot.md))
## Patching Images
If your device have boot ramdisk, you need a copy of the `boot.img`<br>
If your device has boot ramdisk, you need a copy of the `boot.img`<br>
If your device does **NOT** have boot ramdisk, you need a copy of the `recovery.img`
You should be able to extract either of them from official firmware packages, your custom ROM zip (if using one), or go to [XDA-Developers](https://forum.xda-developers.com/) and seek for resources, guides, discussions, or ask for help in your device's forum.
You should be able to extract the file you need from official firmware packages or your custom ROM zip (if using one). If you are still having trouble, go to [XDA-Developers](https://forum.xda-developers.com/) and look for resources, guides, discussions, or ask for help in your device's forum.
- Copy the boot/recovery image to your device
- Press the **Install** button in the Magisk card
@@ -52,7 +52,7 @@ For most devices, reboot into fastboot mode and flash with command:<br>
## Custom Recovery
In some custom recoveries of modern devices, the installer scripts either cannot properly detect the correct device info, or the recovery environment does not meet its expectation, causing the installation to fail (or looks like success but actually bootloops). If you face any issues, use the [Patch Image](#patching-images) method as it is guaranteed to work 100% of the time. Due to this reason, we no longer recommend installing Magisk through custom recoveries on modern devices. The custom recovery installation method exists mostly for legacy support.
In some custom recoveries the installation may fail (this may look like success but actually bootloops). This is because the installer scripts cannot properly detect the correct device info or the recovery environment does not meet its expectation. If you face any issues, use the [Patch Image](#patching-images) method as it is guaranteed to work 100% of the time. Due to this reason, we no longer recommend installing Magisk through custom recoveries on modern devices. The custom recovery installation method exists mostly for legacy support.
- Download the Magisk installer zip
- Reboot to custom recovery
@@ -65,7 +65,7 @@ If your device does not have ramdisk in boot images, Magisk has no choice but to
When Magisk is installed in your recovery, **you CANNOT use custom recoveries to install/upgrade Magisk!** The only way to install/upgrade Magisk is through Magisk Manager. The app will be aware of your device state and install to the correct partition and reboot into the correct mode.
Since Magisk now hijacks the recovery of the device, there is a mechanism to let you *actually* boot into recovery mode when needed: it is determined by **how long you press volume up**.
Since Magisk now hijacks the recovery of the device, there is a mechanism to let you *actually* boot into recovery mode when needed: it is determined by **how long you press the recovery key combo**.
Each device has its own key combo to boot into recovery, as an example for Galaxy S10 it is (Power + Bixby + Volume Up). A quick Google search should easily get you this info of your device. As soon as you press the combo and the device vibrates with a splash screen, release all buttons to boot into Magisk. If you decide to boot into actual recovery mode, continue to press volume up until you see the recovery screen.

18
docs/releases/21400.md Normal file
View File

@@ -0,0 +1,18 @@
## 2021.1.17 Magisk v21.4
**Update**: v21.4 adds more regression hot fixes.
Happy 2021! v21.3 adds a workaround for devices with buggy F2FS Linux kernel drivers. This F2FS bug may cause bootloops on many devices. Checkout the full [v21.0 release notes](https://topjohnwu.github.io/Magisk/releases/21000.html) if coming from older releases.
### v21.4
- [MagiskSU] Fix `su -c` behavior that broke many root apps
- [General] Properly handle read/write over sockets (the `broken pipe` issue)
### v21.3
- [MagiskInit] Avoid mounting `f2fs` userdata as it may result in kernel crashes. This shall fix a lot of bootloops
- [MagiskBoot] Fix a minor header checksum bug for `DHTB` header and ASUS `blob` image formats
- [MagiskHide] Allowing hiding isolated processes if the mount namespace is separated
### Full Changelog: [here](https://topjohnwu.github.io/Magisk/changes.html)

View File

@@ -1,5 +1,6 @@
# Release Notes
- [v21.3](21300.md)
- [v21.2](21200.md)
- [v21.1](21100.md)
- [v21.0](21000.md)

View File

@@ -27,6 +27,6 @@ android.injected.testOnly=false
kapt.incremental.apt=true
# Magisk
magisk.versionCode=21201
magisk.versionCode=21400
magisk.ndkVersion=21d
magisk.fullNdkVersion=21.3.6528147

View File

@@ -4,11 +4,14 @@ LOCAL_PATH := $(call my-dir)
# Binaries
########################
# Global toggle for the WIP zygote injection features
ENABLE_INJECT := 0
ifdef B_MAGISK
include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils libxhook
LOCAL_STATIC_LIBRARIES := libnanopb libsystemproperties libutils
LOCAL_C_INCLUDES := jni/include
LOCAL_SRC_FILES := \
@@ -22,7 +25,6 @@ LOCAL_SRC_FILES := \
core/restorecon.cpp \
core/module.cpp \
magiskhide/magiskhide.cpp \
magiskhide/proc_monitor.cpp \
magiskhide/hide_utils.cpp \
magiskhide/hide_policy.cpp \
resetprop/persist_properties.cpp \
@@ -30,12 +32,21 @@ LOCAL_SRC_FILES := \
su/su.cpp \
su/connect.cpp \
su/pts.cpp \
su/su_daemon.cpp \
su/su_daemon.cpp
LOCAL_LDLIBS := -llog
LOCAL_CPPFLAGS := -DENABLE_INJECT=$(ENABLE_INJECT)
ifeq ($(ENABLE_INJECT),1)
LOCAL_STATIC_LIBRARIES += libxhook
LOCAL_SRC_FILES += \
inject/entry.cpp \
inject/utils.cpp \
inject/hook.cpp
else
LOCAL_SRC_FILES += magiskhide/proc_monitor.cpp
endif
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)
endif

View File

@@ -1,6 +1,4 @@
#include <libgen.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -22,10 +20,11 @@ static int call_applet(int argc, char *argv[]) {
return (*applet_main[i])(argc, argv);
}
}
#if ENABLE_INJECT
if (str_starts(base, "app_process")) {
return app_process_main(argc, argv);
}
#endif
fprintf(stderr, "%s: applet not found\n", base.data());
return 1;
}

View File

@@ -13,6 +13,8 @@
#include <resetprop.hpp>
#include <selinux.hpp>
#include "core.hpp"
using namespace std;
static bool safe_mode = false;
@@ -320,7 +322,7 @@ void post_fs_data(int client) {
stop_magiskhide();
} else {
exec_common_scripts("post-fs-data");
auto_start_magiskhide();
auto_start_magiskhide(false);
handle_modules();
}
@@ -369,7 +371,7 @@ void boot_complete(int client) {
if (access(SECURE_DIR, F_OK) != 0)
xmkdir(SECURE_DIR, 0700);
auto_start_magiskhide();
auto_start_magiskhide(true);
if (!check_manager()) {
if (access(MANAGERAPK, F_OK) == 0) {

26
native/jni/core/core.hpp Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <vector>
extern bool RECOVERY_MODE;
extern int DAEMON_STATE;
void unlock_blocks();
void reboot();
void setup_logfile(bool reset);
// Module stuffs
void handle_modules();
void magic_mount();
void disable_modules();
void remove_modules();
void exec_module_scripts(const char *stage);
// Scripting
void exec_script(const char *script);
void exec_common_scripts(const char *stage);
void exec_module_scripts(const char *stage, const std::vector<std::string> &module_list);
void install_apk(const char *apk);
[[noreturn]] void install_module(const char *file);

View File

@@ -1,6 +1,6 @@
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <csignal>
#include <libgen.h>
#include <sys/un.h>
#include <sys/types.h>
@@ -16,11 +16,14 @@
#include <flags.hpp>
#include <stream.hpp>
#include "core.hpp"
using namespace std;
int SDK_INT = -1;
bool RECOVERY_MODE = false;
string MAGISKTMP;
bool RECOVERY_MODE = false;
int DAEMON_STATE = STATE_NONE;
static struct stat self_st;
@@ -33,10 +36,20 @@ static bool verify_client(pid_t pid) {
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
}
static bool check_zygote(pid_t pid) {
char buf[32];
sprintf(buf, "/proc/%d/attr/current", pid);
auto fp = open_file(buf, "r");
if (!fp)
return false;
fscanf(fp.get(), "%s", buf);
return buf == "u:r:zygote:s0"sv;
}
static void request_handler(int client, int req_code, ucred cred) {
switch (req_code) {
case MAGISKHIDE:
magiskhide_handler(client);
magiskhide_handler(client, &cred);
break;
case SUPERUSER:
su_daemon_handler(client, &cred);
@@ -71,7 +84,12 @@ static void handle_request(int client) {
// Verify client credentials
ucred cred;
get_client_cred(client, &cred);
if (cred.uid != 0 && !verify_client(cred.pid))
bool is_root = cred.uid == 0;
bool is_zygote = check_zygote(cred.pid);
bool is_client = verify_client(cred.pid);
if (!is_root && !is_zygote && !is_client)
goto shortcut;
req_code = read_int(client);
@@ -80,13 +98,12 @@ static void handle_request(int client) {
// Check client permissions
switch (req_code) {
case MAGISKHIDE:
case POST_FS_DATA:
case LATE_START:
case BOOT_COMPLETE:
case SQLITE_CMD:
case GET_PATH:
if (cred.uid != 0) {
if (!is_root) {
write_int(client, ROOT_REQUIRED);
goto shortcut;
}
@@ -97,6 +114,12 @@ static void handle_request(int client) {
goto shortcut;
}
break;
case MAGISKHIDE: // accept hide request from zygote
if (!is_root && !is_zygote) {
write_int(client, ROOT_REQUIRED);
goto shortcut;
}
break;
}
// Simple requests
@@ -184,7 +207,7 @@ static int magisk_log(int prio, const char *fmt, va_list ap) {
localtime_r(&tv.tv_sec, &tm);
size_t len = strftime(buf, sizeof(buf), "%m-%d %T", &tm);
int ms = tv.tv_usec / 1000;
len += sprintf(buf + len, ".%03d %c : ", ms, type);
len += sprintf(buf + len, ".%03d %*d %*d %c : ", ms, 5, getpid(), 5, gettid(), type);
strcpy(buf + len, fmt);
return vfprintf(local_log_file.get(), buf, args);
}

View File

@@ -1,14 +1,10 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <magisk.hpp>
#include <db.hpp>
#include <daemon.hpp>
#include <socket.hpp>
#include <utils.hpp>
#define DB_VERSION 10
@@ -373,8 +369,8 @@ bool validate_manager(string &pkg, int userid, struct stat *st) {
void exec_sql(int client) {
run_finally f([=]{ close(client); });
char *sql = read_string(client);
char *err = db_exec(sql, [&](db_row &row) -> bool {
string sql = read_string(client);
char *err = db_exec(sql.data(), [client](db_row &row) -> bool {
string out;
bool first = true;
for (auto it : row) {
@@ -384,11 +380,9 @@ void exec_sql(int client) {
out += '=';
out += it.second;
}
write_int(client, out.length());
xwrite(client, out.data(), out.length());
write_string(client, out);
return true;
});
free(sql);
write_int(client, 0);
db_err_cmd(err, return; );
}

View File

@@ -7,6 +7,8 @@
#include <selinux.hpp>
#include <flags.hpp>
#include "core.hpp"
using namespace std;
[[noreturn]] static void usage() {
@@ -54,9 +56,8 @@ int magisk_main(int argc, char *argv[]) {
} else if (argv[1] == "-v"sv) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION);
char *v = read_string(fd);
printf("%s\n", v);
free(v);
string v = read_string(fd);
printf("%s\n", v.data());
return 0;
} else if (argv[1] == "-V"sv) {
int fd = connect_daemon();
@@ -99,13 +100,12 @@ int magisk_main(int argc, char *argv[]) {
int fd = connect_daemon();
write_int(fd, SQLITE_CMD);
write_string(fd, argv[2]);
string res;
for (;;) {
char *res = read_string(fd);
if (res[0] == '\0') {
read_string(fd, res);
if (res.empty())
return 0;
}
printf("%s\n", res);
free(res);
printf("%s\n", res.data());
}
} else if (argv[1] == "--remove-modules"sv) {
int fd = connect_daemon();
@@ -114,8 +114,8 @@ int magisk_main(int argc, char *argv[]) {
} else if (argv[1] == "--path"sv) {
int fd = connect_daemon();
write_int(fd, GET_PATH);
char *path = read_string(fd);
printf("%s\n", path);
string path = read_string(fd);
printf("%s\n", path.data());
return 0;
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
install_module(argv[2]);

View File

@@ -5,9 +5,10 @@
#include <utils.hpp>
#include <magisk.hpp>
#include <selinux.hpp>
#include <daemon.hpp>
#include <resetprop.hpp>
#include "core.hpp"
using namespace std;
#define VLOGD(tag, from, to) LOGD("%-8s: %s <- %s\n", tag, to, from)

View File

@@ -1,7 +1,6 @@
#include <string_view>
#include <magisk.hpp>
#include <daemon.hpp>
#include <selinux.hpp>
#include <utils.hpp>

View File

@@ -6,6 +6,8 @@
#include <utils.hpp>
#include <selinux.hpp>
#include "core.hpp"
using namespace std;
#define BBEXEC_CMD bbpath(), "sh"

View File

@@ -1,11 +1,11 @@
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <endian.h>
#include <socket.hpp>
#include <utils.hpp>
using namespace std;
static size_t socket_len(sockaddr_un *sun) {
if (sun->sun_path[0])
return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
@@ -162,43 +162,21 @@ void write_int_be(int fd, int val) {
xwrite(fd, &nl, sizeof(nl));
}
static char *rd_str(int fd, int len) {
char *val = (char *) xmalloc(sizeof(char) * (len + 1));
xxread(fd, val, len);
val[len] = '\0';
return val;
}
char* read_string(int fd) {
void read_string(int fd, std::string &str) {
int len = read_int(fd);
return rd_str(fd, len);
str.clear();
str.resize(len);
xxread(fd, str.data(), len);
}
char* read_string_be(int fd) {
int len = read_int_be(fd);
return rd_str(fd, len);
string read_string(int fd) {
string str;
read_string(fd, str);
return str;
}
void write_string(int fd, const char *val) {
void write_string(int fd, string_view str) {
if (fd < 0) return;
int len = strlen(val);
write_int(fd, len);
xwrite(fd, val, len);
}
void write_string_be(int fd, const char *val) {
int len = strlen(val);
write_int_be(fd, len);
xwrite(fd, val, len);
}
void write_key_value(int fd, const char *key, const char *val) {
write_string_be(fd, key);
write_string_be(fd, val);
}
void write_key_token(int fd, const char *key, int tok) {
char val[16];
sprintf(val, "%d", tok);
write_key_value(fd, key, val);
write_int(fd, str.size());
xwrite(fd, str.data(), str.size());
}

View File

@@ -2,7 +2,6 @@
#include <pthread.h>
#include <string>
#include <vector>
#include <socket.hpp>
@@ -39,38 +38,21 @@ enum {
STATE_BOOT_COMPLETE
};
extern int SDK_INT;
extern bool RECOVERY_MODE;
extern int DAEMON_STATE;
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")
int connect_daemon(bool create = false);
// Daemon handlers
void post_fs_data(int client);
void late_start(int client);
void boot_complete(int client);
void magiskhide_handler(int client);
void magiskhide_handler(int client, ucred *cred);
void su_daemon_handler(int client, ucred *credential);
// Misc
int connect_daemon(bool create = false);
void unlock_blocks();
void reboot();
void setup_logfile(bool reset);
// Module stuffs
void handle_modules();
void magic_mount();
void disable_modules();
void remove_modules();
void exec_module_scripts(const char *stage);
// MagiskHide
void auto_start_magiskhide();
void auto_start_magiskhide(bool late_props);
int stop_magiskhide();
// Scripting
void exec_script(const char *script);
void exec_common_scripts(const char *stage);
void exec_module_scripts(const char *stage, const std::vector<std::string> &module_list);
void install_apk(const char *apk);
[[noreturn]] void install_module(const char *file);
#if ENABLE_INJECT
// For injected process to access daemon
int remote_check_hide(int uid, const char *process);
void remote_request_hide();
#endif

View File

@@ -30,6 +30,9 @@ constexpr const char *init_applet[] = { "magiskpolicy", "supolicy", nullptr };
#define POST_FS_DATA_WAIT_TIME 40
#define POST_FS_DATA_SCRIPT_MAX_TIME 35
extern int SDK_INT;
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")
// Multi-call entrypoints
int magisk_main(int argc, char *argv[]);
int magiskhide_main(int argc, char *argv[]);

View File

@@ -2,6 +2,7 @@
#include <sys/un.h>
#include <sys/socket.h>
#include <string_view>
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name);
int socket_accept(int sockfd, int timeout);
@@ -12,9 +13,6 @@ int read_int(int fd);
int read_int_be(int fd);
void write_int(int fd, int val);
void write_int_be(int fd, int val);
char *read_string(int fd);
char *read_string_be(int fd);
void write_string(int fd, const char *val);
void write_string_be(int fd, const char *val);
void write_key_value(int fd, const char *key, const char *val);
void write_key_token(int fd, const char *key, int tok);
std::string read_string(int fd);
void read_string(int fd, std::string &str);
void write_string(int fd, std::string_view str);

View File

@@ -11,6 +11,8 @@
using namespace std;
vector<string> mount_list;
template<typename Func>
static void parse_cmdline(const Func &fn) {
char cmdline[4096];
@@ -147,10 +149,13 @@ void load_kernel_info(cmdline *cmd) {
xmkdir("/sys", 0755);
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
mount_list.emplace_back("/proc");
mount_list.emplace_back("/sys");
// Log to kernel
setup_klog();
parse_cmdline([=](string_view key, const char *value) -> void {
parse_cmdline([=](string_view key, const char *value) {
if (key == "androidboot.slot_suffix") {
strcpy(cmd->slot, value);
} else if (key == "androidboot.slot") {
@@ -213,6 +218,6 @@ bool check_two_stage() {
if (access("/system/bin/init", F_OK) == 0)
return true;
// If we still have no indication, parse the original init and see what's up
auto init = raw_data::mmap_ro("/.backup/init");
auto init = mmap_data::ro("/.backup/init");
return init.contains("selinux_setup");
}

View File

@@ -29,6 +29,8 @@ struct fstab_entry {
#define INIT_SOCKET "MAGISKINIT"
#define DEFAULT_DT_DIR "/proc/device-tree/firmware/android"
extern std::vector<std::string> mount_list;
void load_kernel_info(cmdline *cmd);
bool check_two_stage();
int dump_magisk(const char *path, mode_t mode);
@@ -42,20 +44,19 @@ class BaseInit {
protected:
cmdline *cmd;
char **argv;
std::vector<std::string> mount_list;
[[noreturn]] void exec_init();
void read_dt_fstab(std::vector<fstab_entry> &fstab);
public:
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {}
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv) {}
virtual ~BaseInit() = default;
virtual void start() = 0;
};
class MagiskInit : public BaseInit {
protected:
auto_data<HEAP> self;
auto_data<HEAP> config;
mmap_data self;
mmap_data config;
std::string custom_rules_dir;
void mount_with_dt();
@@ -100,8 +101,6 @@ private:
public:
SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {
LOGD("%s\n", __FUNCTION__);
// Do not unmount /sys and /proc
mount_list.clear();
};
void start() override {
prepare();

View File

@@ -228,9 +228,9 @@ void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) {
if (setup_block(false) < 0)
goto cache;
}
// Try to mount with either ext4 or f2fs
// Failure means either FDE or metadata encryption
if (!do_mount("ext4") && !do_mount("f2fs"))
// WARNING: DO NOT ATTEMPT TO MOUNT F2FS AS IT MAY CRASH THE KERNEL
// Failure means either f2fs, FDE, or metadata encryption
if (!do_mount("ext4"))
goto cache;
strcpy(p, "/data/unencrypted");
@@ -289,7 +289,7 @@ success:
}
void RootFSInit::early_mount() {
self = raw_data::read("/init");
self = mmap_data::ro("/init");
LOGD("Restoring /init\n");
rename("/.backup/init", "/init");
@@ -301,9 +301,9 @@ void SARBase::backup_files() {
if (access("/overlay.d", F_OK) == 0)
backup_folder("/overlay.d", overlays);
self = raw_data::read("/proc/self/exe");
self = mmap_data::ro("/proc/self/exe");
if (access("/.backup/.magisk", R_OK) == 0)
config = raw_data::read("/.backup/.magisk");
config = mmap_data::ro("/.backup/.magisk");
}
void SARBase::mount_system_root() {
@@ -345,10 +345,8 @@ void SARInit::early_mount() {
mount_system_root();
switch_root("/system_root");
{
auto init = raw_data::mmap_ro("/init");
is_two_stage = init.contains("selinux_setup");
}
// Use the apex folder to determine whether 2SI (Android 10+)
is_two_stage = access("/apex", F_OK) == 0;
LOGD("is_two_stage: [%d]\n", is_two_stage);
if (!is_two_stage) {
@@ -383,7 +381,7 @@ void BaseInit::exec_init() {
static void patch_socket_name(const char *path) {
char rstr[16];
gen_rand_str(rstr, sizeof(rstr));
auto bin = raw_data::mmap_rw(path);
auto bin = mmap_data::rw(path);
bin.patch({ make_pair(MAIN_SOCKET, rstr) });
}

View File

@@ -2,7 +2,7 @@
using namespace std;
int data_holder::patch(str_pairs list) {
int mmap_data::patch(str_pairs list) {
if (buf == nullptr)
return 0;
int count = 0;
@@ -20,7 +20,7 @@ int data_holder::patch(str_pairs list) {
return count;
}
bool data_holder::contains(string_view pattern) {
bool mmap_data::contains(string_view pattern) {
if (buf == nullptr)
return false;
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
@@ -32,33 +32,21 @@ bool data_holder::contains(string_view pattern) {
return false;
}
void data_holder::consume(data_holder &other) {
void mmap_data::consume(mmap_data &other) {
buf = other.buf;
sz = other.sz;
other.buf = nullptr;
other.sz = 0;
}
auto_data<HEAP> raw_data::read(int fd) {
auto_data<HEAP> data;
fd_full_read(fd, data.buf, data.sz);
mmap_data mmap_data::rw(const char *name) {
mmap_data data;
mmap_rw(name, data.buf, data.sz);
return data;
}
auto_data<HEAP> raw_data::read(const char *name) {
auto_data<HEAP> data;
full_read(name, data.buf, data.sz);
return data;
}
auto_data<MMAP> raw_data::mmap_rw(const char *name) {
auto_data<MMAP> data;
::mmap_rw(name, data.buf, data.sz);
return data;
}
auto_data<MMAP> raw_data::mmap_ro(const char *name) {
auto_data<MMAP> data;
::mmap_ro(name, data.buf, data.sz);
mmap_data mmap_data::ro(const char *name) {
mmap_data data;
mmap_ro(name, data.buf, data.sz);
return data;
}

View File

@@ -2,31 +2,23 @@
#include <utils.hpp>
struct data_holder {
struct mmap_data {
uint8_t *buf = nullptr;
size_t sz = 0;
mmap_data() = default;
mmap_data(const mmap_data&) = delete;
mmap_data(mmap_data &&other) { consume(other); }
~mmap_data() { if (buf) munmap(buf, sz); }
mmap_data& operator=(mmap_data &&other) { consume(other); return *this; }
using str_pairs = std::initializer_list<std::pair<std::string_view, std::string_view>>;
int patch(str_pairs list);
bool contains(std::string_view pattern);
protected:
void consume(data_holder &other);
};
enum data_type { HEAP, MMAP };
template <data_type T>
struct auto_data : public data_holder {
auto_data<T>() = default;
auto_data<T>(const auto_data&) = delete;
auto_data<T>(auto_data<T> &&other) { consume(other); }
~auto_data<T>() {}
auto_data<T>& operator=(auto_data<T> &&other) { consume(other); return *this; }
};
template <> inline auto_data<MMAP>::~auto_data<MMAP>() { if (buf) munmap(buf, sz); }
template <> inline auto_data<HEAP>::~auto_data<HEAP>() { free(buf); }
static mmap_data rw(const char *name);
static mmap_data ro(const char *name);
namespace raw_data {
auto_data<HEAP> read(const char *name);
auto_data<HEAP> read(int fd);
auto_data<MMAP> mmap_rw(const char *name);
auto_data<MMAP> mmap_ro(const char *name);
}
private:
void consume(mmap_data &other);
};

View File

@@ -9,12 +9,6 @@
#include "init.hpp"
#include "magiskrc.inc"
#ifdef USE_64BIT
#define LIBNAME "lib64"
#else
#define LIBNAME "lib"
#endif
using namespace std;
static vector<string> rc_list;
@@ -182,7 +176,6 @@ static void magic_mount(const string &sdir, const string &ddir = "") {
#define ROOTMIR MIRRDIR "/system_root"
#define MONOPOLICY "/sepolicy"
#define LIBSELINUX "/system/" LIBNAME "/libselinux.so"
#define NEW_INITRC "/system/etc/init/hw/init.rc"
void SARBase::patch_rootdir() {
@@ -218,7 +211,7 @@ void SARBase::patch_rootdir() {
int patch_count;
{
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
auto init = raw_data::read(src);
auto init = mmap_data::ro("/init");
patch_count = init.patch({
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
@@ -231,15 +224,25 @@ void SARBase::patch_rootdir() {
close(dest);
}
if (patch_count != 2 && access(LIBSELINUX, F_OK) == 0) {
if (patch_count != 2) {
// init is dynamically linked, need to patch libselinux
auto lib = raw_data::read(LIBSELINUX);
lib.patch({make_pair(MONOPOLICY, sepol)});
xmkdirs(dirname(ROOTOVL LIBSELINUX), 0755);
int dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
xwrite(dest, lib.buf, lib.sz);
close(dest);
clone_attr(LIBSELINUX, ROOTOVL LIBSELINUX);
const char *path = "/system/lib64/libselinux.so";
if (access(path, F_OK) != 0) {
path = "/system/lib/libselinux.so";
if (access(path, F_OK) != 0)
path = nullptr;
}
if (path) {
char ovl[128];
sprintf(ovl, ROOTOVL "%s", path);
auto lib = mmap_data::ro(path);
lib.patch({make_pair(MONOPOLICY, sepol)});
xmkdirs(dirname(ovl), 0755);
int dest = xopen(ovl, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
xwrite(dest, lib.buf, lib.sz);
close(dest);
clone_attr(path, ovl);
}
}
// sepolicy
@@ -251,10 +254,9 @@ void SARBase::patch_rootdir() {
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
LOGD("ACK init daemon to write backup files\n");
// Let daemon know where tmp_dir is
write_string(sockfd, tmp_dir.data());
write_string(sockfd, tmp_dir);
// Wait for daemon to finish restoring files
int ack;
read(sockfd, &ack, sizeof(ack));
read_int(sockfd);
} else {
LOGD("Restore backup files locally\n");
restore_folder(ROOTOVL, overlays);
@@ -301,7 +303,7 @@ void RootFSInit::patch_rootfs() {
}
if (patch_sepolicy("/sepolicy")) {
auto init = raw_data::mmap_rw("/init");
auto init = mmap_data::rw("/init");
init.patch({ make_pair(SPLIT_PLAT_CIL, "xxx") });
}
@@ -331,8 +333,8 @@ void MagiskProxy::start() {
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
// Backup stuffs before removing them
self = raw_data::read("/sbin/magisk");
config = raw_data::read("/.backup/.magisk");
self = mmap_data::ro("/sbin/magisk");
config = mmap_data::ro("/.backup/.magisk");
char custom_rules_dir[64];
custom_rules_dir[0] = '\0';
xreadlink(TMP_RULESDIR, custom_rules_dir, sizeof(custom_rules_dir));

View File

@@ -38,35 +38,58 @@ void FirstStageInit::prepare() {
rename("/.backup/init", "/init");
}
// Try to load fstab from dt
vector<fstab_entry> fstab;
read_dt_fstab(fstab);
char fstab_file[128];
fstab_file[0] = '\0';
// Find existing fstab file
for (const char *hw : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
if (hw[0] == '\0')
for (const char *suffix : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
if (suffix[0] == '\0')
continue;
sprintf(fstab_file, "fstab.%s", hw);
if (access(fstab_file, F_OK) != 0) {
fstab_file[0] = '\0';
continue;
} else {
LOGD("Found fstab file: %s\n", fstab_file);
break;
for (const char *prefix: { "odm/etc/fstab", "vendor/etc/fstab", "fstab" }) {
sprintf(fstab_file, "%s.%s", prefix, suffix);
if (access(fstab_file, F_OK) != 0) {
fstab_file[0] = '\0';
} else {
LOGD("Found fstab file: %s\n", fstab_file);
goto exit_loop;
}
}
}
exit_loop:
if (fstab.empty()) {
// fstab has to be somewhere in ramdisk
if (fstab_file[0] == '\0') {
LOGE("Cannot find fstab file in ramdisk!\n");
return;
// Try to load dt fstab
vector<fstab_entry> fstab;
read_dt_fstab(fstab);
if (!fstab.empty()) {
// Dump dt fstab to fstab file in rootfs and force init to use it instead
// All dt fstab entries should be first_stage_mount
for (auto &entry : fstab) {
if (!str_contains(entry.fsmgr_flags, "first_stage_mount")) {
if (!entry.fsmgr_flags.empty())
entry.fsmgr_flags += ',';
entry.fsmgr_flags += "first_stage_mount";
}
}
// Parse and load fstab file
if (fstab_file[0] == '\0') {
const char *suffix =
cmd->fstab_suffix[0] ? cmd->fstab_suffix :
(cmd->hardware[0] ? cmd->hardware :
(cmd->hardware_plat[0] ? cmd->hardware_plat : nullptr));
if (suffix == nullptr) {
LOGE("Cannot determine fstab suffix!\n");
return;
}
sprintf(fstab_file, "fstab.%s", suffix);
}
// Patch init to force IsDtFstabCompatible() return false
auto init = mmap_data::rw("/init");
init.patch({ make_pair("android,fstab", "xxx") });
} else {
// Parse and load the fstab file
file_readline(fstab_file, [&](string_view l) -> bool {
if (l[0] == '#' || l.length() == 1)
return true;
@@ -90,32 +113,6 @@ void FirstStageInit::prepare() {
fstab.emplace_back(std::move(entry));
return true;
});
} else {
// All dt fstab entries should be first_stage_mount
for (auto &entry : fstab) {
if (!str_contains(entry.fsmgr_flags, "first_stage_mount")) {
if (!entry.fsmgr_flags.empty())
entry.fsmgr_flags += ',';
entry.fsmgr_flags += "first_stage_mount";
}
}
// Dump dt fstab to fstab file in rootfs
if (fstab_file[0] == '\0') {
const char *suffix =
cmd->fstab_suffix[0] ? cmd->fstab_suffix :
(cmd->hardware[0] ? cmd->hardware :
(cmd->hardware_plat[0] ? cmd->hardware_plat : nullptr));
if (suffix == nullptr) {
LOGE("Cannot determine fstab suffix!\n");
return;
}
sprintf(fstab_file, "fstab.%s", suffix);
}
// Patch init to force IsDtFstabCompatible() return false
auto init = raw_data::mmap_rw("/init");
init.patch({ make_pair("android,fstab", "xxx") });
}
{
@@ -142,15 +139,13 @@ void FirstStageInit::prepare() {
#define REDIR_PATH "/system/bin/am"
void SARInit::first_stage_prep() {
int pid = getpid();
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
// Patch init binary
int src = xopen("/init", O_RDONLY);
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
{
auto init = raw_data::read(src);
auto init = mmap_data::ro("/init");
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
write(dest, init.buf, init.sz);
fclone_attr(src, dest);
@@ -174,7 +169,7 @@ void SARInit::first_stage_prep() {
sigaddset(&block, SIGUSR1);
sigprocmask(SIG_BLOCK, &block, &old);
if (int child = xfork(); child) {
if (int child = xfork()) {
LOGD("init daemon [%d]\n", child);
// Wait for children signal
int sig;
@@ -190,22 +185,21 @@ void SARInit::first_stage_prep() {
xlisten(sockfd, 1);
// Resume parent
kill(pid, SIGUSR1);
kill(getppid(), SIGUSR1);
// Wait for second stage ack
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
// Write backup files
char *tmp_dir = read_string(client);
chdir(tmp_dir);
free(tmp_dir);
string tmp_dir = read_string(client);
chdir(tmp_dir.data());
int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
xwrite(cfg, config.buf, config.sz);
close(cfg);
restore_folder(ROOTOVL, overlays);
// Ack and bail out!
write(sockfd, &sockfd, sizeof(sockfd));
write_int(sockfd, 0);
close(client);
close(sockfd);

View File

@@ -3,6 +3,7 @@
#include <xhook.h>
#include <utils.hpp>
#include <flags.hpp>
#include <daemon.hpp>
#include "inject.hpp"
@@ -17,18 +18,11 @@ using namespace std;
extern const JNINativeMethod name##_methods[]; \
extern const int name##_methods_num;
// For some reason static vectors won't work, use pointers instead
static vector<tuple<const char *, const char *, void **>> *xhook_list;
static vector<JNINativeMethod> *jni_list;
static JavaVM *g_jvm;
static int prev_fork_pid = -1;
namespace {
struct HookContext {
int pid;
bool unload;
bool do_hide;
};
// JNI method declarations
@@ -38,6 +32,14 @@ DCL_JNI_FUNC(nativeForkSystemServer)
}
// For some reason static vectors won't work, use pointers instead
static vector<tuple<const char *, const char *, void **>> *xhook_list;
static vector<JNINativeMethod> *jni_list;
static JavaVM *g_jvm;
static int prev_fork_pid = -1;
static HookContext *current_ctx;
#define HOOK_JNI(method) \
if (newMethods[i].name == #method##sv) { \
auto orig = new JNINativeMethod(); \
@@ -90,6 +92,17 @@ DCL_HOOK_FUNC(int, fork) {
return pid;
}
DCL_HOOK_FUNC(int, selinux_android_setcontext,
uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname) {
if (current_ctx && current_ctx->do_hide) {
// Ask magiskd to hide ourselves before switching context
// because magiskd socket is not accessible on Android 8.0+
remote_request_hide();
LOGD("hook: process successfully hidden\n");
}
return old_selinux_android_setcontext(uid, isSystemServer, seinfo, pkgname);
}
static int sigmask(int how, int signum) {
sigset_t set;
sigemptyset(&set);
@@ -106,10 +119,43 @@ static int pre_specialize_fork() {
// -----------------------------------------------------------------
static void nativeSpecializeAppProcess_pre(HookContext *ctx,
JNIEnv *env, jclass clazz, jint &uid, jint &gid, jintArray &gids, jint &runtime_flags,
jobjectArray &rlimits, jint &mount_external, jstring &se_info, jstring &nice_name,
jboolean &is_child_zygote, jstring &instruction_set, jstring &app_data_dir,
jboolean &is_top_app, jobjectArray &pkg_data_info_list,
jobjectArray &whitelisted_data_info_list, jboolean &mount_data_dirs,
jboolean &mount_storage_dirs) {
current_ctx = ctx;
const char *process = env->GetStringUTFChars(nice_name, nullptr);
LOGD("hook: %s %s\n", __FUNCTION__, process);
if (mount_external != 0 /* TODO: Handle MOUNT_EXTERNAL_NONE cases */
&& remote_check_hide(uid, process)) {
ctx->do_hide = true;
LOGI("hook: [%s] should be hidden\n", process);
}
env->ReleaseStringUTFChars(nice_name, process);
}
static void nativeSpecializeAppProcess_post(HookContext *ctx, JNIEnv *env, jclass clazz) {
LOGD("hook: %s\n", __FUNCTION__);
if (ctx->do_hide)
self_unload();
current_ctx = nullptr;
}
// -----------------------------------------------------------------
static void nativeForkAndSpecialize_pre(HookContext *ctx,
JNIEnv *env, jclass clazz, jint &uid, jint &gid, jintArray &gids, jint &runtime_flags,
jobjectArray &rlimits, jint &mount_external, jstring &se_info, jstring &nice_name,
jintArray &fds_to_close, jintArray &fds_to_ignore, /* These 2 arguments are unique to fork */
jintArray fds_to_close, jintArray fds_to_ignore, /* These 2 arguments are unique to fork */
jboolean &is_child_zygote, jstring &instruction_set, jstring &app_data_dir,
jboolean &is_top_app, jobjectArray &pkg_data_info_list,
jobjectArray &whitelisted_data_info_list, jboolean &mount_data_dirs,
@@ -120,40 +166,19 @@ static void nativeForkAndSpecialize_pre(HookContext *ctx,
if (ctx->pid != 0)
return;
// TODO: check if we need to do hiding
// Demonstrate self unload in child process
ctx->unload = true;
LOGD("hook: %s\n", __FUNCTION__);
nativeSpecializeAppProcess_pre(
ctx, env, clazz, uid, gid, gids, runtime_flags, rlimits, mount_external, se_info,
nice_name, is_child_zygote, instruction_set, app_data_dir, is_top_app,
pkg_data_info_list, whitelisted_data_info_list, mount_data_dirs, mount_storage_dirs);
}
static void nativeForkAndSpecialize_post(HookContext *ctx, JNIEnv *env, jclass clazz) {
// Unblock SIGCHLD in case the original method didn't
sigmask(SIG_UNBLOCK, SIGCHLD);
if (ctx->pid != 0)
return;
LOGD("hook: %s\n", __FUNCTION__);
if (ctx->unload)
self_unload();
}
// -----------------------------------------------------------------
static void nativeSpecializeAppProcess_pre(HookContext *ctx,
JNIEnv *env, jclass clazz, jint &uid, jint &gid, jintArray &gids, jint &runtime_flags,
jobjectArray &rlimits, jint &mount_external, jstring &se_info, jstring &nice_name,
jboolean &is_child_zygote, jstring &instruction_set, jstring &app_data_dir,
jboolean &is_top_app, jobjectArray &pkg_data_info_list,
jobjectArray &whitelisted_data_info_list, jboolean &mount_data_dirs,
jboolean &mount_storage_dirs) {
LOGD("hook: %s\n", __FUNCTION__);
}
static void nativeSpecializeAppProcess_post(HookContext *ctx, JNIEnv *env, jclass clazz) {
LOGD("hook: %s\n", __FUNCTION__);
nativeSpecializeAppProcess_post(ctx, env, clazz);
}
// -----------------------------------------------------------------
@@ -167,6 +192,7 @@ static void nativeForkSystemServer_pre(HookContext *ctx,
if (ctx->pid != 0)
return;
current_ctx = ctx;
LOGD("hook: %s\n", __FUNCTION__);
}
@@ -178,6 +204,7 @@ static void nativeForkSystemServer_post(HookContext *ctx, JNIEnv *env, jclass cl
return;
LOGD("hook: %s\n", __FUNCTION__);
current_ctx = nullptr;
}
// -----------------------------------------------------------------
@@ -216,6 +243,7 @@ void hook_functions() {
XHOOK_REGISTER(".*\\libandroid_runtime.so$", jniRegisterNativeMethods);
XHOOK_REGISTER(".*\\libandroid_runtime.so$", fork);
XHOOK_REGISTER(".*\\libandroid_runtime.so$", selinux_android_setcontext);
hook_refresh();
}

View File

@@ -443,6 +443,7 @@ void repack(const char* src_img, const char* out_img, bool skip_comp) {
uint32_t second;
uint32_t extra;
uint32_t dtb;
uint32_t total;
} off;
fprintf(stderr, "Repack to boot image: [%s]\n", out_img);
@@ -565,11 +566,12 @@ void repack(const char* src_img, const char* out_img, bool skip_comp) {
restore_buf(fd, LG_BUMP_MAGIC, 16);
}
off.total = lseek(fd, 0, SEEK_CUR);
// Pad image to at least original size if not chromeos (as it requires post processing)
if (!is_flag(CHROMEOS_FLAG)) {
auto current_sz = lseek(fd, 0, SEEK_CUR);
if (current_sz < boot.map_size) {
int padding = boot.map_size - current_sz;
if (off.total < boot.map_size) {
int padding = boot.map_size - off.total;
write_zero(fd, padding);
}
}
@@ -642,11 +644,11 @@ void repack(const char* src_img, const char* out_img, bool skip_comp) {
// DHTB header
auto hdr = reinterpret_cast<dhtb_hdr *>(boot.map_addr);
memcpy(hdr, DHTB_MAGIC, 8);
hdr->size = boot.map_size - sizeof(dhtb_hdr);
hdr->size = off.total - sizeof(dhtb_hdr);
SHA256_hash(boot.map_addr + sizeof(dhtb_hdr), hdr->size, hdr->checksum);
} else if (is_flag(BLOB_FLAG)) {
// Blob header
auto hdr = reinterpret_cast<blob_hdr *>(boot.map_addr);
hdr->size = boot.map_size - sizeof(blob_hdr);
hdr->size = off.total - sizeof(blob_hdr);
}
}

View File

@@ -124,36 +124,35 @@ static void dtb_print(const char *file, bool fstab) {
munmap(dtb, size);
}
[[maybe_unused]]
static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file);
static bool dtb_patch(const char *file) {
bool keepverity = check_env("KEEPVERITY");
bool patched = false;
bool keep_verity = check_env("KEEPVERITY");
size_t size;
uint8_t *dtb;
fprintf(stderr, "Loading dtbs from [%s]\n", file);
mmap_rw(file, dtb, size);
// Loop through all the dtbs
int dtb_num = 0;
bool patched = false;
for (int i = 0; i < size; ++i) {
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
auto fdt = dtb + i;
fprintf(stderr, "Loading dtb.%04d\n", dtb_num);
if (int fstab = find_fstab(fdt); fstab >= 0) {
int node;
fdt_for_each_subnode(node, fdt, fstab) {
const char *name = fdt_get_name(fdt, node, nullptr);
fprintf(stderr, "Found fstab entry [%s]\n", name);
if (!keepverity) {
if (!keep_verity) {
int len;
auto value = fdt_getprop(fdt, node, "fsmgr_flags", &len);
patched |= patch_verity(const_cast<void *>(value), len) != len;
char *value = (char *) fdt_getprop(fdt, node, "fsmgr_flags", &len);
patched |= patch_verity(value, len) != len;
}
}
}
++dtb_num;
i += fdt_totalsize(fdt) - 1;
}
}
fprintf(stderr, "\n");
munmap(dtb, size);
return patched;
}
@@ -176,279 +175,246 @@ int dtb_commands(int argc, char *argv[]) {
}
namespace {
// Unused, but keep these precious code as they took TONs of effort to write
struct fdt_blob {
void *fdt;
uint32_t offset;
uint32_t len;
};
struct fdt_blob {
void *fdt;
uint32_t offset;
uint32_t len;
};
template <class Iter>
class fdt_map_iter {
public:
typedef decltype(std::declval<typename Iter::value_type::second_type>().fdt) value_type;
typedef value_type* pointer;
typedef value_type& reference;
}
explicit fdt_map_iter(Iter j) : i(j) {}
fdt_map_iter& operator++() { ++i; return *this; }
fdt_map_iter operator++(int) { auto tmp = *this; ++(*this); return tmp; }
fdt_map_iter& operator--() { --i; return *this; }
fdt_map_iter operator--(int) { auto tmp = *this; --(*this); return tmp; }
bool operator==(fdt_map_iter j) const { return i == j.i; }
bool operator!=(fdt_map_iter j) const { return !(*this == j); }
reference operator*() { return i->second.fdt; }
pointer operator->() { return &i->second.fdt; }
private:
Iter i;
};
template<class Iter>
inline fdt_map_iter<Iter> make_iter(Iter j) { return fdt_map_iter<Iter>(j); }
template <typename Iter>
static bool fdt_patch(Iter first, Iter last) {
bool keepverity = check_env("KEEPVERITY");
bool redirect = check_env("TWOSTAGEINIT");
bool modified = false;
int idx = 0;
for (auto it = first; it != last; ++it) {
++idx;
auto fdt = *it;
int fstab = find_fstab(fdt);
if (fstab < 0)
continue;
fprintf(stderr, "Found fstab in dtb.%04d\n", idx - 1);
int block;
fdt_for_each_subnode(block, fdt, fstab) {
const char *name = fdt_get_name(fdt, block, nullptr);
fprintf(stderr, "Found entry [%s] in fstab\n", name);
if (!keepverity) {
int size;
auto value = fdt_getprop(fdt, block, "fsmgr_flags", &size);
char *copy = static_cast<char *>(memcpy(malloc(size), value, size));
if (patch_verity(copy, size) != size) {
modified = true;
fdt_setprop_string(fdt, block, "fsmgr_flags", copy);
}
free(copy);
}
if (redirect && name == "system"sv) {
modified = true;
fprintf(stderr, "Changing mnt_point to /system_root\n");
fdt_setprop_string(fdt, block, "mnt_point", "/system_root");
}
}
static bool fdt_patch(void *fdt) {
int fstab = find_fstab(fdt);
if (fstab < 0)
return false;
bool modified = false;
int node;
fdt_for_each_subnode(node, fdt, fstab) {
const char *name = fdt_get_name(fdt, node, nullptr);
// Force remove AVB for 2SI since it may bootloop some devices
int len;
auto value = (const char *) fdt_getprop(fdt, node, "fsmgr_flags", &len);
string copy(value, len);
uint32_t new_len = patch_verity(copy.data(), len);
if (new_len != len) {
modified = true;
fdt_setprop(fdt, node, "fsmgr_flags", copy.data(), new_len);
}
if (name == "system"sv) {
fprintf(stderr, "Setting [mnt_point] to [/system_root]\n");
fdt_setprop_string(fdt, node, "mnt_point", "/system_root");
modified = true;
}
return modified;
}
return modified;
}
#define MAX_FDT_GROWTH 256
template <class Table, class Header>
static int dt_table_patch(const Header *hdr, const char *out) {
map<uint32_t, fdt_blob> dtb_map;
auto buf = reinterpret_cast<const uint8_t *>(hdr);
auto tables = reinterpret_cast<const Table *>(hdr + 1);
template <class Table, class Header>
static bool dt_table_patch(const Header *hdr, const char *out) {
map<uint32_t, fdt_blob> dtb_map;
auto buf = reinterpret_cast<const uint8_t *>(hdr);
auto tables = reinterpret_cast<const Table *>(buf + sizeof(Header));
constexpr bool is_dt_table = std::is_same_v<Header, dt_table_header>;
constexpr bool is_aosp = 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; };
// AOSP DTB store ints in big endian
using endian_conv = uint32_t (*)(uint32_t);
endian_conv be_to_le;
endian_conv le_to_be;
if constexpr (is_aosp) {
be_to_le = fdt32_to_cpu;
le_to_be = cpu_to_fdt32;
} else {
be_to_le = le_to_be = [](uint32_t x) { return x; };
}
// Collect all dtbs
auto num_dtb = be_to_le(hdr->num_dtbs);
for (int i = 0; i < num_dtb; ++i) {
auto offset = be_to_le(tables[i].offset);
if (dtb_map.count(offset) == 0) {
auto blob = buf + offset;
uint32_t size = fdt_totalsize(blob);
auto fdt = xmalloc(size + MAX_FDT_GROWTH);
memcpy(fdt, blob, size);
fdt_open_into(fdt, fdt, size + MAX_FDT_GROWTH);
dtb_map[offset] = { fdt, offset };
}
}
if (dtb_map.empty())
return false;
// Collect all dtbs
auto num_dtb = be_to_le(hdr->num_dtbs);
for (int i = 0; i < num_dtb; ++i) {
auto offset = be_to_le(tables[i].offset);
if (dtb_map.count(offset) == 0) {
auto blob = buf + offset;
uint32_t size = fdt_totalsize(blob);
auto fdt = xmalloc(size + MAX_FDT_GROWTH);
memcpy(fdt, blob, size);
fdt_open_into(fdt, fdt, size + MAX_FDT_GROWTH);
dtb_map[offset] = { fdt, offset };
}
}
if (dtb_map.empty())
return 1;
// Patch fdt
bool modified = false;
for (auto &[_, blob] : dtb_map)
modified |= fdt_patch(blob.fdt);
if (!modified)
return false;
// Patch fdt
if (!fdt_patch(make_iter(dtb_map.begin()), make_iter(dtb_map.end())))
return 1;
unlink(out);
int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
unlink(out);
int fd = xopen(out, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
// This value is only used if AOSP DTB
uint32_t total_size = 0;
uint32_t total_size = 0;
// Copy headers and tables
total_size += xwrite(fd, buf, dtb_map.begin()->first);
// Copy headers and tables
total_size += xwrite(fd, buf, dtb_map.begin()->first);
// mmap rw to patch table values retroactively
auto mmap_sz = lseek(fd, 0, SEEK_CUR);
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// mmap rw to patch table values retroactively
auto mmap_sz = lseek(fd, 0, SEEK_CUR);
auto addr = (uint8_t *) xmmap(nullptr, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// Guess alignment using gcd
uint32_t align = 1;
if constexpr (!is_aosp) {
auto it = dtb_map.begin();
align = (it++)->first;
for (; it != dtb_map.end(); ++it)
align = binary_gcd(align, it->first);
}
// Guess alignment using gcd
uint32_t align = 1;
if constexpr (!is_dt_table) {
auto it = dtb_map.begin();
align = (it++)->first;
for (; it != dtb_map.end(); ++it)
align = binary_gcd(align, it->first);
}
// Write dtbs
for (auto &val : dtb_map) {
val.second.offset = lseek(fd, 0, SEEK_CUR);
auto fdt = val.second.fdt;
fdt_pack(fdt);
auto size = fdt_totalsize(fdt);
total_size += xwrite(fd, fdt, size);
// Write dtbs
for (auto &val : dtb_map) {
val.second.offset = lseek(fd, 0, SEEK_CUR);
auto fdt = val.second.fdt;
fdt_pack(fdt);
auto size = fdt_totalsize(fdt);
total_size += xwrite(fd, fdt, size);
if constexpr (!is_aosp) {
val.second.len = do_align(size, align);
write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), align));
// total_size += align_off(lseek(fd, 0, SEEK_CUR), align); /* Not needed */
free(fdt);
}
// Patch headers
if constexpr (is_dt_table) {
auto hdr_rw = reinterpret_cast<Header *>(addr);
hdr_rw->total_size = le_to_be(total_size);
}
auto tables_rw = reinterpret_cast<Table *>(addr + sizeof(Header));
for (int i = 0; i < num_dtb; ++i) {
auto &blob = dtb_map[be_to_le(tables_rw[i].offset)];
tables_rw[i].offset = le_to_be(blob.offset);
tables_rw[i].len = le_to_be(blob.len);
}
munmap(addr, mmap_sz);
close(fd);
return 0;
free(fdt);
}
static int blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) {
vector<uint8_t *> fdt_list;
vector<uint32_t> padding_list;
for (int i = 0; i < dtb_sz; ++i) {
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
auto len = fdt_totalsize(dtb + i);
auto fdt = static_cast<uint8_t *>(xmalloc(len + MAX_FDT_GROWTH));
memcpy(fdt, dtb + i, len);
fdt_pack(fdt);
uint32_t padding = len - fdt_totalsize(fdt);
padding_list.push_back(padding);
fdt_open_into(fdt, fdt, len + MAX_FDT_GROWTH);
fdt_list.push_back(fdt);
i += len - 1;
}
}
// Patch headers
if constexpr (is_aosp) {
auto hdr_rw = reinterpret_cast<Header *>(addr);
hdr_rw->total_size = le_to_be(total_size);
}
auto tables_rw = reinterpret_cast<Table *>(addr + sizeof(Header));
for (int i = 0; i < num_dtb; ++i) {
auto &blob = dtb_map[be_to_le(tables_rw[i].offset)];
tables_rw[i].offset = le_to_be(blob.offset);
tables_rw[i].len = le_to_be(blob.len);
}
if (!fdt_patch(fdt_list.begin(), fdt_list.end()))
return 1;
munmap(addr, mmap_sz);
close(fd);
unlink(out);
int fd = xopen(out, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
return true;
}
for (int i = 0; i < fdt_list.size(); ++i) {
auto fdt = fdt_list[i];
static bool blob_patch(uint8_t *dtb, size_t dtb_sz, const char *out) {
vector<uint8_t *> fdt_list;
vector<uint32_t> padding_list;
for (int i = 0; i < dtb_sz; ++i) {
if (memcmp(dtb + i, FDT_MAGIC_STR, 4) == 0) {
auto len = fdt_totalsize(dtb + i);
auto fdt = static_cast<uint8_t *>(xmalloc(len + MAX_FDT_GROWTH));
memcpy(fdt, dtb + i, len);
fdt_pack(fdt);
// Only add padding back if it is anything meaningful
if (padding_list[i] > 4) {
auto len = fdt_totalsize(fdt);
fdt_set_totalsize(fdt, len + padding_list[i]);
}
xwrite(fd, fdt, fdt_totalsize(fdt));
free(fdt);
uint32_t padding = len - fdt_totalsize(fdt);
padding_list.push_back(padding);
fdt_open_into(fdt, fdt, len + MAX_FDT_GROWTH);
fdt_list.push_back(fdt);
i += len - 1;
}
close(fd);
return 0;
}
bool modified = false;
for (auto fdt : fdt_list)
modified |= fdt_patch(fdt);
if (!modified)
return false;
unlink(out);
int fd = xopen(out, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
for (int i = 0; i < fdt_list.size(); ++i) {
auto fdt = fdt_list[i];
fdt_pack(fdt);
// Only add padding back if it is anything meaningful
if (padding_list[i] > 4) {
auto len = fdt_totalsize(fdt);
fdt_set_totalsize(fdt, len + padding_list[i]);
}
xwrite(fd, fdt, fdt_totalsize(fdt));
free(fdt);
}
close(fd);
return true;
}
#define MATCH(s) (memcmp(dtb, s, sizeof(s) - 1) == 0)
[[maybe_unused]] static int dtb_patch(const char *in, const char *out) {
if (!out)
out = in;
size_t dtb_sz ;
uint8_t *dtb;
fprintf(stderr, "Loading dtbs from [%s]\n", in);
mmap_ro(in, dtb, dtb_sz);
run_finally f([&]{ munmap(dtb, dtb_sz); });
if (MATCH(QCDT_MAGIC)) {
auto hdr = reinterpret_cast<qcdt_hdr*>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "QCDT v1\n");
return dt_table_patch<qctable_v1>(hdr, out);
case 2:
fprintf(stderr, "QCDT v2\n");
return dt_table_patch<qctable_v2>(hdr, out);
case 3:
fprintf(stderr, "QCDT v3\n");
return dt_table_patch<qctable_v3>(hdr, out);
default:
return 1;
}
} else if (MATCH(DTBH_MAGIC)) {
auto hdr = reinterpret_cast<dtbh_hdr *>(dtb);
switch (hdr->version) {
case 2:
fprintf(stderr, "DTBH v2\n");
return dt_table_patch<bhtable_v2>(hdr, out);
default:
return 1;
}
} else if (MATCH(PXADT_MAGIC)) {
auto hdr = reinterpret_cast<pxadt_hdr *>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "PXA-DT v1\n");
return dt_table_patch<pxatable_v1>(hdr, out);
default:
return 1;
}
} else if (MATCH(PXA19xx_MAGIC)) {
auto hdr = reinterpret_cast<pxa19xx_hdr *>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "PXA-19xx v1\n");
return dt_table_patch<pxatable_v1>(hdr, out);
default:
return 1;
}
} else if (MATCH(SPRD_MAGIC)) {
auto hdr = reinterpret_cast<sprd_hdr *>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "SPRD v1\n");
return dt_table_patch<sprdtable_v1>(hdr, out);
default:
return 1;
}
} else if (MATCH(DT_TABLE_MAGIC)) {
auto hdr = reinterpret_cast<dt_table_header *>(dtb);
switch (hdr->version) {
case 0:
fprintf(stderr, "DT_TABLE v0\n");
return dt_table_patch<dt_table_entry>(hdr, out);
default:
return 1;
}
} else {
return blob_patch(dtb, dtb_sz, out);
static bool dtb_patch_rebuild(uint8_t *dtb, size_t dtb_sz, const char *file) {
if (MATCH(QCDT_MAGIC)) {
auto hdr = reinterpret_cast<qcdt_hdr*>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "QCDT v1\n");
return dt_table_patch<qctable_v1>(hdr, file);
case 2:
fprintf(stderr, "QCDT v2\n");
return dt_table_patch<qctable_v2>(hdr, file);
case 3:
fprintf(stderr, "QCDT v3\n");
return dt_table_patch<qctable_v3>(hdr, file);
default:
return false;
}
} else if (MATCH(DTBH_MAGIC)) {
auto hdr = reinterpret_cast<dtbh_hdr *>(dtb);
switch (hdr->version) {
case 2:
fprintf(stderr, "DTBH v2\n");
return dt_table_patch<bhtable_v2>(hdr, file);
default:
return false;
}
} else if (MATCH(PXADT_MAGIC)) {
auto hdr = reinterpret_cast<pxadt_hdr *>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "PXA-DT v1\n");
return dt_table_patch<pxatable_v1>(hdr, file);
default:
return false;
}
} else if (MATCH(PXA19xx_MAGIC)) {
auto hdr = reinterpret_cast<pxa19xx_hdr *>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "PXA-19xx v1\n");
return dt_table_patch<pxatable_v1>(hdr, file);
default:
return false;
}
} else if (MATCH(SPRD_MAGIC)) {
auto hdr = reinterpret_cast<sprd_hdr *>(dtb);
switch (hdr->version) {
case 1:
fprintf(stderr, "SPRD v1\n");
return dt_table_patch<sprdtable_v1>(hdr, file);
default:
return false;
}
} else if (MATCH(DT_TABLE_MAGIC)) {
auto hdr = reinterpret_cast<dt_table_header *>(dtb);
switch (hdr->version) {
case 0:
fprintf(stderr, "DT_TABLE v0\n");
return dt_table_patch<dt_table_entry>(hdr, file);
default:
return false;
}
} else {
return blob_patch(dtb, dtb_sz, file);
}
}

View File

@@ -48,8 +48,8 @@ void magisk_cpio::patch() {
auto cur = it++;
bool fstab = (!keepverity || !keepforceencrypt) &&
S_ISREG(cur->second->mode) &&
!str_starts(cur->first, ".backup") &&
!str_contains(cur->first, "twrp") &&
!str_starts(cur->first, ".backup") &&
!str_contains(cur->first, "twrp") &&
!str_contains(cur->first, "recovery") &&
str_contains(cur->first, "fstab");
if (!keepverity) {
@@ -73,7 +73,6 @@ void magisk_cpio::patch() {
#define MAGISK_PATCHED (1 << 0)
#define UNSUPPORTED_CPIO (1 << 1)
#define COMPRESSED_CPIO (1 << 2)
#define TWO_STAGE_INIT (1 << 3)
int magisk_cpio::test() {
for (auto file : UNSUPPORT_LIST)
@@ -87,9 +86,6 @@ int magisk_cpio::test() {
decompress();
}
if (exists("apex") || exists("first_stage_ramdisk"))
flags |= TWO_STAGE_INIT;
for (auto file : MAGISK_LIST) {
if (exists(file)) {
flags |= MAGISK_PATCHED;

View File

@@ -77,7 +77,6 @@ static void lazy_unmount(const char* mountpoint) {
LOGD("hide: Unmounted (%s)\n", mountpoint);
}
#if ENABLE_PTRACE_MONITOR
void hide_daemon(int pid) {
if (fork_dont_care() == 0) {
hide_unmount(pid);
@@ -86,7 +85,6 @@ void hide_daemon(int pid) {
_exit(0);
}
}
#endif
#define TMPFS_MNT(dir) (mentry->mnt_type == "tmpfs"sv && \
strncmp(mentry->mnt_dir, "/" #dir, sizeof("/" #dir) - 1) == 0)

View File

@@ -20,7 +20,7 @@ map<int, vector<string_view>> uid_proc_map; /* uid -> list of process */
// Locks the variables above
pthread_mutex_t hide_state_lock = PTHREAD_MUTEX_INITIALIZER;
#if ENABLE_PTRACE_MONITOR
#if !ENABLE_INJECT
static pthread_t monitor_thread;
#endif
@@ -160,11 +160,9 @@ static int add_list(const char *pkg, const char *proc) {
}
int add_list(int client) {
char *pkg = read_string(client);
char *proc = read_string(client);
int ret = add_list(pkg, proc);
free(pkg);
free(proc);
string pkg = read_string(client);
string proc = read_string(client);
int ret = add_list(pkg.data(), proc.data());
if (ret == DAEMON_SUCCESS)
update_uid_map();
return ret;
@@ -200,11 +198,9 @@ static int rm_list(const char *pkg, const char *proc) {
}
int rm_list(int client) {
char *pkg = read_string(client);
char *proc = read_string(client);
int ret = rm_list(pkg, proc);
free(pkg);
free(proc);
string pkg = read_string(client);
string proc = read_string(client);
int ret = rm_list(pkg.data(), proc.data());
if (ret == DAEMON_SUCCESS)
update_uid_map();
return ret;
@@ -246,16 +242,18 @@ static bool init_list() {
if (MAGISKTMP != "/sbin")
add_hide_set(GMS_PKG, GMS_PKG);
update_uid_map();
return true;
}
void ls_list(int client) {
FILE *out = fdopen(recv_fd(client), "a");
for (auto &hide : hide_set)
fprintf(out, "%s|%s\n", hide.first.data(), hide.second.data());
fclose(out);
write_int(client, DAEMON_SUCCESS);
for (auto &hide : hide_set) {
write_int(client, hide.first.size() + hide.second.size() + 1);
xwrite(client, hide.first.data(), hide.first.size());
xwrite(client, "|", 1);
xwrite(client, hide.second.data(), hide.second.size());
}
write_int(client, 0);
close(client);
}
@@ -267,8 +265,8 @@ static void update_hide_config() {
db_err(err);
}
int launch_magiskhide() {
mutex_guard g(hide_state_lock);
int launch_magiskhide(bool late_props) {
mutex_guard lock(hide_state_lock);
if (SDK_INT < 19)
return DAEMON_ERROR;
@@ -276,7 +274,7 @@ int launch_magiskhide() {
if (hide_state)
return HIDE_IS_ENABLED;
if (access("/proc/1/ns/mnt", F_OK) != 0)
if (access("/proc/self/ns/mnt", F_OK) != 0)
return HIDE_NO_NS;
if (procfp == nullptr && (procfp = opendir("/proc")) == nullptr)
@@ -289,10 +287,10 @@ int launch_magiskhide() {
return DAEMON_ERROR;
hide_sensitive_props();
if (DAEMON_STATE >= STATE_BOOT_COMPLETE || DAEMON_STATE == STATE_NONE)
if (late_props)
hide_late_sensitive_props();
#if ENABLE_PTRACE_MONITOR
#if !ENABLE_INJECT
// Start monitoring
if (new_daemon_thread(&proc_monitor))
return DAEMON_ERROR;
@@ -300,6 +298,11 @@ int launch_magiskhide() {
hide_state = true;
update_hide_config();
// Unlock here or else we'll be stuck in deadlock
lock.unlock();
update_uid_map();
return DAEMON_SUCCESS;
}
@@ -310,7 +313,7 @@ int stop_magiskhide() {
LOGI("* Disable MagiskHide\n");
uid_proc_map.clear();
hide_set.clear();
#if ENABLE_PTRACE_MONITOR
#if !ENABLE_INJECT
pthread_kill(monitor_thread, SIGTERMTHRD);
#endif
}
@@ -320,9 +323,9 @@ int stop_magiskhide() {
return DAEMON_SUCCESS;
}
void auto_start_magiskhide() {
void auto_start_magiskhide(bool late_props) {
if (hide_enabled()) {
#if ENABLE_PTRACE_MONITOR
#if !ENABLE_INJECT
pthread_kill(monitor_thread, SIGALRM);
#endif
hide_late_sensitive_props();
@@ -330,14 +333,51 @@ void auto_start_magiskhide() {
db_settings dbs;
get_db_settings(dbs, HIDE_CONFIG);
if (dbs[HIDE_CONFIG])
launch_magiskhide();
launch_magiskhide(late_props);
}
}
#if ENABLE_PTRACE_MONITOR
bool is_hide_target(int uid, string_view process) {
mutex_guard lock(hide_state_lock);
if (uid % 100000 >= 90000) {
// Isolated processes
auto it = uid_proc_map.find(-1);
if (it == uid_proc_map.end())
return false;
for (auto &s : it->second) {
if (str_starts(process, s))
return true;
}
} else {
auto it = uid_proc_map.find(uid);
if (it == uid_proc_map.end())
return false;
for (auto &s : it->second) {
if (s == process)
return true;
}
}
return false;
}
#if !ENABLE_INJECT
void test_proc_monitor() {
if (procfp == nullptr && (procfp = opendir("/proc")) == nullptr)
exit(1);
proc_monitor();
}
#endif
#if ENABLE_INJECT
int check_uid_map(int client) {
if (!hide_enabled())
return 0;
int uid = read_int(client);
string process = read_string(client);
return is_hide_target(uid, process) ? 1 : 0;
}
#endif

View File

@@ -1,19 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <daemon.hpp>
#include <utils.hpp>
#include "magiskhide.hpp"
using namespace std::literals;
using namespace std;
[[noreturn]] static void usage(char *arg0) {
fprintf(stderr,
@@ -35,7 +27,7 @@ using namespace std::literals;
exit(1);
}
void magiskhide_handler(int client) {
void magiskhide_handler(int client, ucred *cred) {
int req = read_int(client);
int res = DAEMON_ERROR;
@@ -53,7 +45,7 @@ void magiskhide_handler(int client) {
switch (req) {
case LAUNCH_MAGISKHIDE:
res = launch_magiskhide();
res = launch_magiskhide(true);
break;
case STOP_MAGISKHIDE:
res = stop_magiskhide();
@@ -70,6 +62,17 @@ void magiskhide_handler(int client) {
case HIDE_STATUS:
res = hide_enabled() ? HIDE_IS_ENABLED : HIDE_NOT_ENABLED;
break;
#if ENABLE_INJECT
case REMOTE_CHECK_HIDE:
res = check_uid_map(client);
break;
case REMOTE_DO_HIDE:
kill(cred->pid, SIGSTOP);
write_int(client, 0);
hide_daemon(cred->pid);
close(client);
return;
#endif
}
write_int(client, res);
@@ -105,7 +108,7 @@ int magiskhide_main(int argc, char *argv[]) {
execvp(argv[2], argv + 2);
exit(1);
}
#if 0 && ENABLE_PTRACE_MONITOR
#if 0 && !ENABLE_INJECT
else if (opt == "test"sv)
test_proc_monitor();
#endif
@@ -120,8 +123,6 @@ int magiskhide_main(int argc, char *argv[]) {
write_string(fd, argv[2]);
write_string(fd, argv[3] ? argv[3] : "");
}
if (req == LS_HIDELIST)
send_fd(fd, STDOUT_FILENO);
// Get response
int code = read_int(fd);
@@ -130,30 +131,66 @@ int magiskhide_main(int argc, char *argv[]) {
break;
case HIDE_NOT_ENABLED:
fprintf(stderr, "MagiskHide is not enabled\n");
break;
goto return_code;
case HIDE_IS_ENABLED:
fprintf(stderr, "MagiskHide is enabled\n");
break;
goto return_code;
case HIDE_ITEM_EXIST:
fprintf(stderr, "Target already exists in hide list\n");
break;
goto return_code;
case HIDE_ITEM_NOT_EXIST:
fprintf(stderr, "Target does not exist in hide list\n");
break;
goto return_code;
case HIDE_NO_NS:
fprintf(stderr, "Your kernel doesn't support mount namespace\n");
break;
goto return_code;
case HIDE_INVALID_PKG:
fprintf(stderr, "Invalid package / process name\n");
break;
goto return_code;
case ROOT_REQUIRED:
fprintf(stderr, "Root is required for this operation\n");
break;
goto return_code;
case DAEMON_ERROR:
default:
fprintf(stderr, "Daemon error\n");
return DAEMON_ERROR;
}
if (req == LS_HIDELIST) {
string res;
for (;;) {
read_string(fd, res);
if (res.empty())
break;
printf("%s\n", res.data());
}
}
return_code:
return req == HIDE_STATUS ? (code == HIDE_IS_ENABLED ? 0 : 1) : code != DAEMON_SUCCESS;
}
#if ENABLE_INJECT
int remote_check_hide(int uid, const char *process) {
int fd = connect_daemon();
write_int(fd, MAGISKHIDE);
write_int(fd, REMOTE_CHECK_HIDE);
write_int(fd, uid);
write_string(fd, process);
int res = read_int(fd);
close(fd);
return res;
}
void remote_request_hide() {
int fd = connect_daemon();
write_int(fd, MAGISKHIDE);
write_int(fd, REMOTE_DO_HIDE);
// Should receive SIGSTOP before reading anything
// During process stop, magiskd will cleanup our mount ns
read_int(fd);
close(fd);
}
#endif

View File

@@ -14,20 +14,20 @@
#define SIGTERMTHRD SIGUSR1
#define ISOLATED_MAGIC "isolated"
// Global toggle for ptrace monitor
#define ENABLE_PTRACE_MONITOR 1
// CLI entries
int launch_magiskhide();
int launch_magiskhide(bool late_props);
int stop_magiskhide();
int add_list(int client);
int rm_list(int client);
void ls_list(int client);
#if ENABLE_PTRACE_MONITOR
#if !ENABLE_INJECT
// Process monitoring
[[noreturn]] void proc_monitor();
[[noreturn]] void test_proc_monitor();
#else
// Response whether target process should be hidden
int check_uid_map(int client);
#endif
// Utility functions
@@ -35,6 +35,7 @@ void crawl_procfs(const std::function<bool (int)> &fn);
void crawl_procfs(DIR *dir, const std::function<bool (int)> &fn);
bool hide_enabled();
void update_uid_map();
bool is_hide_target(int uid, std::string_view process);
// Hide policies
void hide_daemon(int pid);
@@ -52,6 +53,8 @@ enum {
RM_HIDELIST,
LS_HIDELIST,
HIDE_STATUS,
REMOTE_CHECK_HIDE,
REMOTE_DO_HIDE
};
enum {

View File

@@ -183,8 +183,10 @@ static bool check_pid(int pid) {
return true;
}
int uid = st.st_uid;
// UID hasn't changed
if (st.st_uid == 0)
if (uid == 0)
return false;
sprintf(path, "/proc/%d/cmdline", pid);
@@ -200,43 +202,26 @@ static bool check_pid(int pid) {
cmdline == "usap32"sv || cmdline == "usap64"sv)
return false;
int uid = st.st_uid;
// Start accessing uid_proc_map
mutex_guard lock(hide_state_lock);
auto it = uid_proc_map.end();
if (uid % 100000 > 90000) {
// No way to handle isolated process
if (!is_hide_target(uid, cmdline))
goto not_target;
}
it = uid_proc_map.find(uid);
if (it == uid_proc_map.end())
goto not_target;
for (auto &s : it->second) {
if (s != cmdline)
continue;
// Check if ns is separated (could be app zygote)
read_ns(pid, &st);
for (auto &zit : zygote_map) {
if (zit.second.st_ino == st.st_ino &&
zit.second.st_dev == st.st_dev) {
// ns not separated, abort
goto not_target;
}
// Ensure ns is separated
read_ns(pid, &st);
for (auto &zit : zygote_map) {
if (zit.second.st_ino == st.st_ino &&
zit.second.st_dev == st.st_dev) {
// ns not separated, abort
goto not_target;
}
// Finally this is our target!
// Detach from ptrace but should still remain stopped.
// The hide daemon will resume the process.
LOGI("proc_monitor: [%s] PID=[%d] UID=[%d]\n", cmdline, pid, uid);
detach_pid(pid, SIGSTOP);
hide_daemon(pid);
return true;
}
// Detach but the process should still remain stopped
// The hide daemon will resume the process after hiding it
LOGI("proc_monitor: [%s] PID=[%d] UID=[%d]\n", cmdline, pid, uid);
detach_pid(pid, SIGSTOP);
hide_daemon(pid);
return true;
not_target:
PTRACE_LOG("[%s] is not our target\n", cmdline);
detach_pid(pid);

View File

@@ -106,13 +106,14 @@ void sepolicy::magisk_rules() {
// Don't allow pesky processes to monitor audit deny logs when poking magisk daemon socket
dontaudit(ALL, SEPOL_PROC_DOMAIN, "unix_stream_socket", ALL);
// Only allow client processes to connect to magisk daemon socket
// Only allow client processes and zygote to connect to magisk daemon socket
allow(SEPOL_CLIENT_DOMAIN, SEPOL_PROC_DOMAIN, "unix_stream_socket", ALL);
allow("zygote", SEPOL_PROC_DOMAIN, "unix_stream_socket", ALL);
} else {
// Fallback to poking holes in sandbox as Android 4.3 to 7.1 set PR_SET_NO_NEW_PRIVS
// Allow these processes to access MagiskSU
const char *clients[] { "init", "shell", "appdomain" };
const char *clients[] { "init", "shell", "appdomain", "zygote" };
for (auto type : clients) {
if (!exists(type))
continue;

View File

@@ -1,7 +1,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <daemon.hpp>
#include <utils.hpp>
#include <selinux.hpp>
@@ -31,7 +30,7 @@ enum {
? info->uid / 100000 : 0)
#define get_cmd(to) \
(to.command[0] ? to.command : to.shell[0] ? to.shell : DEFAULT_SHELL)
(to.command.empty() ? (to.shell.empty() ? DEFAULT_SHELL : to.shell.data()) : to.command.data())
class Extra {
const char *key;
@@ -43,7 +42,7 @@ class Extra {
union {
int int_val;
bool bool_val;
const char * str_val;
const char *str_val;
};
char buf[32];
public:

View File

@@ -9,13 +9,9 @@
* helper functions to handle raw input mode and terminal window resizing
*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>
#include <pthread.h>
#include <utils.hpp>
@@ -116,7 +112,7 @@ static int stdin_is_raw = 0;
/**
* set_stdin_raw
*
* Changes stdin to raw unbuffered mode, disables echo,
* Changes stdin to raw unbuffered mode, disables echo,
* auto carriage return, etc.
*
* Return Value
@@ -180,7 +176,7 @@ int restore_stdin(void) {
static volatile bool close_sigwinch_watcher = false;
/**
* Thread process. Wait for a SIGWINCH to be received, then update
* Thread process. Wait for a SIGWINCH to be received, then update
* the terminal size.
*/
static void *watch_sigwinch(void *data) {
@@ -214,7 +210,7 @@ static void *watch_sigwinch(void *data) {
* watch_sigwinch_async
*
* After calling this function, if the application receives
* SIGWINCH, the terminal window size will be read from
* SIGWINCH, the terminal window size will be read from
* "input" and set on "output".
*
* NOTE: This function blocks SIGWINCH and spawns a thread.
@@ -228,7 +224,7 @@ static void *watch_sigwinch(void *data) {
*
* Return Value
* on failure, -1 and errno will be set. In this case, no
* thread has been spawned and SIGWINCH will not be
* thread has been spawned and SIGWINCH will not be
* blocked.
* on success, 0
*/

View File

@@ -1,26 +1,19 @@
/*
* Copyright 2017, John Wu (@topjohnwu)
* Copyright 2017 - 2021, John Wu (@topjohnwu)
* Copyright 2015, Pierre-Hugues Husson <phh@phh.me>
* Copyright 2010, Adam Shanks (@ChainsDD)
* Copyright 2008, Zinx Verituse (@zinxv)
*/
/* su.c - The main function running in the daemon
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <pwd.h>
#include <errno.h>
#include <signal.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <magisk.hpp>
#include <daemon.hpp>
#include <utils.hpp>
#include <flags.hpp>
@@ -50,18 +43,6 @@ static void usage(int status) {
exit(status);
}
static char *concat_commands(int argc, char *argv[]) {
char command[ARG_MAX];
command[0] = '\0';
for (int i = optind - 1; i < argc; ++i) {
if (command[0])
sprintf(command, "%s %s", command, argv[i]);
else
strcpy(command, argv[i]);
}
return strdup(command);
}
static void sighandler(int sig) {
restore_stdin();
@@ -121,7 +102,11 @@ int su_client_main(int argc, char *argv[]) {
while ((c = getopt_long(argc, argv, "c:hlmps:Vvuz:M", long_opts, nullptr)) != -1) {
switch (c) {
case 'c':
su_req.command = concat_commands(argc, argv);
for (int i = optind - 1; i < argc; ++i) {
if (!su_req.command.empty())
su_req.command += ' ';
su_req.command += argv[i];
}
optind = argc;
break;
case 'h':

View File

@@ -5,7 +5,6 @@
#include <memory>
#include <db.hpp>
#include <utils.hpp>
#define DEFAULT_SHELL "/system/bin/sh"
@@ -46,19 +45,9 @@ struct su_req_base {
} __attribute__((packed));
struct su_request : public su_req_base {
const char *shell = DEFAULT_SHELL;
const char *command = "";
su_request(bool dyn = false) : dyn(dyn) {}
~su_request() {
if (dyn) {
free(const_cast<char*>(shell));
free(const_cast<char*>(command));
}
}
private:
bool dyn;
} __attribute__((packed));
std::string shell = DEFAULT_SHELL;
std::string command;
};
struct su_context {
std::shared_ptr<su_info> info;

View File

@@ -1,20 +1,14 @@
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <daemon.hpp>
#include <utils.hpp>
#include <selinux.hpp>
#include <db.hpp>
#include "su.hpp"
#include "pts.hpp"
@@ -169,14 +163,14 @@ void su_daemon_handler(int client, struct ucred *credential) {
su_context ctx = {
.info = get_su_info(credential->uid),
.req = su_request(true),
.req = su_request(),
.pid = credential->pid
};
// Read su_request
xxread(client, &ctx.req, sizeof(su_req_base));
ctx.req.shell = read_string(client);
ctx.req.command = read_string(client);
read_string(client, ctx.req.shell);
read_string(client, ctx.req.command);
if (ctx.info->access.log)
app_log(ctx);
@@ -229,18 +223,18 @@ void su_daemon_handler(int client, struct ucred *credential) {
xsetsid();
// Get pts_slave
char *pts_slave = read_string(client);
string pts_slave = read_string(client);
// The FDs for each of the streams
int infd = recv_fd(client);
int outfd = recv_fd(client);
int errfd = recv_fd(client);
if (pts_slave[0]) {
LOGD("su: pts_slave=[%s]\n", pts_slave);
if (!pts_slave.empty()) {
LOGD("su: pts_slave=[%s]\n", pts_slave.data());
// Check pts_slave file is owned by daemon_from_uid
struct stat st;
xstat(pts_slave, &st);
xstat(pts_slave.data(), &st);
// If caller is not root, ensure the owner of pts_slave is the caller
if(st.st_uid != ctx.info->uid && ctx.info->uid != 0)
@@ -249,7 +243,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
// Opening the TTY has to occur after the
// fork() and setsid() so that it becomes
// our controlling TTY and not the daemon's
int ptsfd = xopen(pts_slave, O_RDWR);
int ptsfd = xopen(pts_slave.data(), O_RDWR);
if (infd < 0)
infd = ptsfd;
@@ -259,8 +253,6 @@ void su_daemon_handler(int client, struct ucred *credential) {
errfd = ptsfd;
}
free(pts_slave);
// Swap out stdin, stdout, stderr
xdup2(infd, STDIN_FILENO);
xdup2(outfd, STDOUT_FILENO);
@@ -296,13 +288,13 @@ void su_daemon_handler(int client, struct ucred *credential) {
break;
}
const char *argv[] = { nullptr, nullptr, nullptr, nullptr };
const char *argv[4] = { nullptr };
argv[0] = ctx.req.login ? "-" : ctx.req.shell;
argv[0] = ctx.req.login ? "-" : ctx.req.shell.data();
if (ctx.req.command[0]) {
if (!ctx.req.command.empty()) {
argv[1] = "-c";
argv[2] = ctx.req.command;
argv[2] = ctx.req.command.data();
}
// Setup environment
@@ -327,7 +319,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
setenv("HOME", pw->pw_dir, 1);
setenv("USER", pw->pw_name, 1);
setenv("LOGNAME", pw->pw_name, 1);
setenv("SHELL", ctx.req.shell, 1);
setenv("SHELL", ctx.req.shell.data(), 1);
}
}
@@ -336,8 +328,8 @@ void su_daemon_handler(int client, struct ucred *credential) {
sigemptyset(&block_set);
sigprocmask(SIG_SETMASK, &block_set, nullptr);
set_identity(ctx.req.uid);
execvp(ctx.req.shell, (char **) argv);
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell, strerror(errno));
execvp(ctx.req.shell.data(), (char **) argv);
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell.data(), strerror(errno));
PLOGE("exec");
exit(EXIT_FAILURE);
}

View File

@@ -279,7 +279,6 @@ void *__mmap(const char *filename, size_t *size, bool rw) {
return nullptr;
}
struct stat st;
void *buf;
if (fstat(fd, &st)) {
*size = 0;
return nullptr;
@@ -288,7 +287,9 @@ void *__mmap(const char *filename, size_t *size, bool rw) {
ioctl(fd, BLKGETSIZE64, size);
else
*size = st.st_size;
buf = *size > 0 ? xmmap(nullptr, *size, PROT_READ | (rw ? PROT_WRITE : 0), MAP_SHARED, fd, 0) : nullptr;
void *buf = *size > 0 ?
xmmap(nullptr, *size, PROT_READ | PROT_WRITE, rw ? MAP_SHARED : MAP_PRIVATE, fd, 0) :
nullptr;
close(fd);
return buf;
}
@@ -437,3 +438,16 @@ sDIR make_dir(DIR *dp) {
sFILE make_file(FILE *fp) {
return sFILE(fp, [](FILE *fp){ return fp ? fclose(fp) : 1; });
}
raw_file::raw_file(raw_file &&o) {
path.swap(o.path);
attr = o.attr;
buf = o.buf;
sz = o.sz;
o.buf = nullptr;
o.sz = 0;
}
raw_file::~raw_file() {
free(buf);
}

View File

@@ -21,22 +21,13 @@ struct file_attr {
struct raw_file {
std::string path;
file_attr attr;
uint8_t *buf = nullptr;
size_t sz = 0;
uint8_t *buf;
size_t sz;
raw_file() = default;
raw_file() : attr({}), buf(nullptr), sz(0) {}
raw_file(const raw_file&) = delete;
raw_file(raw_file &&d) {
path = std::move(d.path);
attr = d.attr;
buf = d.buf;
sz = d.sz;
d.buf = nullptr;
d.sz = 0;
}
~raw_file() {
free(buf);
}
raw_file(raw_file &&o);
~raw_file();
};
ssize_t fd_path(int fd, char *path, size_t size);

View File

@@ -13,15 +13,13 @@ public:
explicit mutex_guard(pthread_mutex_t &m): mutex(&m) {
pthread_mutex_lock(mutex);
}
explicit mutex_guard(pthread_mutex_t *m): mutex(m) {
pthread_mutex_lock(mutex);
}
~mutex_guard() {
void unlock() {
pthread_mutex_unlock(mutex);
mutex = nullptr;
}
~mutex_guard() {
if (mutex) pthread_mutex_unlock(mutex);
}
private:
pthread_mutex_t *mutex;
};

View File

@@ -1,7 +1,5 @@
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -63,12 +61,24 @@ int xopenat(int dirfd, const char *pathname, int flags, mode_t mode) {
return fd;
}
// Write exact same size as count
ssize_t xwrite(int fd, const void *buf, size_t count) {
int ret = write(fd, buf, count);
if (count != ret) {
PLOGE("write");
size_t write_sz = 0;
ssize_t ret;
do {
ret = write(fd, (byte *) buf + write_sz, count - write_sz);
if (ret < 0) {
if (errno == EINTR)
continue;
PLOGE("write");
return ret;
}
write_sz += ret;
} while (write_sz != count && ret != 0);
if (write_sz != count) {
PLOGE("write (%zu != %zu)", count, write_sz);
}
return ret;
return write_sz;
}
// Read error other than EOF
@@ -82,11 +92,22 @@ ssize_t xread(int fd, void *buf, size_t count) {
// Read exact same size as count
ssize_t xxread(int fd, void *buf, size_t count) {
int ret = read(fd, buf, count);
if (count != ret) {
PLOGE("read (%zu != %d)", count, ret);
size_t read_sz = 0;
ssize_t ret;
do {
ret = read(fd, (byte *) buf + read_sz, count - read_sz);
if (ret < 0) {
if (errno == EINTR)
continue;
PLOGE("read");
return ret;
}
read_sz += ret;
} while (read_sz != count && ret != 0);
if (read_sz != count) {
PLOGE("read (%zu != %zu)", count, read_sz);
}
return ret;
return read_sz;
}
int xpipe2(int pipefd[2], int flags) {
@@ -242,7 +263,7 @@ ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
return rec;
}
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg) {
errno = pthread_create(thread, attr, start_routine, arg);
if (errno) {

View File

@@ -142,18 +142,13 @@ echo "RECOVERYMODE=$RECOVERYMODE" >> config
"mkdir 000 .backup" \
"add 000 .backup/.magisk config"
if [ $((STATUS & 4)) -ne 0 ]; then
ui_print "- Compressing ramdisk"
./magiskboot cpio ramdisk.cpio compress
fi
rm -f ramdisk.cpio.orig config
#################
# Binary Patches
#################
for dt in dtb kernel_dtb extra recovery_dtbo; do
for dt in dtb kernel_dtb extra; do
[ -f $dt ] && ./magiskboot dtb $dt patch && ui_print "- Patch fstab in $dt"
done

View File

@@ -608,7 +608,7 @@ copy_sepolicy_rules() {
local active_dir=$(magisk --path)/.magisk/mirror/sepolicy.rules
if [ -e $active_dir ]; then
RULESDIR=$(readlink -f $active_dir)
elif [ -d /data/unencrypted ] && ! grep ' /data ' /proc/mounts | grep -q 'dm-'; then
elif [ -d /data/unencrypted ] && ! grep ' /data ' /proc/mounts | grep -qE 'dm-|f2fs'; then
RULESDIR=/data/unencrypted/magisk
elif grep -q ' /cache ' /proc/mounts; then
RULESDIR=/cache/magisk