Commit Graph

130 Commits

Author SHA1 Message Date
topjohnwu
a5d7c41d20 Support Safe Mode detection
When detecting device is booting as Safe Mode, disable all modules and
MagiskHide and skip all operations. The only thing that'll be available
in this state is root (Magisk Manager will also be disabled by system).

Since the next normal boot will also have all modules disabled, this can
be used to rescue a device in the case when a rogue module causes
bootloop and no custom recovery is available (or recoveries without
the ability to decrypt data).
2020-05-08 00:45:11 -07:00
topjohnwu
232ae2a189 Update resetprop to partially use system impl 2020-05-07 23:54:00 -07:00
topjohnwu
aa8b23105f Modernize resetprop with fancy C++ 2020-05-07 06:08:30 -07:00
topjohnwu
5fd574a14f Fix --remove-modules command 2020-04-30 01:27:48 -07:00
topjohnwu
69a9d7485b Support injecting magisk bins 2020-04-18 05:15:59 -07:00
topjohnwu
a73e7e9f99 Introduce new module mount implementation
Rewrite the whole module mounting logic from scratch.
Even the algorithm is different compared to the old one.

This new design focuses on a few key points:
- Modular: Custom nodes can be injected into the mount tree.
  It's the main reason for starting the rewrite (needed for Android 11)
- Efficient: Compared to the existing implementation, this is the most
  efficient (both in terms of computation and memory usage) design I
  currently can come up with.
- Accurate: The old mounting logic relies on handling specifically every
  edge case I can think of. During this rewrite I actually found some
  cases that the old design does not handle properly. This new design is
  architected in a way (node types and its rankings) that it should
  handle edge cases all by itself when constructing mount trees.
2020-04-18 02:00:48 -07:00
topjohnwu
e0a281583d Preparation for dynamic tmpfs path 2020-04-12 05:34:56 -07:00
topjohnwu
ba7cb47383 Make version reporting consistent 2020-03-23 01:17:13 -07:00
topjohnwu
cf54cad3ce deleteprop -> delprop 2020-03-09 02:05:24 -07:00
topjohnwu
a0998009c1 Small native code reorganization 2020-03-09 01:50:30 -07:00
topjohnwu
6180558068 Add support for genfscon sepolicy rules
Close #2367
2020-02-02 01:16:42 +08:00
topjohnwu
b39f407596 Load libsqlite dynamically 2020-01-11 03:20:59 +08:00
osm0sis
615ad0cc5a core: remove remaining legacy workarounds/leftovers 2020-01-10 23:31:43 +08:00
topjohnwu
7668e45890 Cleanup legacy code 2019-12-17 17:15:31 -05:00
topjohnwu
695c8bc5d0 Detect package name for copying binaries
Close #2152
2019-12-17 16:38:12 -05:00
topjohnwu
490e6a6f23 Add new API to load sepolicy rule file 2019-12-09 04:14:30 -05:00
topjohnwu
25c557248c Use ContentProvider call method for communication
Previously, we use either BroadcastReceivers or Activities to receive
messages from our native daemon, but both have their own downsides.
Some OEMs blocks broadcasts if the app is not running in the background,
regardless of who the caller is. Activities on the other hand, despite
working 100% of the time, will steal the focus of the current foreground
app, even though we are just doing some logging and showing a toast.
In addition, since stubs for hiding Magisk Manager is introduced, our
only communication method is left with the broadcast option, as
only broadcasting allows targeting a specific package name, not a
component name (which will be obfuscated in the case of stubs).

To make sure root requests will work on all devices, Magisk had to do
some experiments every boot to test whether broadcast is deliverable or
not. This makes the whole thing even more complicated then ever.

So lets take a look at another kind of component in Android apps:
ContentProviders. It is a vital part of Android's ecosystem, and as far
as I know no OEMs will block requests to ContentProviders (or else
tons of functionality will break catastrophically). Starting at API 11,
the system supports calling a specific method in ContentProviders,
optionally sending extra data along with the method call. This is
perfect for the native daemon to start a communication with Magisk
Manager. Another cool thing is that we no longer need to know the
component name of the reciever, as ContentProviders identify themselves
with an "authority" name, which in Magisk Manager's case is tied to the
package name. We already have a mechanism to keep track of our current
manager package name, so this works out of the box.

So yay! No more flaky broadcast tests, no more stupid OEMs blocking
broadcasts for some bizzare reasons. This method should in theory
work on almost all devices and situations.
2019-11-04 14:32:28 -05:00
topjohnwu
8277896ca1 Make sure uninstall.sh is executed on remove 2019-11-01 03:07:12 -04:00
topjohnwu
0f74e89b44 Introduce component agnostic communication
Usually, the communication between native and the app is done via
sending intents to either broadcast or activity. These communication
channels are for launching root requests dialogs, sending root request
notifications (the toast you see when an app gained root access), and
root request logging.

