diff --git a/README.MD b/README.MD index ed520c8da..0634e0054 100644 --- a/README.MD +++ b/README.MD @@ -24,7 +24,7 @@ Here are some feature highlights: ## Useful Links - [Installation Instruction](https://topjohnwu.github.io/Magisk/install.html) -- [OTA Upgrade Guide](https://topjohnwu.github.io/Magisk/ota.html) +- [Frequently Asked Questions](https://topjohnwu.github.io/Magisk/faq.html) - [Full Official Docs](https://topjohnwu.github.io/Magisk/) - [Magisk Troubleshoot Wiki](https://www.didgeridoohan.com/magisk/HomePage) (by [@Didgeridoohan](https://github.com/Didgeridoohan)) diff --git a/docs/README.md b/docs/README.md index 010d102ed..c4c191c86 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,8 @@ # Magisk Documentation -(Updated on 2020.3.23) +(Updated on 2020.10.2) - [Installation Instructions](install.md) -- [OTA Upgrade Guides](ota.md) +- [Frequently Asked Questions](faq.md) The following sections are for developers diff --git a/docs/boot.md b/docs/boot.md index 4701e876d..a6e70c632 100644 --- a/docs/boot.md +++ b/docs/boot.md @@ -30,12 +30,12 @@ Method | Initial rootdir | Final rootdir - Devices that does not fall in any of Method B and C's criteria - **Method B - Legacy SAR**: This method was first seen on Pixel 1. The kernel directly mounts the `system` partition as rootdir and exec `/init` to boot. - Devices with `(LV = 28)` - - Google: Pixel 1 and 2. Pixel 3 and 3a with `(RV = 28)` only. - - OnePlus: 5T - 7 + - Google: Pixel 1 and 2. Pixel 3 and 3a when `(RV = 28)`. + - OnePlus: 6 - 7 - Maybe some `(LV < 29)` Android Go devices? - **Method C - 2SI ramdisk SAR**: This method was first seen on Pixel 3 Android 10 developer preview. The kernel uses `initramfs` as rootdir and exec `/init` in `rootfs`. This `init` is responsible to mount the `system` partition and use it as the new rootdir, then finally exec `/system/bin/init` to boot. - Devices with `(LV >= 29)` - - Devices with `(LV < 28, RV >= 29)`, excluding exceptions that were using Method B + - Devices with `(LV < 28, RV >= 29)`, excluding those that were already using Method B - Google: Pixel 3 and 3a with `(RV >= 29)` ### Discussion @@ -47,7 +47,7 @@ However for Magisk, the real difference lies in what the device ends up using wh The criteria for Method C is a little complicated, in layman's words: either your device is modern enough to launch with Android 10+, or you are running an Android 10+ custom ROM on a device that was using Method A. - Any Method A device running Android 10+ will automatically be using Method C -- **Method B devices are stuck with Method B**, maybe only with the exception of Pixel 3 and 3a, which Google retrofitted the device to adapt the new method. +- **Method B devices are stuck with Method B**, with the only exception being Pixel 3 and 3a, which Google retrofitted the device to adapt the new method. SAR is a very important part of [Project Treble](https://source.android.com/devices/architecture#hidl) as rootdir should be tied to the platform. This is also the reason why Method B and C comes with `(LV >= ver)` criterion as Google has enforced all OEMs to comply with updated requirements every year. @@ -57,7 +57,9 @@ When Google released the first generation Pixel, it also introduced [A/B (Seamle Let's go back in time when Google is first designing A/B. If using SAR (only Boot Method B exists at that time), the kernel doesn't need `initramfs` to boot Android (because rootdir is in `system`). This mean we can be smart and just stuff the recovery ramdisk (containing the minimalist Linux environment) into `boot`, remove `recovery`, and let the kernel pick whichever rootdir to use (ramdisk or `system`) based on information from the bootloader. -As time passed from Android 7.1 to Android 10, Google introduced [Dynamic Partitions](https://source.android.com/devices/tech/ota/dynamic_partitions/implement). This is bad news for SAR, because the Linux kernel cannot understand this new partition format, thus unable to directly use `system` as rootdir. This is when they came up with Boot Method C: always boot into `initramfs`, and let userspace handle the rest of booting. +As time passed from Android 7.1 to Android 10, Google introduced [Dynamic Partitions](https://source.android.com/devices/tech/ota/dynamic_partitions/implement). This is bad news for SAR, because the Linux kernel cannot directly understand this new partition format, thus unable to directly mount `system` as rootdir. This is when they came up with Boot Method C: always boot into `initramfs`, and let userspace handle the rest of booting. This includes deciding whether to boot into Android or recovery, or as they officially call: `USES_RECOVERY_AS_BOOT`. + +Some modern devices using A/B with 2SI also comes with `recovery_a/_b` partitions. This is officially supported with Google's standard. These devices will then only use the boot ramdisk to boot into Android as recovery is stored on a separate partition. ## Piecing Things Together @@ -66,10 +68,9 @@ With all the knowledge above, now we can categorize all Android devices into the Type | Boot Method | Partition | 2SI | Ramdisk in `boot` :---: | :---: | :---: | :---: | :---: **I** | A | A-only | No | `boot` ramdisk -**II** | B | A/B | No | `recovery` ramdisk -**III** | B | A-only | No | ***N/A*** +**II** | B | A/B | Any | `recovery` ramdisk +**III** | B | A-only | Any | ***N/A*** **IV** | C | Any | Yes | Hybrid ramdisk -**II\* / III\*** | B | II / III | Yes | II / III These types are ordered chronologically by the time they were first available. @@ -77,8 +78,7 @@ These types are ordered chronologically by the time they were first available. - **Type II**: Legacy A/B devices. Pixel 1 is the first device of this type, being both the first A/B and SAR device - **Type III**: Late 2018 - 2019 devices that are A-only. **The worst type of device to ever exist as far as Magisk is concerned.** - **Type IV**: All devices using Boot Method C are Type IV. A/B Type IV ramdisk can boot into either Android or recovery based on info from bootloader; A-only Type IV ramdisk can only boot into Android. -- **Type \***: Type II* and III* are Boot Method B devices running on Android 10+ (2SI). **They are NOT new device types**. In Magisk the code treat them drastically different due to complicated reasons, hence mentioning them here. Further details on Type III devices: Magisk is always installed in the ramdisk of a boot image. For all other device types, because their `boot` partition have ramdisk included, Magisk can be easily installed by patching boot image through Magisk Manager or flash zip in custom recovery. However for Type III devices, they are **limited to install Magisk into the `recovery` partition**. Magisk will not function when booted normally; instead Type III device owners have to always reboot to recovery to maintain Magisk access. -Some Type III devices' bootloader will still accept and provide `initramfs` manually added to `boot` image to the kernel (e.g. some Xiaomi phones), but many device don't (e.g. Samsung S10, Note 10). It solely depends on how the OEM implements its bootloader. +Some Type III devices' bootloader will still accept and provide `initramfs` that was manually added to the `boot` image to the kernel (e.g. some Xiaomi phones), but many device don't (e.g. Samsung S10, Note 10). It solely depends on how the OEM implements its bootloader. diff --git a/docs/deploy.md b/docs/deploy.md index 531b9e186..49244b4be 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -1,5 +1,5 @@ # Deployment -(Note: This is not a user tutorial for installing Magisk, this is an explaination of how Magisk can be installed, and a guide for developers to properly deploy Magisk in various different situations) +(Note: This is not a user tutorial for installing Magisk, this is an explanation of how Magisk can be installed, and a guide for developers to properly deploy Magisk in various different situations) ## Systemless When a user flashes a Magisk zip in custom recoveries or have boot images patched in Magisk Manager, Magisk is installed in the systemless fashion. This is the only officially supported method to install Magisk on a device. The systemless method installs Magisk into a boot image's ramdisk CPIO, sometimes require additional patches to the kernel. diff --git a/docs/details.md b/docs/details.md index c8d18e1e3..a8b4e55df 100644 --- a/docs/details.md +++ b/docs/details.md @@ -1,43 +1,54 @@ # Internal Details + ## File Structure -### Paths in "sbin tmpfs overlay" -One of Magisk's breakthrough designs is sbin tmpfs overlay. It is required to support system-as-root devices, and also is the key to hiding Magisk from detection. All Magisk binaries, applets, mirrors, and other trivial stuffs are all located in the `tmpfs` mounted on `/sbin`. MagiskHide can just simply unmount `/sbin` and the bind mounts to hide all modifications easily. + +### Paths in "Magisk tmpfs directory" + +Magisk will mount a `tmpfs` directory to store some temporary data. For devices with the `/sbin` folder, it will be chosen as it will also act as an overlay to inject binaries into `PATH`. From Android 11 onwards, the `/sbin` folder might not exist, so Magisk will randomly create a folder under `/dev` and use it as the base folder. ``` +# In order to get the current base folder Magisk is using, +# use the command `magisk --path`. # Binaries like magisk, magiskinit, and all symlinks to -# applets are directly stored in /sbin, so they -# are all in PATH for apps and shell to access them +# applets are directly stored in this path. This means when +# this is /sbin, these binaries will be directly in PATH. +MAGISKPATH=$(magisk --path) # Magisk internal stuffs -MAGISKTMP=/sbin/.magisk +MAGISKTMP=$MAGISKBASE/.magisk -# Magisk BusyBox path -BBPATH=$MAGISKTMP/busybox +# Magisk's BusyBox directory. Within this folder stores +# the busybox binary and symlinks to all of its applets. +# Any usage of this directory is deprecated, please +# directly call /data/adb/magisk/busybox and use +# BusyBox's ASH Standalone mode. +# The creation of this path will be removed in the future. +$MAGISKTMP/busybox -# /data/adb/modules will be bind mounted here +# /data/adb/modules will be bind mounted here. +# The original folder is not used due to nosuid mount flag. $MAGISKTMP/modules -# The configuration used in last installation +# The current Magisk installation config $MAGISKTMP/config -# Partition mirrors. -# There would be system, vendor, data, and possibly product -# in this directory, each is the mirror to the name of the partition +# Partition mirrors +# Each directory in this path will be mounted with the +# partition of its directory name. +# e.g. system, system_ext, vendor, data ... $MAGISKTMP/mirror +# Block devices Magisk creates internally to mount mirrors. +$MAGISKTMP/block + # Root directory patch files # On system-as-root devices, / is not writable. -# All patched files are stored here and bind mounted at boot. +# All pre-init patched files are stored here and bind mounted. $MAGISKTMP/rootdir - -# The patched sepolicy file on system-as-root devices. -# This is required as /sepolicy does not exist -# on those devices and / is not writable. -/sbin/.se - ``` ### Paths in `/data` + Some binaries and files should be stored on non-volatile storages in `/data`. In order to prevent detection, everything has to be stored somewhere safe and undetectable in `/data`. The folder `/data/adb` was chosen because of the following advantages: - It is an existing folder on modern Android, so it cannot be used as an indication of the existence of Magisk. @@ -66,31 +77,36 @@ $SECURE_DIR/modules_update # Database storing settings and root permissions MAGISKDB=$SECURE_DIR/magisk.db -# All magisk related binaries, containing busybox, +# All magisk related binaries, including busybox, # scripts, and magisk binaries. Used in supporting # module installation, addon.d, Magisk Manager etc. -# This folder will be bind mounted to $BINMIRROR DATABIN=$SECURE_DIR/magisk ``` ## Magisk Booting Process + ### Pre-Init + `magiskinit` will replace `init` as the first program to run. -- Early mount required partitions. On system-as-root devices, we will switch root to system -- Inject magisk services into `init.rc` +- Early mount required partitions. On legacy system-as-root devices, we switch root to system; on 2SI devices, we patch fstab and execute the original `init` to mount partitions for us. - Load sepolicy either from `/sepolicy`, precompiled sepolicy in vendor, or compile split sepolicy -- Patch sepolicy rules and dump to `/sepolicy` or `/sbin/.se` and patch `init` or `libselinux.so` to load the patched policies -- Execute the original `init` to start the ordinary boot process +- Patch sepolicy rules and dump to `/sepolicy` or `/sbin/.se` or `/dev/.se` +- Patch `init` or `libselinux.so` to force the system to load the patched policies +- Inject magisk services into `init.rc` +- Execute the original `init` to continue the boot process ### post-fs-data -This triggers on `post-fs-data` when `/data` is properly decrypted (if required) and mounted. The daemon `magiskd` will be launched, post-fs-data scripts are executed, and module files are magic mounted. + +This triggers on `post-fs-data` when `/data` is decrypted and mounted. The daemon `magiskd` will be launched, post-fs-data scripts are executed, and module files are magic mounted. ### late_start -Later in the booting process, the class `late_start` will be triggered, and Magisk "service" mode will be started. In this mode, service scripts are executed, and it will try to install Magisk Manager if it doesn't exist. + +Later in the booting process, the class `late_start` will be triggered, and Magisk "service" mode will be started. In this mode, service scripts are executed. ## Resetprop + Usually, system properties are designed to only be updated by `init` and read-only to non-root processes. With root you can change properties by sending requests to `property_service` (hosted by `init`) using commands such as `setprop`, but changing read-only props (props that start with `ro.` like `ro.build.product`) and deleting properties are still prohibited. `resetprop` is implemented by distilling out the source code related to system properties from AOSP and patched to allow direct modification to property area, or `prop_area`, bypassing the need to go through `property_service`. Since we are bypassing `property_service`, there are a few caveats: @@ -99,16 +115,21 @@ Usually, system properties are designed to only be updated by `init` and read-on - persist properties (props that starts with `persist.`, like `persist.sys.usb.config`) are stored in both `prop_area` and `/data/property`. By default, deleting props will **NOT** remove it from persistent storage, meaning the property will be restored after the next reboot; reading props will **NOT** read from persistent storage, as this is the behavior of `getprop`. With the flag `-p`, deleting props will remove the prop in **BOTH** `prop_area` and `/data/property`, and reading props will be read from **BOTH** `prop_area` and persistent storage. ## Magic Mount -I will skip the details in the actual implementation and algorithm of Magic Mount, but you can always directly dive into the source code if interested. (`bootstages.cpp`) -Even though the mounting logic is pretty complicated, the final result of Magic Mount is actually pretty simple. For each module, the folder `$MODPATH/system` will be recursively merged into the real `/system`; that is: existing files in the real system will be replaced by the one in modules' system, and new files in modules' system will be added to the real system. +The details of the actual implementation and algorithm of Magic Mount is omitted here, please directly dive into the source code if interested (`core/module.cpp`). + +Even though the mounting logic is very complicated, the final result of Magic Mount is actually pretty simple. For each module, the folder `$MODPATH/system` will be recursively merged into the real `/system`; that is: existing files in the real system will be replaced by the one in modules' system, and new files in modules' system will be added to the real system. There is one additional trick you can use: if you place an empty file named `.replace` in any of the folders in a module's system, instead of merging the contents, that folder will directly replace the one in the real system. This will be very handy in some cases, for example swapping out a system app. If you want to replace files in `/vendor` or `/product`, please place them under `$MODPATH/system/vendor` or `$MODPATH/system/product`. Magisk will transparently handle both cases, whether vendor or product is a separate partition or not. -## Miscellaneous -Here are some tidbits in Magisk but unable to be categorized into any sections: +## SELinux Policies -- Socket name randomization: when you call `su`, `magiskhide`, and some commands in `magisk`, it connects to the magisk daemon `magiskd` running in the background. The connections are established through an abstract Unix socket. Any process can go through all active Unix sockets and see if the specifc name used by Magisk is in the list to determine whether `magiskd` is running. Starting from v15.4, the abstract name used in `magiskd` and `magisklogd` are randomized by `magiskinit` on each boot. -- Sevice name randomization: each service started up by `init` will be recorded. Some apps will detect the name of magisk boot services to determine whether Magisk is installed. Starting from v17.2, the service name assigned in `init.magisk.rc` is randomized by `magiskinit`. +Magisk will patch the stock `sepolicy` to make sure root and Magisk operations can be done in a safe and secure way. The new domain `magisk` is effectively permissive, which is what `magiskd` and all root shell will run in. `magisk_file` is a new file type that is setup to be allowed to be accessed by every domain (unrestricted file context). + +Before Android 8.0, all allowed su client domains are allowed to directly connect to `magiskd` and establish connection with the daemon to get a remote root shell. Magisk also have to relax some `ioctl` operations so root shells can function properly. + +After Android 8.0, to reduce relaxation of rules in Android's sandbox, a new SELinux model is deployed. The `magisk` binary is labelled with `magisk_exec` file type, and processes running as allowed su client domains executing the `magisk` binary (this includes the `su` command) will transit to `magisk_client` by using a `type_transition` rule. Rules strictly restrict that only `magisk` domain processes are allowed to attribute files to `magisk_exec`. Direct connection to sockets of `magiskd` are not allowed; the only way to access the daemon is through a `magisk_client` process. These changes allow us to keep the sandbox intact, and keep Magisk specific rules separated from the rest of the policies. + +The full set of rules can be found in `magiskpolicy/rules.cpp`. diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 000000000..deff3a235 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,11 @@ +# Frequently Asked Questions + +### Q: Why is X app detecting root? + +Manually enable MagiskHide in settings (MagiskHide is no longer enabled by default). Also, there are known methods to detect Magisk, so your mileage may vary. + +### Q: I installed a module and it bootlooped my device. Help! + +If you have USB debugging enabled in developer options, connect your phone to the PC. If your device is detected (check by `adb devices`), enter ADB shell and run the command `magisk --remove-modules`. This will remove all your modules and automatically reboot the device. + +If unfortunately you do not have USB debugging enabled, reboot into Safe Mode. Most modern Android devices support pressing a special key combo at boot to enter Safe Mode as an emergency option. Magisk will detect Safe Mode being activated, and all modules will be disabled. Then reboot back to normal mode (the module disable state persists) and manage your modules through Magisk Manager. diff --git a/docs/guides.md b/docs/guides.md index 41bf050f3..47d34f0b4 100644 --- a/docs/guides.md +++ b/docs/guides.md @@ -1,5 +1,18 @@ # Developer Guides +## BusyBox +Magisk ships with a feature complete BusyBox binary (including full SELinux support). The executable is located at `/data/adb/magisk/busybox`. Magisk's BusyBox supports runtime toggle-able "ASH Standalone Shell Mode". What this standalone mode means is that when running in the `ash` shell of BusyBox, every single command will directly use the applet within BusyBox, regardless of what is set as `PATH`. For example, commands like `ls`, `rm`, `chmod` will **NOT** use what is in `PATH` (in the case of Android by default it will be `/system/bin/ls`, `/system/bin/rm`, and `/system/bin/chmod` respectively), but will instead directly call internal BusyBox applets. This makes sure that scripts always run in a predictable environment and always have the full suite of commands no matter which Android version it is running on. To force a command *not* to use BusyBox, you have to call the executable with full paths. + +Every single shell script running in the context of Magisk will be executed in BusyBox's `ash` shell with standalone mode enabled. For what is relevant to 3rd party developers, this includes all boot scripts and module installation scripts. + +For those who want to use this "Standalone Mode" feature outside of Magisk, there are 2 ways to enable it: + +1. Set environment variable `ASH_STANDALONE` to `1`
Example: `ASH_STANDALONE=1 /data/adb/magisk/busybox sh