Sending intents by am (activity manager) usually requires specifying
the component name in the format of <pkg>/<class name>. This means parts
of Magisk Manager cannot be randomized or else the native daemon is
unable to know where to send data to the app.

On modern Android (not sure which API is it introduced), it is possible
to send broadcasts to a package, not a specific component. Which
component will receive the intent depends on the intent filter declared
in AndroidManifest.xml. Since we already have a mechanism in native code
to keep track of the package name of Magisk Manager, this makes it
perfect to pass intents to Magisk Manager that have components being
randomly obfuscated (stub APKs).

There are a few caveats though. Although this broadcasting method works
perfectly fine on AOSP and most systems, there are OEMs out there
shipping ROMs blocking broadcasts unexpectedly. In order to make sure
Magisk works in all kinds of scenarios, we run actual tests every boot
to determine which communication method should be used.

We have 3 methods in total, ordered in preference:
1. Broadcasting to a package
2. Broadcasting to a specific component
3. Starting a specific activity component

Method 3 will always work on any device, but the downside is anytime
a communication happens, Magisk Manager will steal foreground focus
regardless of whether UI is drawn. Method 1 is the only way to support
obfuscated stub APKs. The communication test will test method 1 and 2,
and if Magisk Manager is able to receive the messages, it will then
update the daemon configuration to use whichever is preferable. If none
of the broadcasts can be delivered, then the fallback method 3 will be
used.
2019-10-21 13:59:04 -04:00
topjohnwu
e31e687602 Allow ADB shell to remove modules and reboot 2019-09-13 03:14:21 -04:00
topjohnwu
736729f5ef Maintain a list of pre-init mounts
Keep track of everything to unmount
2019-07-16 23:54:52 -07:00
topjohnwu
7ba8202af5 Introduce new root overlay system 2019-07-16 01:08:28 -07:00
topjohnwu
a462435f2f Load custom sepolicy 2019-06-25 21:34:02 -07:00
topjohnwu
4fcdcd9a8a Detect UID from data directories 2019-06-03 23:32:49 -07:00
topjohnwu
80cd85b061 Try to use broadcast for su logging and notify
In commit 8d4c407, native Magisk always launches an activity for
communicating with Magisk Manager. While this works extremely well,
since it also workaround stupid OEMs that blocks broadcasts, it has a
problem: launching an activity will claim the focus of the device,
which could be super annoying in some circumstances.

This commit adds a new feature to run a broadcast test on boot complete.
If Magisk Manager successfully receives the broadcast, it will toggle
a setting in magiskd so all future su loggings and notifies will always
use broadcasts instead of launching activities.

Fix #1412
2019-05-13 02:01:10 -07:00
topjohnwu
003e44fb84 Remove requirement to use early-init daemon
We used to construct /sbin tmpfs overlay in early-init stage after
SELinux is properly initialized. However the way it is implemented
(forking daemon from magiskinit with complicated file waiting triggers)
is extremely complicated and error prone.

This commit moves the construction of the sbin overlay to pre-init
stage. The catch is that since SELinux is not present at that point,
proper selabel has to be reconstructed afterwards. Some additional
SEPolicy rules are added to make sure init can access magisk binaries,
and the secontext relabeling task is assigned to the main Magisk daemon.
2019-04-24 00:13:48 -04:00
topjohnwu
dab32e1599 Use our own device nodes for mirrors 2019-04-08 01:40:04 -04:00
topjohnwu
86789a8694 Add logging in magiskinit 2019-04-04 00:26:16 -04:00
topjohnwu
a385e5cd92 Use wrapper script on system with APEX
Thanks to moving libandroidicu.so to APEX runtime linker namespace,
we need a wrapper to link against libsqlite.so on Q
2019-04-03 17:25:47 -04:00
topjohnwu
df4161ffcc Reboot to recovery when running as recovery 2019-03-30 06:49:29 -04:00
topjohnwu
8de03eef3f Allow modules to have custom uninstaller script 2019-03-23 03:50:55 -04:00
topjohnwu
c0447009db Allow entrypoint for rootfs construction simulation 2019-03-16 04:45:56 -04:00
topjohnwu
f0240b1f06 Support Android Q new split sepolicy setup 2019-03-15 06:17:37 -04:00
topjohnwu
a1b5185ecb Make sure rootfs file selabels are correct
Android Q init assumes rootfs to always be on EXT4 images, thus
never runs restorecon on the whole root directory. This is an issue
because some folders in rootfs were set with special selabels in
the system partition, but when copying over to initramfs by magiskinit,
these labels will not be preserved.

So the solution is to relabel the files in rootfs with the original
context right? Yes, but rootfs does not allow security xattr to be set
on files before the kernel SELinux initializes with genfs_contexts.
We have to load our sepolicy to the kernel before we clone the root
directory from system partition, which we will also restore the selabel
in the meantime.

Unfortunately this means that for each reboot, the exact same policy
will be loaded to the kernel twice: once in magiskinit so we can label
rootfs properly, and once by the original init, which is part of the
boot procedure. There is no easy way to prevent init from loading
sepolicy, as init will refuse to continue if policy loading has failed.
2019-03-14 22:27:29 -04:00
topjohnwu
081074ad9d Better zygote process detection 2019-03-08 23:53:53 -05:00
topjohnwu
0204d05316 Remove Zygote notifier
Temporary trigger process scan on packages.xml updates, will find better methods
2019-03-08 03:35:17 -05:00
topjohnwu
82c864d57e Make zygote notifier more reliable 2019-03-06 18:22:04 -05:00
topjohnwu
370015a853 Modernize database code (again) 2019-03-06 08:16:12 -05:00
topjohnwu
04ef1e6405 Make parse prop file a util function 2019-03-05 20:27:09 -05:00
topjohnwu
b278d07b05 Switch to Zygote ptrace-ing
No matter if we use the old, buggy, error prone am_proc_start monitoring,
or the new APK inotify method, both methods rely on MagiskHide 'reacting'
fast enough to hijack the process before any detection has been done.

However, this is not reliable and practical. There are apps that utilize
native libraries to start detects and register SIGCONT signal handlers
to mitigate all existing MagiskHide process monitoring mechanism. So
our only solution is to hijack an app BEFORE it is started.

All Android apps' process is forked from zygote, so it is easily the
target to be monitored. All forks will be notified, and subsequent
thread spawning (Android apps are heaviliy multithreaded) from children
are also closely monitored to find the earliest possible point to
identify what the process will eventually be (before am_proc_bound).

ptrace is extremely complicated and very difficult to get right. The
current code is heaviliy tested on a stock Android 9.0 Pixel system,
so in theory it should work fine on most devices, but more tests and
potentially fixes are expected to follow this commit.
2019-03-05 20:23:27 -05:00
topjohnwu
6c3896079d Add zygote server notifier 2019-03-05 20:23:27 -05:00
topjohnwu
8032bd0bac Introduce /data mirror
Since we switched to imageless Magisk, module files are directly
stored in /data. However, /data is mounted with nosuid, which also
prevents SELinux typetransition to work (auto transition from one
domain to another when executing files with specific context).
This could cause serious issues when we are replacing system critical
components (e.g. app_process for Xposed), because most of them
are daemons that run in special process domains.

This commit introduced /data mirror. Using similar mirroring technique
we used for system and vendor, we mount another mirror that mounts
/data without nosuid flag. All module files are then mounted from this
mirror mountpoint instead of directly from /data.

Close #1080
2019-02-25 06:13:42 -05:00
topjohnwu
2f1b0fe57f Remove unused scripts 2019-02-18 03:08:40 -05:00
topjohnwu
f4f2274c60 Auto reinstall system apps on hide list
Since we are parsing through /data/app/ to find target APKs for
monitoring, system apps will not be covered in this case.
Automatically reinstall system apps as if they received an update
and refresh the monitor target after it's done.

As a bonus, use RAII idioms for locking pthread_mutex_t.
2019-02-16 02:24:35 -05:00
topjohnwu
19ee189468 Separate scripting code 2019-02-15 20:45:05 -05:00
topjohnwu
a19c7215d2 Better nice name 2019-02-15 04:31:39 -05:00
Park Ju Hyung
7384d2d330 Completely rework MagiskHide
Previous MagiskHide detects new app launches via listening through logcat
and filtering launch info messages.

This is extremely inefficient and prone to cause multiple issues both
theoratically and practically.

Rework this by using inotify to detect open() syscalls to target APKs.

This also solves issues related to Zygote-forked caching mechanisms such as
OnePlus OxygenOS' embryo.

Signed-off-by: Park Ju Hyung <qkrwngud825@gmail.com>
2019-02-12 23:39:57 -05:00
topjohnwu
ed027ec3ee Refactor build flags 2019-02-12 05:17:02 -05:00
topjohnwu
ed4df87b57 Remove imgtool 2019-02-12 02:44:46 -05:00
topjohnwu
1321f097b8 Remove usage of magisk.img
Mounting ext4 images causes tons of issues, such as unmountable with broken F2FS drivers.
Resizing is also very complicated and does not work properly on all devices.
Each step in either measuring free space, resizing, and shrinking the image is a
point of failure, and either step's failure could cause the module system completely broken.

The new method is to directly store modules into /data/adb/modules, and for module installation
on boot /data/adb/modules_update. Several compatibility layers has been done: the new path is
bind mounted to the old path (/sbin/.magisk/img), and the helper functions in util_functions.sh
will now transparently make existing modules install to the new location without any changes.

MagiskHide is also updated to unmount module files stored in this new location.
2019-02-12 02:14:57 -05:00