Compare commits

..

225 Commits
v14.5 ... v16.6

Author SHA1 Message Date
topjohnwu
375cd0e42b Bump Magisk Manager version 2018-07-08 06:56:47 +08:00
topjohnwu
3934821436 Don't clean output 2018-07-08 00:02:18 +08:00
topjohnwu
c3b473e4bc Fix get_outfd in embedded mode 2018-07-07 17:48:05 +08:00
topjohnwu
7ed2c077de Support deodexed ROM on Oreo 2018-07-07 01:37:04 +08:00
topjohnwu
1283167595 Maintain our own set of loop devices 2018-07-07 01:32:58 +08:00
topjohnwu
23c2e22910 Update image functions 2018-07-06 22:04:06 +08:00
topjohnwu
f44b2dbd45 Rename log_monitor -> log_daemon 2018-07-06 07:57:18 +08:00
topjohnwu
46ee2c3f4e Improve handshake between the 2 daemons 2018-07-06 07:51:17 +08:00
topjohnwu
5d5ec08566 Test the log buffers before running command 2018-07-06 07:32:16 +08:00
topjohnwu
c3a6179a21 Update scripts 2018-07-05 17:29:13 +08:00
topjohnwu
ef175e3cbe Open log file in append mode 2018-07-04 23:46:40 +08:00
topjohnwu
4de51d93ef Tweak info when installing 2018-07-04 23:46:16 +08:00
topjohnwu
e7a2144def Optimize magiskhide to work with the log daemon 2018-07-04 01:52:23 +08:00
topjohnwu
52a2c6958b Optimize log daemon 2018-07-03 22:25:39 +08:00
topjohnwu
70243d7a47 Add fallback to parse block from fstabs 2018-07-03 18:28:44 +08:00
topjohnwu
b5b8c4b725 First find blocks by-name, then fallback to parsing sysfs 2018-07-03 02:57:57 +08:00
topjohnwu
6c4d81b1e9 Invincible mode implemented in magisklogd 2018-07-03 01:38:19 +08:00
topjohnwu
c88dc8795b Single log file 2018-07-02 22:48:26 +08:00
topjohnwu
a8030c39b1 Separate logging into its own daemon 2018-07-02 22:11:28 +08:00
topjohnwu
7243b9e72f Improve log_monitor implementation 2018-07-01 18:18:12 +08:00
topjohnwu
d149af9628 Fix bootloop when upgrading from older Magisk 2018-07-01 14:58:31 +08:00
topjohnwu
c0ac2d540b Update build.py to build Magisk Manager
Sorry I forgot to commit this change :p
2018-06-27 16:26:48 +08:00
topjohnwu
528634d755 Remove unused code 2018-06-27 06:04:16 +08:00
topjohnwu
3283439fd4 New uninstaller 2018-06-27 06:00:01 +08:00
topjohnwu
c8216f9bc5 Fix uninstaller 2018-06-26 22:41:03 +08:00
topjohnwu
e579f314a6 Fix MagiskSU force denying root access 2018-06-26 18:46:18 +08:00
Jat
d1a7372bd2 fix a bug when $ABILONG is arm64-v8a 2018-06-26 05:03:07 +08:00
topjohnwu
e837bdc8ad Update BusyBox
BusyBox is unable to run properly on non-root applications due to seccomp introduced in Android 8.0.
The SDK-21 libc.a has system call wrappers that uses the system calls on the whitelist, so binaries compiled with the updated libc can work properly.
2018-06-25 16:11:31 +08:00
topjohnwu
7265450e2e Precise free space calculation for magisk.img
1. Introduce new applet: imgtool for better separation from the main program
2. Actually mount the image and check statvfs for free space in the image

This shall eliminate any possible module installation failure from image resizing issues.
2018-06-22 06:18:06 +08:00
topjohnwu
058dbc9f9e Add more indentation 2018-06-21 18:11:43 +08:00
topjohnwu
daf9b019c6 More elaborate bb_setup 2018-06-21 16:39:10 +08:00
topjohnwu
14eebd582f Source addon.d script from data 2018-06-21 11:54:21 +08:00
topjohnwu
9a8eeacee8 Fix output of addon.d, and add support for addon.d-v2 2018-06-21 10:53:49 +08:00
topjohnwu
45b0bf5bc5 Remove unnecessary variable 2018-06-21 01:48:46 +08:00
topjohnwu
88db822c43 Get device blocks with sysfs 2018-06-21 01:37:08 +08:00
Sheryl Hohman
fbf3588fdf fix typos 2018-06-19 14:28:09 -07:00
osm0sis
a82ef6bd35 MagiskHide: add ro.boot.vbmeta.device_state=locked 2018-06-19 14:23:06 -07:00
npes87184
312466aaf8 Prevent setting zero over than bound
The &cmd will return a pointer which point to a pointer of cmdline.
It is a memory address which is usually 8 bytes in 64 bits machine.

However, the struct cmdline is 4 bytes. This will cause setting zero
beyond the bound.

Below is a simple example to show the differentiation:

struct cmdline {
        char skip_initramfs;
        char slot[3];
};

static void parse_cmdline(struct cmdline *cmd)
{
        printf("%lu\n", sizeof(*cmd)); /* 4 */
        printf("%lu\n", sizeof(&cmd)); /* 8 */
}

int main()
{
        struct cmdline cmd;
        parse_cmdline(&cmd);
        return 0;
}

This patch prevents this.

Signed-off-by: npes87184 <npes87184@gmail.com>
2018-06-19 14:22:11 -07:00
John Wu
c0ca99f4b4 Make sure APK exists before signing AVB 1.0
Check all possible APK locations before actually running the verification
2018-06-19 14:19:38 -07:00
XiNGRZ
196f15d240 Fix survival script for AVB 1.0 signed boot image 2018-06-19 14:19:38 -07:00
topjohnwu
bfddef2671 Bump Magisk Manager 2018-06-20 04:55:34 +08:00
topjohnwu
44395e8ff0 Fix root loss issue when MagiskHide is enabled
In previous implementations, proc_monitor checks whether the mount namespace of an app is actually separated from zygote using a list generated at startup.
However, for some unknown reason, some devices (e.g. Samsung) has multiple zygote servers running in the background.
This means that app processes spawned from the unlisted zygotes are not checked whether the separation is done or not, causing MagiskHide unmount stuffs in the namespace of zygote, and since zygote is the "mother" of all apps, all apps will no longer have root access.

Since I'm not sure of the reason why multiple zygotes exists, so instead of checking the namespace against a list, compare the current namespace against the parent process's namespace.
This will make sure the namespace is NOT the same as the parent process, which is supposed to be the zygote server.
2018-06-20 04:55:34 +08:00
topjohnwu
835ece5469 Update default flag logic, fix S9/S9+ DTB patches 2018-06-18 01:40:56 +08:00
topjohnwu
d93fc67a75 Improve detecting device status 2018-06-17 17:59:24 +08:00
topjohnwu
838f3cc01e Simplify hiding conditions 2018-06-17 05:16:52 +08:00
topjohnwu
4d5841332a Change to applet name to prevent showing magisk.bin 2018-06-17 01:47:55 +08:00
topjohnwu
9b41976252 Preserve last log 2018-06-17 01:38:58 +08:00
topjohnwu
d08fd0561a Remove invincible mode 2018-06-17 01:28:29 +08:00
topjohnwu
a6958ac139 Fix adbd on GSIs 2018-06-17 01:25:27 +08:00
topjohnwu
d7d76f54cc Install stub APK when needed 2018-06-14 05:09:54 +08:00
topjohnwu
970a2e87b3 Bundle in stub APK into magiskinit 2018-06-14 02:54:38 +08:00
topjohnwu
cabaae8403 MagiskSU improvements 2018-06-14 02:54:33 +08:00
topjohnwu
f2064a84ed Move database logic outside of MagiskSU 2018-06-13 04:34:05 +08:00
topjohnwu
6db27c7758 Allow file constructed JarMap getOutputStream 2018-06-12 02:57:46 +08:00
topjohnwu
3f83919e09 Fix bootloops when flashing Magisk after data wipe on FBE devices 2018-06-11 02:26:18 +08:00
topjohnwu
72a5b83544 Support patching dtb placed in extra section (S9/S9+) 2018-06-10 20:36:18 +08:00
topjohnwu
d2e8ecc646 Fix error return code when patching dtb 2018-06-10 20:36:18 +08:00
topjohnwu
30eb4074cb Update binary dump method 2018-06-10 16:55:00 +08:00
Jason A. Donenfeld
9929e7d8e8 Remove update file on boot
It's not important to check the return value of unlink(2) or even verify
that the file exists. If this code is running, it means the system has
rebooted, and thus the update file, if any, should be removed so that
MagiskManager doesn't keep displaying the same message. We also handle
this before we handle "disable" so that disabled modules don't keep
requesting a reboot to update.
2018-06-10 03:02:56 +08:00
Alexandre Boeglin
f6ee252572 magiskboot: Check dtb header content to avoid false positives 2018-06-10 03:02:13 +08:00
topjohnwu
90d218ebc8 Update SafetyNet extension implementation 2018-06-10 02:35:03 +08:00
topjohnwu
b0a5dbb4c2 Push to SDK 28 2018-06-09 15:47:16 +08:00
topjohnwu
0abdfda5a2 Fix busybox issues 2018-06-09 15:45:56 +08:00
msdx321
a7ceb04cb7 Fix early mount on S9/S9+
Unlike other common OEMs, Samsung use uppper case partition name.

e.g: /dev/block/platform/11120000.ufs/by-name/SYSTEM

This will cause setup_block() fails to find a match partition.
Thus, we should use strcasecmp instead of strcmp.

Signed-off-by: msdx321 <msdx321@gmail.com>
2018-06-03 17:02:30 +08:00
topjohnwu
274efb49e7 Fix modules installation error 2018-06-03 17:01:10 +08:00
Andrew Gunnerson
b3cd83bbca magiskinit: Only unmount /system and /vendor if it was mounted by magisk
This fixes an issue where if /system or /vendor was already mounted
prior to magiskinit running, then they would get unmounted.

Signed-off-by: Andrew Gunnerson <andrewgunnerson@gmail.com>
2018-06-03 15:25:38 +08:00
topjohnwu
b8bd83ba05 Update busybox to 1.28.4 2018-06-03 15:17:31 +08:00
topjohnwu
34dcf49fbc Update restorecon implementation 2018-06-03 14:43:03 +08:00
topjohnwu
ef2f8d485b Add key alias option to config.prop 2018-05-27 14:59:08 +08:00
topjohnwu
9fb9212b0a Add stub apk support 2018-05-27 14:55:24 +08:00
topjohnwu
f31a24b16d Update setenv functions (also fixes uninstalling) 2018-05-26 23:14:09 +08:00
topjohnwu
b436bce565 Minor optimizations 2018-05-26 21:25:59 +08:00
topjohnwu
886286a819 Disable config ondemand when using Gradle > 4.6 2018-05-26 17:35:02 +08:00
topjohnwu
6d93831488 Fix zipsigner when using external keys 2018-05-20 15:24:47 +08:00
topjohnwu
bcdadc6581 Update busybox 2018-05-20 02:34:06 +08:00
topjohnwu
36448191b7 Fix applet invocation 2018-05-20 00:49:48 +08:00
topjohnwu
be5be108c3 Fix build all 2018-05-19 16:53:00 +08:00
topjohnwu
c9ca42aaa9 Support fixing Magisk environment 2018-05-13 18:14:44 +08:00
topjohnwu
c0e2f44092 Use wrapper script to prevent crazy LD_XXX flags 2018-05-13 14:32:21 +08:00
topjohnwu
1412fcbb22 Update sepolicy rules 2018-05-13 14:30:41 +08:00
topjohnwu
9b445d89a1 Add extract feature to update-binary 2018-05-13 14:26:28 +08:00
topjohnwu
c3c78428c4 Use lower API level for static binaries 2018-05-13 05:22:46 +08:00
topjohnwu
c6d2bf577f Massive building system rewrite 2018-05-13 03:04:40 +08:00
topjohnwu
25703c1750 Do not force LD_LIBRARY_PATH in recovery 2018-05-06 01:49:01 +08:00
topjohnwu
3a9a3ed184 Bump Magisk Manager version 2018-04-29 15:20:41 +08:00
topjohnwu
88fae36b8a Hide sub-services of apps for hiding
Close #383
2018-04-29 15:10:35 +08:00
topjohnwu
fc9d4034a9 Fix installation in custom recoveries 2018-04-29 14:04:18 +08:00
topjohnwu
cecc0b932d Remove some traits 2018-04-29 12:34:36 +08:00
topjohnwu
0faed7159c Add invincible mode back 2018-04-29 12:17:28 +08:00
topjohnwu
fb491cfdcf Add Protobuf support to resetprop 2018-04-29 01:20:48 +08:00
topjohnwu
fc706dcb40 Bump busybox to 1.28.3 2018-04-22 14:28:16 +08:00
topjohnwu
a2c1b024f3 Use 32-bit binaries only 2018-04-22 14:13:27 +08:00
Frieder Bluemle
3d865394d7 Update Gradle wrapper to 4.6 2018-04-22 03:09:02 +08:00
topjohnwu
76ef1d0d86 Cleanup sepolicy rules 2018-04-22 03:06:40 +08:00
topjohnwu
9484ec0c17 Massive refactoring
Remove post-fs mode
2018-04-22 02:16:56 +08:00
topjohnwu
614c552e55 Improve daemon startup 2018-04-21 20:16:59 +08:00
topjohnwu
7db3d84ba2 Forgot to update the default file secontext 2018-04-21 13:20:42 +08:00
topjohnwu
87f6018468 Massive sepolicy refactor 2018-04-15 03:18:18 +08:00
topjohnwu
9194c50590 Update build.gradle 2018-04-15 03:17:28 +08:00
topjohnwu
7ff45974c6 Upstream selinux 2018-04-14 17:18:29 +08:00
topjohnwu
2533a4fc4a Fix APK installation on Android P 2018-04-08 03:22:22 +08:00
topjohnwu
42284c5efb Test logcat instead of checking logd 2018-04-08 02:12:40 +08:00
topjohnwu
7d7686da33 Update Magisk Manager 2018-03-28 15:23:55 +08:00
topjohnwu
65e455ef0b Update Android gradle plugin 2018-03-28 02:43:03 +08:00
topjohnwu
ac05e2f2e2 Fix tail size calculation
Close #381
2018-03-27 00:45:18 +08:00
topjohnwu
787f7b3035 Remove backwards compatibility symlinks
These links cause magiskhide unable to work ideally and add complications. I think I gave enough time for migration
2018-03-27 00:35:59 +08:00
topjohnwu
31bd642b80 Update to busybox 1.28.2 2018-03-26 22:12:04 +08:00
topjohnwu
f0bac6b154 Resetprop small refactor 2018-03-26 21:21:48 +08:00
topjohnwu
cc7e74ca11 Cleanup build.gradle 2018-03-26 03:53:06 +08:00
topjohnwu
e8a44646b8 Update Magisk Manager 2018-03-18 12:34:07 +08:00
topjohnwu
ae97d011ae Change MagiskHide state if logd is disabled 2018-03-18 12:17:10 +08:00
imswebra
1b7657a374 tips.md Grammar Fix 2018-03-18 12:16:57 +08:00
topjohnwu
5665e04014 Force using system binaries 2018-03-17 21:42:42 +08:00
topjohnwu
bb70385a42 Update Magisk Manager 2018-03-11 08:37:13 +08:00
topjohnwu
9855877b03 Update rules for Android P 2018-03-11 08:36:20 +08:00
topjohnwu
76c9188fae Android P renamed nonplat_properties 2018-03-11 02:53:57 +08:00
topjohnwu
e4e5269836 Android P have no make_ext4fs, use mke2fs as fallback 2018-03-11 02:52:24 +08:00
topjohnwu
9e737df534 Update high compression mode detection logic 2018-03-10 15:55:55 +08:00
Shaka Huang
0b3192c4d5 Check dtb even if kernel is not available
By the flow of unpacking boot image of Chrome OS there will be no kernel file but an dtb image. In that case the dtb image won’t be added when repacking boot image.

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2018-03-03 20:57:55 +08:00
Shaka Huang
968e6237bd Fix error parsing MTK boot.img
Should be copy & paste error:

1. boot->r_fmt should be re-checked instead of boot->k_fmt once MTK header was found in ramdisk.

2. ramdisk_size should be restored instead of kernel_size when uncompressed ramdisk was found.

3. Correct header of ramdisk

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2018-03-03 20:57:37 +08:00
worstperson
d780b5a0e4 Add support for the Nook Tablet, Acclaim
Also changed occurences of NOOK with NOOKHD
2018-03-03 20:55:44 +08:00
worstperson
3e48427eaf Add support for the new NOOK_MAGIC
The new cmdline value that's been in use since Marshmallow
2018-03-03 20:55:44 +08:00
worstperson
31360c34ed Set NOOK_PRE_HEADER_SZ from 0xFFFFF to 0x100000
All applicable Nook HD/HD+ roms are using this offset
2018-03-03 20:55:44 +08:00
topjohnwu
e9624e2304 Update submodules 2018-02-22 02:49:54 +08:00
topjohnwu
9c6e64f47d Workaround compiler optimization bug 2018-02-21 14:44:24 +08:00
topjohnwu
0afa601551 Fix F2FS manager crashing 2018-02-20 05:15:06 +08:00
topjohnwu
a94fa81195 Support non skip_initramfs device with slot suffix 2018-02-14 00:57:52 +08:00
topjohnwu
6119c24720 Bump Magisk Manager version 2018-02-13 08:04:47 +08:00
topjohnwu
7da205f4c8 Round sizes to nearest integer 2018-02-12 04:56:50 +08:00
topjohnwu
754fafcfe9 Check logd before logging 2018-02-12 02:48:15 +08:00
topjohnwu
bd7766b17e Prevent small memory leak 2018-02-11 21:55:57 +08:00
Andrew Gunnerson
70b7d73453 utils/cpio.c: Fix off-by-one error in cpio_vec_insert
Previously, if `cpio_vec_insert()` needed to replace a file and the file
already exists as the first entry, then a duplicate entry would get
created.

This fixes the bug I reported at:
https://forum.xda-developers.com/showpost.php?p=75449768&postcount=22647

Signed-off-by: Andrew Gunnerson <andrewgunnerson@gmail.com>
2018-02-11 18:50:42 +08:00
Andrew Gunnerson
5ad4702a5b utils/file.c: NULL terminate all files read into memory
Some functions, like `patch_init_rc()`, treat buffers read into memory
as a string instead of a byte buffer. Since the buffers weren't
NULL-terminated, this resulted in out-of-bounds reads and caused crashes
in certain conditions.

THis commit updates fd_full_read() to always NULL-terminate the buffers
so that they can be treated as strings when working with text files.

Signed-off-by: Andrew Gunnerson <andrewgunnerson@gmail.com>
2018-02-11 18:50:42 +08:00
topjohnwu
40b6fe03c2 Tweak enum 2018-02-11 18:50:42 +08:00
topjohnwu
49ecba2476 Obfuscate filenames to prevent detection
Because why not
2018-02-11 04:04:47 +08:00
topjohnwu
ebd509d92d Obfuscate socket name to prevent detection
Because why not
2018-02-11 03:59:54 +08:00
topjohnwu
7193374a7e Better Windows support 2018-02-10 19:54:58 +08:00
topjohnwu
6728445542 Support separate ramdisk images 2018-02-10 03:34:13 +08:00
topjohnwu
10ed299c78 Detect recovery on FBE devices with no DE access 2018-02-10 03:31:00 +08:00
topjohnwu
32b124913e Change busybox config 2018-02-06 05:52:25 +08:00
topjohnwu
599ae95251 Support moving files across filesystems 2018-02-02 04:47:16 +08:00
topjohnwu
d1be34c34a Support sepolicy_debug 2018-02-02 04:17:13 +08:00
topjohnwu
bc2cac90fe Hardlink files recursively 2018-02-02 03:22:38 +08:00
topjohnwu
28350e3ad9 Support Nook Green Loader 2018-01-30 05:56:59 +08:00
topjohnwu
f48e6c93b8 Support Tegra blobs 2018-01-30 05:20:18 +08:00
topjohnwu
7cfc24d68f Add DHTB header support 2018-01-29 22:16:02 +08:00
topjohnwu
a58d3ea04d Use libmincrypt 2018-01-29 15:34:05 +08:00
topjohnwu
dfee9954e0 Small refactor of magiskboot 2018-01-29 03:12:35 +08:00
topjohnwu
eed86c760f Add support to PXA devices
Close #340
2018-01-29 02:44:30 +08:00
topjohnwu
c471bb6f67 Update external sources 2018-01-29 02:41:39 +08:00
topjohnwu
518c2b0f95 Update README 2018-01-28 04:44:46 +08:00
topjohnwu
328fc44194 Rename module core to native 2018-01-27 09:11:28 +08:00
topjohnwu
b6f735a8f6 Rename module 2018-01-27 08:34:40 +08:00
topjohnwu
deae08fc4b Port zipadjust to Java 2018-01-27 08:25:34 +08:00
topjohnwu
c61135ee7b Embed testkeys into jar 2018-01-27 00:19:35 +08:00
topjohnwu
97cf15007f Update crypto 2018-01-23 05:06:34 +08:00
topjohnwu
e8302dfbe2 Update Magisk Manager 2018-01-13 06:28:22 +08:00
topjohnwu
558f95cf7e Improve APK installation and add logging 2018-01-13 06:28:07 +08:00
topjohnwu
18f6ead891 Fix alignment when boot image has head offset 2018-01-13 06:28:07 +08:00
topjohnwu
10bd25be52 Suppress harmless error logs 2018-01-12 00:23:38 +08:00
topjohnwu
65511845d2 Fix APK installation on some devices
Close #367. Android 6.0 and before doesn't like the new path
2018-01-11 20:57:05 +08:00
topjohnwu
1c743839ea Add MS_SILENT to xmount and cleanup function wraps 2018-01-11 03:06:20 +08:00
topjohnwu
bcae9dec41 Fix a bug when only one script will run 2018-01-11 02:48:15 +08:00
Shaka Huang
482c9af41f Fix segmentation fault
When both keepverity and keepforceencrypt are false, ‘e’ will be freed after removing ‘verity_key’ and segmentation fault might happened in strstr(e->filename, “fstab”)

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2018-01-11 02:08:52 +08:00
topjohnwu
2bf2e7461f Update diagram URL 2018-01-09 06:50:03 +08:00
topjohnwu
7d1082b1cb Fix magiskhide in graph 2018-01-09 06:48:58 +08:00
topjohnwu
0dbae83aec Update diagram URL 2018-01-09 06:08:54 +08:00
topjohnwu
f927c1b997 Update procedure diagram 2018-01-09 06:07:12 +08:00
topjohnwu
89ec7dad2b Update documentation to v15.2 2018-01-08 22:33:55 +08:00
topjohnwu
4fd61345af Happy New Year 2018-01-02 01:27:20 +08:00
topjohnwu
66cca24453 Samsung need more rules :) 2018-01-02 00:11:26 +08:00
topjohnwu
e733484fab Some devices don't like all log buffers 2018-01-01 23:58:13 +08:00
topjohnwu
e5c3183025 Update scripts 2018-01-01 16:46:28 +08:00
topjohnwu
930c82316a Slightly change logging style 2017-12-31 21:54:39 +08:00
Shaka Huang
3dc22db265 Support loading split sepolicy on non skip_initramfs devices
For certain device (e.g ZenFone 4 ZE554KL) there’s no sepolicy under rootfs and no a/b partition (implies no vendor partition) Magisk will failed to patch SELinux policy database and the system won’t boot up.

In order to cope with this configuration the status of loading policy db needs to be checked, once it failed we have to mount the system partition and do patch_sepolicy() again.

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2017-12-31 21:30:56 +08:00
topjohnwu
d8c51cb286 Update sepolicy handling 2017-12-31 19:32:04 +08:00
topjohnwu
2f79d0c3b3 Fix segfault while patching dtb 2017-12-31 19:30:56 +08:00
topjohnwu
d8bb3af06b Miscellaneous 2017-12-29 04:25:30 +08:00
topjohnwu
e139e8777b Fix faulty magiskboot ramdisk patch code 2017-12-29 04:25:03 +08:00
topjohnwu
d52d7cfbd9 Update magiskpolicy 2017-12-26 04:24:48 +08:00
topjohnwu
4f74a259e3 Update Magisk Manager 2017-12-26 04:00:01 +08:00
topjohnwu
74da6e1dc0 Support new 1500 template 2017-12-26 03:23:58 +08:00
topjohnwu
84ffdf0ed5 Eliminate a possbility to cause segfault 2017-12-25 05:21:40 +08:00
topjohnwu
022b18c8ce Properly detect /data status 2017-12-25 05:21:40 +08:00
topjohnwu
b92b1dcddb cil: Allow redeclare types[attributes] and disable neverallow 2017-12-25 05:21:40 +08:00
topjohnwu
1472dbb291 Add cache magisk image merging support 2017-12-22 16:10:38 +08:00
topjohnwu
d58a8dc868 Update Magisk Manager 2017-12-22 06:44:22 +08:00
topjohnwu
e94be0b70e Prevent creating 128M images
make_ext4fs will fail creating 128M ext4 images, LOL WTF? Change it to 132M to fix this issue
2017-12-22 02:39:44 +08:00
topjohnwu
f6ae7e1bf1 Allow su to work when manager uninstalled 2017-12-22 00:30:08 +08:00
topjohnwu
f7b4935677 Add recommend KEEPVERITY and KEEPFORCEENCRYPT flags 2017-12-21 15:42:03 +08:00
topjohnwu
a3c49de6a5 Refactor magiskboot 2017-12-21 03:36:18 +08:00
topjohnwu
e8dd1b292f Update snet 2017-12-19 15:51:01 +08:00
topjohnwu
d21264d01b Let magiskinit directly spawn new magisk_daemon process 2017-12-19 14:27:54 +08:00
topjohnwu
b0567eadfd Reduce effort and memory of log monitor 2017-12-18 18:17:37 +08:00
topjohnwu
5fc2058336 Show version code when report client 2017-12-18 16:00:44 +08:00
topjohnwu
d0567d29d2 Update su to match Linux's implementation 2017-12-18 15:46:18 +08:00
topjohnwu
4db0ad32f0 Fix install scripts 2017-12-18 03:08:53 +08:00
topjohnwu
d065040321 Fix magiskinit invincible mode and logcat monitor 2017-12-18 02:51:27 +08:00
topjohnwu
17f0fea3fc Fix unreleased resource in rootfs 2017-12-16 04:42:16 +08:00
topjohnwu
8ca1e43533 Move all /data files into /data/adb 2017-12-16 04:42:16 +08:00
topjohnwu
bd01c314dc Change database location 2017-12-12 03:04:55 +08:00
topjohnwu
e404476609 Fix logs on decrypted /data 2017-12-07 23:25:43 +08:00
topjohnwu
942c870981 Properly handle KEEPVERITY and HIGHCOMP 2017-12-07 04:20:27 +08:00
topjohnwu
baff9256c5 Dynamic patch verity and forceencrypt flag 2017-12-07 03:21:13 +08:00
topjohnwu
b4c0a255fc Separate pattern logic 2017-12-07 01:30:48 +08:00
topjohnwu
9f6a27c20d Add high compression ramdisk support 2017-12-06 12:51:16 +08:00
topjohnwu
742dc137ed More fail proof to magiskinit 2017-12-05 21:05:20 +08:00
topjohnwu
39a6bd33ce Fix critical bug 2017-12-05 05:32:15 +08:00
topjohnwu
4672a5fad6 Add cpio extract all feature 2017-12-05 03:32:37 +08:00
topjohnwu
e649b0a2df Update README.md 2017-12-04 22:59:29 +08:00
topjohnwu
fd8dbe3eff Greatly reduce Gradle sync time and frequency 2017-12-04 22:21:19 +08:00
topjohnwu
bb97cc594d Cleanup and small fixes 2017-12-04 18:05:07 +08:00
topjohnwu
70a322263e Fix Android Studio gradle sync 2017-12-04 15:32:18 +08:00
topjohnwu
c6f144d482 Update README.md 2017-12-04 15:21:06 +08:00
topjohnwu
3709489b3a Massive project restructure 2017-12-04 15:16:41 +08:00
topjohnwu
145ef32e28 Tidy up external 2017-12-04 03:37:00 +08:00
topjohnwu
2212800a23 Add symlink feature to cpio 2017-12-04 03:37:00 +08:00
topjohnwu
2e25431bb6 Generalize cpio functions 2017-12-04 03:37:00 +08:00
topjohnwu
32c8e7522f More precise logging configuration 2017-12-01 17:38:57 +08:00
topjohnwu
a5e4f3cc6b Separate cpio logic from MagiskBoot 2017-12-01 17:17:24 +08:00
topjohnwu
a30777bd9f Fix bug in compiling split cil 2017-12-01 03:33:25 +08:00
topjohnwu
e989195a68 Update magiskpolicy 2017-11-30 20:57:40 +08:00
topjohnwu
997d58932e Adjust daemon initialization 2017-11-28 04:43:46 +08:00
topjohnwu
b4015f877f New invincible implementation 2017-11-28 03:42:48 +08:00
topjohnwu
d15fff95b9 Use inotify to monitor files 2017-11-27 15:37:28 +08:00
160 changed files with 10915 additions and 5150 deletions

19
.gitignore vendored
View File

@@ -1,9 +1,20 @@
out/
obj/
libs/
out
*.zip
*.jks
*.apk
config.prop
# Manually dumped jars
snet/libs
# Built binaries
ziptools/zipadjust
native/out
# Android Studio / Gradle
*.iml
.gradle
/local.properties
/.idea
/build
/captures
.externalNativeBuild

37
.gitmodules vendored
View File

@@ -1,27 +1,30 @@
[submodule "jni/selinux"]
path = jni/external/selinux
[submodule "selinux"]
path = native/jni/external/selinux
url = https://github.com/topjohnwu/selinux.git
[submodule "jni/su"]
path = jni/su
[submodule "su"]
path = native/jni/su
url = https://github.com/topjohnwu/MagiskSU.git
[submodule "jni/magiskpolicy"]
path = jni/magiskpolicy
[submodule "magiskpolicy"]
path = native/jni/magiskpolicy
url = https://github.com/topjohnwu/magiskpolicy.git
[submodule "MagiskManager"]
path = java
path = app
url = https://github.com/topjohnwu/MagiskManager.git
[submodule "jni/busybox"]
path = jni/external/busybox
[submodule "busybox"]
path = native/jni/external/busybox
url = https://github.com/topjohnwu/ndk-busybox.git
[submodule "jni/external/dtc"]
path = jni/external/dtc
[submodule "dtc"]
path = native/jni/external/dtc
url = https://github.com/dgibson/dtc
[submodule "jni/external/lz4"]
path = jni/external/lz4
[submodule "lz4"]
path = native/jni/external/lz4
url = https://github.com/lz4/lz4.git
[submodule "jni/external/bzip2"]
path = jni/external/bzip2
[submodule "bzip2"]
path = native/jni/external/bzip2
url = https://github.com/nemequ/bzip2.git
[submodule "jni/external/xz"]
path = jni/external/xz
[submodule "xz"]
path = native/jni/external/xz
url = https://github.com/xz-mirror/xz.git
[submodule "nanopb"]
path = native/jni/external/nanopb
url = https://github.com/nanopb/nanopb.git

View File

@@ -1,25 +1,19 @@
# Magisk
## How to build Magisk
## Building Environment Requirements
#### Building has been tested on 3 major platforms: macOS, Ubuntu, Windows 10
### Environment Requirements
1. A 64-bit machine: `cmake` for Android is only available in 64-bit
2. Python 3.5+: run `build.py` script
3. Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips
4. Latest Android SDK: `ANDROID_HOME` environment variable should point to the Android SDK folder
5. Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or specify custom path `ANDROID_NDK`
6. (Windows Only) Colorama: Install Colorama with `pip install colorama`, used for ANSI color codes
7. (Unix only) C compiler: Build `zipadjust`. Windows users can use the pre-built `zipadjust.exe`
### Instructions and Notes
1. Magisk can be built with the latest NDK (r16 as of writing), however official released binaries will be built with NDK r10e due to ELF incompatibilities with the binaries built from newer NDKs.
2. The easiest way to setup a working environment is to open Magisk Manager with Android Studio. The IDE will download required components and construct the environment for you. Don't forget to set `ANDROID_HOME` environment variable to the SDK path.
3. Run the script with `-h` as an argument to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
4. By default, the script will build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (through the flag `--release`), you will need to place your Java Keystore file at `release_signature.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
1. Python 3.5+: run `build.py` script
2. Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips
3. Latest Android SDK: set `ANDROID_HOME` environment variable to the path to Android SDK
4. Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or optionally specify a custom path `ANDROID_NDK`
5. (Windows Only) Python package Colorama: Install with `pip install colorama`, used for ANSI color codes
## Building Notes and Instructions
1. Building is tested on macOS, Ubuntu, and Windows 10 using the latest stable NDK and NDK r10e. Officially released binaries were built with NDK r10e.
2. Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
3. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
4. By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `--release` flag), you need a Java Keystore file `release-key.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
5. The SafetyNet extension pack requires the full Magisk Manager as a `compileOnly` dependency. Build the **release** APK, convert it back to Java `.class` files (I use [dex2jar](https://github.com/pxb1988/dex2jar)), and place the converted JAR under `snet/libs` before compiling.
## License
@@ -40,41 +34,41 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
## Credits
**MagiskManager** (`java`)
**MagiskManager** (`app`)
* Copyright 2016-2017, John Wu (@topjohnwu)
* All contributors and translators
* Copyright 2016-2018, John Wu (@topjohnwu)
* All contributors and translators on Github
**MagiskSU** (`jni/su`)
**MagiskSU** (`native/jni/su`)
* Copyright 2016-2017, John Wu (@topjohnwu)
* Copyright 2016-2018, John Wu (@topjohnwu)
* Copyright 2015, Pierre-Hugues Husson (phh@phh.me)
* Copyright 2013, Koushik Dutta (@koush)
* Copyright 2010, Adam Shanks (@ChainsDD)
* Copyright 2008, Zinx Verituse (@zinxv)
**MagiskPolicy** (`jni/magiskpolicy`)
**MagiskPolicy** (`native/jni/magiskpolicy`)
* Copyright 2016-2017, John Wu (@topjohnwu)
* Copyright 2016-2018, John Wu (@topjohnwu)
* Copyright 2015, Pierre-Hugues Husson (phh@phh.me)
* Copyright 2015, Joshua Brindle (@joshua_brindle)
**MagiskHide** (`jni/magiskhide`)
**MagiskHide** (`native/jni/magiskhide`)
* Copyright 2016-2017, John Wu (@topjohnwu)
* Copyright 2016-2018, John Wu (@topjohnwu)
* Copyright 2016, Pierre-Hugues Husson (phh@phh.me)
**resetprop** (`jni/resetprop`)
**resetprop** (`native/jni/resetprop`)
* Copyright 2016-2017 John Wu (@topjohnwu)
* Copyright 2016-2018 John Wu (@topjohnwu)
* Copyright 2016 nkk71 (nkk71x@gmail.com)
**ndk-busybox** (`jni/external/busybox`)
**External Dependencies** (`native/jni/external`)
* Makefile for NDK, generated by [ndk-busybox-kitchen](https://github.com/topjohnwu/ndk-busybox-kitchen): Copyright 2017, John Wu (@topjohnwu)
* Patches for NDK: Many contributors along the way, all placed in [osm0sis/android-busybox-ndk](https://github.com/osm0sis/android-busybox-ndk)
* The copyright message for busybox should be included in its own directory
* Makefile for busybox, generated by [ndk-busybox-kitchen](https://github.com/topjohnwu/ndk-busybox-kitchen)
* Each dependencies has its own license/copyright information in each subdirectory.
All of them are either GPL or GPL compatible.
**Others Not Mentioned** (exclude `jni/external`)
**Others Not Mentioned**
* Copyright 2016-2017, John Wu (@topjohnwu)
* Copyright 2016-2018, John Wu (@topjohnwu)

1
app Submodule

Submodule app added at b885ccbd63

34
build.gradle Normal file
View File

@@ -0,0 +1,34 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
ext {
compileSdkVersion = 28
buildToolsVersion = "28.0.0"
supportLibVersion = "27.1.1"
}
task clean(type: Delete) {
delete rootProject.buildDir
}

431
build.py
View File

@@ -4,8 +4,8 @@ import os
import subprocess
if os.name == 'nt':
from colorama import init
init()
import colorama
colorama.init()
def error(str):
print('\n' + '\033[41m' + str + '\033[0m' + '\n')
@@ -16,7 +16,7 @@ def header(str):
# Environment checks
if not sys.version_info >= (3, 5):
error('Requires Python >= 3.5')
error('Requires Python 3.5+')
if 'ANDROID_HOME' not in os.environ:
error('Please add Android SDK path to ANDROID_HOME environment variable!')
@@ -24,14 +24,7 @@ if 'ANDROID_HOME' not in os.environ:
try:
subprocess.run(['java', '-version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except FileNotFoundError:
error('Please install Java and make sure \'java\' is available in PATH')
# If not Windows, we need gcc to compile
if os.name != 'nt':
try:
subprocess.run(['gcc', '-v'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except FileNotFoundError:
error('Please install C compiler and make sure \'gcc\' is available in PATH')
error('Please install JDK and make sure \'java\' is available in PATH')
import argparse
import multiprocessing
@@ -43,17 +36,30 @@ import lzma
import base64
import tempfile
if 'ANDROID_NDK' in os.environ:
ndk_build = os.path.join(os.environ['ANDROID_NDK'], 'ndk-build')
else:
ndk_build = os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build')
cpu_count = multiprocessing.cpu_count()
archs = ['armeabi-v7a', 'x86']
def mv(source, target):
print('mv: {} -> {}'.format(source, target))
shutil.move(source, target)
try:
shutil.move(source, target)
except:
pass
def cp(source, target):
print('cp: {} -> {}'.format(source, target))
shutil.copyfile(source, target)
try:
shutil.copyfile(source, target)
print('cp: {} -> {}'.format(source, target))
except:
pass
def rm(file):
try:
os.remove(file)
os.remove(file)
except OSError as e:
if e.errno != errno.ENOENT:
raise
@@ -74,161 +80,199 @@ def zip_with_msg(zipfile, source, target):
zipfile.write(source, target)
def build_all(args):
build_binary(args)
build_apk(args)
build_binary(args)
zip_main(args)
zip_uninstaller(args)
build_snet(args)
def collect_binary():
for arch in archs:
mkdir_p(os.path.join('native', 'out', arch))
for bin in ['magisk', 'magiskinit', 'magiskboot', 'busybox', 'b64xz']:
source = os.path.join('native', 'libs', arch, bin)
target = os.path.join('native', 'out', arch, bin)
mv(source, target)
def build_binary(args):
header('* Building Magisk binaries')
# If nothing specified, build everything
try:
targets = args.target
except:
targets = []
# Force update Android.mk timestamp to trigger recompilation
os.utime(os.path.join('jni', 'Android.mk'))
if len(targets) == 0:
targets = ['magisk', 'magiskinit', 'magiskboot', 'busybox', 'b64xz']
debug_flag = '' if args.release else '-DMAGISK_DEBUG'
cflag = 'MAGISK_FLAGS=\"-DMAGISK_VERSION=\\\"{}\\\" -DMAGISK_VER_CODE={} {}\"'.format(args.versionString, args.versionCode, debug_flag)
header('* Building binaries: ' + ' '.join(targets))
if 'ANDROID_NDK' in os.environ:
ndk_build = os.path.join(os.environ['ANDROID_NDK'], 'ndk-build')
else:
ndk_build = os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build')
# Force update logging.h timestamp to trigger recompilation for the flags to make a difference
os.utime(os.path.join('native', 'jni', 'include', 'logging.h'))
# Prebuild
proc = subprocess.run('{} PRECOMPILE=true {} -j{}'.format(ndk_build, cflag, multiprocessing.cpu_count()), shell=True)
# Basic flags
base_flags = 'MAGISK_VERSION=\"{}\" MAGISK_VER_CODE={} MAGISK_DEBUG={}'.format(config['version'], config['versionCode'],
'' if args.release else '-DMAGISK_DEBUG')
if 'magisk' in targets:
# Magisk is special case as it is a dependency of magiskinit
proc = subprocess.run('{} -C native {} B_MAGISK=1 -j{}'.format(ndk_build, base_flags, cpu_count), shell=True)
if proc.returncode != 0:
error('Build Magisk binary failed!')
collect_binary()
old_platform = False
flags = base_flags
if 'b64xz' in targets:
flags += ' B_BXZ=1'
old_platform = True
if old_platform:
proc = subprocess.run('{} -C native OLD_PLAT=1 {} -j{}'.format(ndk_build, flags, cpu_count), shell=True)
if proc.returncode != 0:
error('Build binaries failed!')
collect_binary()
other = False
flags = base_flags
if 'magiskinit' in targets:
for arch in archs:
bin_file = os.path.join('native', 'out', arch, 'magisk')
if not os.path.exists(bin_file):
error('Build "magisk" before building "magiskinit"')
with open(os.path.join('native', 'out', arch, 'binaries_arch_xz.h'), 'w') as out:
with open(bin_file, 'rb') as src:
xz_dump(src, out, 'magisk_xz')
stub_apk = os.path.join(config['outdir'], 'stub-release.apk')
if not os.path.exists(stub_apk):
error('Build release stub APK before building "magiskinit"')
with open(os.path.join('native', 'out', 'binaries_xz.h'), 'w') as out:
with open(stub_apk, 'rb') as src:
xz_dump(src, out, 'manager_xz')
flags += ' B_INIT=1'
other = True
if 'magiskboot' in targets:
flags += ' B_BOOT=1'
other = True
if 'busybox' in targets:
flags += ' B_BB=1'
other = True
if other:
proc = subprocess.run('{} -C native {} -j{}'.format(ndk_build, flags, cpu_count), shell=True)
if proc.returncode != 0:
error('Build binaries failed!')
collect_binary()
def sign_apk(source, target):
# Find the latest build tools
build_tool = os.path.join(os.environ['ANDROID_HOME'], 'build-tools',
sorted(os.listdir(os.path.join(os.environ['ANDROID_HOME'], 'build-tools')))[-1])
proc = subprocess.run([os.path.join(build_tool, 'zipalign'), '-vpf', '4', source, target], stdout=subprocess.DEVNULL)
if proc.returncode != 0:
error('Build Magisk binary failed!')
error('Zipalign Magisk Manager failed!')
print('')
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
mkdir_p(os.path.join('out', arch))
with open(os.path.join('out', arch, 'dump.h'), 'w') as dump:
dump.write('#include "stdlib.h"\n')
mv(os.path.join('libs', arch, 'magisk'), os.path.join('out', arch, 'magisk'))
with open(os.path.join('out', arch, 'magisk'), 'rb') as bin:
dump.write('const uint8_t magisk_dump[] = "')
dump.write(''.join("\\x{:02X}".format(c) for c in lzma.compress(bin.read(), preset=9)))
dump.write('";\n')
# Find apksigner.jar
apksigner = ''
for root, dirs, files in os.walk(build_tool):
if 'apksigner.jar' in files:
apksigner = os.path.join(root, 'apksigner.jar')
break
if not apksigner:
error('Cannot find apksigner.jar in Android SDK build tools')
print('')
proc = subprocess.run('{} {} -j{}'.format(ndk_build, cflag, multiprocessing.cpu_count()), shell=True)
proc = subprocess.run('java -jar {} sign --ks release-key.jks --ks-pass pass:{} --ks-key-alias {} --key-pass pass:{} {}'.format(
apksigner, config['keyStorePass'], config['keyAlias'], config['keyPass'], target), shell=True)
if proc.returncode != 0:
error('Build Magisk binary failed!')
print('')
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
for binary in ['magiskinit', 'magiskboot', 'b64xz', 'busybox']:
try:
mv(os.path.join('libs', arch, binary), os.path.join('out', arch, binary))
except:
pass
error('Release sign Magisk Manager failed!')
def build_apk(args):
header('* Building Magisk Manager')
for key in ['public.certificate.x509.pem', 'private.key.pk8']:
source = os.path.join('ziptools', key)
target = os.path.join('java', 'app', 'src', 'main', 'assets', key)
cp(source, target)
for script in ['magisk_uninstaller.sh', 'util_functions.sh']:
source = os.path.join('scripts', script)
target = os.path.join('java', 'app', 'src', 'main', 'assets', script)
cp(source, target)
os.chdir('java')
source = os.path.join('scripts', 'util_functions.sh')
target = os.path.join('app', 'src', 'full', 'res', 'raw', 'util_functions.sh')
cp(source, target)
if args.release:
if not os.path.exists(os.path.join('..', 'release_signature.jks')):
error('Please generate a java keystore and place it in \'release_signature.jks\'')
if not os.path.exists('release-key.jks'):
error('Please generate a java keystore and place it in \'release-key.jks\'')
proc = subprocess.run('{} app:assembleRelease'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build Magisk Manager failed!')
unsigned = os.path.join('app', 'build', 'outputs', 'apk', 'release', 'app-release-unsigned.apk')
aligned = os.path.join('app', 'build', 'outputs', 'apk', 'release', 'app-release-aligned.apk')
release = os.path.join('app', 'build', 'outputs', 'apk', 'release', 'app-release.apk')
# Find the latest build tools
build_tool = sorted(os.listdir(os.path.join(os.environ['ANDROID_HOME'], 'build-tools')))[-1]
rm(aligned)
rm(release)
proc = subprocess.run([
os.path.join(os.environ['ANDROID_HOME'], 'build-tools', build_tool, 'zipalign'),
'-v', '-p', '4', unsigned, aligned], stdout=subprocess.DEVNULL)
if proc.returncode != 0:
error('Zipalign Magisk Manager failed!')
# Find apksigner.jar
apksigner = ''
for root, dirs, files in os.walk(os.path.join(os.environ['ANDROID_HOME'], 'build-tools', build_tool)):
if 'apksigner.jar' in files:
apksigner = os.path.join(root, 'apksigner.jar')
break
if not apksigner:
error('Cannot find apksigner.jar in Android SDK build tools')
proc = subprocess.run('java -jar {} sign --ks {} --out {} {}'.format(
apksigner,
os.path.join('..', 'release_signature.jks'),
release, aligned), shell=True)
if proc.returncode != 0:
error('Release sign Magisk Manager failed!')
unsigned = os.path.join('app', 'build', 'outputs', 'apk', 'full', 'release', 'app-full-release-unsigned.apk')
release = os.path.join(config['outdir'], 'app-release.apk')
sign_apk(unsigned, release)
header('Output: ' + release)
rm(unsigned)
rm(aligned)
mkdir(os.path.join('..', 'out'))
target = os.path.join('..', 'out', 'app-release.apk')
print('')
mv(release, target)
unsigned = os.path.join('app', 'build', 'outputs', 'apk', 'stub', 'release', 'app-stub-release-unsigned.apk')
release = os.path.join(config['outdir'], 'stub-release.apk')
sign_apk(unsigned, release)
header('Output: ' + release)
rm(unsigned)
else:
proc = subprocess.run('{} app:assembleDebug'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build Magisk Manager failed!')
source = os.path.join('app', 'build', 'outputs', 'apk', 'debug', 'app-debug.apk')
mkdir(os.path.join('..', 'out'))
target = os.path.join('..', 'out', 'app-debug.apk')
print('')
source = os.path.join('app', 'build', 'outputs', 'apk', 'full', 'debug', 'app-full-debug.apk')
target = os.path.join(config['outdir'], 'app-debug.apk')
mv(source, target)
header('Output: ' + target)
# Return to upper directory
os.chdir('..')
source = os.path.join('app', 'build', 'outputs', 'apk', 'stub', 'debug', 'app-stub-debug.apk')
target = os.path.join(config['outdir'], 'stub-debug.apk')
mv(source, target)
header('Output: ' + target)
def build_snet(args):
os.chdir('java')
proc = subprocess.run('{} snet:assembleRelease'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build snet extention failed!')
source = os.path.join('snet', 'build', 'outputs', 'apk', 'release', 'snet-release-unsigned.apk')
mkdir(os.path.join('..', 'out'))
target = os.path.join('..', 'out', 'snet.apk')
print('')
mv(source, target)
os.chdir('..')
target = os.path.join(config['outdir'], 'snet.apk')
# Re-compress the whole APK for smaller size
with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zout:
with zipfile.ZipFile(source) as zin:
for item in zin.infolist():
zout.writestr(item.filename, zin.read(item))
rm(source)
header('Output: ' + target)
def xz_dump(src, out, var_name):
out.write('const static unsigned char {}[] = {{'.format(var_name))
for i, c in enumerate(lzma.compress(src.read(), preset=9)):
if i % 16 == 0:
out.write('\n')
out.write('0x{:02X},'.format(c))
out.write('\n};\n')
out.flush()
def gen_update_binary():
update_bin = []
binary = os.path.join('out', 'armeabi-v7a', 'b64xz')
binary = os.path.join('native', 'out', 'armeabi-v7a', 'b64xz')
if not os.path.exists(binary):
error('Please build \'binary\' before zipping!')
with open(binary, 'rb') as b64xz:
update_bin.append('#! /sbin/sh\nEX_ARM=\'')
update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read()))
binary = os.path.join('out', 'x86', 'b64xz')
binary = os.path.join('native', 'out', 'x86', 'b64xz')
with open(binary, 'rb') as b64xz:
update_bin.append('\'\nEX_X86=\'')
update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read()))
binary = os.path.join('out', 'armeabi-v7a', 'busybox')
binary = os.path.join('native', 'out', 'armeabi-v7a', 'busybox')
with open(binary, 'rb') as busybox:
update_bin.append('\'\nBB_ARM=')
update_bin.append(base64.b64encode(lzma.compress(busybox.read(), preset=9)).decode('ascii'))
binary = os.path.join('out', 'x86', 'busybox')
binary = os.path.join('native', 'out', 'x86', 'busybox')
with open(binary, 'rb') as busybox:
update_bin.append('\nBB_X86=')
update_bin.append(base64.b64encode(lzma.compress(busybox.read(), preset=9)).decode('ascii'))
@@ -254,14 +298,14 @@ def zip_main(args):
zip_with_msg(zipf, source, target)
# Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
for lib_dir, zip_dir in [('armeabi-v7a', 'arm'), ('x86', 'x86')]:
for binary in ['magiskinit', 'magiskboot']:
source = os.path.join('out', lib_dir, binary)
source = os.path.join('native', 'out', lib_dir, binary)
target = os.path.join(zip_dir, binary)
zip_with_msg(zipf, source, target)
# APK
source = os.path.join('out', 'app-release.apk' if args.release else 'app-debug.apk')
source = os.path.join(config['outdir'], 'app-release.apk' if args.release else 'app-debug.apk')
target = os.path.join('common', 'magisk.apk')
zip_with_msg(zipf, source, target)
@@ -274,14 +318,14 @@ def zip_main(args):
source = os.path.join('scripts', 'util_functions.sh')
with open(source, 'r') as script:
# Add version info util_functions.sh
util_func = script.read().replace(
'MAGISK_VERSION_STUB', 'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(args.versionString, args.versionCode))
util_func = script.read().replace('#MAGISK_VERSION_STUB',
'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(config['version'], config['versionCode']))
target = os.path.join('common', 'util_functions.sh')
print('zip: ' + source + ' -> ' + target)
zipf.writestr(target, util_func)
# addon.d.sh
source = os.path.join('scripts', 'addon.d.sh')
target = os.path.join('addon.d', '99-magisk.sh')
target = os.path.join('common', 'addon.d.sh')
zip_with_msg(zipf, source, target)
# Prebuilts
@@ -291,8 +335,10 @@ def zip_main(args):
# End of zipping
output = os.path.join('out', 'Magisk-v{}.zip'.format(args.versionString))
output = os.path.join(config['outdir'], 'Magisk-v{}.zip'.format(config['version']) if config['prettyName'] else
'magisk-release.zip' if args.release else 'magisk-debug.zip')
sign_adjust_zip(unsigned, output)
header('Output: ' + output)
def zip_uninstaller(args):
header('* Packing Uninstaller Zip')
@@ -306,30 +352,25 @@ def zip_uninstaller(args):
print('zip: ' + target)
zipf.writestr(target, gen_update_binary())
# updater-script
source = os.path.join('scripts', 'uninstaller_loader.sh')
source = os.path.join('scripts', 'magisk_uninstaller.sh')
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
zip_with_msg(zipf, source, target)
# Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
source = os.path.join('out', lib_dir, 'magiskboot')
target = os.path.join(zip_dir, 'magiskboot')
zip_with_msg(zipf, source, target)
source = os.path.join('scripts', 'magisk_uninstaller.sh')
target = 'magisk_uninstaller.sh'
zip_with_msg(zipf, source, target)
for lib_dir, zip_dir in [('armeabi-v7a', 'arm'), ('x86', 'x86')]:
for bin in ['magisk', 'magiskboot']:
source = os.path.join('native', 'out', lib_dir, bin)
target = os.path.join(zip_dir, bin)
zip_with_msg(zipf, source, target)
# Scripts
# util_functions.sh
source = os.path.join('scripts', 'util_functions.sh')
with open(source, 'r') as script:
# Remove the stub
util_func = script.read().replace(
'MAGISK_VERSION_STUB', '')
target = os.path.join('util_functions.sh')
print('zip: ' + source + ' -> ' + target)
zipf.writestr(target, util_func)
zipf.writestr(target, script.read())
# Prebuilts
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
@@ -338,95 +379,81 @@ def zip_uninstaller(args):
# End of zipping
output = os.path.join('out', 'Magisk-uninstaller-{}.zip'.format(datetime.datetime.now().strftime('%Y%m%d')))
output = os.path.join(config['outdir'], 'Magisk-uninstaller-{}.zip'.format(datetime.datetime.now().strftime('%Y%m%d'))
if config['prettyName'] else 'magisk-uninstaller.zip')
sign_adjust_zip(unsigned, output)
header('Output: ' + output)
def sign_adjust_zip(unsigned, output):
signer_name = 'zipsigner-1.0.jar'
jarsigner = os.path.join('java', 'crypto', 'build', 'libs', signer_name)
signer_name = 'zipsigner-2.2.jar'
jarsigner = os.path.join('utils', 'build', 'libs', signer_name)
if os.name != 'nt' and not os.path.exists(os.path.join('ziptools', 'zipadjust')):
header('* Building zipadjust')
# Compile zipadjust
proc = subprocess.run('gcc -o ziptools/zipadjust ziptools/zipadjust_src/*.c -lz', shell=True)
if proc.returncode != 0:
error('Build zipadjust failed!')
if not os.path.exists(jarsigner):
header('* Building ' + signer_name)
os.chdir('java')
proc = subprocess.run('{} crypto:shadowJar'.format(os.path.join('.', 'gradlew')), shell=True)
proc = subprocess.run('{} utils:shadowJar'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build {} failed!'.format(signer_name))
os.chdir('..')
header('* Signing / Adjusting Zip')
publicKey = os.path.join('ziptools', 'public.certificate.x509.pem')
privateKey = os.path.join('ziptools', 'private.key.pk8')
header('* Signing Zip')
signed = tempfile.mkstemp()[1]
# Unsigned->signed
proc = subprocess.run(['java', '-jar', jarsigner,
publicKey, privateKey, unsigned, signed])
proc = subprocess.run(['java', '-jar', jarsigner, unsigned, output])
if proc.returncode != 0:
error('First sign flashable zip failed!')
adjusted = tempfile.mkstemp()[1]
# Adjust zip
proc = subprocess.run([os.path.join('ziptools', 'zipadjust'), signed, adjusted])
if proc.returncode != 0:
error('Adjust flashable zip failed!')
# Adjusted -> output
proc = subprocess.run(['java', '-jar', jarsigner,
"-m", publicKey, privateKey, adjusted, output])
if proc.returncode != 0:
error('Second sign flashable zip failed!')
# Cleanup
rm(unsigned)
rm(signed)
rm(adjusted)
error('Signing zip failed!')
def cleanup(args):
if len(args.target) == 0:
args.target = ['binary', 'java', 'zip']
args.target = ['native', 'java']
if 'binary' in args.target:
header('* Cleaning binaries')
subprocess.run(os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build') + ' clean', shell=True)
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
shutil.rmtree(os.path.join('out', arch), ignore_errors=True)
if 'native' in args.target:
header('* Cleaning native')
subprocess.run(ndk_build + ' -C native B_MAGISK=1 B_INIT=1 B_BOOT=1 B_BXZ=1 B_BB=1 clean', shell=True)
shutil.rmtree(os.path.join('native', 'out'), ignore_errors=True)
if 'java' in args.target:
header('* Cleaning java')
os.chdir('java')
subprocess.run('{} clean'.format(os.path.join('.', 'gradlew')), shell=True)
os.chdir('..')
for f in os.listdir('out'):
if '.apk' in f:
rm(os.path.join('out', f))
subprocess.run('{} app:clean snet:clean utils:clean'.format(os.path.join('.', 'gradlew')), shell=True)
if 'zip' in args.target:
header('* Cleaning zip files')
for f in os.listdir('out'):
if '.zip' in f:
rm(os.path.join('out', f))
def parse_config():
c = {}
with open('config.prop', 'r') as f:
for line in [l.strip(' \t\r\n') for l in f]:
if line.startswith('#') or len(line) == 0:
continue
prop = line.split('=')
c[prop[0].strip(' \t\r\n')] = prop[1].strip(' \t\r\n')
if 'version' not in c or 'versionCode' not in c:
error('"version" and "versionCode" is required in "config.prop"')
try:
c['versionCode'] = int(c['versionCode'])
except ValueError:
error('"versionCode" is required to be an integer')
if 'prettyName' not in c:
c['prettyName'] = 'false'
c['prettyName'] = c['prettyName'].lower() == 'true'
if 'outdir' not in c:
c['outdir'] = 'out'
mkdir_p(c['outdir'])
return c
config = parse_config()
parser = argparse.ArgumentParser(description='Magisk build script')
parser.add_argument('--release', action='store_true', help='compile Magisk for release')
subparsers = parser.add_subparsers(title='actions')
all_parser = subparsers.add_parser('all', help='build everything and create flashable zip with uninstaller')
all_parser.add_argument('versionString')
all_parser.add_argument('versionCode', type=int)
all_parser = subparsers.add_parser('all', help='build everything (binaries/apks/zips)')
all_parser.set_defaults(func=build_all)
binary_parser = subparsers.add_parser('binary', help='build Magisk binaries')
binary_parser.add_argument('versionString')
binary_parser.add_argument('versionCode', type=int)
binary_parser = subparsers.add_parser('binary', help='build binaries. target: magisk magiskinit magiskboot busybox b64xz')
binary_parser.add_argument('target', nargs='*')
binary_parser.set_defaults(func=build_binary)
apk_parser = subparsers.add_parser('apk', help='build Magisk Manager APK')
@@ -436,20 +463,18 @@ snet_parser = subparsers.add_parser('snet', help='build snet extention for Magis
snet_parser.set_defaults(func=build_snet)
zip_parser = subparsers.add_parser('zip', help='zip and sign Magisk into a flashable zip')
zip_parser.add_argument('versionString')
zip_parser.add_argument('versionCode', type=int)
zip_parser.set_defaults(func=zip_main)
uninstaller_parser = subparsers.add_parser('uninstaller', help='create flashable uninstaller')
uninstaller_parser.set_defaults(func=zip_uninstaller)
clean_parser = subparsers.add_parser('clean', help='clean [target...] targets: binary java zip')
clean_parser = subparsers.add_parser('clean', help='cleanup. target: binary java zip')
clean_parser.add_argument('target', nargs='*')
clean_parser.set_defaults(func=cleanup)
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
parser.print_help()
sys.exit(1)
args = parser.parse_args()

15
config.prop.sample Normal file
View File

@@ -0,0 +1,15 @@
# The version string and version code of Magisk
version=
versionCode=
outdir=out
# Whether use pretty names for zips, e.g. Magisk-v${version}.zip, Magisk-uninstaller-${date}.zip
# The default output names are magisk-${release/debug/uninstaller}.zip
prettyName=false
# These pwds are passed to apksigner for release-key.jks. Necessary when building release apks
# keyPass is the pwd for the specified keyAlias
keyStorePass=
keyAlias=
keyPass=

View File

@@ -1,28 +1,36 @@
# Magisk Documentations
(Updated on 2017.9.28) ([Changelog](changelog.md))
(Updated on 2018.1.8) ([Changelog](changelog.md))
## Table of Contents
- [Introduction](#introduction)
- [Procedure Diagram](https://cdn.rawgit.com/topjohnwu/Magisk/cc1809688299f1f8b5db494a234850852712c0c9/docs/procedures.html)
- [Magisk Details](details.md)
- [Tips and Tricks](tips.md)
- [OTA Installation Tips](tips.md#ota-installation-tips)
The following are for developers
- [Procedure Diagram](https://cdn.rawgit.com/topjohnwu/Magisk/7d1082b1cb91db90ed0a29d8b092723fc3d69c58/docs/procedures.html)
- [Magisk Details](details.md)
- [Boot Stages](details.md#boot-stages)
- [Magic Mount Details](details.md#magic-mount-details)
- [Simple Mount Details](details.md#simple-mount-details)
- [Available Applets](applets.md)
- [magisk](applets.md#magisk)
- [su](applets.md#su)
- [resetprop](applets.md#resetprop)
- [magiskpolicy](applets.md#magiskpolicy)
- [magiskhide](applets.md#magiskhide)
- [Modules and Repos](module_repo.md)
- [Modules and Templates](module_repo.md#magisk-module-format)
- [Submit Modules to Repo](module_repo.md#submit-your-module-to-magisk-modules-repo)
- [Available Tools](tools.md)
- [magiskboot](tools.md#magiskboot)
- [magiskinit](tools.md#magiskinit)
- [magiskpolicy](tools.md#magiskpolicy)
- [magisk](tools.md#magisk)
- [su](tools.md#su)
- [resetprop](tools.md#resetprop)
- [magiskhide](tools.md#magiskhide)
- [Modules](modules.md)
- [Modules and Templates](modules.md#magisk-module-format)
- [Submit Modules to Repo](https://github.com/topjohnwu/Magisk_Repo_Submissions)
- [Tips and Tricks](tips.md)
- [OTA Installation Tips](tips.md#ota-installation-tips)
- [Remove Files](tips.md#remove-files)
- [Remove Folders](tips.md#remove-folders)
## Introduction
Magisk is a suite of open source tools for devices running Android version higher than 5.0 Lollipop (API 21). It establishes an environment which covers most Android aftermarket customization needs, such as root, boot scripts, SELinux patches, dm-verity/forceencrypt patches etc.. Furthermore, Magisk also provides a **Systemless Interface** to alter the system (or vendor) arbitrarily while the actual partitions stay completely intact, all of which accomplished by only patching the boot image, and adding some files into `/data`. With its systemless nature along with several other hacks, Magisk can hide modifications from device integrity verifications, one of the main target is to hide from [Google's SafetyNet API](https://developer.android.com/training/safetynet/index.html).
Magisk is a suite of open source tools for devices running Android version higher than 5.0 Lollipop (API 21). It establishes an environment which covers most stuffs you need for Android customization, such as root, boot scripts, SELinux patches, AVB2.0 / dm-verity / forceencrypt patches etc..
Furthermore, Magisk provides a **Systemless Interface** to alter the system (or vendor) arbitrarily while the actual partitions stay completely intact, all of which accomplished by only patching the boot image. With its systemless nature along with several other hacks, Magisk can hide modifications from nearly any existing system integrity verifications, one of the main target is to hide from [Google's SafetyNet API](https://developer.android.com/training/safetynet/index.html).

View File

@@ -1,166 +0,0 @@
## Available Applets
Magisk has a core binary which acts as a multi-call program with many applets. Here is an introduction to all available applets.
### magisk
The magisk binary itself provides a lot of utility functions when called with the name `magisk`. They are used in both Magisk installation and module installation. The entry point for `init` to invoke magisk's boot procedures are also listed here.
Command help message:
```
Usage: magisk [applet [arguments]...]
or: magisk [options]...
Options:
-c print current binary version
-v print running daemon version
-V print running daemon version code
--list list all availible applets
--install [SOURCE] DIR symlink all applets to DIR. SOURCE is optional
--createimg IMG SIZE create ext4 image. SIZE is interpreted in MB
--imgsize IMG report ext4 image used/total size
--resizeimg IMG SIZE resize ext4 image. SIZE is interpreted in MB
--mountimg IMG PATH mount IMG to PATH and prints the loop device
--umountimg PATH LOOP unmount PATH and delete LOOP device
--[boot stage] start boot stage service
--unlock-blocks set BLKROSET flag to OFF for all block devices
Supported boot stages:
post-fs, post-fs-data, service
Supported applets:
su, resetprop, magiskpolicy, supolicy, magiskhide
```
### su
The MagiskSU entrypoint. Call `su` to gain a root shell.
Command help message:
```
Usage: su [options] [--] [-] [LOGIN] [--] [args...]
Options:
-c, --command COMMAND pass COMMAND to the invoked shell
-h, --help display this help message and exit
-, -l, --login pretend the shell to be a login shell
-m, -p,
--preserve-environment do not change environment variables
-s, --shell SHELL use SHELL instead of the default /system/bin/sh
-u display the multiuser mode and exit
-v, --version display version number and exit
-V display version code and exit,
this is used almost exclusively by Superuser.apk
-mm, -M,
--mount-master run in the global mount namespace,
use if you need to publicly apply mounts
```
Note: even though the `-Z, --context` option is not listed above, it actually still exists. However MagiskSU will silently ignore the option since it's not needed anymore. It is still left over because some apps still request root shell with specific contexts as an option.
### resetprop
An advanced system prop manipulation utility; you can arbitrarily alter system props using this tool. Here's some background knowledge:
> System props are stored in a hybrid trie/binary tree data structure in memory; it was originally designed to only support adding nodes, and no nodes should be removed. Props can be read by many processes (e.g. via the `getprop` command); however, only the `init` process have write access to the property data. `init` provides a `property_service` to accept property update requests, so all property changes are monitored and controlled by `init` Restrictions such as **read-only** props (props that starts with `ro.`), which can only be set once and cannot be changed afterwards, is therefore implemented in `init`.
**resetprop** acts just like `init`: directly access the data structure, bypassing the whole `property_service` part. Doing so, we gain **arbitrary modification** power, including altering read-only props and deleting properties. Delete properties, which was stated *"forbidden"* in the data structure, is implemented through some tricks in the data structure.
One subtle thing to be aware of is that if we change props by directly modifying the data structure, `on property:foo=bar` triggers registered in `*.rc` scripts will not be triggered properly. This may be a good thing or a bad thing, depending on what behavior you expect. I made the default behavior to match the original setprop command, which **WILL** trigger events, but of course I provide a flag (`-n`) to disable it if you need this special behavior.
Command help message:
```
Usage: resetprop [options] [args...]
Options:
-v show verbose output
-n only modify property in memory
resetprop NAME VALUE set property entry NAME with VALUE
resetprop --file FILE load props from FILE
resetprop --delete NAME remove prop entry NAME
```
### magiskpolicy
(This tool is aliased to `supolicy` for compatibility)
A tool to patch `sepolicy`. **magiskpolicy** also comes with built-in rules to unleash restrictions to make Magisk work properly. `sepolicy` is a compiled binary containing SELinux rules; we directly patch rules in the binary format since we don't have access to the SELinux policy source (`*.te`) files.
The Magisk daemon itself, the root shell, and all processes spawned from the daemon and root shell are all running in the context `u:r:su:s0`. This context is not only patched to be permissive, but also patched to allow any transition from `u:r:su:s0` to any domain. This was done because Samsung devices do not support permissive out of the box.
The built in patches are split to 3 parts: minimal, medium, and large. The full patch will result in a huge policy file, which might cause the `sepolicy` file unable to fit in `boot.img`.
- The minimal patch is just enough to start Magisk daemon and allow the daemon to further patch the policy during boot time (which is called **live patch**). It is done at installation and directly into `boot.img`.
- The medium patch covers most common operations, and is live patched as soon as Magisk daemon is started (blocking boot process).
- The large patch contains the full patch. Due to the concern of greatly increasing the boot time, it is designed to run in the background until it's joined in the non-blocking late_start bootstage.
What this all means is that **only late_start service mode is guaranteed to run in a fully patched environment**. If any script is not time critical, it is **highly recommended to run those scripts in late_start service mode**.
Command help message:
```
Usage: magiskpolicy [--options...] [policystatements...]
Options:
--live directly load patched policy to device
--minimal minimal patches, used for boot image patches
--load <infile> load policies from <infile>
(load from live policies if not specified)
--save <outfile> save policies to <outfile>
One policy statement should be treated as one parameter;
this means a full policy statement should be enclosed in quotes;
multiple policy statements can be provided in a single command
The statements has a format of "<action> [args...]"
Use '*' in args to represent every possible match.
Collections wrapped in curly brackets can also be used as args.
Supported policy statements:
Type 1:
"<action> source-class target-class permission-class permission"
Action: allow, deny, auditallow, auditdeny
Type 2:
"<action> source-class target-class permission-class ioctl range"
Action: allowxperm, auditallowxperm, dontauditxperm
Type 3:
"<action> class"
Action: create, permissive, enforcing
Type 4:
"attradd class attribute"
Type 5:
"typetrans source-class target-class permission-class default-class (optional: object-name)"
Notes:
- typetrans does not support the all match '*' syntax
- permission-class cannot be collections
- source-class and target-class can also be attributes
Example: allow { source1 source2 } { target1 target2 } permission-class *
Will be expanded to:
allow source1 target1 permission-class { all-permissions }
allow source1 target2 permission-class { all-permissions }
allow source2 target1 permission-class { all-permissions }
allow source2 target2 permission-class { all-permissions }
```
### magiskhide
This is the CLI to control the state of MagiskHide.
Command help message:
```
Usage: magiskhide [--options [arguments...] ]
Options:
--enable Start magiskhide
--disable Stop magiskhide
--add PROCESS Add PROCESS to the hide list
--rm PROCESS Remove PROCESS from the hide list
--ls Print out the current hide list
```

View File

@@ -4,3 +4,5 @@
- 2017.9.28
- Update applets info to Magisk v14.1
- Add OTA tips
- 2017.1.8
- Update to Magisk v15.2

View File

@@ -2,59 +2,58 @@
If you are working on complicated projects, you shall need more control to the whole process. Magisk can run scripts in different boot stages, so you can fine tune exactly what you want to do. It's recommended to read this documentation along with the procedure graph.
- post-fs mode
- **This stage is BLOCKING. Boot process will NOT continue until everything is done, or 20 seconds has passed**
- Happens after most partitions are mounted, except `/data`
- Magisk will bind mount files under `/cache/magisk_mount/system` to corresponding paths
- **This stage is BLOCKING. Boot process will NOT continue until everything is done, or 10 seconds has passed**
- Happens after most partitions are mounted. `/data` might not be available since `vold` is not started yet
- Magisk will bind mount files under `/cache/magisk_mount/system` and `/cache/magisk_mount/vendor`
- It is only **Simple Mount**, which means it will replace existing files, but cannot add/remove files.
- This part is mostly deprecated (reasons in details)
- post-fs-data mode
- **This stage is BLOCKING. Boot process will NOT continue until everything is done, or 60 seconds has passed**
- **This stage is BLOCKING. Boot process will NOT continue until everything is done, or 10 seconds has passed**
- Happens after `/data` is ready (including the case when `/data` is encrypted)
- Happens before Zygote and system servers are started (which means pretty much everything)
- Mirrors will be mounted. These mirrors play a critical role in **Magic Mount**
- `/data/magisk.img` will be merged, trimmed, and mounted to `/magisk`
- Magisk will run scripts under `/magisk/.core/post-fs-data.d`
- Magisk will run scripts: `/magisk/$MODID/post-fs-data.sh` (placed in each module directory)
- `/data/adb/magisk.img` will be merged, trimmed, and mounted to `MOUNTPOINT=/sbin/.core/img`
- Magisk will run scripts under `$MOUNTPOINT/.core/post-fs-data.d`
- Magisk will run scripts: `$MOUNTPOINT/$MODID/post-fs-data.sh` (placed in each module directory)
- Magisk will finally **Magisk Mount** module files
- late_start service mode
- **This stage is NON-BLOCKING, it will run in parallel with other processes**
- Happens when class late_start is started
- Put time consuming but non time critical tasks here. Boot process will be stuck if it took too long to finish your tasks in previous modes
- SELinux is guaranteed to be fully patched in this stage; **it is recommended to run most scripts in this stage**, unless your scripts require some time critical operations
- Magisk will run scripts under `/magisk/.core/service.d`
- Magisk will run scripts: `/magisk/$MODID/service.sh` (placed in each module directory)
- Happens when class late_start is triggered
- The daemon will wait for the full `sepolicy` patch before running this stage, so SELinux is guaranteed to be fully patched
- Put time consuming scripts here. Boot process will get stuck if it took too long to finish your tasks in `post-fs-data`
- **It is recommended to run all scripts in this stage**, unless your scripts requires doing stuffs before Zygote is started
- Magisk will run scripts under `$MOUNTPOINT/.core/service.d`
- Magisk will run scripts: `$MOUNTPOINT/$MODID/service.sh` (placed in each module directory)
## Magic Mount Details
### Terminology
- **Item**: A folder, file, or symbolic link
- **Leaf**: The very end of a directory structure tree, can be either a file or symbolic link
- **Leaf**: An item that is on the very end of a directory structure tree. It can be either a file or symbolic link
- **`$MODPATH`**: A variable to represent the path of a module folder
- **Source item**: An item under `$MODPATH/system`, for example, `$MODPATH/system/build.prop` is a source item
- **Existing item**: An item under `/system`, for example, `/system/bin/app_process` is an existing item
- **Target item**: A corresponding item of a source item. For example, the target item of `$MODPATH/system/build.prop` is `/system/build.prop`
- **Source item**: An item under `$MODPATH/system`, for example, `$MODPATH/system/bin/app_process32` is a source item
- **Existing item**: An item in the actual filesystem, for example, `/system/bin/app_process32` is an existing item
- **Target item**: The corresponding item of a source item. For example, the target item of `$MODPATH/system/bin/app_process32` is `/system/bin/app_process32`
Note: A target item does not imply it is an existing item. A target item might not exist in the actual `/system`
Note: A target item **does not** imply it is an existing item. A target item might not exist in the actual filesystem
### Policies
- For a source leaf: if its target item is also an existing item, the existing item will be replaced with the source leaf
- For a source leaf: if its target item is not an existing item, the source leaf will be added to the path of its target item
- For any existing item that's not a target item, it will stay intact
Above is the rule of thumb. Basically it means that Magic Mount merges the files from `$MODPATH/system` into the real `/system`. A simpler way to understand is to think as it dirty copies the contents from `$MODPATH/system` into `/system`.
Above is the rule of thumb. Basically it means that Magic Mount merges the two folders, `$MODPATH/system` into `/system`. A simpler way to understand is to think as the items is dirty copied from `$MODPATH/system` into `/system`.
However, an addition rule will override the above policies:
- For a source folder containing the file `.replace`, the source folder will be treated as if it is a source leaf. That is, the items within the target folder will be completely discarded, and the target folder will be replaced with the source folder.
- For a source folder containing the file `.replace`, the source folder will be treated as if it is a leaf. That is, the items within the target folder will be completely discarded, and the target folder will be replaced with the source folder.
Directories containing a file named `.replace` will NOT be merged into the system. It will directly replace the target directory. A simpler way to understand is to think as if it wipes the target folder, and then copies the whole folder to the target path.
Directories containing a file named `.replace` will **NOT** be merged, instead it directly replaces the target directory. A simpler way to understand is to think as if it wipes the target folder, and then copies the whole folder to the target path.
### Notes
- Sometimes, completely replacing a folder is inevitable. For example you want to replace `/system/priv-app/SystemUI` in your stock rom. In stock roms, system apps usually comes with pre-optimized files. If your replacement `SystemUI.apk` is deodexed (which is most likely the case), you would want to replace the whole `/system/priv-app/SystemUI` to make sure the folder only contains the modified `SystemUI.apk` and **NOT** merge with the pre-optimized files.
- If you want to replace files in `/vendor`, please place it under `$MODPATH/system/vendor`. Magisk will handle both cases, whether the vendor partition is separated or not under-the-hood, developers don't need to bother.
- Sometimes, completely replacing a folder is inevitable. For example you want to replace `/system/priv-app/SystemUI` in your stock rom. In stock roms, system apps usually comes with pre-optimized files. If your replacement `SystemUI.apk` is deodexed (which is most likely the case), you would want to replace the whole `/system/priv-app/SystemUI` to make sure the folder only contains the modified `SystemUI.apk` without the pre-optimized files.
- If you are using the [Magisk Module Template](https://github.com/topjohnwu/magisk-module-template), you can create a list of folders you want to replace in the file `config.sh`. The installation scripts will handle the creation of `.replace` files into the listed folders for you.
- Adding non-existing target items is a relatively expensive operation. Magisk would need to do **MANY** under-the-hood tasks to achieve it. Replacing a whole folder is recommended if viable, it reduces the complexity of the construction of the mounting tree and could speed up the booting time
## Simple Mount Details
Some files require to be mounted much earlier in the boot process, currently known are bootanimation and some libs (most users won't change them). You can simply place your modified files into the corresponding path under `/cache/magisk_mount`. At boot time, Magisk will **clone all the attributes from the target file**, which includes selinux context, permission mode, owner, group. It'll then bind mount the file to the target. This means you don't need to worry about the metadatas for files placed under `/cache/magisk_mount`: copy the file to the correct place, reboot then you're done!
(Note: this part is mostly deprecated, since starting with devices using A/B partitions, there is no longer a dedicated partition for cache because OTAs are applied live at boot. Instead, `/cache` now points to `/data/cache`, which means `post-fs` mode does not have access to `/cache` anymore)
This mode does not feature the same complex Magic Mount implementation, it will mount a source leaf to an existing target item under `/system`.
For example, you want to replace `/system/media/bootanimation.zip`, copy your new boot animation zip to `/cache/magisk_mount/system/media/bootanimation.zip,` Magisk will mount your files in the next reboot.
Some files require to be mounted much earlier in the boot process, currently known are bootanimation and some libs (most users won't change them). You can simply place your modified files into the corresponding path under `/cache/magisk_mount`. For example, you want to replace `/system/media/bootanimation.zip`, copy your new boot animation zip to `/cache/magisk_mount/system/media/bootanimation.zip`, and Magisk will mount your files in the next reboot. Magisk will **clone all the attributes from the target file**, which includes selinux context, permission mode, owner, group. This means you don't need to worry about the metadata for files placed under `/cache/magisk_mount`: just copy the file to the correct place, reboot then you're done!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB

BIN
docs/images/restore_img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

@@ -1,76 +0,0 @@
# Magisk Modules and Online Repo
## Magisk Module Format
The Magisk module is a folder under `magisk`, which has a structure as described below:
```
magisk
├── .
├── .
├── a_module <--- The ID of the module, should match with module.prop
│   ├── auto_mount <--- If this file exists, auto mount is enabled
│   ├── disable <--- If this file exists, the module is disabled
│   ├── module.prop <--- This files stores the indentity and properties of the module
│   ├── post-fs-data.sh <--- This script will be executed in post-fs-data
│   ├── remove <--- If this file exists, the module will be removed next reboot
│   ├── service.sh <--- This script will be executed in late_start service
│   ├── system.prop <--- This file will be loaded as system props
│   ├── system <--- If auto mount is enabled, Magisk will "Magic Mount" this folder
│   │   ├── app
│   │   ├── .
│   │   └── .
│   ├── vendor <--- Auto generated. A symlink to $MODID/system/vendor
│   ├── . <--- Any other files/folders are allowed
│   └── .
├── another_module
│   ├── .
│   └── .
├── .
├── .
```
## Magisk Module Template
The **Magisk Module Template** is hosted **[here](https://github.com/topjohnwu/magisk-module-template)**.
It is a template to create a flashable zip to install Magisk Modules. It is created to be simple to use so that anyone can create their own modules easily. The template itself contains minimal scripting for installation; most of the functions are located externally in [util_functions.sh](https://github.com/topjohnwu/Magisk/blob/master/scripts/util_functions.sh), which will be installed along with Magisk, and can be upgraded through a Magisk upgrade without the need of a template update.
The template should meet most modules' needs. Add files into `system`, which will be cloned into `/system` by Magisk after installing the module, and in addition to module files, `system.prop`, `post-fs-data.sh`, `service.sh` are also installable through this template.
Here are some files you would want to know:
- `config.sh`: A simple script used as a configuration file for the actual installation file to correctly install your module. It is the place you can select which features your module needs/disables.
- `module.prop`: This file contains your module's indentity and properties, including name and versions etc.. This file will be used to identify your module on an actual device and in the [Magisk Modules Repo](https://github.com/Magisk-Modules-Repo)
- `common/*`: These files will be installed to the module with the correspond role
- `META-INF/com/google/android/update-binary`: The actual installation script. Modify this file for advanced custom behavior
## Create a Magisk Module With The Template
1. Clone / download [this repo](https://github.com/topjohnwu/magisk-module-template)
1. Open `config.sh` and carefully read the fully documented file. Follow the instructions within the script
1. You should at least have `config.sh` and `module.prop` modified
1. Directly zip all files; the result zip file is a flashable zip that can be used in both Magisk Manager and custom recoveries
1. Please check [**Notes**](#notes) for several precautions
## Submit Your Module to Magisk Modules Repo
If you want to share your module with others, you can submit your modules to [Magisk Modules Repo](https://github.com/Magisk-Modules-Repo). You would need some basic `git` knowledge here.
1. Create a module as stated above, and test if it works properly
1. Fork [this repo](https://github.com/topjohnwu/magisk-module-template) to your account
1. Commit and push your changes to your forked repo
1. Open an issue in [topjohnwu/Magisk_Repo_Central](https://github.com/topjohnwu/Magisk_Repo_Central/issues/new) with your repo link
1. I will review your module, and once accepted, your repo should be cloned into [Magisk-Modules-Repo](https://github.com/Magisk-Modules-Repo)
1. You should receive an email to become the collaborator so you can edit the repo in the future.
#### Once your module is live on the Modules Repo, the description of your repo should be the ID of your module. Please do NOT change the description, repeat, do NOT change the description.
![repo_description.png](images/repo_description.png)
## Notes
- The Module Template depends on external scripts, be aware of the minimal required Magisk version of the template.
- **Windows users please check here!!** The line endings of all text files should be in the **Unix format**. Please use advanced text editors like Sublime, Atom, Notepad++ etc. to edit **ALL** text files, **NEVER** use Windows Notepad.
- In `module.prop`, `version` can be an arbitrary string, so any fancy version name (e.g. ultra-beta-v1.1.1.1) is allowed. However, `versionCode` **MUST** be an integer. The value is used for version comparison.
- Make sure your module ID **does not contain any spaces**.
## Notes For Repo Developers
- Magisk Manager monitors all repo's `master` branch. Any changes to the branch `master` will be reflected to all users immediately. If you are working on an update for a module, please work on another branch, make sure it works, then finally merge the changes back to `master`.
- Once you finished upgrading your repo, increase at least the `versionCode` in `module.prop`. Magisk Manager uses this value to compare with the local installed module to determine whether an update is availible.
- The description of your repo should be the same as your module ID. If you changed your description, Magisk Manager will fail to identify your repo, and cannot relate installed module to the online repo together.

49
docs/modules.md Normal file
View File

@@ -0,0 +1,49 @@
# Magisk Modules
## Magisk Module Format
A Magisk module is a folder placed in the root folder in `magisk.img`, which has a structure as described below:
```
$MOUNTPOINT
├── .
├── .
├── $MODID <--- The ID of the module, should match with module.prop
│   ├── auto_mount <--- If this file exists, auto mount is enabled
│   ├── disable <--- If this file exists, the module is disabled
│   ├── module.prop <--- This files stores the identity and properties of the module
│   ├── post-fs-data.sh <--- This script will be executed in post-fs-data
│   ├── remove <--- If this file exists, the module will be removed next reboot
│   ├── service.sh <--- This script will be executed in late_start service
│   ├── system.prop <--- This file will be loaded as system props
│   ├── system <--- If auto mount is enabled, Magisk will "Magic Mount" this folder
│   │   ├── .
│   │   ├── .
│   │   └── .
│   ├── vendor <--- Auto generated. A symlink to $MODID/system/vendor
│   ├── . <--- Any other files/folders are allowed
│   └── .
├── another_module
│   ├── .
│   └── .
├── .
├── .
```
You are not required to use my Magisk Module Template to create a module. As long as you place files with the structure above, it will be recognized as a module.
## Magisk Module Template
The **Magisk Module Template** is hosted **[here](https://github.com/topjohnwu/magisk-module-template)**.
It is a template to create a flashable zip to install Magisk Modules. It is designed to be simple to use so that anyone can create their own modules easily. The template itself contains minimal scripting for installation; most of the functions are located externally in [util_functions.sh](https://github.com/topjohnwu/Magisk/blob/master/scripts/util_functions.sh), which will be installed along with Magisk, and can be upgraded through a Magisk upgrade without the need of a template update.
Here are some files you would want to know:
- `config.sh`: A simple script used as a configuration file. It is the place to configure which features your module needs/disables. A detailed instructions on how to use the template is also written in this file.
- `module.prop`: This file contains your module's indentity and properties, including name and versions etc.. This file will be used to identify your module on an actual device and in the [Magisk Modules Repo](https://github.com/Magisk-Modules-Repo)
- `common/*`: Boot stage scripts and `system.prop`
- `META-INF/com/google/android/update-binary`: The actual installation script. Modify this file for advanced custom behavior
And here are some notes to be aware of:
- The template depends on external Magisk scripts, please specify the correct `minMagisk` value in `module.prop` with the template version your module is based on, or the minimum Magisk version your module is tested on.
- **Windows users please check here!!** The line endings of all text files should be in the **Unix format**. Please use advanced text editors like Sublime, Atom, Notepad++ etc. to edit **ALL** text files, **NEVER** use Windows Notepad.
- In `module.prop`, `version` can be an arbitrary string, so any fancy version name (e.g. `ultra-beta-v1.1.1.1`) is allowed. However, `versionCode` **MUST** be an integer. The value is used for version comparison.
- Make sure your module ID **does not contain any spaces**.

File diff suppressed because one or more lines are too long

View File

@@ -1,25 +1,25 @@
# Tips and Tricks
## OTA Installation Tips
Magisk do modifications systemless-ly, which means applying official OTAs is much simpler. Here I provide a few tutorials for several different kind of devices to apply OTAs and preserve Magisk after the installation if possible.
Magisk does modifications systemless-ly, which means applying official OTAs is much simpler. Here I provide a few tutorials for several different kind of devices to apply OTAs and preserve Magisk after the installation if possible.
**This tutorial is only for Magisk v14.1+**
**NOTE: In order to apply OTAs, you HAVE to make sure you haven't modified `/system` (and `/vendor` if available) in anyway, even remounting the partition to rw will tamper block verification!!**
**NOTE: In order to apply OTAs, you HAVE to make sure you haven't modified `/system` (and `/vendor` if available) in any way. Even remounting the partition to rw will tamper block verification!!**
#### Prerequisites
1. Please disable *Automatic system updates* in developer options, so it won't install OTAs without your acknowledgement.
<img src="images/disable_auto_ota.png" width="250">
1. When an OTA is available, please go to Magisk Manager → Uninstall → Restore Stock Boot. **Do not reboot immediately or you will have Magisk uninstalled.** This will restore your boot back to 100% untouched stock boot image in order to pass boot verification. **This step is required before doing any of the following steps written below!**
<img src="images/restore_boot.png" width="250">
1. When an OTA is available, please go to Magisk Manager → Uninstall → Restore Images. **Do not reboot immediately or you will have Magisk uninstalled.** This will restore your boot (or dtbo if available) back to 100% untouched stock images in order to pass verifications. **This step is required before doing any of the following steps written below!**
<img src="images/restore_img.png" width="250">
#### Devices with A/B Partitions
(Includes Pixel family)
Due to the fact that these devices have two separate partitions and the OTA installation happens live when the system is still running, these devices have the best support: the out-of-the-box OTA installation works seamlessly and Magisk will be preserved after the installation.
Due to the fact that these devices have two separate partitions, and the OTA installation happens live while the system is still running, these devices have the best support: the out-of-the-box OTA installation works seamlessly and Magisk will be preserved after the installation.
1. After restoring stock boot image, apply OTAs as you normally would (Settings → System → System Updates)
1. Once the installation passed step 1 and starting step 2, go to Magisk Manager → Install → Install to Second Slot. This will install Magisk into the second boot image slot, which is the updated slot.
1. After restoring stock boot image, apply OTAs as you normally would (Settings → System → System Updates).
1. Once the installation has passed step 1 and is starting step 2, go to Magisk Manager → Install → Install to Second Slot. This will install Magisk into the second boot image slot, which is the updated slot.
<img src="images/ota_step2.png" width="250"> <img src="images/install_second_slot.png" width="250">
1. Let the OTA finish its job. After a reboot, the bootloader will switch to the updated system. Magisk should still be installed since we already patched the new boot image.
@@ -27,7 +27,7 @@ Due to the fact that these devices have two separate partitions and the OTA inst
(Includes Pixel family, Nexus family, Samsung devices)
(If you are using a device with A/B partitions, I **strongly** recommend you to use the method stated above since it uses the stock OTA installation mechanism and will always work under any circumstances)
The [FlashFire](https://play.google.com/store/apps/details?id=eu.chainfire.flash) app developed by Chainfire is a great app to apply OTAs and preserve root at the same time. However, whether it supports your device/system combination depends on the application itself, and support may also change in the future. If you face any issues, please directly [report to Chainfire](https://forum.xda-developers.com/general/paid-software/flashfire-t3075433).
The [FlashFire](https://play.google.com/store/apps/details?id=eu.chainfire.flash) app developed by Chainfire is a great app to apply OTAs and preserve root at the same time. However, whether it supports your device/system combination depends on the application itself, and support may change in the future. If you face any issues, please directly [report to Chainfire](https://forum.xda-developers.com/general/paid-software/flashfire-t3075433).
1. After restoring the stock boot image, download the OTA (Settings → System → System Updates), **do not press reboot to install.**
1. Open FlashFire, it should detect your OTA zip. Select OK in the popup dialog to let it do its setup.
@@ -36,18 +36,18 @@ The [FlashFire](https://play.google.com/store/apps/details?id=eu.chainfire.flash
1. Press the big **Flash** button, after a few minutes it should reboot updated with Magisk installed.
#### Other Devices - General Case
Unfortunately, there are no real good ways to apply OTAs on all devices. Also, the tutorial provided below will not preserve Magisk - you will have to manually re-root your device after the upgrade, and this will require PC access. Here I share my personal experience with my daily driver - HTC U11.
Unfortunately, there are no real good ways to apply OTAs on all devices. Also, the tutorial provided below will not preserve Magisk - you will have to manually re-root your device after the upgrade, and this will require PC access. Here I share my personal experience with HTC U11.
1. To properly install OTAs, you should have your stock recovery installed on your device. If you have custom recovery installed, you can restore it from your previous backup, or dumps found online, or factory images provided by OEMs.
If you decide to start by installing Magisk without touching your recovery partition, you have a few choices, either way you will end up with a Magisk rooted device, but recovery remain stock untouched:
If you decide to start by installing Magisk without touching your recovery partition, you have a few choices, either way you will end up with a Magisk rooted device, but recovery remains stock untouched:
- If supported, use `fastboot boot <recovery_img>` to boot the custom recovery and install Magisk.
- If you have a copy of your stock boot image dump, install Magisk by patching boot image via Magisk Manager, and manually flash it through download mode / fastboot mode / Odin
1. Once your device have stock recovery and stock boot image restored, download the OTA. Optionally, once you downloaded the OTA update zip, you can find a way to copy the zip out since you are still rooted. Personally I will extract the stock boot image and recovery image from the OTA zip for future usage (to patch via Magisk Manager or restore stock recovery etc.)
1. Once your device has stock recovery and stock boot image restored, download the OTA. Optionally, once you have downloaded the OTA update zip, you can find a way to copy the zip out, since you are still rooted. Personally, I extract the stock boot image and recovery image from the OTA zip for future usage (to patch via Magisk Manager or restore stock recovery etc.)
1. Apply and reboot your device. This will use the official stock OTA installation mechanism of your device to upgrade your system.
1. Once it's done you will be left with an upgraded, 100% stock, un-rooted device. You will have to manually flash Magisk back. Consider using the methods stated in step 1. to flash Magisk without touching the recovery partition if you want to receive stock OTAs frequently.
## Remove Files
How to efficiently remove a file systemless-ly? To actually make the file **disappear** is complicated (possible, not worth the effort). **Replacing it with a dummy file should be good enough**! Create an empty file with the same name and place it in the same path within a module, it shall replace your target file with a dummy file.
How to remove a file systemless-ly? To actually make the file **disappear** is complicated (possible, not worth the effort). **Replacing it with a dummy file should be good enough**! Create an empty file with the same name and place it in the same path within a module, it shall replace your target file with a dummy file.
## Remove Folders
Same as mentioned above, actually making the folder to **disappear** is not worth the effort. **Replacing it with an empty folder should be good enough**! A handy trick for module developers using [Magisk Module Template](https://github.com/topjohnwu/magisk-module-template) is to add the folder you want to remove into the `REPLACE` list within `config.sh`. If your module doesn't provide a correspond folder, it will create an empty folder, and automatically add `.replace` into the empty folder so the dummy folder will properly replace the one in `/system`.
Same as mentioned above, actually making the folder **disappear** is not worth the effort. **Replacing it with an empty folder should be good enough**! A handy trick for module developers using [Magisk Module Template](https://github.com/topjohnwu/magisk-module-template) is to add the folder you want to remove into the `REPLACE` list within `config.sh`. If your module doesn't provide a corresponding folder, it will create an empty folder, and automatically add `.replace` into the empty folder so the dummy folder will properly replace the one in `/system`.

287
docs/tools.md Normal file
View File

@@ -0,0 +1,287 @@
## Available Tools
Magisk comes with a lot of tools for installation, programs running as a daemon, and utilities for developers. This documentation covers 3 binaries, and many more tools are available as applets. The relation between tools are shown below:
```
magiskboot /* binary */
magiskinit /* binary */
magiskpolicy -> magiskinit
supolicy -> magiskinit /* alias of magiskpolicy */
magisk /* binary */
magiskhide -> magisk
resetprop -> magisk
su -> magisk
```
### magiskboot
A tool to unpack / repack boot images, parse and patch cpio and dtbs, hex patch binaries, compress / decompress with multiple algorithms. It is used to install Magisk into boot images.
`magiskboot` natively supports (which means it does not call external tools) all popular compression methods including `gzip` (used everywhere for compressing kernel and ramdisk), `lz4` (used to compress kernel in modern devices like Pixel), `lz4_legacy` (legacy LZ4 block format with special metadata used [only on LG](https://events.static.linuxfound.org/sites/events/files/lcjpcojp13_klee.pdf) to compress kernel), `lzma` (LZMA1 algorithm natively supported in Linux kernel, used in some custom kernel to compress ramdisk), `xz` (LZMA2 algorithm, very high compression rate, used in Magisk for high compression mode and storing binaries), and `bzip2` (used in desktop Linux boot images to create bzImage, haven't seen on Android yet).
The concept of `magiskboot` is to keep the images as intact as possible. For unpacking, it extracts the large chunks of data (kernel, ramdisk, second, dtb, extra etc.) and decompress them if possible. When repacking a boot image, the original boot image has to be provided so it can use the original headers (including MTK specific headers) with only changing the necessary entries such as the data chunk sizes, and re-compress all data with the original compression method. The same concept also applies to CPIO patching: it does not extract all files, modify in file system, archive all files back to cpio as usually done to create Linux `initramfs`, instead we do modifications directly in the cpio level in memory without involving any data extraction.
Command help message:
```
Usage: magiskboot <action> [args...]
Supported actions:
--parse <bootimg>
Parse <bootimg> only, do not unpack. Return values:
0:OK 1:error 2:insufficient boot partition size
3:chromeos 4:ELF32 5:ELF64
--unpack <bootimg>
Unpack <bootimg> to kernel, ramdisk.cpio, (second), (dtb), (extra) into
the current directory. Return value is the same as --parse
--repack <origbootimg> [outbootimg]
Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory
to [outbootimg], or new-boot.img if not specified.
It will compress ramdisk.cpio with the same method used in <origbootimg>,
or attempt to find ramdisk.cpio.[ext], and repack directly with the
compressed ramdisk file
--hexpatch <file> <hexpattern1> <hexpattern2>
Search <hexpattern1> in <file>, and replace with <hexpattern2>
--cpio <incpio> [commands...]
Do cpio commands to <incpio> (modifications are done directly)
Each command is a single argument, use quotes if necessary
Supported commands:
rm [-r] ENTRY
Remove ENTRY, specify [-r] to remove recursively
mkdir MODE ENTRY
Create directory ENTRY in permissions MODE
ln TARGET ENTRY
Create a symlink to TARGET with the name ENTRY
mv SOURCE DEST
Move SOURCE to DEST
add MODE ENTRY INFILE
Add INFILE as ENTRY in permissions MODE; replaces ENTRY if exists
extract [ENTRY OUT]
Extract ENTRY to OUT, or extract all entries to current directory
test
Test the current cpio's patch status. Return value:
0:stock 1:Magisk 2:other (phh, SuperSU, Xposed)
patch KEEPVERITY KEEPFORCEENCRYPT
Ramdisk patches. KEEP**** are boolean values
backup ORIG [SHA1]
Create ramdisk backups from ORIG
SHA1 of stock boot image is optional
restore
Restore ramdisk from ramdisk backup stored within incpio
magisk ORIG HIGHCOMP KEEPVERITY KEEPFORCEENCRYPT [SHA1]
Do Magisk patches and backups all in one step
Create ramdisk backups from ORIG
HIGHCOMP, KEEP**** are boolean values
SHA1 of stock boot image is optional
sha1
Print stock boot SHA1 if previously stored
--dtb-<cmd> <dtb>
Do dtb related cmds to <dtb> (modifications are done directly)
Supported commands:
dump
Dump all contents from dtb for debugging
test
Check if fstab has verity/avb flags. Return value:
0:no flags 1:flag exists
patch
Search for fstab and remove verity/avb
--compress[=method] <infile> [outfile]
Compress <infile> with [method] (default: gzip), optionally to [outfile]
<infile>/[outfile] can be '-' to be STDIN/STDOUT
Supported methods: gzip xz lzma bzip2 lz4 lz4_legacy
--decompress <infile> [outfile]
Detect method and decompress <infile>, optionally to [outfile]
<infile>/[outfile] can be '-' to be STDIN/STDOUT
Supported methods: gzip xz lzma bzip2 lz4 lz4_legacy
--sha1 <file>
Print the SHA1 checksum for <file>
--cleanup
Cleanup the current working directory
```
### magiskinit
This tool is created to unify Magisk support for both legacy "normal" devices and new `skip_initramfs` devices. The compiled binary will replace `init` in the ramdisk, so things could be done even before `init` is started.
`magiskinit` is responsible for constructing a proper rootfs on devices which the actual rootfs is placed in the system partition instead of ramdisk in `boot.img`, such as the Pixel familiy and most Treble enabled devices, or I like to call it `skip_initramfs` devices: it will parse kernel cmdline, mount sysfs, parse through uevent files to make the system (or vendor if available) block device node, then copy rootfs files from system. For normal "traditional" devices, it will simply swap `init` back to the original one and continue on to the next stage.
With a proper rootfs, `magiskinit` goes on and does all pre-init operations to setup a Magisk environment. It patches rootfs on the fly, providing fundamental support such as patching `init`, `init.rc`, run preliminary `sepolicy` patches, and extracts `magisk` and `init.magisk.rc` (these two files are embedded into `magiskinit`). Once all is done, it will spawn another process (`magiskinit_daemon`) to asynchronously run a full `sepolicy` patch, then starts monitoring the main Magisk daemon to make sure it is always running (a.k.a invincible mode); at the same time, it will execute the original `init` to hand the boot process back.
### magiskpolicy
(This tool is aliased to `supolicy` for compatibility with SuperSU's sepolicy tool)
This tool is an applet of `magiskinit`: once `magiskinit` had finished its mission in the pre-init stage, it will preserve an entry point for `magiskpolicy`. This tool could be used for advanced developers messing with `sepolicy`, a compiled binary containing SELinux rules. Normally Linux server admins directly modifies the SELinux policy sources (`*.te`) and recompile the `sepolicy` binary, but here we directly patch the binary file since we don't have access to the sources.
All processes spawned from the Magisk daemon, including root shells and all its forks, are running in the context `u:r:su:s0`. Magisk splits the built in patches into 2 parts: preliminary and full
- The preliminary patch should allow all Magisk internal procedures to run properly (can be done manually by the `--magisk` option). It also contains quite a few additional patches so most scripts can run in the daemon before the full patch is done
- The full patch adds the rule `allow su * * *` on top of the preliminary rules. This is done because stock Samsung ROMs do not support permissive; adding this rule makes the domain effectively permissive. Due to the concern of greatly increasing the boot time, the Magisk daemon will not wait for this patch to finish until the boot stage `late_start` triggers. What this means is that **only `late_start` service mode is guaranteed to run in a fully patched environment**. For non-Samsung devices it doesn't matter because `u:r:su:s0` is permissive anyways, but for full compatibility, it is **highly recommended to run boot scripts in `late_start` service mode**.
Command help message:
```
Usage: magiskpolicy [--options...] [policystatements...]
Options:
--live directly apply patched policy live
--magisk built-in rules for a Magisk selinux environment
--load FILE load policies from <infile>
--save FILE save policies to <outfile>
If no input file is specified, it will load from current policies
If neither --live nor --save is specified, nothing will happen
One policy statement should be treated as one parameter;
this means a full policy statement should be enclosed in quotes;
multiple policy statements can be provided in a single command
The statements has a format of "<action> [args...]"
Use '*' in args to represent every possible match.
Collections wrapped in curly brackets can also be used as args.
Supported policy statements:
Type 1:
"<action> source-class target-class permission-class permission"
Action: allow, deny, auditallow, auditdeny
Type 2:
"<action> source-class target-class permission-class ioctl range"
Action: allowxperm, auditallowxperm, dontauditxperm
Type 3:
"<action> class"
Action: create, permissive, enforcing
Type 4:
"attradd class attribute"
Type 5:
"typetrans source-class target-class permission-class default-class (optional: object-name)"
Notes:
- typetrans does not support the all match '*' syntax
- permission-class cannot be collections
- source-class and target-class can also be attributes
Example: allow { source1 source2 } { target1 target2 } permission-class *
Will be expanded to:
allow source1 target1 permission-class { all-permissions }
allow source1 target2 permission-class { all-permissions }
allow source2 target1 permission-class { all-permissions }
allow source2 target2 permission-class { all-permissions }
```
### magisk
The magisk binary contains all the magic of Magisk, providing all the features Magisk has to offer. When called with the name `magisk`, it works as an utility tool with many helper functions, and also the entry point for `init` to start Magisk services. These helper functions are extensively used by the [Magisk Module Template](https://github.com/topjohnwu/magisk-module-template) and Magisk Manager.
Command help message:
```
Usage: magisk [applet [arguments]...]
or: magisk [options]...
Options:
-c print current binary version
-v print running daemon version
-V print running daemon version code
--list list all available applets
--install [SOURCE] DIR symlink all applets to DIR. SOURCE is optional
--createimg IMG SIZE create ext4 image. SIZE is interpreted in MB
--imgsize IMG report ext4 image used/total size
--resizeimg IMG SIZE resize ext4 image. SIZE is interpreted in MB
--mountimg IMG PATH mount IMG to PATH and prints the loop device
--umountimg PATH LOOP unmount PATH and delete LOOP device
--[init service] start init service
--unlock-blocks set BLKROSET flag to OFF for all block devices
--restorecon fix selinux context on Magisk files and folders
--clone-attr SRC DEST clone permission, owner, and selinux context
Supported init services:
daemon, post-fs, post-fs-data, service
Supported applets:
su, resetprop, magiskhide
```
### su
An applet of `magisk`, the MagiskSU entry point, the good old `su` command.
Command help message:
```
Usage: su [options] [-] [user [argument...]]
Options:
-c, --command COMMAND pass COMMAND to the invoked shell
-h, --help display this help message and exit
-, -l, --login pretend the shell to be a login shell
-m, -p,
--preserve-environment preserve the entire environment
-s, --shell SHELL use SHELL instead of the default /system/bin/sh
-v, --version display version number and exit
-V display version code and exit,
this is used almost exclusively by Superuser.apk
-mm, -M,
--mount-master run in the global mount namespace,
use if you need to publicly apply mounts
```
Note: even though the `-Z, --context` option is not listed above, it actually still exists for compatibility with apps using SuperSU. However MagiskSU will silently ignore the option since it's no more relevant.
### resetprop
An applet of `magisk`, an advanced system property manipulation utility. Here's some background knowledge:
System properties are stored in a hybrid trie/binary tree data structure in memory. These properties are allowed to be read by many processes (natively via `libcutils`, in shells via the `getprop` command); however, only the `init` process have direct write access to the memory of property data. `init` provides a `property_service` to accept property update requests and acts as a gatekeeper, doing things such as preventing **read-only** props to be overridden and storing **persist** props to non-volatile storages. In addition, property triggers registered in `*.rc` scripts are also handled here.
`resetprop` is created by pulling out the portion of source code managing properties from AOSP and try to mimic what `init` is doing. With some hackery the result is that we have direct access to the data structure, bypassing the need to go through `property_service` to gain arbitrary control. Here is a small implementation detail: the data structure and the stack-like memory allocation method does not support removing props (they are **designed NOT** to be removed); prop deletion is accomplished by detaching the target node from the tree structure, making it effectively invisible. As we cannot reclaim the memory allocated to store the property, this wastes a few bytes of memory but it shouldn't be a big deal unless you are adding and deleting hundreds of thousands of props over and over again.
Due to the fact that we bypassed `property_service`, there are a few things developer should to be aware of:
- `on property:foo=bar` triggers registered in `*.rc` scripts will not be triggered when props are changed. This could be a good thing or a bad thing, depending on what behavior you expect. The default behavior of `resetprop` matches the original `setprop`, which **WILL** trigger events (implemented by deleting the prop and set the props via `property_service`), but there is a flag (`-n`) to disable it if you need this special behavior.
- persist props are stored both in memory and in `/data/property`. By default, deleting props will **NOT** remove it from persistent storage, meaning the prop will be restored after the next reboot; reading props will **NOT** read from persistent storage, as this is the behavior of normal `getprop`. With the flag `-p` enabled, deleting props will remove the prop **BOTH** in memory and `/data/property`; props will be read from **BOTH** in memory and persistent storage.
Command help message:
```
Usage: resetprop [flags] [options...]
Options:
-h, --help show this message
(no arguments) print all properties
NAME get property
NAME VALUE set property entry NAME with VALUE
--file FILE load props from FILE
--delete NAME delete property
Flags:
-v print verbose output to stderr
-n set properties without init triggers
only affects setprop
-p access actual persist storage
only affects getprop and deleteprop
```
### magiskhide
An applet of `magisk`, the CLI to control MagiskHide. Use this tool to communicate with the daemon to change MagiskHide settings.
Command help message:
```
Usage: magiskhide [--options [arguments...] ]
Options:
--enable Start magiskhide
--disable Stop magiskhide
--add PROCESS Add PROCESS to the hide list
--rm PROCESS Remove PROCESS from the hide list
--ls Print out the current hide list
```

25
gradle.properties Normal file
View File

@@ -0,0 +1,25 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2560m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true
# When set to true the Gradle daemon is used to run the build. For local developer builds this is our favorite property.
# The developer environment is optimized for speed and feedback so we nearly always run Gradle jobs with the daemon.
org.gradle.daemon=true
# Configuration on demand is not supported by the current version of the Android Gradle plugin since you are using Gradle version 4.6 or above
org.gradle.configureondemand=false

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
gradlew vendored Executable file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
java

Submodule java deleted from f5ceee547c

View File

@@ -1,4 +0,0 @@
APP_ABI := x86 x86_64 armeabi-v7a arm64-v8a
APP_PLATFORM := android-21
APP_CFLAGS := $(MAGISK_FLAGS) -std=gnu99
APP_CPPFLAGS := -std=c++11

View File

@@ -1,334 +0,0 @@
/* daemon.c - Magisk Daemon
*
* Start the daemon and wait for requests
* Connect the daemon and send requests through sockets
*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <selinux/selinux.h>
#include "magisk.h"
#include "utils.h"
#include "daemon.h"
#include "magiskpolicy.h"
#include "resetprop.h"
pthread_t sepol_patch;
int is_restart = 0;
static void *request_handler(void *args) {
int client = *((int *) args);
free(args);
client_request req = read_int(client);
struct ucred credentials;
get_client_cred(client, &credentials);
switch (req) {
case LAUNCH_MAGISKHIDE:
case STOP_MAGISKHIDE:
case ADD_HIDELIST:
case RM_HIDELIST:
case LS_HIDELIST:
case POST_FS:
case POST_FS_DATA:
case LATE_START:
if (credentials.uid != 0) {
write_int(client, ROOT_REQUIRED);
close(client);
return NULL;
}
default:
break;
}
switch (req) {
case LAUNCH_MAGISKHIDE:
launch_magiskhide(client);
break;
case STOP_MAGISKHIDE:
stop_magiskhide(client);
break;
case ADD_HIDELIST:
add_hide_list(client);
break;
case RM_HIDELIST:
rm_hide_list(client);
break;
case LS_HIDELIST:
ls_hide_list(client);
break;
case SUPERUSER:
su_daemon_receiver(client);
break;
case CHECK_VERSION:
write_string(client, MAGISK_VER_STR);
close(client);
break;
case CHECK_VERSION_CODE:
write_int(client, MAGISK_VER_CODE);
close(client);
break;
case POST_FS:
post_fs(client);
break;
case POST_FS_DATA:
post_fs_data(client);
break;
case LATE_START:
late_start(client);
break;
default:
break;
}
return NULL;
}
/* Setup the address and return socket fd */
static int setup_socket(struct sockaddr_un *sun) {
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_LOCAL;
memcpy(sun->sun_path, REQUESTOR_DAEMON_PATH, sizeof(REQUESTOR_DAEMON_PATH) - 1);
return fd;
}
static void *start_magisk_hide(void *args) {
launch_magiskhide(-1);
return NULL;
}
void auto_start_magiskhide() {
char *hide_prop = getprop2(MAGISKHIDE_PROP, 1);
if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) {
pthread_t thread;
xpthread_create(&thread, NULL, start_magisk_hide, NULL);
pthread_detach(thread);
}
free(hide_prop);
}
void start_daemon() {
setsid();
setcon("u:r:su:s0");
umask(0);
int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
xdup2(fd, STDIN_FILENO);
xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO);
close(fd);
// Block user signals
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, SIGUSR1);
sigaddset(&block_set, SIGUSR2);
pthread_sigmask(SIG_SETMASK, &block_set, NULL);
struct sockaddr_un sun;
fd = setup_socket(&sun);
xbind(fd, (struct sockaddr*) &sun, sizeof(sun));
xlisten(fd, 10);
if ((is_restart = access(MAGISKTMP, F_OK) == 0)) {
// Restart stuffs if the daemon is restarted
exec_command_sync("logcat", "-b", "all", "-c", NULL);
auto_start_magiskhide();
start_debug_log();
}
// Start the log monitor
monitor_logs();
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n");
// Change process name
strcpy(argv0, "magisk_daemon");
// Unlock all blocks for rw
unlock_blocks();
// Notifiy init the daemon is started
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT));
// Loop forever to listen for requests
while(1) {
int *client = xmalloc(sizeof(int));
*client = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC);
pthread_t thread;
xpthread_create(&thread, NULL, request_handler, client);
// Detach the thread, we will never join it
pthread_detach(thread);
}
}
/* Connect the daemon, and return a socketfd */
int connect_daemon() {
struct sockaddr_un sun;
int fd = setup_socket(&sun);
if (xconnect(fd, (struct sockaddr*) &sun, sizeof(sun))) {
// If we cannot access the daemon, we start a daemon in the child process if possible
if (getuid() != UID_ROOT || getgid() != UID_ROOT) {
fprintf(stderr, "No daemon is currently running!\n");
exit(1);
}
if (xfork() == 0) {
LOGD("client: connect fail, try launching new daemon process\n");
close(fd);
start_daemon();
}
do {
// Wait for 10ms
usleep(10);
} while (connect(fd, (struct sockaddr*) &sun, sizeof(sun)));
}
return fd;
}
/*
* Receive a file descriptor from a Unix socket.
* Contributed by @mkasick
*
* Returns the file descriptor on success, or -1 if a file
* descriptor was not actually included in the message
*
* On error the function terminates by calling exit(-1)
*/
int recv_fd(int sockfd) {
// Need to receive data from the message, otherwise don't care about it.
char iovbuf;
struct iovec iov = {
.iov_base = &iovbuf,
.iov_len = 1,
};
char cmsgbuf[CMSG_SPACE(sizeof(int))];
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = cmsgbuf,
.msg_controllen = sizeof(cmsgbuf),
};
xrecvmsg(sockfd, &msg, MSG_WAITALL);
// Was a control message actually sent?
switch (msg.msg_controllen) {
case 0:
// No, so the file descriptor was closed and won't be used.
return -1;
case sizeof(cmsgbuf):
// Yes, grab the file descriptor from it.
break;
default:
goto error;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg == NULL ||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
error:
LOGE("unable to read fd");
exit(-1);
}
return *(int *)CMSG_DATA(cmsg);
}
/*
* Send a file descriptor through a Unix socket.
* Contributed by @mkasick
*
* On error the function terminates by calling exit(-1)
*
* fd may be -1, in which case the dummy data is sent,
* but no control message with the FD is sent.
*/
void send_fd(int sockfd, int fd) {
// Need to send some data in the message, this will do.
struct iovec iov = {
.iov_base = "",
.iov_len = 1,
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
char cmsgbuf[CMSG_SPACE(sizeof(int))];
if (fd != -1) {
// Is the file descriptor actually open?
if (fcntl(fd, F_GETFD) == -1) {
if (errno != EBADF) {
PLOGE("unable to send fd");
}
// It's closed, don't send a control message or sendmsg will EBADF.
} else {
// It's open, send the file descriptor in a control message.
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(cmsg) = fd;
}
}
xsendmsg(sockfd, &msg, 0);
}
int read_int(int fd) {
int val;
xxread(fd, &val, sizeof(int));
return val;
}
void write_int(int fd, int val) {
if (fd < 0) return;
xwrite(fd, &val, sizeof(int));
}
char* read_string(int fd) {
int len = read_int(fd);
if (len > PATH_MAX || len < 0) {
LOGE("invalid string length %d", len);
exit(1);
}
char* val = xmalloc(sizeof(char) * (len + 1));
xxread(fd, val, len);
val[len] = '\0';
return val;
}
void write_string(int fd, const char* val) {
if (fd < 0) return;
int len = strlen(val);
write_int(fd, len);
xwrite(fd, val, len);
}

View File

@@ -1,155 +0,0 @@
/* log_monitor.c - New thread to monitor logcat
*
* A universal logcat monitor for many usages. Add listeners to the list,
* and the pointer of the new log line will be sent through pipes to trigger
* asynchronous events without polling
*/
#include <stdio.h>
#include <limits.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include "magisk.h"
#include "utils.h"
int logcat_events[] = { -1, -1, -1 };
extern int is_restart;
#ifdef MAGISK_DEBUG
static int debug_log_pid, debug_log_fd;
#endif
static void *logger_thread(void *args) {
int log_fd = -1, log_pid;
char line[4096];
LOGD("log_monitor: logger start");
while (1) {
// Start logcat
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-b", "all" , "-v", "threadtime", "-s", "am_proc_start", "Magisk", NULL);
while (fdgets(line, sizeof(line), log_fd)) {
for (int i = 0; i < (sizeof(logcat_events) / sizeof(int)); ++i) {
if (logcat_events[i] > 0) {
char *s = strdup(line);
xwrite(logcat_events[i], &s, sizeof(s));
}
}
if (kill(log_pid, 0))
break;
}
// Clear buffer if restart required
exec_command_sync("logcat", "-b", "all", "-c", NULL);
}
// Should never be here, but well...
return NULL;
}
static void *magisk_log_thread(void *args) {
int have_data = 0;
// Temp buffer for logs before we have data access
struct vector logs;
vec_init(&logs);
FILE *log;
int pipefd[2];
if (xpipe2(pipefd, O_CLOEXEC) == -1)
return NULL;
// Register our listener
logcat_events[LOG_EVENT] = pipefd[1];
LOGD("log_monitor: magisk log dumper start");
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) {
char *ss;
if ((ss = strstr(line, " Magisk")) && (ss[-1] != 'D') && (ss[-1] != 'V')) {
if (!have_data) {
if ((have_data = check_data())) {
// Dump buffered logs to file
if (!is_restart)
rename(LOGFILE, LASTLOG);
log = xfopen(LOGFILE, "a");
setbuf(log, NULL);
char *tmp;
vec_for_each(&logs, tmp) {
fprintf(log, "%s", tmp);
free(tmp);
}
vec_destroy(&logs);
} else {
vec_push_back(&logs, strdup(line));
}
}
if (have_data)
fprintf(log, "%s", line);
}
}
return NULL;
}
static void *debug_magisk_log_thread(void *args) {
FILE *log = xfopen(DEBUG_LOG, "a");
setbuf(log, NULL);
int pipefd[2];
if (xpipe2(pipefd, O_CLOEXEC) == -1)
return NULL;
LOGD("log_monitor: debug log dumper start");
// Register our listener
logcat_events[DEBUG_EVENT] = pipefd[1];
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) {
char *ss;
if ((ss = strstr(line, "Magisk")))
fprintf(log, "%s", line);
}
return NULL;
}
/* Start new threads to monitor logcat and dump to logfile */
void monitor_logs() {
pthread_t thread;
// Start log file dumper before monitor
xpthread_create(&thread, NULL, magisk_log_thread, NULL);
pthread_detach(thread);
// Start logcat monitor
xpthread_create(&thread, NULL, logger_thread, NULL);
pthread_detach(thread);
}
void start_debug_full_log() {
#ifdef MAGISK_DEBUG
// Log everything initially
debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", "-v", "threadtime", NULL);
close(debug_log_fd);
#endif
}
void stop_debug_full_log() {
#ifdef MAGISK_DEBUG
// Stop recording the boot logcat after every boot task is done
kill(debug_log_pid, SIGTERM);
waitpid(debug_log_pid, NULL, 0);
// Start debug thread
start_debug_log();
#endif
}
void start_debug_log() {
#ifdef MAGISK_DEBUG
pthread_t thread;
// Start debug thread
xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL);
pthread_detach(thread);
#endif
}

View File

@@ -1,180 +0,0 @@
/* main.c - The multicall entry point
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <libgen.h>
#include "utils.h"
#include "magisk.h"
#include "daemon.h"
char *argv0;
char *applet[] =
{ "su", "resetprop", "magiskhide", NULL };
int (*applet_main[]) (int, char *[]) =
{ su_client_main, resetprop_main, magiskhide_main, NULL };
int create_links(const char *bin, const char *path) {
char self[PATH_MAX], linkpath[PATH_MAX];
if (bin == NULL) {
xreadlink("/proc/self/exe", self, sizeof(self));
bin = self;
}
int ret = 0;
for (int i = 0; applet[i]; ++i) {
snprintf(linkpath, sizeof(linkpath), "%s/%s", path, applet[i]);
unlink(linkpath);
ret |= symlink(bin, linkpath);
}
return ret;
}
static void usage() {
fprintf(stderr,
"Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) multi-call binary\n"
"\n"
"Usage: %s [applet [arguments]...]\n"
" or: %s [options]...\n"
"\n"
"Options:\n"
" -c print current binary version\n"
" -v print running daemon version\n"
" -V print running daemon version code\n"
" --list list all availible applets\n"
" --install [SOURCE] DIR symlink all applets to DIR. SOURCE is optional\n"
" --createimg IMG SIZE create ext4 image. SIZE is interpreted in MB\n"
" --imgsize IMG report ext4 image used/total size\n"
" --resizeimg IMG SIZE resize ext4 image. SIZE is interpreted in MB\n"
" --mountimg IMG PATH mount IMG to PATH and prints the loop device\n"
" --umountimg PATH LOOP unmount PATH and delete LOOP device\n"
" --[init service] start init service\n"
" --unlock-blocks set BLKROSET flag to OFF for all block devices\n"
" --restorecon fix selinux context on Magisk files and folders\n"
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
"\n"
"Supported init services:\n"
" daemon, post-fs, post-fs-data, service\n"
"\n"
"Supported applets:\n"
, argv0, argv0);
for (int i = 0; applet[i]; ++i)
fprintf(stderr, i ? ", %s" : " %s", applet[i]);
fprintf(stderr, "\n\n");
exit(1);
}
int main(int argc, char *argv[]) {
argv0 = argv[0];
if (strcmp(basename(argv[0]), "magisk") == 0) {
if (argc < 2) usage();
if (strcmp(argv[1], "-c") == 0) {
printf("%s\n", MAGISK_VER_STR);
return 0;
} else if (strcmp(argv[1], "-v") == 0) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION);
char *v = read_string(fd);
printf("%s\n", v);
free(v);
return 0;
} else if (strcmp(argv[1], "-V") == 0) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION_CODE);
printf("%d\n", read_int(fd));
return 0;
} else if (strcmp(argv[1], "--install") == 0) {
if (argc < 3) usage();
if (argc == 3) return create_links(NULL, argv[2]);
else return create_links(argv[2], argv[3]);
} else if (strcmp(argv[1], "--list") == 0) {
for (int i = 0; applet[i]; ++i)
printf("%s\n", applet[i]);
return 0;
} else if (strcmp(argv[1], "--createimg") == 0) {
if (argc < 4) usage();
int size;
sscanf(argv[3], "%d", &size);
return create_img(argv[2], size);
} else if (strcmp(argv[1], "--imgsize") == 0) {
if (argc < 3) usage();
int used, total;
if (get_img_size(argv[2], &used, &total)) {
fprintf(stderr, "Cannot check %s size\n", argv[2]);
return 1;
}
printf("%d %d\n", used, total);
return 0;
} else if (strcmp(argv[1], "--resizeimg") == 0) {
if (argc < 4) usage();
int used, total, size;
sscanf(argv[3], "%d", &size);
if (get_img_size(argv[2], &used, &total)) {
fprintf(stderr, "Cannot check %s size\n", argv[2]);
return 1;
}
if (size <= used) {
fprintf(stderr, "Cannot resize smaller than %dM\n", used);
return 1;
}
return resize_img(argv[2], size);
} else if (strcmp(argv[1], "--mountimg") == 0) {
if (argc < 4) usage();
char *loop = mount_image(argv[2], argv[3]);
if (loop == NULL) {
fprintf(stderr, "Cannot mount image!\n");
return 1;
} else {
printf("%s\n", loop);
free(loop);
return 0;
}
} else if (strcmp(argv[1], "--umountimg") == 0) {
if (argc < 4) usage();
umount_image(argv[2], argv[3]);
return 0;
} else if (strcmp(argv[1], "--unlock-blocks") == 0) {
unlock_blocks();
return 0;
} else if (strcmp(argv[1], "--restorecon") == 0) {
fix_filecon();
return 0;
} else if (strcmp(argv[1], "--clone-attr") == 0) {
if (argc < 4) usage();
clone_attr(argv[2], argv[3]);
return 0;
} else if (strcmp(argv[1], "--daemon") == 0) {
// Start daemon, this process won't return
start_daemon();
} else if (strcmp(argv[1], "--post-fs") == 0) {
int fd = connect_daemon();
write_int(fd, POST_FS);
return read_int(fd);
} else if (strcmp(argv[1], "--post-fs-data") == 0) {
int fd = connect_daemon();
write_int(fd, POST_FS_DATA);
return read_int(fd);
} else if (strcmp(argv[1], "--service") == 0) {
int fd = connect_daemon();
write_int(fd, LATE_START);
return read_int(fd);
} else {
// It's calling applets
--argc;
++argv;
}
}
// Applets
for (int i = 0; applet[i]; ++i) {
if (strcmp(basename(argv[0]), applet[i]) == 0)
return (*applet_main[i])(argc, argv);
}
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
return 1;
}

Submodule jni/external/busybox deleted from e3a1a4d91f

1
jni/external/dtc vendored

Submodule jni/external/dtc deleted from 22a65c5331

1
jni/external/lz4 vendored

Submodule jni/external/lz4 deleted from c10863b98e

Submodule jni/external/selinux deleted from 2fefdfc40f

View File

@@ -1,66 +0,0 @@
/* magisk.h - Top header
*/
#ifndef _MAGISK_H_
#define _MAGISK_H_
#include "logging.h"
#define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK"
#define REQUESTOR_DAEMON_PATH "\0MAGISK"
#ifndef ARG_MAX
#define ARG_MAX 4096
#endif
#define LOGFILE "/cache/magisk.log"
#define LASTLOG "/cache/last_magisk.log"
#define DEBUG_LOG "/data/magisk_debug.log"
#define UNBLOCKFILE "/dev/.magisk.unblock"
#define PATCHSTART "/dev/.magisk.patch.start"
#define PATCHDONE "/dev/.magisk.patch.done"
#define DISABLEFILE "/cache/.disable_magisk"
#define UNINSTALLER "/cache/magisk_uninstaller.sh"
#define CACHEMOUNT "/cache/magisk_mount"
#define MAGISKTMP "/sbin/.core"
#define MIRRDIR MAGISKTMP "/mirror"
#define BBPATH MAGISKTMP "/busybox"
#define MOUNTPOINT MAGISKTMP "/img"
#define FAKEPOINT "/magisk"
#define COREDIR MOUNTPOINT "/.core"
#define HOSTSFILE COREDIR "/hosts"
#define HIDELIST COREDIR "/hidelist"
#define MAINIMG "/data/magisk.img"
#define DATABIN "/data/magisk"
#define MANAGERAPK MIRRDIR "/bin/magisk.apk"
#define MAGISKRC "/init.magisk.rc"
#define SELINUX_PATH "/sys/fs/selinux/"
#define SELINUX_ENFORCE SELINUX_PATH "enforce"
#define SELINUX_POLICY SELINUX_PATH "policy"
#define SELINUX_LOAD SELINUX_PATH "load"
#define MAGISKHIDE_PROP "persist.magisk.hide"
extern char *argv0; /* For changing process name */
extern char *applet[];
extern int (*applet_main[]) (int, char *[]);
int create_links(const char *bin, const char *path);
// Multi-call entrypoints
int magiskhide_main(int argc, char *argv[]);
int magiskpolicy_main(int argc, char *argv[]);
int su_client_main(int argc, char *argv[]);
#ifdef __cplusplus
extern "C" {
#endif
int resetprop_main(int argc, char *argv[]);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,36 +0,0 @@
/* magiskpolicy.h - Public API for policy patching
*/
#ifndef _MAGISKPOLICY_H
#define _MAGISKPOLICY_H
#include <stdlib.h>
#define ALL NULL
// policydb functions
int load_policydb(const char *filename);
int dump_policydb(const char *filename);
void destroy_policydb();
// Handy functions
int sepol_allow(char *s, char *t, char *c, char *p);
int sepol_deny(char *s, char *t, char *c, char *p);
int sepol_auditallow(char *s, char *t, char *c, char *p);
int sepol_auditdeny(char *s, char *t, char *c, char *p);
int sepol_typetrans(char *s, char *t, char *c, char *d, char *o);
int sepol_allowxperm(char *s, char *t, char *c, char *range);
int sepol_auditallowxperm(char *s, char *t, char *c, char *range);
int sepol_dontauditxperm(char *s, char *t, char *c, char *range);
int sepol_create(char *s);
int sepol_permissive(char *s);
int sepol_enforce(char *s);
int sepol_attradd(char *s, char *a);
int sepol_exists(char *source);
// Built in rules
void sepol_min_rules();
void sepol_med_rules();
void sepol_full_rules();
#endif

View File

@@ -1,46 +0,0 @@
const char magiskrc[] =
// Triggers
"on post-fs\n"
" start logd\n"
" start magisk_daemon\n"
" wait /dev/.magisk.unblock 5\n"
" rm /dev/.magisk.unblock\n"
" start magisk_pfs\n"
" wait /dev/.magisk.unblock 10\n"
"\n"
"on post-fs-data\n"
" load_persist_props\n"
" rm /dev/.magisk.unblock\n"
" start magisk_pfsd\n"
" wait /dev/.magisk.unblock 10\n"
" rm /dev/.magisk.unblock\n"
"\n"
// Services
"service magisk_daemon /sbin/magisk --daemon\n"
" user root\n"
" seclabel u:r:su:s0\n"
"\n"
"service magisk_pfs /sbin/magisk --post-fs\n"
" user root\n"
" seclabel u:r:su:s0\n"
" oneshot\n"
"\n"
"service magisk_pfsd /sbin/magisk --post-fs-data\n"
" user root\n"
" seclabel u:r:su:s0\n"
" oneshot\n"
"\n"
"service magisk_service /sbin/magisk --service\n"
" class late_start\n"
" user root\n"
" seclabel u:r:su:s0\n"
" oneshot\n"
;

View File

@@ -1,315 +0,0 @@
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "bootimg.h"
#include "magiskboot.h"
#include "utils.h"
#include "logging.h"
static void dump(void *buf, size_t size, const char *filename) {
int fd = creat(filename, 0644);
xwrite(fd, buf, size);
close(fd);
}
static size_t restore(const char *filename, int fd) {
int ifd = xopen(filename, O_RDONLY);
size_t size = lseek(ifd, 0, SEEK_END);
lseek(ifd, 0, SEEK_SET);
xsendfile(fd, ifd, NULL, size);
close(ifd);
return size;
}
static void restore_buf(int fd, const void *buf, size_t size) {
xwrite(fd, buf, size);
}
static void print_hdr(const boot_img_hdr *hdr) {
fprintf(stderr, "KERNEL [%d] @ 0x%08x\n", hdr->kernel_size, hdr->kernel_addr);
fprintf(stderr, "RAMDISK [%d] @ 0x%08x\n", hdr->ramdisk_size, hdr->ramdisk_addr);
fprintf(stderr, "SECOND [%d] @ 0x%08x\n", hdr->second_size, hdr->second_addr);
fprintf(stderr, "EXTRA [%d] @ 0x%08x\n", hdr->extra_size, hdr->tags_addr);
fprintf(stderr, "PAGESIZE [%d]\n", hdr->page_size);
if (hdr->os_version != 0) {
int a,b,c,y,m = 0;
int os_version, os_patch_level;
os_version = hdr->os_version >> 11;
os_patch_level = hdr->os_version & 0x7ff;
a = (os_version >> 14) & 0x7f;
b = (os_version >> 7) & 0x7f;
c = os_version & 0x7f;
fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c);
y = (os_patch_level >> 4) + 2000;
m = os_patch_level & 0xf;
fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m);
}
fprintf(stderr, "NAME [%s]\n", hdr->name);
fprintf(stderr, "CMDLINE [%s]\n", hdr->cmdline);
fprintf(stderr, "\n");
}
int parse_img(void *orig, size_t size, boot_img *boot) {
void *base, *end;
size_t pos = 0;
int ret = 0;
memset(boot, 0, sizeof(*boot));
for(base = orig, end = orig + size; base < end; base += 256, size -= 256) {
switch (check_type(base)) {
case CHROMEOS:
// The caller should know it's chromeos, as it needs additional signing
ret = 2;
continue;
case ELF32:
exit(3);
case ELF64:
exit(4);
case AOSP:
// Read the header
memcpy(&boot->hdr, base, sizeof(boot->hdr));
pos += boot->hdr.page_size;
print_hdr(&boot->hdr);
boot->kernel = base + pos;
pos += boot->hdr.kernel_size;
mem_align(&pos, boot->hdr.page_size);
boot->ramdisk = base + pos;
pos += boot->hdr.ramdisk_size;
mem_align(&pos, boot->hdr.page_size);
if (boot->hdr.second_size) {
boot->second = base + pos;
pos += boot->hdr.second_size;
mem_align(&pos, boot->hdr.page_size);
}
if (boot->hdr.extra_size) {
boot->extra = base + pos;
pos += boot->hdr.extra_size;
mem_align(&pos, boot->hdr.page_size);
}
if (pos < size) {
boot->tail = base + pos;
boot->tail_size = end - base - pos;
}
// Search for dtb in kernel
for (int i = 0; i < boot->hdr.kernel_size; ++i) {
if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) {
boot->dtb = boot->kernel + i;
boot->dt_size = boot->hdr.kernel_size - i;
boot->hdr.kernel_size = i;
fprintf(stderr, "DTB [%d]\n", boot->dt_size);
}
}
boot->ramdisk_type = check_type(boot->ramdisk);
boot->kernel_type = check_type(boot->kernel);
// Check MTK
if (boot->kernel_type == MTK) {
fprintf(stderr, "MTK_KERNEL_HDR [512]\n");
boot->flags |= MTK_KERNEL;
memcpy(&boot->mtk_kernel_hdr, boot->kernel, sizeof(mtk_hdr));
boot->kernel += 512;
boot->hdr.kernel_size -= 512;
boot->kernel_type = check_type(boot->kernel);
}
if (boot->ramdisk_type == MTK) {
fprintf(stderr, "MTK_RAMDISK_HDR [512]\n");
boot->flags |= MTK_RAMDISK;
memcpy(&boot->mtk_ramdisk_hdr, boot->ramdisk, sizeof(mtk_hdr));
boot->ramdisk += 512;
boot->hdr.ramdisk_size -= 512;
boot->ramdisk_type = check_type(boot->ramdisk);
}
char fmt[16];
get_type_name(boot->kernel_type, fmt);
fprintf(stderr, "KERNEL_FMT [%s]\n", fmt);
get_type_name(boot->ramdisk_type, fmt);
fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt);
fprintf(stderr, "\n");
return ret;
default:
continue;
}
}
LOGE("No boot image magic found!\n");
return 1;
}
void unpack(const char* image) {
size_t size;
void *orig;
mmap_ro(image, &orig, &size);
int fd;
boot_img boot;
// Parse image
fprintf(stderr, "Parsing boot image: [%s]\n\n", image);
int ret = parse_img(orig, size, &boot);
// Dump kernel
if (COMPRESSED(boot.kernel_type)) {
fd = creat(KERNEL_FILE, 0644);
decomp(boot.kernel_type, fd, boot.kernel, boot.hdr.kernel_size);
close(fd);
} else {
dump(boot.kernel, boot.hdr.kernel_size, KERNEL_FILE);
}
if (boot.dt_size) {
// Dump dtb
dump(boot.dtb, boot.dt_size, DTB_FILE);
}
// Dump ramdisk
if (COMPRESSED(boot.ramdisk_type)) {
fd = creat(RAMDISK_FILE, 0644);
decomp(boot.ramdisk_type, fd, boot.ramdisk, boot.hdr.ramdisk_size);
close(fd);
} else {
dump(boot.ramdisk, boot.hdr.ramdisk_size, RAMDISK_FILE ".raw");
LOGE("Unknown ramdisk format! Dumped to %s\n", RAMDISK_FILE ".raw");
}
if (boot.hdr.second_size) {
// Dump second
dump(boot.second, boot.hdr.second_size, SECOND_FILE);
}
if (boot.hdr.extra_size) {
// Dump extra
dump(boot.extra, boot.hdr.extra_size, EXTRA_FILE);
}
munmap(orig, size);
exit(ret);
}
void repack(const char* orig_image, const char* out_image) {
size_t size;
void *orig;
boot_img boot;
// There are possible two MTK headers
size_t mtk_kernel_off, mtk_ramdisk_off;
// Load original image
mmap_ro(orig_image, &orig, &size);
// Parse original image
fprintf(stderr, "Parsing boot image: [%s]\n\n", orig_image);
parse_img(orig, size, &boot);
fprintf(stderr, "Repack to boot image: [%s]\n\n", out_image);
// Create new image
int fd = creat(out_image, 0644);
// Skip a page for header
write_zero(fd, boot.hdr.page_size);
if (boot.flags & MTK_KERNEL) {
// Record position and skip MTK header
mtk_kernel_off = lseek(fd, 0, SEEK_CUR);
write_zero(fd, 512);
}
if (COMPRESSED(boot.kernel_type)) {
size_t raw_size;
void *kernel_raw;
mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size);
boot.hdr.kernel_size = comp(boot.kernel_type, fd, kernel_raw, raw_size);
munmap(kernel_raw, raw_size);
} else {
boot.hdr.kernel_size = restore(KERNEL_FILE, fd);
}
// Restore dtb
if (boot.dt_size && access(DTB_FILE, R_OK) == 0) {
boot.hdr.kernel_size += restore(DTB_FILE, fd);
}
file_align(fd, boot.hdr.page_size, 1);
if (boot.flags & MTK_RAMDISK) {
// Record position and skip MTK header
mtk_ramdisk_off = lseek(fd, 0, SEEK_CUR);
write_zero(fd, 512);
}
if (access(RAMDISK_FILE, R_OK) == 0) {
// If we found raw cpio, compress to original format
size_t cpio_size;
void *cpio;
mmap_ro(RAMDISK_FILE, &cpio, &cpio_size);
boot.hdr.ramdisk_size = comp(boot.ramdisk_type, fd, cpio, cpio_size);
munmap(cpio, cpio_size);
} else {
// Find compressed ramdisk
char name[PATH_MAX];
int found = 0;
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
if (access(name, R_OK) == 0) {
found = 1;
break;
}
}
if (!found)
LOGE("No ramdisk exists!\n");
boot.hdr.ramdisk_size = restore(name, fd);
}
file_align(fd, boot.hdr.page_size, 1);
// Restore second
if (boot.hdr.second_size && access(SECOND_FILE, R_OK) == 0) {
boot.hdr.second_size = restore(SECOND_FILE, fd);
file_align(fd, boot.hdr.page_size, 1);
}
// Restore extra
if (boot.hdr.extra_size && access(EXTRA_FILE, R_OK) == 0) {
boot.hdr.extra_size = restore(EXTRA_FILE, fd);
file_align(fd, boot.hdr.page_size, 1);
}
// Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE
if (boot.tail_size >= 16) {
if (memcmp(boot.tail, "SEANDROIDENFORCE", 16) == 0 ||
memcmp(boot.tail, LG_BUMP_MAGIC, 16) == 0 ) {
restore_buf(fd, boot.tail, 16);
}
}
// Write MTK headers back
if (boot.flags & MTK_KERNEL) {
lseek(fd, mtk_kernel_off, SEEK_SET);
boot.mtk_kernel_hdr.size = boot.hdr.kernel_size;
boot.hdr.kernel_size += 512;
restore_buf(fd, &boot.mtk_kernel_hdr, sizeof(mtk_hdr));
}
if (boot.flags & MTK_RAMDISK) {
lseek(fd, mtk_ramdisk_off, SEEK_SET);
boot.mtk_ramdisk_hdr.size = boot.hdr.ramdisk_size;
boot.hdr.ramdisk_size += 512;
restore_buf(fd, &boot.mtk_ramdisk_hdr, sizeof(mtk_hdr));
}
// Main header
lseek(fd, 0, SEEK_SET);
restore_buf(fd, &boot.hdr, sizeof(boot.hdr));
// Print new image info
print_hdr(&boot.hdr);
munmap(orig, size);
close(fd);
}

View File

@@ -1,122 +0,0 @@
/* tools/mkbootimg/bootimg.h
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include <stdint.h>
#include "types.h"
#ifndef _BOOT_IMAGE_H_
#define _BOOT_IMAGE_H_
typedef struct boot_img_hdr boot_img_hdr;
#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
#define BOOT_EXTRA_ARGS_SIZE 1024
struct boot_img_hdr
{
uint8_t magic[BOOT_MAGIC_SIZE];
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
uint32_t extra_size; /* extra blob size in bytes */
/* operating system version and security patch level; for
* version "A.B.C" and patch level "Y-M-D":
* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
* lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
* os_version = ver << 11 | lvl */
uint32_t os_version;
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
uint8_t cmdline[BOOT_ARGS_SIZE];
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
/* Supplemental command line data; kept here to maintain
* binary compatibility with older versions of mkbootimg */
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
} __attribute__((packed));
/*
** +-----------------+
** | boot header | 1 page
** +-----------------+
** | kernel | n pages
** +-----------------+
** | ramdisk | m pages
** +-----------------+
** | second stage | o pages
** +-----------------+
** | extra blobs | p pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
** p = (extra_size + page_size - 1) / page_size
**
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
** 2. second is optional (second_size == 0 -> no second)
** 3. load each element (kernel, ramdisk, second) at
** the specified physical address (kernel_addr, etc)
** 4. prepare tags at tag_addr. kernel_args[] is
** appended to the kernel commandline in the tags.
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
** 6. if second_size != 0: jump to second_addr
** else: jump to kernel_addr
*/
typedef struct mtk_hdr {
uint8_t magic[4]; /* MTK magic */
uint32_t size; /* Size of the content */
uint8_t name[32]; /* The type of the header */
} mtk_hdr;
// Flags
#define MTK_KERNEL 0x1
#define MTK_RAMDISK 0x2
typedef struct boot_img {
boot_img_hdr hdr;
void *kernel;
void *dtb;
uint32_t dt_size;
void *ramdisk;
void *second;
void *extra;
void *tail;
uint32_t tail_size;
uint32_t flags;
file_t kernel_type, ramdisk_type;
mtk_hdr mtk_kernel_hdr, mtk_ramdisk_hdr;
} boot_img;
#endif

View File

@@ -1,546 +0,0 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "magiskboot.h"
#include "cpio.h"
#include "logging.h"
#include "utils.h"
static uint32_t x8u(char *hex) {
uint32_t val, inpos = 8, outpos;
char pattern[6];
while (*hex == '0') {
hex++;
if (!--inpos) return 0;
}
// Because scanf gratuitously treats %*X differently than printf does.
sprintf(pattern, "%%%dx%%n", inpos);
sscanf(hex, pattern, &val, &outpos);
if (inpos != outpos) LOGE("bad cpio header\n");
return val;
}
static void cpio_free(cpio_entry *f) {
if (f) {
free(f->filename);
free(f->data);
free(f);
}
}
static void cpio_vec_insert(struct vector *v, cpio_entry *n) {
cpio_entry *f;
vec_for_each(v, f) {
if (strcmp(f->filename, n->filename) == 0) {
// Replace, then all is done
cpio_free(f);
vec_cur(v) = n;
return;
}
}
vec_push_back(v, n);
}
static int cpio_cmp(const void *a, const void *b) {
return strcmp((*(cpio_entry **) a)->filename, (*(cpio_entry **) b)->filename);
}
// Parse cpio file to a vector of cpio_entry
static void parse_cpio(const char *filename, struct vector *v) {
fprintf(stderr, "Loading cpio: [%s]\n\n", filename);
int fd = xopen(filename, O_RDONLY);
cpio_newc_header header;
cpio_entry *f;
while(xxread(fd, &header, 110) != -1) {
f = xcalloc(sizeof(*f), 1);
// f->ino = x8u(header.ino);
f->mode = x8u(header.mode);
f->uid = x8u(header.uid);
f->gid = x8u(header.gid);
// f->nlink = x8u(header.nlink);
// f->mtime = x8u(header.mtime);
f->filesize = x8u(header.filesize);
// f->devmajor = x8u(header.devmajor);
// f->devminor = x8u(header.devminor);
// f->rdevmajor = x8u(header.rdevmajor);
// f->rdevminor = x8u(header.rdevminor);
f->namesize = x8u(header.namesize);
// f->check = x8u(header.check);
f->filename = xmalloc(f->namesize);
xxread(fd, f->filename, f->namesize);
file_align(fd, 4, 0);
if (strcmp(f->filename, ".") == 0 || strcmp(f->filename, "..") == 0) {
cpio_free(f);
continue;
}
if (strcmp(f->filename, "TRAILER!!!") == 0) {
cpio_free(f);
break;
}
if (f->filesize) {
f->data = malloc(f->filesize);
xxread(fd, f->data, f->filesize);
file_align(fd, 4, 0);
}
vec_push_back(v, f);
}
close(fd);
}
static void dump_cpio(const char *filename, struct vector *v) {
fprintf(stderr, "\nDump cpio: [%s]\n\n", filename);
int fd = creat(filename, 0644);
unsigned inode = 300000;
char header[111];
// Sort by name
vec_sort(v, cpio_cmp);
cpio_entry *f;
vec_for_each(v, f) {
if (f->remove) continue;
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
inode++, // f->ino
f->mode,
f->uid,
f->gid,
1, // f->nlink
0, // f->mtime
f->filesize,
0, // f->devmajor
0, // f->devminor
0, // f->rdevmajor
0, // f->rdevminor
f->namesize,
0 // f->check
);
xwrite(fd, header, 110);
xwrite(fd, f->filename, f->namesize);
file_align(fd, 4, 1);
if (f->filesize) {
xwrite(fd, f->data, f->filesize);
file_align(fd, 4, 1);
}
}
// Write trailer
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", inode++, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0);
xwrite(fd, header, 110);
xwrite(fd, "TRAILER!!!\0", 11);
file_align(fd, 4, 1);
close(fd);
}
static void cpio_vec_destroy(struct vector *v) {
// Free each cpio_entry
cpio_entry *f;
vec_for_each(v, f) {
cpio_free(f);
}
vec_destroy(v);
}
static void cpio_rm(int recursive, const char *entry, struct vector *v) {
cpio_entry *f;
vec_for_each(v, f) {
if (strncmp(f->filename, entry, strlen(entry)) == 0) {
char next = f->filename[strlen(entry)];
if ((recursive && next == '/') || next == '\0') {
if (!f->remove) {
fprintf(stderr, "Remove [%s]\n", f->filename);
f->remove = 1;
}
if (!recursive) return;
}
}
}
}
static void cpio_mkdir(mode_t mode, const char *entry, struct vector *v) {
cpio_entry *f = xcalloc(sizeof(*f), 1);
f->mode = S_IFDIR | mode;
f->namesize = strlen(entry) + 1;
f->filename = strdup(entry);
cpio_vec_insert(v, f);
fprintf(stderr, "Create directory [%s] (%04o)\n",entry, mode);
}
static void cpio_add(mode_t mode, const char *entry, const char *filename, struct vector *v) {
int fd = xopen(filename, O_RDONLY);
cpio_entry *f = xcalloc(sizeof(*f), 1);
f->mode = S_IFREG | mode;
f->namesize = strlen(entry) + 1;
f->filename = strdup(entry);
f->filesize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
f->data = xmalloc(f->filesize);
xxread(fd, f->data, f->filesize);
close(fd);
cpio_vec_insert(v, f);
fprintf(stderr, "Add entry [%s] (%04o)\n", entry, mode);
}
static void cpio_test(struct vector *v) {
#define STOCK_BOOT 0x0
#define MAGISK_PATCH 0x1
#define OTHER_PATCH 0x2
int ret = STOCK_BOOT;
cpio_entry *f;
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL };
const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL };
vec_for_each(v, f) {
for (int i = 0; OTHER_LIST[i]; ++i) {
if (strcmp(f->filename, OTHER_LIST[i]) == 0) {
ret |= OTHER_PATCH;
// Already find other files, abort
exit(OTHER_PATCH);
}
}
for (int i = 0; MAGISK_LIST[i]; ++i) {
if (strcmp(f->filename, MAGISK_LIST[i]) == 0)
ret = MAGISK_PATCH;
}
}
cpio_vec_destroy(v);
exit(ret);
}
int check_verity_pattern(const char *s) {
int pos = 0;
if (s[0] == ',') ++pos;
if (strncmp(s + pos, "verify", 6) == 0)
pos += 6;
else if (strncmp(s + pos, "avb", 3) == 0)
pos += 3;
else
return -1;
if (s[pos] == '=') {
while (s[pos] != '\0' && s[pos] != ' ' && s[pos] != '\n' && s[pos] != ',') ++pos;
}
return pos;
}
int check_encryption_pattern(const char *s) {
const char *encrypt_list[] = { "forceencrypt", "forcefdeorfbe", NULL };
for (int i = 0 ; encrypt_list[i]; ++i) {
int len = strlen(encrypt_list[i]);
if (strncmp(s, encrypt_list[i], len) == 0)
return len;
}
return -1;
}
static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
cpio_entry *f;
int skip, write;
vec_for_each(v, f) {
if (!keepverity) {
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
write = 0;
for (int read = 0; read < f->filesize; ++write, ++read) {
if ((skip = check_verity_pattern(f->data + read)) > 0) {
fprintf(stderr, "Remove pattern [%.*s] in [%s]\n", skip, f->data + read, f->filename);
read += skip;
}
f->data[write] = f->data[read];
}
f->filesize = write;
} else if (strcmp(f->filename, "verity_key") == 0) {
fprintf(stderr, "Remove [verity_key]\n");
f->remove = 1;
}
}
if (!keepforceencrypt) {
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
write = 0;
for (int read = 0; read < f->filesize; ++write, ++read) {
if ((skip = check_encryption_pattern(f->data + read)) > 0) {
// assert(skip > 11)!
fprintf(stderr, "Replace pattern [%.*s] with [encryptable] in [%s]\n", skip, f->data + read, f->filename);
memcpy(f->data + write, "encryptable", 11);
write += 11;
read += skip;
}
f->data[write] = f->data[read];
}
f->filesize = write;
}
}
}
}
static void cpio_extract(const char *entry, const char *filename, struct vector *v) {
cpio_entry *f;
vec_for_each(v, f) {
if (strcmp(f->filename, entry) == 0 && S_ISREG(f->mode)) {
fprintf(stderr, "Extracting [%s] to [%s]\n\n", entry, filename);
int fd = creat(filename, 0644);
xwrite(fd, f->data, f->filesize);
fchmod(fd, f->mode);
fchown(fd, f->uid, f->gid);
close(fd);
exit(0);
}
}
LOGE("Cannot find the file entry [%s]\n", entry);
}
static void cpio_backup(const char *orig, const char *sha1, struct vector *v) {
struct vector o_body, *o = &o_body, bak;
cpio_entry *m, *n, *rem, *cksm;
char buf[PATH_MAX];
int res, doBak;
if (sha1) cksm = xcalloc(sizeof(*cksm), 1);
vec_init(o);
vec_init(&bak);
m = xcalloc(sizeof(*m), 1);
m->filename = strdup(".backup");
m->namesize = strlen(m->filename) + 1;
m->mode = S_IFDIR;
vec_push_back(&bak, m);
m = xcalloc(sizeof(*m), 1);
m->filename = strdup(".backup/.magisk");
m->namesize = strlen(m->filename) + 1;
m->mode = S_IFREG;
vec_push_back(&bak, m);
rem = xcalloc(sizeof(*rem), 1);
rem->filename = strdup(".backup/.rmlist");
rem->namesize = strlen(rem->filename) + 1;
rem->mode = S_IFREG;
vec_push_back(&bak, rem);
if (sha1) vec_push_back(&bak, cksm);
parse_cpio(orig, o);
// Remove possible backups in original ramdisk
cpio_rm(1, ".backup", o);
cpio_rm(1, ".backup", v);
// Sort both vectors before comparing
vec_sort(v, cpio_cmp);
vec_sort(o, cpio_cmp);
if (sha1) {
fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1);
cksm->filename = strdup(".backup/.sha1");
cksm->namesize = strlen(cksm->filename) + 1;
cksm->mode = S_IFREG;
cksm->data = strdup(sha1);
cksm->filesize = strlen(sha1) + 1;
}
// Start comparing
size_t i = 0, j = 0;
while(i != vec_size(o) || j != vec_size(v)) {
doBak = 0;
if (i != vec_size(o) && j != vec_size(v)) {
m = vec_entry(o)[i];
n = vec_entry(v)[j];
res = strcmp(m->filename, n->filename);
} else if (i == vec_size(o)) {
n = vec_entry(v)[j];
res = 1;
} else if (j == vec_size(v)) {
m = vec_entry(o)[i];
res = -1;
}
if (res < 0) {
// Something is missing in new ramdisk, backup!
++i;
doBak = 1;
fprintf(stderr, "Backup missing entry: ");
} else if (res == 0) {
++i; ++j;
if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0)
continue;
// Not the same!
doBak = 1;
fprintf(stderr, "Backup mismatch entry: ");
} else {
// Someting new in ramdisk, record in rem
++j;
if (n->remove) continue;
rem->data = xrealloc(rem->data, rem->filesize + n->namesize);
memcpy(rem->data + rem->filesize, n->filename, n->namesize);
rem->filesize += n->namesize;
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", n->filename);
}
if (doBak) {
m->namesize += 8;
m->filename = realloc(m->filename, m->namesize);
strcpy(buf, m->filename);
sprintf(m->filename, ".backup/%s", buf);
fprintf(stderr, "[%s] -> [%s]\n", buf, m->filename);
vec_push_back(&bak, m);
// NULL the original entry, so it won't be freed
vec_entry(o)[i - 1] = NULL;
}
}
// Add the backup files to the original ramdisk
vec_for_each(&bak, m) {
vec_push_back(v, m);
}
if (rem->filesize == 0)
rem->remove = 1;
// Cleanup
cpio_vec_destroy(o);
}
static int cpio_restore(struct vector *v) {
cpio_entry *f, *n;
int ret = 1;
vec_for_each(v, f) {
if (strstr(f->filename, ".backup") != NULL) {
ret = 0;
f->remove = 1;
if (f->filename[7] == '\0') continue;
if (f->filename[8] == '.') {
if (strcmp(f->filename, ".backup/.rmlist") == 0) {
for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1)
cpio_rm(0, f->data + pos, v);
}
continue;
} else {
n = xcalloc(sizeof(*n), 1);
memcpy(n, f, sizeof(*f));
n->namesize -= 8;
n->filename = strdup(f->filename + 8);
n->data = f->data;
f->data = NULL;
n->remove = 0;
fprintf(stderr, "Restore [%s] -> [%s]\n", f->filename, n->filename);
cpio_vec_insert(v, n);
}
}
}
// Some known stuff we can remove
cpio_rm(0, "sbin/magic_mask.sh", v);
cpio_rm(0, "init.magisk.rc", v);
cpio_rm(0, "magisk", v);
return ret;
}
static void cpio_stocksha1(struct vector *v) {
cpio_entry *f;
char sha1[41];
vec_for_each(v, f) {
if (strcmp(f->filename, "init.magisk.rc") == 0
|| strcmp(f->filename, "overlay/init.magisk.rc") == 0) {
for (char *pos = f->data; pos < f->data + f->filesize; pos = strchr(pos + 1, '\n') + 1) {
if (memcmp(pos, "# STOCKSHA1=", 12) == 0) {
pos += 12;
memcpy(sha1, pos, 40);
sha1[40] = '\0';
printf("%s\n", sha1);
return;
}
}
} else if (strcmp(f->filename, ".backup/.sha1") == 0) {
printf("%s\n", f->data);
}
}
}
static void cpio_mv(struct vector *v, const char *from, const char *to) {
struct cpio_entry *f, *t;
vec_for_each(v, f) {
if (strcmp(f->filename, from) == 0) {
fprintf(stderr, "Move [%s] -> [%s]\n", from, to);
vec_for_each(v, t) {
if (strcmp(t->filename, to) == 0) {
t->remove = 1;
break;
}
}
free(f->filename);
f->namesize = strlen(to) + 1;
f->filename = strdup(to);
return;
}
}
fprintf(stderr, "Cannot find entry %s\n", from);
exit(1);
}
int cpio_commands(const char *command, int argc, char *argv[]) {
int recursive = 0, ret = 0;
command_t cmd;
char *incpio = argv[0];
++argv;
--argc;
if (strcmp(command, "test") == 0) {
cmd = TEST;
} else if (strcmp(command, "restore") == 0) {
cmd = RESTORE;
} else if (strcmp(command, "stocksha1") == 0) {
cmd = STOCKSHA1;
} else if (argc >= 1 && strcmp(command, "backup") == 0) {
cmd = BACKUP;
} else if (argc > 0 && strcmp(command, "rm") == 0) {
cmd = RM;
if (argc == 2 && strcmp(argv[0], "-r") == 0) {
recursive = 1;
++argv;
--argc;
}
} else if (argc == 2 && strcmp(command, "mv") == 0) {
cmd = MV;
} else if (argc == 2 && strcmp(command, "patch") == 0) {
cmd = PATCH;
} else if (argc == 2 && strcmp(command, "extract") == 0) {
cmd = EXTRACT;
} else if (argc == 2 && strcmp(command, "mkdir") == 0) {
cmd = MKDIR;
} else if (argc == 3 && strcmp(command, "add") == 0) {
cmd = ADD;
} else {
cmd = NONE;
}
struct vector v;
vec_init(&v);
parse_cpio(incpio, &v);
switch(cmd) {
case TEST:
cpio_test(&v);
break;
case RESTORE:
ret = cpio_restore(&v);
break;
case STOCKSHA1:
cpio_stocksha1(&v);
return 0;
case BACKUP:
cpio_backup(argv[0], argc > 1 ? argv[1] : NULL, &v);
case RM:
cpio_rm(recursive, argv[0], &v);
break;
case PATCH:
cpio_patch(&v, strcmp(argv[0], "true") == 0, strcmp(argv[1], "true") == 0);
break;
case EXTRACT:
cpio_extract(argv[0], argv[1], &v);
break;
case MKDIR:
cpio_mkdir(strtoul(argv[0], NULL, 8), argv[1], &v);
break;
case ADD:
cpio_add(strtoul(argv[0], NULL, 8), argv[1], argv[2], &v);
break;
case MV:
cpio_mv(&v, argv[0], argv[1]);
break;
case NONE:
return 1;
}
dump_cpio(incpio, &v);
cpio_vec_destroy(&v);
exit(ret);
}

View File

@@ -1,56 +0,0 @@
#ifndef _CPIO_H_
#define _CPIO_H_
#include <stdint.h>
typedef struct cpio_entry {
// uint32_t ino;
uint32_t mode;
uint32_t uid;
uint32_t gid;
// uint32_t nlink;
// uint32_t mtime;
uint32_t filesize;
// uint32_t devmajor;
// uint32_t devminor;
// uint32_t rdevmajor;
// uint32_t rdevminor;
uint32_t namesize;
// uint32_t check;
char *filename;
char *data;
int remove;
} cpio_entry;
typedef struct cpio_newc_header {
char magic[6];
char ino[8];
char mode[8];
char uid[8];
char gid[8];
char nlink[8];
char mtime[8];
char filesize[8];
char devmajor[8];
char devminor[8];
char rdevmajor[8];
char rdevminor[8];
char namesize[8];
char check[8];
} cpio_newc_header;
typedef enum {
NONE,
RM,
MKDIR,
ADD,
MV,
EXTRACT,
TEST,
PATCH,
BACKUP,
RESTORE,
STOCKSHA1
} command_t;
#endif

View File

@@ -1,150 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include "magiskboot.h"
#include "utils.h"
#include "sha1.h"
/********************
Patch Boot Image
*********************/
static void usage(char *arg0) {
fprintf(stderr,
"Usage: %s <action> [args...]\n"
"\n"
"Supported actions:\n"
" --unpack <bootimg>\n"
" Unpack <bootimg> to kernel, ramdisk.cpio, (second), (dtb), (extra) into\n"
" the current directory\n"
"\n"
" --repack <origbootimg> [outbootimg]\n"
" Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory\n"
" to [outbootimg], or new-boot.img if not specified.\n"
" It will compress ramdisk.cpio with the same method used in <origbootimg>\n"
" if exists, or attempt to find ramdisk.cpio.[ext], and repack\n"
" directly with the compressed ramdisk file\n"
"\n"
" --hexpatch <file> <hexpattern1> <hexpattern2>\n"
" Search <hexpattern1> in <file>, and replace with <hexpattern2>\n"
"\n"
" --cpio-<cmd> <incpio> [flags...] [args...]\n"
" Do cpio related cmds to <incpio> (modifications are done directly)\n"
" Supported commands:\n"
" -rm [-r] <entry>\n"
" Remove entry from <incpio>, flag -r to remove recursively\n"
" -mkdir <mode> <entry>\n"
" Create directory as an <entry>\n"
" -add <mode> <entry> <infile>\n"
" Add <infile> as an <entry>; replaces <entry> if already exists\n"
" -mv <from-entry> <to-entry>\n"
" Move <from-entry> to <to-entry>\n"
" -extract <entry> <outfile>\n"
" Extract <entry> to <outfile>\n"
" -test\n"
" Return value: 0/stock 1/Magisk 2/other (phh, SuperSU, Xposed)\n"
" -patch <KEEPVERITY> <KEEPFORCEENCRYPT>\n"
" Patch cpio for Magisk. KEEP**** are true/false values\n"
" -backup <origcpio> [SHA1]\n"
" Create ramdisk backups into <incpio> from <origcpio>\n"
" SHA1 of stock boot image is optional\n"
" -restore\n"
" Restore ramdisk from ramdisk backup within <incpio>\n"
" -stocksha1\n"
" Get stock boot SHA1 recorded within <incpio>\n"
"\n"
" --dtb-<cmd> <dtb>\n"
" Do dtb related cmds to <dtb> (modifications are done directly)\n"
" Supported commands:\n"
" -dump\n"
" Dump all contents from dtb for debugging\n"
" -patch\n"
" Search for fstab and remove verity/avb\n"
"\n"
" --compress[=method] <infile> [outfile]\n"
" Compress <infile> with [method] (default: gzip), optionally to [outfile]\n"
" <infile>/[outfile] can be '-' to be STDIN/STDOUT\n"
" Supported methods: "
, arg0);
for (int i = 0; SUP_LIST[i]; ++i)
fprintf(stderr, "%s ", SUP_LIST[i]);
fprintf(stderr,
"\n"
"\n"
" --decompress <infile> [outfile]\n"
" Detect method and decompress <infile>, optionally to [outfile]\n"
" <infile>/[outfile] can be '-' to be STDIN/STDOUT\n"
" Supported methods: ");
for (int i = 0; SUP_LIST[i]; ++i)
fprintf(stderr, "%s ", SUP_LIST[i]);
fprintf(stderr,
"\n"
"\n"
" --sha1 <file>\n"
" Print the SHA1 checksum for <file>\n"
"\n"
" --cleanup\n"
" Cleanup the current working directory\n"
"\n");
exit(1);
}
int main(int argc, char *argv[]) {
fprintf(stderr, "MagiskBoot v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Boot Image Modification Tool\n\n");
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
fprintf(stderr, "Cleaning up...\n\n");
char name[PATH_MAX];
unlink(KERNEL_FILE);
unlink(RAMDISK_FILE);
unlink(RAMDISK_FILE ".raw");
unlink(SECOND_FILE);
unlink(DTB_FILE);
unlink(EXTRA_FILE);
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
unlink(name);
}
} else if (argc > 2 && strcmp(argv[1], "--sha1") == 0) {
char sha1[21], *buf;
size_t size;
mmap_ro(argv[2], (void **) &buf, &size);
SHA1(sha1, buf, size);
for (int i = 0; i < 20; ++i)
printf("%02x", sha1[i]);
printf("\n");
munmap(buf, size);
} else if (argc > 2 && strcmp(argv[1], "--unpack") == 0) {
unpack(argv[2]);
} else if (argc > 2 && strcmp(argv[1], "--repack") == 0) {
repack(argv[2], argc > 3 ? argv[3] : NEW_BOOT);
} else if (argc > 2 && strcmp(argv[1], "--decompress") == 0) {
decomp_file(argv[2], argc > 3 ? argv[3] : NULL);
} else if (argc > 2 && strncmp(argv[1], "--compress", 10) == 0) {
char *method;
method = strchr(argv[1], '=');
if (method == NULL) method = "gzip";
else method++;
comp_file(method, argv[2], argc > 3 ? argv[3] : NULL);
} else if (argc > 4 && strcmp(argv[1], "--hexpatch") == 0) {
hexpatch(argv[2], argv[3], argv[4]);
} else if (argc > 2 && strncmp(argv[1], "--cpio", 6) == 0) {
char *cmd = argv[1] + 6;
if (*cmd == '\0') usage(argv[0]);
else ++cmd;
if (cpio_commands(cmd, argc - 2, argv + 2)) usage(argv[0]);
} else if (argc > 2 && strncmp(argv[1], "--dtb", 5) == 0) {
char *cmd = argv[1] + 5;
if (*cmd == '\0') usage(argv[0]);
else ++cmd;
if (dtb_commands(cmd, argc - 2, argv + 2)) usage(argv[0]);
} else {
usage(argv[0]);
}
return 0;
}

View File

@@ -1,295 +0,0 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#define SHA1HANDSOFF
#include <stdio.h>
#include <string.h>
/* for uint32_t */
#include <stdint.h>
#include "sha1.h"
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if BYTE_ORDER == LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#elif BYTE_ORDER == BIG_ENDIAN
#define blk0(i) block->l[i]
#else
#error "Endianness not defined!"
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(
uint32_t state[5],
const unsigned char buffer[64]
)
{
uint32_t a, b, c, d, e;
typedef union
{
unsigned char c[64];
uint32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
memcpy(block, buffer, 64);
#else
/* The following had better never be used because it causes the
* pointer-to-const buffer to be cast into a pointer to non-const.
* And the result is written through. I threw a "const" in, hoping
* this will cause a diagnostic.
*/
CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a, b, c, d, e, 0);
R0(e, a, b, c, d, 1);
R0(d, e, a, b, c, 2);
R0(c, d, e, a, b, 3);
R0(b, c, d, e, a, 4);
R0(a, b, c, d, e, 5);
R0(e, a, b, c, d, 6);
R0(d, e, a, b, c, 7);
R0(c, d, e, a, b, 8);
R0(b, c, d, e, a, 9);
R0(a, b, c, d, e, 10);
R0(e, a, b, c, d, 11);
R0(d, e, a, b, c, 12);
R0(c, d, e, a, b, 13);
R0(b, c, d, e, a, 14);
R0(a, b, c, d, e, 15);
R1(e, a, b, c, d, 16);
R1(d, e, a, b, c, 17);
R1(c, d, e, a, b, 18);
R1(b, c, d, e, a, 19);
R2(a, b, c, d, e, 20);
R2(e, a, b, c, d, 21);
R2(d, e, a, b, c, 22);
R2(c, d, e, a, b, 23);
R2(b, c, d, e, a, 24);
R2(a, b, c, d, e, 25);
R2(e, a, b, c, d, 26);
R2(d, e, a, b, c, 27);
R2(c, d, e, a, b, 28);
R2(b, c, d, e, a, 29);
R2(a, b, c, d, e, 30);
R2(e, a, b, c, d, 31);
R2(d, e, a, b, c, 32);
R2(c, d, e, a, b, 33);
R2(b, c, d, e, a, 34);
R2(a, b, c, d, e, 35);
R2(e, a, b, c, d, 36);
R2(d, e, a, b, c, 37);
R2(c, d, e, a, b, 38);
R2(b, c, d, e, a, 39);
R3(a, b, c, d, e, 40);
R3(e, a, b, c, d, 41);
R3(d, e, a, b, c, 42);
R3(c, d, e, a, b, 43);
R3(b, c, d, e, a, 44);
R3(a, b, c, d, e, 45);
R3(e, a, b, c, d, 46);
R3(d, e, a, b, c, 47);
R3(c, d, e, a, b, 48);
R3(b, c, d, e, a, 49);
R3(a, b, c, d, e, 50);
R3(e, a, b, c, d, 51);
R3(d, e, a, b, c, 52);
R3(c, d, e, a, b, 53);
R3(b, c, d, e, a, 54);
R3(a, b, c, d, e, 55);
R3(e, a, b, c, d, 56);
R3(d, e, a, b, c, 57);
R3(c, d, e, a, b, 58);
R3(b, c, d, e, a, 59);
R4(a, b, c, d, e, 60);
R4(e, a, b, c, d, 61);
R4(d, e, a, b, c, 62);
R4(c, d, e, a, b, 63);
R4(b, c, d, e, a, 64);
R4(a, b, c, d, e, 65);
R4(e, a, b, c, d, 66);
R4(d, e, a, b, c, 67);
R4(c, d, e, a, b, 68);
R4(b, c, d, e, a, 69);
R4(a, b, c, d, e, 70);
R4(e, a, b, c, d, 71);
R4(d, e, a, b, c, 72);
R4(c, d, e, a, b, 73);
R4(b, c, d, e, a, 74);
R4(a, b, c, d, e, 75);
R4(e, a, b, c, d, 76);
R4(d, e, a, b, c, 77);
R4(c, d, e, a, b, 78);
R4(b, c, d, e, a, 79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
memset(block, '\0', sizeof(block));
#endif
}
/* SHA1Init - Initialize new context */
void SHA1Init(
SHA1_CTX * context
)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(
SHA1_CTX * context,
const unsigned char *data,
uint32_t len
)
{
uint32_t i;
uint32_t j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1]++;
context->count[1] += (len >> 29);
j = (j >> 3) & 63;
if ((j + len) > 63)
{
memcpy(&context->buffer[j], data, (i = 64 - j));
SHA1Transform(context->state, context->buffer);
for (; i + 63 < len; i += 64)
{
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else
i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void SHA1Final(
unsigned char digest[20],
SHA1_CTX * context
)
{
unsigned i;
unsigned char finalcount[8];
unsigned char c;
#if 0 /* untested "improvement" by DHR */
/* Convert context->count to a sequence of bytes
* in finalcount. Second element first, but
* big-endian order within element.
* But we do it all backwards.
*/
unsigned char *fcp = &finalcount[8];
for (i = 0; i < 2; i++)
{
uint32_t t = context->count[i];
int j;
for (j = 0; j < 4; t >>= 8, j++)
*--fcp = (unsigned char) t}
#else
for (i = 0; i < 8; i++)
{
finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
}
#endif
c = 0200;
SHA1Update(context, &c, 1);
while ((context->count[0] & 504) != 448)
{
c = 0000;
SHA1Update(context, &c, 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++)
{
digest[i] = (unsigned char)
((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
}
/* Wipe variables */
memset(context, '\0', sizeof(*context));
memset(&finalcount, '\0', sizeof(finalcount));
}
void SHA1(
char *hash_out,
const char *str,
int len)
{
SHA1_CTX ctx;
unsigned int ii;
SHA1Init(&ctx);
for (ii=0; ii<len; ii+=1)
SHA1Update(&ctx, (const unsigned char*)str + ii, 1);
SHA1Final((unsigned char *)hash_out, &ctx);
hash_out[20] = '\0';
}

View File

@@ -1,83 +0,0 @@
#include <string.h>
#include "bootimg.h"
#include "types.h"
char *SUP_LIST[] = { "gzip", "xz", "lzma", "bzip2", "lz4", "lz4_legacy", NULL };
char *SUP_EXT_LIST[] = { "gz", "xz", "lzma", "bz2", "lz4", "lz4", NULL };
file_t SUP_TYPE_LIST[] = { GZIP, XZ, LZMA, BZIP2, LZ4, LZ4_LEGACY, 0 };
file_t check_type(const void *buf) {
if (memcmp(buf, CHROMEOS_MAGIC, 8) == 0) {
return CHROMEOS;
} else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
return AOSP;
} else if (memcmp(buf, ELF32_MAGIC, 5) == 0) {
return ELF32;
} else if (memcmp(buf, ELF64_MAGIC, 5) == 0) {
return ELF64;
} else if (memcmp(buf, GZIP_MAGIC, 4) == 0) {
return GZIP;
} else if (memcmp(buf, LZOP_MAGIC, 9) == 0) {
return LZOP;
} else if (memcmp(buf, XZ_MAGIC, 6) == 0) {
return XZ;
} else if (memcmp(buf, "\x5d\x00\x00", 3) == 0
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
return LZMA;
} else if (memcmp(buf, BZIP_MAGIC, 3) == 0) {
return BZIP2;
} else if (memcmp(buf, LZ4_MAGIC, 4) == 0) {
return LZ4;
} else if (memcmp(buf, LZ4_LEG_MAGIC, 4) == 0) {
return LZ4_LEGACY;
} else if (memcmp(buf, MTK_MAGIC, 4) == 0) {
return MTK;
} else if (memcmp(buf, DTB_MAGIC, 4) == 0) {
return DTB;
} else {
return UNKNOWN;
}
}
void get_type_name(file_t type, char *name) {
char *s;
switch (type) {
case CHROMEOS:
s = "chromeos";
break;
case AOSP:
s = "aosp";
break;
case GZIP:
s = "gzip";
break;
case LZOP:
s = "lzop";
break;
case XZ:
s = "xz";
break;
case LZMA:
s = "lzma";
break;
case BZIP2:
s = "bzip2";
break;
case LZ4:
s = "lz4";
break;
case LZ4_LEGACY:
s = "lz4_legacy";
break;
case MTK:
s = "mtk";
break;
case DTB:
s = "dtb";
break;
default:
s = "raw";
}
strcpy(name, s);
}

View File

@@ -1,43 +0,0 @@
#ifndef _TYPES_H_
#define _TYPES_H_
typedef enum {
UNKNOWN,
CHROMEOS,
AOSP,
ELF32,
ELF64,
GZIP,
LZOP,
XZ,
LZMA,
BZIP2,
LZ4,
LZ4_LEGACY,
MTK,
DTB
} file_t;
#define COMPRESSED(type) (type >= GZIP && type <= LZ4_LEGACY)
#define CHROMEOS_MAGIC "CHROMEOS"
#define ELF32_MAGIC "\x7f""ELF\x01"
#define ELF64_MAGIC "\x7f""ELF\x02"
#define GZIP_MAGIC "\x1f\x8b\x08\x00"
#define LZOP_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
#define XZ_MAGIC "\xfd""7zXZ\x00"
#define BZIP_MAGIC "BZh"
#define LZ4_MAGIC "\x04\x22\x4d\x18"
#define LZ4_LEG_MAGIC "\x02\x21\x4c\x18"
#define MTK_MAGIC "\x88\x16\x88\x58"
#define DTB_MAGIC "\xd0\x0d\xfe\xed"
#define LG_BUMP_MAGIC "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79"
extern char *SUP_LIST[];
extern char *SUP_EXT_LIST[];
extern file_t SUP_TYPE_LIST[];
file_t check_type(const void *buf);
void get_type_name(file_t type, char *name);
#endif

View File

@@ -1,265 +0,0 @@
/* proc_monitor.c - Monitor am_proc_start events and unmount
*
* We monitor the logcat am_proc_start events. When a target starts up,
* we pause it ASAP, and fork a new process to join its mount namespace
* and do all the unmounting/mocking
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include "magisk.h"
#include "utils.h"
#include "magiskhide.h"
static char init_ns[32], zygote_ns[2][32], cache_block[256];
static int hide_queue = 0, zygote_num, has_cache = 1, pipefd[2] = { -1, -1 };
// Workaround for the lack of pthread_cancel
static void term_thread(int sig) {
LOGD("proc_monitor: running cleanup\n");
destroy_list();
hideEnabled = 0;
// Unregister listener
logcat_events[HIDE_EVENT] = -1;
close(pipefd[0]);
close(pipefd[1]);
pipefd[0] = pipefd[1] = -1;
pthread_mutex_destroy(&hide_lock);
pthread_mutex_destroy(&file_lock);
LOGD("proc_monitor: terminating...\n");
pthread_exit(NULL);
}
static void hide_done(int sig) {
--hide_queue;
if (hide_queue == 0) {
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
xsymlink(MOUNTPOINT, FAKEPOINT);
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
}
}
static int read_namespace(const int pid, char* target, const size_t size) {
char path[32];
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
if (access(path, R_OK) == -1)
return 1;
xreadlink(path, target, size);
return 0;
}
static void store_zygote_ns(int pid) {
if (zygote_num == 2) return;
do {
usleep(500);
read_namespace(pid, zygote_ns[zygote_num], 32);
} while (strcmp(zygote_ns[zygote_num], init_ns) == 0);
++zygote_num;
}
static void lazy_unmount(const char* mountpoint) {
if (umount2(mountpoint, MNT_DETACH) != -1)
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
else
LOGD("hide_daemon: Unmount Failed (%s)\n", mountpoint);
}
static void hide_daemon(int pid, int ppid) {
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
char *line, buffer[PATH_MAX];
struct vector mount_list;
manage_selinux();
clean_magisk_props();
if (switch_mnt_ns(pid))
goto exit;
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
vec_init(&mount_list);
file_to_vector(buffer, &mount_list);
// Find the cache block name if not found yet
if (has_cache && cache_block[0] == '\0') {
vec_for_each(&mount_list, line) {
if (strstr(line, " /cache ")) {
sscanf(line, "%256s", cache_block);
break;
}
}
if (strlen(cache_block) == 0)
has_cache = 0;
}
// Unmout cache mounts
if (has_cache) {
vec_for_each(&mount_list, line) {
if (strstr(line, cache_block) && (strstr(line, " /system/") || strstr(line, " /vendor/"))) {
sscanf(line, "%*s %4096s", buffer);
lazy_unmount(buffer);
}
}
}
// Unmount dummy skeletons, /sbin links
vec_for_each(&mount_list, line) {
if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin")) {
sscanf(line, "%*s %4096s", buffer);
lazy_unmount(buffer);
}
free(line);
}
vec_destroy(&mount_list);
// Re-read mount infos
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
vec_init(&mount_list);
file_to_vector(buffer, &mount_list);
// Unmount any loop mounts
vec_for_each(&mount_list, line) {
if (strstr(line, "/dev/block/loop")) {
sscanf(line, "%*s %4096s", buffer);
lazy_unmount(buffer);
}
free(line);
}
exit:
// Send resume signal
kill(pid, SIGCONT);
// Free up memory
vec_destroy(&mount_list);
// Wait a while and link it back
sleep(10);
kill(ppid, HIDE_DONE);
_exit(0);
}
void proc_monitor() {
// Unblock user signals
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, TERM_THREAD);
sigaddset(&block_set, HIDE_DONE);
pthread_sigmask(SIG_UNBLOCK, &block_set, NULL);
// Register the cancel signal
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = term_thread;
sigaction(TERM_THREAD, &act, NULL);
act.sa_handler = hide_done;
sigaction(HIDE_DONE, &act, NULL);
cache_block[0] = '\0';
// Get the mount namespace of init
if (read_namespace(1, init_ns, 32)) {
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
term_thread(TERM_THREAD);
}
LOGI("proc_monitor: init ns=%s\n", init_ns);
// Get the mount namespace of zygote
zygote_num = 0;
while(!zygote_num) {
// Check zygote every 2 secs
sleep(2);
ps_filter_proc_name("zygote", store_zygote_ns);
}
ps_filter_proc_name("zygote64", store_zygote_ns);
switch(zygote_num) {
case 1:
LOGI("proc_monitor: zygote ns=%s\n", zygote_ns[0]);
break;
case 2:
LOGI("proc_monitor: zygote ns=%s zygote64 ns=%s\n", zygote_ns[0], zygote_ns[1]);
break;
}
// Register our listener to logcat monitor
xpipe2(pipefd, O_CLOEXEC);
logcat_events[HIDE_EVENT] = pipefd[1];
for (char *log, *line; 1; free(log)) {
if (read(pipefd[0], &log, sizeof(log)) != sizeof(log)) {
/* It might be interrupted */
log = NULL;
continue;
}
char *ss;
if ((ss = strstr(log, "am_proc_start")) && (ss = strchr(ss, '['))) {
int pid, ret, comma = 0;
char *pos = ss, processName[256], ns[32];
while(1) {
pos = strchr(pos, ',');
if(pos == NULL)
break;
pos[0] = ' ';
++comma;
}
if (comma == 6)
ret = sscanf(ss, "[%*d %d %*d %*d %256s", &pid, processName);
else
ret = sscanf(ss, "[%*d %d %*d %256s", &pid, processName);
if(ret != 2)
continue;
ret = 0;
// Critical region
pthread_mutex_lock(&hide_lock);
vec_for_each(hide_list, line) {
if (strcmp(processName, line) == 0) {
while(1) {
ret = 1;
for (int i = 0; i < zygote_num; ++i) {
read_namespace(pid, ns, sizeof(ns));
if (strcmp(ns, zygote_ns[i]) == 0) {
usleep(50);
ret = 0;
break;
}
}
if (ret) break;
}
// Send pause signal ASAP
if (kill(pid, SIGSTOP) == -1) continue;
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, pid, ns);
/*
* The setns system call do not support multithread processes
* We have to fork a new process, setns, then do the unmounts
*/
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
unlink(FAKEPOINT);
unlink(MAGISKRC);
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
++hide_queue;
int selfpid = getpid();
if (fork_dont_care() == 0)
hide_daemon(pid, selfpid);
break;
}
}
pthread_mutex_unlock(&hide_lock);
}
}
}

Submodule jni/magiskpolicy deleted from e5b6121d17

1
jni/su

Submodule jni/su deleted from a9d966dc7a

View File

@@ -1,231 +0,0 @@
/* img.c - All image related functions
*/
#include <unistd.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <linux/loop.h>
#include "magisk.h"
#include "utils.h"
static int e2fsck(const char *img) {
// Check and repair ext4 image
char buffer[128];
int pid, fd = -1;
pid = exec_command(1, &fd, NULL, "e2fsck", "-yf", img, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd))
LOGD("magisk_img: %s", buffer);
waitpid(pid, NULL, 0);
close(fd);
return 0;
}
static char *loopsetup(const char *img) {
char device[20];
struct loop_info64 info;
int i, lfd, ffd;
memset(&info, 0, sizeof(info));
// First get an empty loop device
for (i = 0; i <= 7; ++i) {
sprintf(device, "/dev/block/loop%d", i);
lfd = xopen(device, O_RDWR);
if (ioctl(lfd, LOOP_GET_STATUS64, &info) == -1)
break;
close(lfd);
}
if (i == 8) return NULL;
ffd = xopen(img, O_RDWR);
if (ioctl(lfd, LOOP_SET_FD, ffd) == -1)
return NULL;
strcpy((char *) info.lo_file_name, img);
ioctl(lfd, LOOP_SET_STATUS64, &info);
close(lfd);
close(ffd);
return strdup(device);
}
int create_img(const char *img, int size) {
unlink(img);
LOGI("Create %s with size %dM\n", img, size);
int ret;
char buffer[16];
snprintf(buffer, sizeof(buffer), "%dM", size);
ret = exec_command_sync("make_ext4fs", "-l", buffer, img, NULL);
if (ret < 0)
return 1;
return ret;
}
int get_img_size(const char *img, int *used, int *total) {
if (access(img, R_OK) == -1)
return 1;
char buffer[PATH_MAX];
int pid, fd = -1, status = 1;
pid = exec_command(1, &fd, NULL, "e2fsck", "-n", img, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd)) {
if (strstr(buffer, img)) {
char *tok = strtok(buffer, ",");
while(tok != NULL) {
if (strstr(tok, "blocks")) {
status = 0;
break;
}
tok = strtok(NULL, ",");
}
if (status) continue;
sscanf(tok, "%d/%d", used, total);
*used = *used / 256 + 1;
*total /= 256;
break;
}
}
close(fd);
waitpid(pid, NULL, 0);
return 0;
}
int resize_img(const char *img, int size) {
LOGI("Resize %s to %dM\n", img, size);
if (e2fsck(img))
return 1;
char buffer[128];
int pid, fd = -1, used, total;
snprintf(buffer, sizeof(buffer), "%dM", size);
pid = exec_command(1, &fd, NULL, "resize2fs", img, buffer, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd))
LOGD("magisk_img: %s", buffer);
close(fd);
waitpid(pid, NULL, 0);
// Double check our image size
get_img_size(img, &used, &total);
if (total != size) {
// Sammy crap occurs or resize2fs failed, lets create a new image!
char *dir = dirname(img);
snprintf(buffer, sizeof(buffer), "%s/tmp.img", dir);
create_img(buffer, size);
char *s_loop, *t_loop;
s_loop = mount_image(img, SOURCE_TMP);
if (s_loop == NULL) return 1;
t_loop = mount_image(buffer, TARGET_TMP);
if (t_loop == NULL) return 1;
cp_afc(SOURCE_TMP, TARGET_TMP);
umount_image(SOURCE_TMP, s_loop);
umount_image(TARGET_TMP, t_loop);
rmdir(SOURCE_TMP);
rmdir(TARGET_TMP);
free(s_loop);
free(t_loop);
rename(buffer, img);
}
return 0;
}
char *mount_image(const char *img, const char *target) {
if (access(img, F_OK) == -1)
return NULL;
if (access(target, F_OK) == -1) {
if (xmkdir_p(target, 0755) == -1) {
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
xmkdir_p(target, 0755);
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
}
}
if (e2fsck(img))
return NULL;
char *device = loopsetup(img);
if (device)
xmount(device, target, "ext4", 0, NULL);
return device;
}
void umount_image(const char *target, const char *device) {
xumount(target);
int fd = xopen(device, O_RDWR);
ioctl(fd, LOOP_CLR_FD);
close(fd);
}
int merge_img(const char *source, const char *target) {
if (access(source, F_OK) == -1)
return 0;
LOGI("* Merging %s -> %s\n", source, target);
if (access(target, F_OK) == -1) {
xrename(source, target);
return 0;
}
char buffer[PATH_MAX];
// resize target to worst case
int s_used, s_total, t_used, t_total, n_total;
get_img_size(source, &s_used, &s_total);
get_img_size(target, &t_used, &t_total);
n_total = round_size(s_used + t_used);
if (n_total > t_total)
resize_img(target, n_total);
xmkdir(SOURCE_TMP, 0755);
xmkdir(TARGET_TMP, 0755);
char *s_loop, *t_loop;
s_loop = mount_image(source, SOURCE_TMP);
if (s_loop == NULL) return 1;
t_loop = mount_image(target, TARGET_TMP);
if (t_loop == NULL) return 1;
DIR *dir;
struct dirent *entry;
if (!(dir = xopendir(SOURCE_TMP)))
return 1;
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) {
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0 ||
strcmp(entry->d_name, ".core") == 0 ||
strcmp(entry->d_name, "lost+found") == 0)
continue;
// Cleanup old module if exists
snprintf(buffer, sizeof(buffer), "%s/%s", TARGET_TMP, entry->d_name);
if (access(buffer, F_OK) == 0) {
LOGI("Upgrade module: %s\n", entry->d_name);
rm_rf(buffer);
} else {
LOGI("New module: %s\n", entry->d_name);
}
}
}
closedir(dir);
cp_afc(SOURCE_TMP, TARGET_TMP);
// Unmount all loop devices
umount_image(SOURCE_TMP, s_loop);
umount_image(TARGET_TMP, t_loop);
rmdir(SOURCE_TMP);
rmdir(TARGET_TMP);
free(s_loop);
free(t_loop);
unlink(source);
return 0;
}
void trim_img(const char *img) {
int used, total, new_size;
get_img_size(img, &used, &total);
new_size = round_size(used);
if (new_size != total)
resize_img(img, new_size);
}

3
native/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/build
obj
libs

22
native/build.gradle Normal file
View File

@@ -0,0 +1,22 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
externalNativeBuild {
ndkBuild {
path 'jni/Android.mk'
}
}
defaultConfig {
externalNativeBuild {
ndkBuild {
// Pass arguments to ndk-build.
arguments('B_MAGISK=1', 'B_INIT=1', 'B_BOOT=1', 'MAGISK_VERSION=debug',
'MAGISK_VER_CODE=99999', 'MAGISK_DEBUG=-DMAGISK_DEBUG')
}
}
}
}

View File

@@ -9,52 +9,61 @@ LIBLZMA := $(EXT_PATH)/xz/src/liblzma/api
LIBLZ4 := $(EXT_PATH)/lz4/lib
LIBBZ2 := $(EXT_PATH)/bzip2
LIBFDT := $(EXT_PATH)/dtc/libfdt
LIBNANOPB := $(EXT_PATH)/nanopb
UTIL_SRC := utils/cpio.c \
utils/file.c \
utils/img.c \
utils/list.c \
utils/misc.c \
utils/pattern.c \
utils/vector.c \
utils/xwrap.c
########################
# Binaries
########################
ifdef PRECOMPILE
ifdef B_MAGISK
# magisk main binary
include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
LOCAL_STATIC_LIBRARIES := libnanopb
LOCAL_C_INCLUDES := \
jni/include \
jni/external \
$(LIBSELINUX)
jni/magiskpolicy \
$(EXT_PATH)/include \
$(LIBSELINUX) \
$(LIBNANOPB)
LOCAL_SRC_FILES := \
core/magisk.c \
core/daemon.c \
core/log_monitor.c \
core/log_daemon.c \
core/bootstages.c \
utils/misc.c \
utils/vector.c \
utils/xwrap.c \
utils/list.c \
utils/img.c \
utils/file.c \
core/socket.c \
core/db.c \
magiskhide/magiskhide.c \
magiskhide/proc_monitor.c \
magiskhide/hide_utils.c \
resetprop/resetprop.cpp \
resetprop/persist_props.c \
resetprop/resetprop.c \
resetprop/system_properties.cpp \
su/su.c \
su/activity.c \
su/db.c \
su/pts.c \
su/su_daemon.c \
su/su_socket.c
su/su_socket.c \
$(UTIL_SRC)
LOCAL_CFLAGS := -DIS_DAEMON
LOCAL_CFLAGS := -DIS_DAEMON -DSELINUX
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)
# precompile
else
endif
ifdef B_INIT
# magiskinit
include $(CLEAR_VARS)
@@ -62,30 +71,34 @@ LOCAL_MODULE := magiskinit
LOCAL_STATIC_LIBRARIES := libsepol liblzma
LOCAL_C_INCLUDES := \
jni/include \
jni/magiskpolicy \
out \
out/$(TARGET_ARCH_ABI) \
$(LIBSEPOL) \
$(LIBLZMA)
LOCAL_SRC_FILES := \
core/magiskinit.c \
utils/vector.c \
utils/file.c \
utils/xwrap.c \
magiskpolicy/api.c \
magiskpolicy/magiskpolicy.c \
magiskpolicy/rules.c \
magiskpolicy/sepolicy.c
magiskpolicy/sepolicy.c \
$(UTIL_SRC)
LOCAL_CFLAGS := -DNO_SELINUX
LOCAL_LDFLAGS := -static
include $(BUILD_EXECUTABLE)
endif
ifdef B_BOOT
# magiskboot
include $(CLEAR_VARS)
LOCAL_MODULE := magiskboot
LOCAL_STATIC_LIBRARIES := liblzma liblz4 libbz2 libfdt
LOCAL_STATIC_LIBRARIES := libmincrypt liblzma liblz4 libbz2 libfdt
LOCAL_C_INCLUDES := \
jni/include \
$(EXT_PATH)/include \
$(LIBLZMA) \
$(LIBLZ4) \
$(LIBBZ2) \
@@ -96,21 +109,19 @@ LOCAL_SRC_FILES := \
magiskboot/bootimg.c \
magiskboot/hexpatch.c \
magiskboot/compress.c \
magiskboot/cpio.c \
magiskboot/sha1.c \
magiskboot/types.c \
magiskboot/format.c \
magiskboot/dtb.c \
utils/xwrap.c \
utils/file.c \
utils/vector.c
magiskboot/ramdisk.c \
$(UTIL_SRC)
LOCAL_CFLAGS := -DNO_SELINUX
LOCAL_CFLAGS := -DXWRAP_EXIT
LOCAL_LDLIBS := -lz
include $(BUILD_EXECUTABLE)
# 32-bit static binaries
ifneq ($(TARGET_ARCH_ABI), x86_64)
ifneq ($(TARGET_ARCH_ABI), arm64-v8a)
endif
ifdef B_BXZ
# b64xz
include $(CLEAR_VARS)
LOCAL_MODULE := b64xz
@@ -119,12 +130,14 @@ LOCAL_C_INCLUDES := $(LIBLZMA)
LOCAL_SRC_FILES := b64xz.c
LOCAL_LDFLAGS := -static
include $(BUILD_EXECUTABLE)
# Busybox
include jni/external/busybox/Android.mk
endif
endif
# Precompile
ifdef B_BB
# Busybox
include jni/external/busybox/Android.mk
endif
########################

10
native/jni/Application.mk Normal file
View File

@@ -0,0 +1,10 @@
APP_ABI := x86 armeabi-v7a
APP_CFLAGS := -std=gnu99 ${MAGISK_DEBUG} \
-DMAGISK_VERSION="${MAGISK_VERSION}" -DMAGISK_VER_CODE=${MAGISK_VER_CODE}
APP_CPPFLAGS := -std=c++11
APP_SHORT_COMMANDS := true
ifdef OLD_PLAT
APP_PLATFORM := android-9
else
APP_PLATFORM := android-21
endif

View File

@@ -11,20 +11,19 @@
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <linux/loop.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <selinux/selinux.h>
#include "magisk.h"
#include "db.h"
#include "utils.h"
#include "daemon.h"
#include "resetprop.h"
#include "magiskpolicy.h"
static char *buf, *buf2;
static struct vector module_list;
static int seperate_vendor = 0;
extern char **environ;
@@ -54,7 +53,7 @@ struct node_entry {
static void concat_path(struct node_entry *node) {
if (node->parent)
concat_path(node->parent);
int len = strlen(buf);
size_t len = strlen(buf);
buf[len] = '/';
strcpy(buf + len + 1, node->name);
}
@@ -115,11 +114,11 @@ static struct node_entry *insert_child(struct node_entry *p, struct node_entry *
* setenvs *
***********/
static void bb_setenv(struct vector *v) {
static void set_path(struct vector *v) {
for (int i = 0; environ[i]; ++i) {
if (strncmp(environ[i], "PATH=", 5) == 0) {
snprintf(buf, PATH_MAX, "PATH=%s:%s", BBPATH, strchr(environ[i], '=') + 1);
vec_push_back(v, strdup(buf));
vec_push_back(v, strdup("PATH=" BBPATH ":/sbin:" MIRRDIR "/system/bin:"
MIRRDIR "/system/xbin:" MIRRDIR "/vendor/bin"));
} else {
vec_push_back(v, strdup(environ[i]));
}
@@ -127,15 +126,6 @@ static void bb_setenv(struct vector *v) {
vec_push_back(v, NULL);
}
static void pm_setenv(struct vector *v) {
for (int i = 0; environ[i]; ++i) {
if (strncmp(environ[i], "CLASSPATH=", 10) != 0)
vec_push_back(v, strdup(environ[i]));
}
vec_push_back(v, strdup("CLASSPATH=/system/framework/pm.jar"));
vec_push_back(v, NULL);
}
/***********
* Scripts *
***********/
@@ -143,18 +133,18 @@ static void pm_setenv(struct vector *v) {
static void exec_common_script(const char* stage) {
DIR *dir;
struct dirent *entry;
snprintf(buf, PATH_MAX, "%s/%s.d", COREDIR, stage);
snprintf(buf2, PATH_MAX, "%s/%s.d", COREDIR, stage);
if (!(dir = xopendir(buf)))
if (!(dir = xopendir(buf2)))
return;
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_REG) {
snprintf(buf2, PATH_MAX, "%s/%s", buf, entry->d_name);
snprintf(buf2, PATH_MAX, "%s/%s.d/%s", COREDIR, stage, entry->d_name);
if (access(buf2, X_OK) == -1)
continue;
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
int pid = exec_command(0, NULL, bb_setenv, "sh", buf2, NULL);
int pid = exec_command(0, NULL, set_path, "sh", buf2, NULL);
if (pid != -1)
waitpid(pid, NULL, 0);
}
@@ -171,7 +161,7 @@ static void exec_module_script(const char* stage) {
if (access(buf2, F_OK) == -1 || access(buf, F_OK) == 0)
continue;
LOGI("%s: exec [%s.sh]\n", module, stage);
int pid = exec_command(0, NULL, bb_setenv, "sh", buf2, NULL);
int pid = exec_command(0, NULL, set_path, "sh", buf2, NULL);
if (pid != -1)
waitpid(pid, NULL, 0);
}
@@ -277,7 +267,7 @@ static void clone_skeleton(struct node_entry *node) {
char *con;
xstat(full_path, &s);
getfilecon(full_path, &con);
LOGI("tmpfs: %s\n", full_path);
LOGI("mnt_tmpfs : %s\n", full_path);
xmount("tmpfs", full_path, "tmpfs", 0, NULL);
chmod(full_path, s.st_mode & 0777);
chown(full_path, s.st_uid, s.st_gid);
@@ -298,7 +288,7 @@ static void clone_skeleton(struct node_entry *node) {
if (child->parent->parent == NULL && strcmp(child->name, "vendor") == 0) {
if (IS_LNK(child)) {
cp_afc(MIRRDIR "/system/vendor", "/system/vendor");
LOGI("cplink: %s -> %s\n", MIRRDIR "/system/vendor", "/system/vendor");
LOGI("creat_link: %s <- %s\n", "/system/vendor", MIRRDIR "/system/vendor");
}
// Skip
continue;
@@ -317,11 +307,11 @@ static void clone_skeleton(struct node_entry *node) {
if (IS_LNK(child)) {
// Copy symlinks directly
cp_afc(buf2, buf);
#ifdef MAGISK_DEBUG
LOGI("cplink: %s -> %s\n",buf2, buf);
#else
LOGI("cplink: %s\n", buf);
#endif
#ifdef MAGISK_DEBUG
LOGI("creat_link: %s <- %s\n",buf, buf2);
#else
LOGI("creat_link: %s\n", buf);
#endif
} else {
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
bind_mount(buf2, buf);
@@ -362,7 +352,7 @@ static void simple_mount(const char *path) {
DIR *dir;
struct dirent *entry;
snprintf(buf, PATH_MAX, "%s%s", CACHEMOUNT, path);
snprintf(buf, PATH_MAX, "%s%s", SIMPLEMOUNT, path);
if (!(dir = opendir(buf)))
return;
@@ -380,7 +370,7 @@ static void simple_mount(const char *path) {
free(new_path);
} else if (entry->d_type == DT_REG) {
// Actual file path
snprintf(buf, PATH_MAX, "%s%s", CACHEMOUNT, buf2);
snprintf(buf, PATH_MAX, "%s%s", SIMPLEMOUNT, buf2);
// Clone all attributes
clone_attr(buf2, buf);
// Finally, mount the file
@@ -395,107 +385,16 @@ static void simple_mount(const char *path) {
* Miscellaneous *
*****************/
// A one time setup
static void daemon_init() {
LOGI("* Creating /sbin overlay");
DIR *dir;
struct dirent *entry;
int root, sbin;
// Setup links under /sbin
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
xmkdir("/root", 0755);
chmod("/root", 0755);
root = xopen("/root", O_RDONLY | O_CLOEXEC);
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
dir = xfdopendir(sbin);
while((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
linkat(sbin, entry->d_name, root, entry->d_name, 0);
if (strcmp(entry->d_name, "magisk") == 0)
unlinkat(sbin, entry->d_name, 0);
}
close(sbin);
xmount("tmpfs", "/sbin", "tmpfs", 0, NULL);
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
fchmod(sbin, 0755);
fsetfilecon(sbin, "u:object_r:rootfs:s0");
dir = xfdopendir(root);
while((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
snprintf(buf, PATH_MAX, "/root/%s", entry->d_name);
snprintf(buf2, PATH_MAX, "/sbin/%s", entry->d_name);
xsymlink(buf, buf2);
}
for (int i = 0; applet[i]; ++i) {
snprintf(buf2, PATH_MAX, "/sbin/%s", applet[i]);
xsymlink("/root/magisk", buf2);
}
xsymlink(MOUNTPOINT, FAKEPOINT);
close(root);
close(sbin);
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
LOGI("* Mounting mirrors");
struct vector mounts;
vec_init(&mounts);
file_to_vector("/proc/mounts", &mounts);
char *line;
int skip_initramfs = 0;
// Check whether skip_initramfs device
vec_for_each(&mounts, line) {
if (strstr(line, " /system_root ")) {
xmkdir_p(MIRRDIR "/system", 0755);
bind_mount("/system_root/system", MIRRDIR "/system");
skip_initramfs = 1;
break;
}
}
vec_for_each(&mounts, line) {
if (!skip_initramfs && strstr(line, " /system ")) {
sscanf(line, "%s", buf);
xmkdir_p(MIRRDIR "/system", 0755);
xmount(buf, MIRRDIR "/system", "ext4", MS_RDONLY, NULL);
#ifdef MAGISK_DEBUG
LOGI("mount: %s -> %s\n", buf, MIRRDIR "/system");
#else
LOGI("mount: %s\n", MIRRDIR "/system");
#endif
} else if (strstr(line, " /vendor ")) {
seperate_vendor = 1;
sscanf(line, "%s", buf);
xmkdir_p(MIRRDIR "/vendor", 0755);
xmount(buf, MIRRDIR "/vendor", "ext4", MS_RDONLY, NULL);
#ifdef MAGISK_DEBUG
LOGI("mount: %s -> %s\n", buf, MIRRDIR "/vendor");
#else
LOGI("mount: %s\n", MIRRDIR "/vendor");
#endif
}
free(line);
}
vec_destroy(&mounts);
if (!seperate_vendor) {
xsymlink(MIRRDIR "/system/vendor", MIRRDIR "/vendor");
#ifdef MAGISK_DEBUG
LOGI("link: %s -> %s\n", MIRRDIR "/system/vendor", MIRRDIR "/vendor");
#else
LOGI("link: %s\n", MIRRDIR "/vendor");
#endif
}
xmkdir_p(MIRRDIR "/bin", 0755);
bind_mount(DATABIN, MIRRDIR "/bin");
LOGI("* Setting up internal busybox");
xmkdir_p(BBPATH, 0755);
exec_command_sync(MIRRDIR "/bin/busybox", "--install", "-s", BBPATH, NULL);
xsymlink(MIRRDIR "/bin/busybox", BBPATH "/busybox");
}
#define alt_img ((char *[]) \
{ "/cache/magisk.img", "/data/magisk_merge.img", "/data/adb/magisk_merge.img", NULL })
static int prepare_img() {
// First merge images
if (merge_img("/data/magisk_merge.img", MAINIMG)) {
LOGE("Image merge /data/magisk_merge.img -> " MAINIMG " failed!\n");
return 1;
// Merge images
for (int i = 0; alt_img[i]; ++i) {
if (merge_img(alt_img[i], MAINIMG)) {
LOGE("Image merge %s -> " MAINIMG " failed!\n", alt_img[i]);
return 1;
}
}
if (access(MAINIMG, F_OK) == -1) {
@@ -509,8 +408,6 @@ static int prepare_img() {
if (magiskloop == NULL)
return 1;
vec_init(&module_list);
xmkdir(COREDIR, 0755);
xmkdir(COREDIR "/post-fs-data.d", 0755);
xmkdir(COREDIR "/service.d", 0755);
@@ -531,33 +428,44 @@ static int prepare_img() {
rm_rf(buf);
continue;
}
snprintf(buf, PATH_MAX, "%s/%s/update", MOUNTPOINT, entry->d_name);
unlink(buf);
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, entry->d_name);
if (access(buf, F_OK) == 0)
continue;
vec_push_back(&module_list, strdup(entry->d_name));
}
}
closedir(dir);
// Trim image
umount_image(MOUNTPOINT, magiskloop);
if (trim_img(MAINIMG, MOUNTPOINT, magiskloop))
return 1;
free(magiskloop);
trim_img(MAINIMG);
// Remount them back :)
magiskloop = mount_image(MAINIMG, MOUNTPOINT);
free(magiskloop);
// Fix file selinux contexts
fix_filecon();
return 0;
}
void fix_filecon() {
int dirfd = xopen(MOUNTPOINT, O_RDONLY | O_CLOEXEC);
restorecon(dirfd, 0);
close(dirfd);
void install_apk(const char *apk) {
setfilecon(apk, "u:object_r:"SEPOL_FILE_DOMAIN":s0");
while (1) {
sleep(5);
LOGD("apk_install: attempting to install APK");
int apk_res = -1, pid;
pid = exec_command(1, &apk_res, NULL, "/system/bin/pm", "install", "-r", apk, NULL);
if (pid != -1) {
int err = 0;
while (fdgets(buf, PATH_MAX, apk_res) > 0) {
LOGD("apk_install: %s", buf);
err |= strstr(buf, "Error:") != NULL;
}
waitpid(pid, NULL, 0);
close(apk_res);
// Keep trying until pm is started
if (err)
continue;
break;
}
}
unlink(apk);
}
/****************
@@ -569,79 +477,222 @@ static void unblock_boot_process() {
pthread_exit(NULL);
}
void post_fs(int client) {
LOGI("** post-fs mode running\n");
// ack
write_int(client, 0);
close(client);
static const char wrapper[] =
"#!/system/bin/sh\n"
"unset LD_LIBRARY_PATH\n"
"unset LD_PRELOAD\n"
"exec /sbin/magisk.bin \"${0##*/}\" \"$@\"\n";
// Allow magiskinit to full patch
close(creat(PATCHSTART, 0));
// Uninstall or core only mode
if (access(UNINSTALLER, F_OK) == 0 || access(DISABLEFILE, F_OK) == 0)
goto unblock;
// Allocate buffer
buf = xmalloc(PATH_MAX);
buf2 = xmalloc(PATH_MAX);
simple_mount("/system");
simple_mount("/vendor");
unblock:
unblock_boot_process();
}
void post_fs_data(int client) {
// ack
write_int(client, 0);
close(client);
void startup() {
if (!check_data())
goto unblock;
unblock_boot_process();
// Start the debug log
start_debug_full_log();
if (access(SECURE_DIR, F_OK) != 0) {
/* If the folder is not automatically created by the system,
* do NOT proceed further. Manual creation of the folder
* will cause bootloops on FBE devices. */
LOGE(SECURE_DIR" is not present, abort...");
unblock_boot_process();
}
LOGI("** post-fs-data mode running\n");
// No uninstaller or core-only mode
if (access(DISABLEFILE, F_OK) != 0) {
// Allocate buffer
buf = xmalloc(PATH_MAX);
buf2 = xmalloc(PATH_MAX);
// Allocate buffer
if (buf == NULL) buf = xmalloc(PATH_MAX);
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
simple_mount("/system");
simple_mount("/vendor");
}
// Magisk binaries
LOGI("** Initializing Magisk\n");
// Unlock all blocks for rw
unlock_blocks();
LOGI("* Creating /sbin overlay");
DIR *dir;
struct dirent *entry;
int root, sbin, fd;
char buf[PATH_MAX];
void *magisk, *init;
size_t magisk_size, init_size;
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
// Remove some traits of Magisk
unlink("/init.magisk.rc");
// GSIs will have to override /sbin/adbd with /system/bin/adbd
if (access("/sbin/adbd", F_OK) == 0 && access("/system/bin/adbd", F_OK) == 0) {
umount2("/sbin/adbd", MNT_DETACH);
cp_afc("/system/bin/adbd", "/sbin/adbd");
}
// Create hardlink mirror of /sbin to /root
mkdir("/root", 0750);
clone_attr("/sbin", "/root");
full_read("/sbin/magisk", &magisk, &magisk_size);
unlink("/sbin/magisk");
full_read("/sbin/magiskinit", &init, &init_size);
unlink("/sbin/magiskinit");
root = xopen("/root", O_RDONLY | O_CLOEXEC);
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
link_dir(sbin, root);
close(sbin);
// Mount the /sbin tmpfs overlay
xmount("tmpfs", "/sbin", "tmpfs", 0, NULL);
chmod("/sbin", 0755);
setfilecon("/sbin", "u:object_r:rootfs:s0");
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
// Create wrapper
fd = creat("/sbin/magisk", 0755);
xwrite(fd, wrapper, sizeof(wrapper) - 1);
close(fd);
setfilecon("/sbin/magisk", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
// Setup magisk symlinks
fd = creat("/sbin/magisk.bin", 0755);
xwrite(fd, magisk, magisk_size);
close(fd);
free(magisk);
setfilecon("/sbin/magisk.bin", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
for (int i = 0; applet[i]; ++i) {
snprintf(buf, PATH_MAX, "/sbin/%s", applet[i]);
xsymlink("/sbin/magisk", buf);
}
// Setup magiskinit symlinks
fd = creat("/sbin/magiskinit", 0755);
xwrite(fd, init, init_size);
close(fd);
free(init);
setfilecon("/sbin/magiskinit", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
for (int i = 0; init_applet[i]; ++i) {
snprintf(buf, PATH_MAX, "/sbin/%s", init_applet[i]);
xsymlink("/sbin/magiskinit", buf);
}
// Create symlinks pointing back to /root
dir = xfdopendir(root);
while((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
snprintf(buf, PATH_MAX, "/root/%s", entry->d_name);
symlinkat(buf, sbin, entry->d_name);
}
close(sbin);
close(root);
// Alternative binaries paths
char *alt_bin[] = { "/cache/data_bin", "/data/.magisk",
"/data/data/com.topjohnwu.magisk/install",
"/data/user_de/0/com.topjohnwu.magisk/install", NULL };
char *bin_path = NULL;
if (access("/cache/data_bin", F_OK) == 0)
bin_path = "/cache/data_bin";
else if (access("/data/data/com.topjohnwu.magisk/install", F_OK) == 0)
bin_path = "/data/data/com.topjohnwu.magisk/install";
else if (access("/data/user_de/0/com.topjohnwu.magisk/install", F_OK) == 0)
bin_path = "/data/user_de/0/com.topjohnwu.magisk/install";
for (int i = 0; alt_bin[i]; ++i) {
if (access(alt_bin[i], F_OK) == 0) {
bin_path = alt_bin[i];
break;
}
}
if (bin_path) {
rm_rf(DATABIN);
cp_afc(bin_path, DATABIN);
rm_rf(bin_path);
}
// Lazy.... use shell blob to match files
exec_command_sync("sh", "-c", "mv -f /data/magisk/stock_*.img.gz /data", NULL);
// Remove legacy stuffs
rm_rf("/data/magisk");
unlink("/data/magisk.img");
unlink("/data/magisk_debug.log");
// Initialize
daemon_init();
// Create directories in tmpfs overlay
xmkdirs(MIRRDIR "/system", 0755);
xmkdir(MIRRDIR "/bin", 0755);
xmkdir(BBPATH, 0755);
xmkdir(MOUNTPOINT, 0755);
xmkdir(BLOCKDIR, 0755);
// uninstaller
if (access(UNINSTALLER, F_OK) == 0) {
close(open(UNBLOCKFILE, O_RDONLY | O_CREAT));
setenv("BOOTMODE", "true", 1);
exec_command(0, NULL, bb_setenv, "sh", UNINSTALLER, NULL);
return;
LOGI("* Mounting mirrors");
struct vector mounts;
vec_init(&mounts);
file_to_vector("/proc/mounts", &mounts);
char *line;
int skip_initramfs = 0;
// Check whether skip_initramfs device
vec_for_each(&mounts, line) {
if (strstr(line, " /system_root ")) {
bind_mount("/system_root/system", MIRRDIR "/system");
skip_initramfs = 1;
} else if (!skip_initramfs && strstr(line, " /system ")) {
sscanf(line, "%s", buf);
xmount(buf, MIRRDIR "/system", "ext4", MS_RDONLY, NULL);
#ifdef MAGISK_DEBUG
LOGI("mount: %s <- %s\n", MIRRDIR "/system", buf);
#else
LOGI("mount: %s\n", MIRRDIR "/system");
#endif
} else if (strstr(line, " /vendor ")) {
seperate_vendor = 1;
sscanf(line, "%s", buf);
xmkdir(MIRRDIR "/vendor", 0755);
xmount(buf, MIRRDIR "/vendor", "ext4", MS_RDONLY, NULL);
#ifdef MAGISK_DEBUG
LOGI("mount: %s <- %s\n", MIRRDIR "/vendor", buf);
#else
LOGI("mount: %s\n", MIRRDIR "/vendor");
#endif
}
free(line);
}
vec_destroy(&mounts);
if (!seperate_vendor) {
xsymlink(MIRRDIR "/system/vendor", MIRRDIR "/vendor");
#ifdef MAGISK_DEBUG
LOGI("link: %s <- %s\n", MIRRDIR "/vendor", MIRRDIR "/system/vendor");
#else
LOGI("link: %s\n", MIRRDIR "/vendor");
#endif
}
xmkdirs(DATABIN, 0755);
bind_mount(DATABIN, MIRRDIR "/bin");
if (access(MIRRDIR "/bin/busybox", X_OK) == 0) {
LOGI("* Setting up internal busybox");
exec_command_sync(MIRRDIR "/bin/busybox", "--install", "-s", BBPATH, NULL);
xsymlink(MIRRDIR "/bin/busybox", BBPATH "/busybox");
}
// Start post-fs-data mode
execl("/sbin/magisk.bin", "magisk", "--post-fs-data", NULL);
}
void post_fs_data(int client) {
// ack
write_int(client, 0);
close(client);
// If post-fs-data mode is started, it means startup succeeded
setup_done = 1;
LOGI("** post-fs-data mode running\n");
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
full_patch_pid = exec_command(0, NULL, NULL, "/sbin/magiskpolicy", "--live", "allow "SEPOL_PROC_DOMAIN" * * *", NULL);
// Allocate buffer
buf = xmalloc(PATH_MAX);
buf2 = xmalloc(PATH_MAX);
vec_init(&module_list);
// Merge, trim, mount magisk.img, which will also travel through the modules
// After this, it will create the module list
if (prepare_img())
goto core_only; // Mounting fails, we can only do core only stuffs
restorecon();
chmod(SECURE_DIR, 0700);
// Run common scripts
LOGI("* Running post-fs-data.d scripts\n");
exec_common_script("post-fs-data");
@@ -728,8 +779,6 @@ core_only:
}
auto_start_magiskhide();
unblock:
unblock_boot_process();
}
@@ -739,14 +788,24 @@ void late_start(int client) {
write_int(client, 0);
close(client);
if (access(SECURE_DIR, F_OK) != 0) {
// It's safe to create the folder at this point if the system didn't create it
xmkdir(SECURE_DIR, 0700);
}
if (!setup_done) {
// The setup failed for some reason, reboot and try again
exec_command_sync("/system/bin/reboot", NULL);
return;
}
// Allocate buffer
if (buf == NULL) buf = xmalloc(PATH_MAX);
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
// Wait till the full patch is done
while (access(PATCHDONE, F_OK) == -1)
usleep(500); /* Wait 0.5ms */
unlink(PATCHDONE);
if (full_patch_pid > 0)
waitpid(full_patch_pid, NULL, 0);
// Run scripts after full patch, most reliable way to run scripts
LOGI("* Running service.d scripts\n");
@@ -760,25 +819,21 @@ void late_start(int client) {
exec_module_script("service");
core_only:
// Install Magisk Manager if exists
if (access(MANAGERAPK, F_OK) == 0) {
while (1) {
sleep(5);
int apk_res = -1, pid;
pid = exec_command(1, &apk_res, pm_setenv,
"app_process",
"/system/bin", "com.android.commands.pm.Pm",
"install", "-r", MANAGERAPK, NULL);
if (pid != -1) {
waitpid(pid, NULL, 0);
fdgets(buf, PATH_MAX, apk_res);
close(apk_res);
// Keep trying until pm is started
if (strstr(buf, "Error:") == NULL)
break;
}
// Install Magisk Manager if exists
rename(MANAGERAPK, "/data/magisk.apk");
install_apk("/data/magisk.apk");
} else {
// Check whether we have a valid manager installed
sqlite3 *db = get_magiskdb();
struct db_strings str;
INIT_DB_STRINGS(&str);
get_db_strings(db, SU_MANAGER, &str);
if (validate_manager(str.s[SU_MANAGER], 0, NULL)) {
// There is no manager installed, install the stub
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk", NULL);
install_apk("/data/magisk.apk");
}
unlink(MANAGERAPK);
}
// All boot stage done, cleanup everything
@@ -786,6 +841,4 @@ core_only:
free(buf2);
buf = buf2 = NULL;
vec_deep_destroy(&module_list);
stop_debug_full_log();
}

200
native/jni/core/daemon.c Normal file
View File

@@ -0,0 +1,200 @@
/* daemon.c - Magisk Daemon
*
* Start the daemon and wait for requests
* Connect the daemon and send requests through sockets
*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <selinux/selinux.h>
#include "magisk.h"
#include "utils.h"
#include "daemon.h"
#include "resetprop.h"
#include "magiskpolicy.h"
int setup_done = 0;
int seperate_vendor = 0;
int full_patch_pid = -1;
static void *request_handler(void *args) {
int client = *((int *) args);
free(args);
int req = read_int(client);
struct ucred credential;
get_client_cred(client, &credential);
switch (req) {
case LAUNCH_MAGISKHIDE:
case STOP_MAGISKHIDE:
case ADD_HIDELIST:
case RM_HIDELIST:
case LS_HIDELIST:
case POST_FS_DATA:
case LATE_START:
if (credential.uid != 0) {
write_int(client, ROOT_REQUIRED);
close(client);
return NULL;
}
default:
break;
}
switch (req) {
case LAUNCH_MAGISKHIDE:
launch_magiskhide(client);
break;
case STOP_MAGISKHIDE:
stop_magiskhide(client);
break;
case ADD_HIDELIST:
add_hide_list(client);
break;
case RM_HIDELIST:
rm_hide_list(client);
break;
case LS_HIDELIST:
ls_hide_list(client);
break;
case SUPERUSER:
su_daemon_receiver(client, &credential);
break;
case CHECK_VERSION:
write_string(client, MAGISK_VER_STR);
close(client);
break;
case CHECK_VERSION_CODE:
write_int(client, MAGISK_VER_CODE);
close(client);
break;
case POST_FS_DATA:
post_fs_data(client);
break;
case LATE_START:
late_start(client);
break;
case HANDSHAKE:
/* Do NOT close the client, make it hold */
break;
default:
close(client);
break;
}
return NULL;
}
static void *start_magisk_hide(void *args) {
launch_magiskhide(-1);
return NULL;
}
void auto_start_magiskhide() {
char *hide_prop = getprop2(MAGISKHIDE_PROP, 1);
if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) {
pthread_t thread;
xpthread_create(&thread, NULL, start_magisk_hide, NULL);
pthread_detach(thread);
}
free(hide_prop);
}
void main_daemon() {
setsid();
setcon("u:r:"SEPOL_PROC_DOMAIN":s0");
int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO);
close(fd);
fd = xopen("/dev/zero", O_RDWR | O_CLOEXEC);
xdup2(fd, STDIN_FILENO);
close(fd);
// Start the log monitor
loggable = exec_command_sync("/system/bin/logcat", "-d", "-f", "/dev/null", NULL) == 0;
if (loggable) {
connect_daemon2(LOG_DAEMON, &fd);
write_int(fd, HANDSHAKE);
close(fd);
}
struct sockaddr_un sun;
fd = setup_socket(&sun, MAIN_DAEMON);
if (xbind(fd, (struct sockaddr*) &sun, sizeof(sun)))
exit(1);
xlisten(fd, 10);
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n");
// Change process name
strcpy(argv0, "magiskd");
// Block all user signals
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, SIGUSR1);
sigaddset(&block_set, SIGUSR2);
pthread_sigmask(SIG_SETMASK, &block_set, NULL);
// Ignore SIGPIPE
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
// Loop forever to listen for requests
while(1) {
int *client = xmalloc(sizeof(int));
*client = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC);
pthread_t thread;
xpthread_create(&thread, NULL, request_handler, client);
// Detach the thread, we will never join it
pthread_detach(thread);
}
}
/* Connect the daemon, set sockfd, and return if new daemon is spawned */
int connect_daemon2(daemon_t d, int *sockfd) {
struct sockaddr_un sun;
*sockfd = setup_socket(&sun, d);
if (connect(*sockfd, (struct sockaddr*) &sun, sizeof(sun))) {
if (getuid() != UID_ROOT || getgid() != UID_ROOT) {
fprintf(stderr, "No daemon is currently running!\n");
exit(1);
}
if (fork_dont_care() == 0) {
LOGD("client: connect fail, try launching new daemon process\n");
close(*sockfd);
switch (d) {
case MAIN_DAEMON:
main_daemon();
break;
case LOG_DAEMON:
log_daemon();
break;
}
}
while (connect(*sockfd, (struct sockaddr*) &sun, sizeof(sun)))
usleep(10000);
return 1;
}
return 0;
}
int connect_daemon() {
int fd;
connect_daemon2(MAIN_DAEMON, &fd);
return fd;
}

158
native/jni/core/db.c Normal file
View File

@@ -0,0 +1,158 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "magisk.h"
#include "db.h"
void INIT_DB_STRINGS(struct db_strings *str) {
for (int i = 0; i < DB_STRING_NUM; ++i)
str->s[i][0] = '\0';
}
static int policy_cb(void *v, int col_num, char **data, char **col_name) {
struct su_access *su = v;
for (int i = 0; i < col_num; i++) {
if (strcmp(col_name[i], "policy") == 0)
su->policy = (policy_t) atoi(data[i]);
else if (strcmp(col_name[i], "logging") == 0)
su->log = atoi(data[i]);
else if (strcmp(col_name[i], "notification") == 0)
su->notify = atoi(data[i]);
}
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su->policy, su->log, su->notify);
return 0;
}
static int settings_cb(void *v, int col_num, char **data, char **col_name) {
struct db_settings *dbs = v;
int key = -1, value;
for (int i = 0; i < col_num; ++i) {
if (strcmp(col_name[i], "key") == 0) {
for (int k = 0; k < DB_SETTINGS_NUM; ++k) {
if (strcmp(data[i], DB_SETTING_KEYS[k]) == 0)
key = k;
}
} else if (strcmp(col_name[i], "value") == 0) {
value = atoi(data[i]);
}
}
if (key >= 0) {
dbs->v[key] = value;
LOGD("magiskdb: query %s=[%d]\n", DB_SETTING_KEYS[key], value);
}
return 0;
}
static int strings_cb(void *v, int col_num, char **data, char **col_name) {
struct db_strings *dbs = v;
int key = -1;
char *value;
for (int i = 0; i < col_num; ++i) {
if (strcmp(col_name[i], "key") == 0) {
for (int k = 0; k < DB_STRING_NUM; ++k) {
if (strcmp(data[i], DB_STRING_KEYS[k]) == 0)
key = k;
}
} else if (strcmp(col_name[i], "value") == 0) {
value = data[i];
}
}
if (key >= 0) {
strcpy(dbs->s[key], value);
LOGD("magiskdb: query %s=[%s]\n", DB_STRING_KEYS[key], value);
}
return 0;
}
sqlite3 *get_magiskdb() {
sqlite3 *db = NULL;
if (access(MAGISKDB, R_OK) == 0) {
// Open database
int ret = sqlite3_open_v2(MAGISKDB, &db, SQLITE_OPEN_READONLY, NULL);
if (ret) {
LOGE("sqlite3 open failure: %s\n", sqlite3_errstr(ret));
sqlite3_close(db);
db = NULL;
}
}
return db;
}
int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs) {
if (db == NULL)
return 1;
char *err;
if (key > 0) {
char query[128];
sprintf(query, "SELECT key, value FROM settings WHERE key=%d", key);
sqlite3_exec(db, query, settings_cb, dbs, &err);
} else {
sqlite3_exec(db, "SELECT key, value FROM settings", settings_cb, dbs, &err);
}
if (err) {
LOGE("sqlite3_exec: %s\n", err);
return 1;
}
return 0;
}
int get_db_strings(sqlite3 *db, int key, struct db_strings *str) {
if (db == NULL)
return 1;
char *err;
if (key > 0) {
char query[128];
sprintf(query, "SELECT key, value FROM strings WHERE key=%d", key);
sqlite3_exec(db, query, strings_cb, str, &err);
} else {
sqlite3_exec(db, "SELECT key, value FROM strings", strings_cb, str, &err);
}
if (err) {
LOGE("sqlite3_exec: %s\n", err);
return 1;
}
return 0;
}
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
if (db == NULL)
return 1;
char query[256], *err;
sprintf(query, "SELECT policy, logging, notification FROM policies "
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(NULL));
sqlite3_exec(db, query, policy_cb, su, &err);
if (err) {
LOGE("sqlite3_exec: %s\n", err);
return 1;
}
return 0;
}
int validate_manager(char *pkg, int userid, struct stat *st) {
if (st == NULL) {
struct stat stat;
st = &stat;
}
// Prefer DE storage
const char *base = access("/data/user_de", F_OK) == 0 ? "/data/user_de" : "/data/user";
char app_path[128];
sprintf(app_path, "%s/%d/%s", base, userid, pkg[0] ? pkg : "xxx");
if (stat(app_path, st)) {
// Check the official package name
sprintf(app_path, "%s/%d/"JAVA_PACKAGE_NAME, base, userid);
if (stat(app_path, st)) {
LOGE("su: cannot find manager");
memset(st, 0, sizeof(*st));
pkg[0] = '\0';
return 1;
} else {
// Switch to official package if exists
strcpy(pkg, JAVA_PACKAGE_NAME);
}
}
return 0;
}

View File

@@ -0,0 +1,166 @@
/* log_daemon.c - A dedicated daemon to monitor logcat
*
* A universal logcat monitor for many usages. Add listeners to the list,
* and the new log line will be sent through sockets to trigger
* asynchronous events without polling
*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "magisk.h"
#include "utils.h"
#include "daemon.h"
int loggable = 1;
static struct vector log_cmd, clear_cmd;
static int sockfd;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
enum {
HIDE_EVENT,
LOG_EVENT
};
struct log_listener {
int fd;
int (*filter) (const char*);
};
static int am_proc_start_filter(const char *log) {
return strstr(log, "am_proc_start") != NULL;
}
static int magisk_log_filter(const char *log) {
return !am_proc_start_filter(log);
}
static struct log_listener events[] = {
{ /* HIDE_EVENT */
.fd = -1,
.filter = am_proc_start_filter
},
{ /* LOG_EVENT */
.fd = -1,
.filter = magisk_log_filter
}
};
#define EVENT_NUM (sizeof(events) / sizeof(struct log_listener))
static void sigpipe_handler(int sig) {
close(events[HIDE_EVENT].fd);
events[HIDE_EVENT].fd = -1;
}
static void *monitor_thread(void *args) {
// Block SIGPIPE to prevent interruption
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, SIGPIPE);
pthread_sigmask(SIG_SETMASK, &block_set, NULL);
// Give the main daemon some time before we monitor it
sleep(5);
int fd;
char b;
while (1) {
fd = connect_daemon();
write_int(fd, HANDSHAKE);
// This should hold unless the daemon is killed
read(fd, &b, sizeof(b));
// The main daemon crashed, spawn a new one
close(fd);
}
}
static void *logcat_thread(void *args) {
int log_fd = -1, log_pid;
char line[4096];
while (1) {
// Start logcat
log_pid = exec_array(0, &log_fd, NULL, (char **) vec_entry(&log_cmd));
FILE *logs = fdopen(log_fd, "r");
while (fgets(line, sizeof(line), logs)) {
if (line[0] == '-')
continue;
size_t len = strlen(line);
pthread_mutex_lock(&lock);
for (int i = 0; i < EVENT_NUM; ++i) {
if (events[i].fd > 0 && events[i].filter(line))
write(events[i].fd, line, len);
}
pthread_mutex_unlock(&lock);
}
fclose(logs);
log_fd = -1;
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
LOGI("magisklogd: logcat output EOF");
// Clear buffer
log_pid = exec_array(0, NULL, NULL, (char **) vec_entry(&clear_cmd));
waitpid(log_pid, NULL, 0);
}
}
void log_daemon() {
setsid();
struct sockaddr_un sun;
sockfd = setup_socket(&sun, LOG_DAEMON);
if (xbind(sockfd, (struct sockaddr*) &sun, sizeof(sun)))
exit(1);
xlisten(sockfd, 10);
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") logger started\n");
strcpy(argv0, "magisklogd");
// Set SIGPIPE handler
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = sigpipe_handler;
sigaction(SIGPIPE, &act, NULL);
// Setup log dumps
rename(LOGFILE, LOGFILE ".bak");
events[LOG_EVENT].fd = xopen(LOGFILE, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC | O_APPEND, 0644);
// Construct cmdline
vec_init(&log_cmd);
vec_push_back(&log_cmd, "/system/bin/logcat");
// Test whether these buffers actually works
const char* b[] = { "main", "events", "crash" };
for (int i = 0; i < 3; ++i) {
if (exec_command_sync("/system/bin/logcat", "-b", b[i], "-d", "-f", "/dev/null", NULL) == 0)
vec_push_back_all(&log_cmd, "-b", b[i], NULL);
}
vec_dup(&log_cmd, &clear_cmd);
vec_push_back_all(&log_cmd, "-v", "threadtime", "-s", "am_proc_start", "Magisk", "*:F", NULL);
vec_push_back(&log_cmd, NULL);
vec_push_back(&clear_cmd, "-c");
vec_push_back(&clear_cmd, NULL);
// Start worker threads
pthread_t thread;
pthread_create(&thread, NULL, monitor_thread, NULL);
pthread_detach(thread);
xpthread_create(&thread, NULL, logcat_thread, NULL);
pthread_detach(thread);
while(1) {
int fd = xaccept4(sockfd, NULL, NULL, SOCK_CLOEXEC);
switch(read_int(fd)) {
case HIDE_CONNECT:
pthread_mutex_lock(&lock);
close(events[HIDE_EVENT].fd);
events[HIDE_EVENT].fd = fd;
pthread_mutex_unlock(&lock);
break;
case HANDSHAKE:
default:
close(fd);
break;
}
}
}

151
native/jni/core/magisk.c Normal file
View File

@@ -0,0 +1,151 @@
/* main.c - The multicall entry point
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <libgen.h>
#include "utils.h"
#include "magisk.h"
#include "daemon.h"
char *argv0;
int (*applet_main[]) (int, char *[]) =
{ su_client_main, resetprop_main, magiskhide_main, imgtool_main, NULL };
int create_links(const char *bin, const char *path) {
char self[PATH_MAX], linkpath[PATH_MAX];
if (bin == NULL) {
xreadlink("/proc/self/exe", self, sizeof(self));
bin = self;
}
int ret = 0;
for (int i = 0; applet[i]; ++i) {
snprintf(linkpath, sizeof(linkpath), "%s/%s", path, applet[i]);
unlink(linkpath);
ret |= symlink(bin, linkpath);
}
return ret;
}
static void usage() {
fprintf(stderr,
"Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) multi-call binary\n"
"\n"
"Usage: magisk [applet [arguments]...]\n"
" or: magisk [options]...\n"
"\n"
"Options:\n"
" -c print current binary version\n"
" -v print running daemon version\n"
" -V print running daemon version code\n"
" --list list all available applets\n"
" --install [SOURCE] DIR symlink all applets to DIR. SOURCE is optional\n"
" --daemon manually start magisk daemon\n"
" --[init trigger] start service for init trigger\n"
" --unlock-blocks set BLKROSET flag to OFF for all block devices\n"
" --restorecon fix selinux context on Magisk files and folders\n"
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
"\n"
"Supported init triggers:\n"
" startup, post-fs-data, service\n"
"\n"
"Supported applets:\n");
for (int i = 0; applet[i]; ++i)
fprintf(stderr, i ? ", %s" : " %s", applet[i]);
fprintf(stderr, "\n\n");
exit(1);
}
int magisk_main(int argc, char *argv[]) {
if (argc < 2)
usage();
if (strcmp(argv[1], "-c") == 0) {
printf("%s (%d)\n", MAGISK_VER_STR, MAGISK_VER_CODE);
return 0;
} else if (strcmp(argv[1], "-v") == 0) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION);
char *v = read_string(fd);
printf("%s\n", v);
free(v);
return 0;
} else if (strcmp(argv[1], "-V") == 0) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION_CODE);
printf("%d\n", read_int(fd));
return 0;
} else if (strcmp(argv[1], "--install") == 0) {
if (argc < 3) usage();
if (argc == 3) return create_links(NULL, argv[2]);
else return create_links(argv[2], argv[3]);
} else if (strcmp(argv[1], "--list") == 0) {
for (int i = 0; applet[i]; ++i)
printf("%s\n", applet[i]);
return 0;
} else if (strcmp(argv[1], "--unlock-blocks") == 0) {
unlock_blocks();
return 0;
} else if (strcmp(argv[1], "--restorecon") == 0) {
restorecon();
return 0;
} else if (strcmp(argv[1], "--clone-attr") == 0) {
if (argc < 4) usage();
clone_attr(argv[2], argv[3]);
return 0;
} else if (strcmp(argv[1], "--daemon") == 0) {
int fd = connect_daemon();
write_int(fd, DO_NOTHING);
return 0;
} else if (strcmp(argv[1], "--startup") == 0) {
startup();
return 0;
} else if (strcmp(argv[1], "--post-fs-data") == 0) {
int fd = connect_daemon();
write_int(fd, POST_FS_DATA);
return read_int(fd);
} else if (strcmp(argv[1], "--service") == 0) {
int fd = connect_daemon();
write_int(fd, LATE_START);
return read_int(fd);
}
// Applets
argc--;
argv++;
for (int i = 0; applet[i]; ++i) {
if (strcmp(basename(argv[0]), applet[i]) == 0) {
strcpy(argv0, basename(argv[0]));
return (*applet_main[i])(argc, argv);
}
}
usage();
return 1;
}
int main(int argc, char *argv[]) {
umask(0);
argv0 = argv[0];
if (strcmp(basename(argv0), "magisk.bin") == 0) {
if (argc >= 2) {
// It's calling applets
--argc;
++argv;
}
}
// Applets
for (int i = 0; applet[i]; ++i) {
if (strcmp(basename(argv[0]), applet[i]) == 0) {
strcpy(argv0, basename(argv[0]));
return (*applet_main[i])(argc, argv);
}
}
// Not an applet
return magisk_main(argc, argv);
}

View File

@@ -21,6 +21,7 @@
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -38,17 +39,27 @@
#include <lzma.h>
#include <cil/cil.h>
#include "magisk.h"
#include "binaries_xz.h"
#include "binaries_arch_xz.h"
#include "magiskrc.h"
#include "utils.h"
#include "magiskpolicy.h"
#include "magiskrc.h"
#include "dump.h"
#include "daemon.h"
#include "cpio.h"
#include "magisk.h"
// #define VLOG(fmt, ...) printf(fmt, __VA_ARGS__) /* Enable to debug */
#ifdef MAGISK_DEBUG
#define VLOG(fmt, ...) printf(fmt, __VA_ARGS__)
#else
#define VLOG(fmt, ...)
#endif
extern policydb_t *policydb;
int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, NULL };
struct cmdline {
int skip_initramfs;
char skip_initramfs;
char slot[3];
};
@@ -60,33 +71,29 @@ struct device {
char path[64];
};
extern policydb_t *policydb;
static void parse_cmdline(struct cmdline *cmd) {
// cleanup
cmd->skip_initramfs = 0;
cmd->slot[0] = '\0';
memset(cmd, 0, sizeof(*cmd));
char *tok;
char cmdline[4096];
mkdir("/proc", 0555);
mount("proc", "/proc", "proc", 0, NULL);
xmount("proc", "/proc", "proc", 0, NULL);
int fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
close(fd);
umount("/proc");
tok = strtok(cmdline, " ");
while (tok != NULL) {
for (char *tok = strtok(cmdline, " "); tok; tok = strtok(NULL, " ")) {
if (strncmp(tok, "androidboot.slot_suffix", 23) == 0) {
sscanf(tok, "androidboot.slot_suffix=%s", cmd->slot);
} else if (strncmp(tok, "androidboot.slot", 16) == 0) {
cmd->slot[0] = '_';
sscanf(tok, "androidboot.slot=%s", cmd->slot + 1);
sscanf(tok, "androidboot.slot=%c", cmd->slot + 1);
} else if (strcmp(tok, "skip_initramfs") == 0) {
cmd->skip_initramfs = 1;
}
tok = strtok(NULL, " ");
}
VLOG("cmdline: skip_initramfs[%d] slot[%s]\n", cmd->skip_initramfs, cmd->slot);
}
static void parse_device(struct device *dev, char *uevent) {
@@ -124,7 +131,7 @@ static int setup_block(struct device *dev, const char *partname) {
buffer[size] = '\0';
close(fd);
parse_device(dev, buffer);
if (strcmp(dev->partname, partname) == 0) {
if (strcasecmp(dev->partname, partname) == 0) {
snprintf(dev->path, sizeof(dev->path), "/dev/block/%s", dev->devname);
found = 1;
break;
@@ -141,60 +148,29 @@ static int setup_block(struct device *dev, const char *partname) {
return 0;
}
static void *patch_init_rc(char *data, uint32_t *size) {
int injected = 0;
char *new_data = malloc(*size + 23);
char *old_data = data;
uint32_t pos = 0;
for (char *tok = strsep(&old_data, "\n"); tok; tok = strsep(&old_data, "\n")) {
if (!injected && strncmp(tok, "import", 6) == 0) {
if (strstr(tok, "init.magisk.rc")) {
injected = 1;
} else {
strcpy(new_data + pos, "import /init.magisk.rc\n");
pos += 23;
injected = 1;
}
} else if (strstr(tok, "selinux.reload_policy")) {
continue;
}
// Copy the line
strcpy(new_data + pos, tok);
pos += strlen(tok);
new_data[pos++] = '\n';
}
*size = pos;
return new_data;
}
static void patch_ramdisk() {
void *addr;
size_t size;
mmap_rw("/init", &addr, &size);
for (int i = 0; i < size; ++i) {
if (memcmp(addr + i, "/system/etc/selinux/plat_sepolicy.cil", 37) == 0) {
memcpy(addr + i, "/system/etc/selinux/plat_sepolicy.xxx", 37);
if (memcmp(addr + i, SPLIT_PLAT_CIL, sizeof(SPLIT_PLAT_CIL) - 1) == 0) {
memcpy(addr + i + sizeof(SPLIT_PLAT_CIL) - 4, "xxx", 3);
break;
}
}
munmap(addr, size);
mmap_rw("/init.rc", &addr, &size);
uint32_t new_size = size;
void *init_rc = patch_init_rc(addr, &new_size);
munmap(addr, size);
int fd = open("/init.rc", O_WRONLY | O_TRUNC | O_CLOEXEC);
write(fd, init_rc, new_size);
full_read("/init.rc", &addr, &size);
patch_init_rc(&addr, &size);
int fd = creat("/init.rc", 0750);
write(fd, addr, size);
close(fd);
free(init_rc);
free(addr);
}
static int strend(const char *s1, const char *s2) {
int l1 = strlen(s1);
int l2 = strlen(s2);
size_t l1 = strlen(s1);
size_t l2 = strlen(s2);
return strcmp(s1 + l1 - l2, s2);
}
@@ -210,34 +186,38 @@ static int compile_cil() {
cil_db_init(&db);
cil_set_mls(db, 1);
cil_set_multiple_decls(db, 1);
cil_set_disable_neverallow(db, 1);
cil_set_target_platform(db, SEPOL_TARGET_SELINUX);
cil_set_policy_version(db, POLICYDB_VERSION_XPERMS_IOCTL);
cil_set_attrs_expand_generated(db, 0);
// plat
mmap_ro("/system/etc/selinux/plat_sepolicy.cil", &addr, &size);
cil_add_file(db, "/system/etc/selinux/plat_sepolicy.cil", addr, size);
mmap_ro(SPLIT_PLAT_CIL, &addr, &size);
VLOG("cil_add[%s]\n", SPLIT_PLAT_CIL);
cil_add_file(db, SPLIT_PLAT_CIL, addr, size);
munmap(addr, size);
// mapping
char plat[10];
int fd = open("/vendor/etc/selinux/plat_sepolicy_vers.txt", O_RDONLY | O_CLOEXEC);
if (fd > 0) {
plat[read(fd, plat, sizeof(plat)) - 1] = '\0';
snprintf(path, sizeof(path), "/system/etc/selinux/mapping/%s.cil", plat);
mmap_ro(path, &addr, &size);
cil_add_file(db, path, addr, size);
munmap(addr, size);
close(fd);
}
int fd = open(SPLIT_NONPLAT_VER, O_RDONLY | O_CLOEXEC);
plat[read(fd, plat, sizeof(plat)) - 1] = '\0';
snprintf(path, sizeof(path), SPLIT_PLAT_MAPPING, plat);
mmap_ro(path, &addr, &size);
VLOG("cil_add[%s]\n", path);
cil_add_file(db, path, addr, size);
munmap(addr, size);
close(fd);
dir = opendir("/vendor/etc/selinux");
// nonplat
dir = opendir(NONPLAT_POLICY_DIR);
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".cil") == 0) {
snprintf(path, sizeof(path), "/vendor/etc/selinux/%s", entry->d_name);
snprintf(path, sizeof(path), NONPLAT_POLICY_DIR "%s", entry->d_name);
mmap_ro(path, &addr, &size);
VLOG("cil_add[%s]\n", path);
cil_add_file(db, path, addr, size);
munmap(addr, size);
}
@@ -259,45 +239,58 @@ static int verify_precompiled() {
int fd;
char sys_sha[70], ven_sha[70];
dir = opendir("/vendor/etc/selinux");
// init the strings with different value
sys_sha[0] = 0;
ven_sha[0] = 1;
dir = opendir(NONPLAT_POLICY_DIR);
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".sha256") == 0) {
fd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_CLOEXEC);
ven_sha[read(fd, ven_sha, sizeof(ven_sha))] = '\0';
ven_sha[read(fd, ven_sha, sizeof(ven_sha)) - 1] = '\0';
close(fd);
break;
}
}
closedir(dir);
dir = opendir("/system/etc/selinux");
dir = opendir(PLAT_POLICY_DIR);
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".sha256") == 0) {
fd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_CLOEXEC);
sys_sha[read(fd, sys_sha, sizeof(sys_sha))] = '\0';
sys_sha[read(fd, sys_sha, sizeof(sys_sha)) - 1] = '\0';
close(fd);
break;
}
}
closedir(dir);
return strcmp(sys_sha, ven_sha);
VLOG("sys_sha[%s]\nven_sha[%s]\n", sys_sha, ven_sha);
return strcmp(sys_sha, ven_sha) == 0;
}
static void patch_sepolicy() {
if (access("/sepolicy", R_OK) == 0) {
static int patch_sepolicy() {
if (access("/sepolicy", R_OK) == 0)
load_policydb("/sepolicy");
} else if (access("/vendor/etc/selinux/precompiled_sepolicy", R_OK) == 0
&& verify_precompiled() == 0) {
load_policydb("/vendor/etc/selinux/precompiled_sepolicy");
} else if (access("/system/etc/selinux/plat_sepolicy.cil", R_OK) == 0) {
else if (access(SPLIT_PRECOMPILE, R_OK) == 0 && verify_precompiled())
load_policydb(SPLIT_PRECOMPILE);
else if (access(SPLIT_PLAT_CIL, R_OK) == 0)
compile_cil();
else
return 1;
sepol_magisk_rules();
dump_policydb("/sepolicy");
// Remove the stupid debug sepolicy and use our own
if (access("/sepolicy_debug", F_OK) == 0) {
unlink("/sepolicy_debug");
link("/sepolicy", "/sepolicy_debug");
}
sepol_med_rules();
dump_policydb("/sepolicy");
return 0;
}
#define BUFSIZE (1 << 20)
@@ -306,7 +299,7 @@ static int unxz(const void *buf, size_t size, int fd) {
lzma_stream strm = LZMA_STREAM_INIT;
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK)
return 1;
lzma_ret ret = 0;
lzma_ret ret;
void *out = malloc(BUFSIZE);
strm.next_in = buf;
strm.avail_in = size;
@@ -328,7 +321,15 @@ static int unxz(const void *buf, size_t size, int fd) {
static int dump_magisk(const char *path, mode_t mode) {
unlink(path);
int fd = creat(path, mode);
int ret = unxz(magisk_dump, sizeof(magisk_dump), fd);
int ret = unxz(magisk_xz, sizeof(magisk_xz), fd);
close(fd);
return ret;
}
static int dump_manager(const char *path, mode_t mode) {
unlink(path);
int fd = creat(path, mode);
int ret = unxz(manager_xz, sizeof(manager_xz), fd);
close(fd);
return ret;
}
@@ -340,101 +341,168 @@ static int dump_magiskrc(const char *path, mode_t mode) {
return 0;
}
static void patch_socket_name(const char *path) {
void *buf;
char name[sizeof(MAIN_SOCKET)];
size_t size;
mmap_rw(path, &buf, &size);
for (int i = 0; i < size; ++i) {
if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) {
gen_rand_str(name, sizeof(name));
memcpy(buf + i, name, sizeof(name));
i += sizeof(name);
}
if (memcmp(buf + i, LOG_SOCKET, sizeof(LOG_SOCKET)) == 0) {
gen_rand_str(name, sizeof(name));
memcpy(buf + i, name, sizeof(name));
i += sizeof(name);
}
}
munmap(buf, size);
}
int main(int argc, char *argv[]) {
umask(0);
if (strcmp(basename(argv[0]), "magiskpolicy") == 0 || strcmp(basename(argv[0]), "supolicy") == 0)
return magiskpolicy_main(argc, argv);
if (argc > 1 && (strcmp(argv[1], "magiskpolicy") == 0 || strcmp(argv[1], "supolicy") == 0))
return magiskpolicy_main(argc - 1, argv + 1);
for (int i = 0; init_applet[i]; ++i) {
if (strcmp(basename(argv[0]), init_applet[i]) == 0)
return (*init_applet_main[i])(argc, argv);
}
if (argc > 1 && strcmp(argv[1], "-x") == 0) {
if (strcmp(argv[2], "magisk") == 0)
return dump_magisk(argv[3], 0755);
else if (strcmp(argv[2], "manager") == 0)
return dump_manager(argv[3], 0644);
else if (strcmp(argv[2], "magiskrc") == 0)
return dump_magiskrc(argv[3], 0755);
}
// Extract and link files
mkdir("/overlay", 0000);
dump_magiskrc("/overlay/init.magisk.rc", 0750);
mkdir("/overlay/sbin", 0755);
dump_magisk("/overlay/sbin/magisk", 0755);
mkdir("/overlay/root", 0755);
link("/init", "/overlay/root/magiskinit");
symlink("/root/magiskinit", "/overlay/root/magiskpolicy");
symlink("/root/magiskinit", "/overlay/root/supolicy");
// Prevent file descriptor confusion
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
int null = open("/null", O_RDWR | O_CLOEXEC);
unlink("/null");
dup3(null, STDIN_FILENO, O_CLOEXEC);
dup3(null, STDOUT_FILENO, O_CLOEXEC);
dup3(null, STDERR_FILENO, O_CLOEXEC);
if (null > STDERR_FILENO)
close(null);
// Backup self
link("/init", "/init.bak");
struct cmdline cmd;
parse_cmdline(&cmd);
VLOG("cmdline: skip_initramfs=[%d] slot_suffix=[%s]\n", cmd.skip_initramfs, cmd.slot);
/* ***********
* Initialize
* ***********/
int root = open("/", O_RDONLY | O_CLOEXEC);
if (cmd.skip_initramfs) {
// Exclude overlay folder
excl_list = (char *[]) { "overlay", ".backup", NULL };
// Clear rootfs
excl_list = (char *[]) { "overlay", ".backup", "init.bak", NULL };
frm_rf(root);
mkdir("/sys", 0755);
mount("sysfs", "/sys", "sysfs", 0, NULL);
char partname[32];
snprintf(partname, sizeof(partname), "system%s", cmd.slot);
struct device dev;
setup_block(&dev, partname);
mkdir("/system_root", 0755);
mount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL);
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
// Exclude system folder
excl_list = (char *[]) { "system", NULL };
clone_dir(system_root, root);
mkdir("/system", 0755);
mount("/system_root/system", "/system", NULL, MS_BIND, NULL);
snprintf(partname, sizeof(partname), "vendor%s", cmd.slot);
// We need to mount independent vendor partition
if (setup_block(&dev, partname) == 0)
mount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL);
close(system_root);
} else if (access("/ramdisk.cpio.xz", R_OK) == 0) {
// High compression mode
void *addr;
size_t size;
mmap_ro("/ramdisk.cpio.xz", &addr, &size);
int fd = creat("/ramdisk.cpio", 0);
unxz(addr, size, fd);
munmap(addr, size);
close(fd);
struct vector v;
vec_init(&v);
parse_cpio(&v, "/ramdisk.cpio");
excl_list = (char *[]) { "overlay", ".backup", NULL };
frm_rf(root);
chdir("/");
cpio_extract_all(&v);
cpio_vec_destroy(&v);
} else {
// Revert original init binary
unlink("/init");
link("/.backup/init", "/init");
}
int overlay = open("/overlay", O_RDONLY | O_CLOEXEC);
mv_dir(overlay, root);
/* ************
* Early Mount
* ************/
int mounted_system = 0;
int mounted_vendor = 0;
// If skip_initramfs or using split policies, we need early mount
if (cmd.skip_initramfs || access("/sepolicy", R_OK) != 0) {
char partname[32];
struct device dev;
// Mount sysfs
mkdir("/sys", 0755);
xmount("sysfs", "/sys", "sysfs", 0, NULL);
// Mount system
snprintf(partname, sizeof(partname), "system%s", cmd.slot);
setup_block(&dev, partname);
if (cmd.skip_initramfs) {
mkdir("/system_root", 0755);
xmount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL);
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
// Clone rootfs except /system
excl_list = (char *[]) { "system", NULL };
clone_dir(system_root, root);
close(system_root);
mkdir("/system", 0755);
xmount("/system_root/system", "/system", NULL, MS_BIND, NULL);
} else {
xmount(dev.path, "/system", "ext4", MS_RDONLY, NULL);
mounted_system = 1;
}
// Mount vendor
snprintf(partname, sizeof(partname), "vendor%s", cmd.slot);
if (setup_block(&dev, partname) == 0) {
xmount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL);
mounted_vendor = 1;
}
}
/* *************
* Patch rootfs
* *************/
// Only patch rootfs if not intended to run in recovery
if (access("/etc/recovery.fstab", F_OK) != 0) {
int fd;
// Handle ramdisk overlays
fd = open("/overlay", O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
mv_dir(fd, root);
close(fd);
rmdir("/overlay");
}
patch_ramdisk();
patch_sepolicy();
// Dump binaries
dump_magiskrc("/init.magisk.rc", 0750);
dump_magisk("/sbin/magisk", 0755);
patch_socket_name("/sbin/magisk");
rename("/init.bak", "/sbin/magiskinit");
}
// Clean up
rmdir("/overlay");
close(overlay);
close(root);
patch_ramdisk();
patch_sepolicy();
umount("/vendor");
if (fork() == 0) {
// Fork a new process for full patch
setsid();
sepol_allow("su", ALL, ALL, ALL);
while (access(PATCHSTART, W_OK) == -1)
usleep(500); /* Wait 0.5ms */
unlink(PATCHSTART);
dump_policydb(SELINUX_LOAD);
close(open(PATCHDONE, O_RDONLY | O_CREAT, 0));
destroy_policydb();
return 0;
}
if (mounted_system)
umount("/system");
if (mounted_vendor)
umount("/vendor");
// Finally, give control back!
execv("/init", argv);

161
native/jni/core/socket.c Normal file
View File

@@ -0,0 +1,161 @@
/* socket.c - All socket related operations
*/
#include <fcntl.h>
#include "daemon.h"
#include "logging.h"
#include "utils.h"
#include "magisk.h"
/* Setup the address and return socket fd */
int setup_socket(struct sockaddr_un *sun, daemon_t d) {
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_LOCAL;
sun->sun_path[0] = '\0';
const char *name;
switch (d) {
case MAIN_DAEMON:
name = MAIN_SOCKET;
break;
case LOG_DAEMON:
name = LOG_SOCKET;
break;
}
strcpy(sun->sun_path + 1, name);
return fd;
}
/*
* Receive a file descriptor from a Unix socket.
* Contributed by @mkasick
*
* Returns the file descriptor on success, or -1 if a file
* descriptor was not actually included in the message
*
* On error the function terminates by calling exit(-1)
*/
int recv_fd(int sockfd) {
// Need to receive data from the message, otherwise don't care about it.
char iovbuf;
struct iovec iov = {
.iov_base = &iovbuf,
.iov_len = 1,
};
char cmsgbuf[CMSG_SPACE(sizeof(int))];
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = cmsgbuf,
.msg_controllen = sizeof(cmsgbuf),
};
xrecvmsg(sockfd, &msg, MSG_WAITALL);
// Was a control message actually sent?
switch (msg.msg_controllen) {
case 0:
// No, so the file descriptor was closed and won't be used.
return -1;
case sizeof(cmsgbuf):
// Yes, grab the file descriptor from it.
break;
default:
goto error;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg == NULL ||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
error:
LOGE("unable to read fd");
exit(-1);
}
return *(int *)CMSG_DATA(cmsg);
}
/*
* Send a file descriptor through a Unix socket.
* Contributed by @mkasick
*
* On error the function terminates by calling exit(-1)
*
* fd may be -1, in which case the dummy data is sent,
* but no control message with the FD is sent.
*/
void send_fd(int sockfd, int fd) {
// Need to send some data in the message, this will do.
struct iovec iov = {
.iov_base = "",
.iov_len = 1,
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
char cmsgbuf[CMSG_SPACE(sizeof(int))];
if (fd != -1) {
// Is the file descriptor actually open?
if (fcntl(fd, F_GETFD) == -1) {
if (errno != EBADF) {
PLOGE("unable to send fd");
}
// It's closed, don't send a control message or sendmsg will EBADF.
} else {
// It's open, send the file descriptor in a control message.
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(cmsg) = fd;
}
}
xsendmsg(sockfd, &msg, 0);
}
int read_int(int fd) {
int val;
xxread(fd, &val, sizeof(int));
return val;
}
void write_int(int fd, int val) {
if (fd < 0) return;
xwrite(fd, &val, sizeof(int));
}
char* read_string(int fd) {
int len = read_int(fd);
if (len > PATH_MAX || len < 0) {
LOGE("invalid string length %d", len);
exit(1);
}
char* val = xmalloc(sizeof(char) * (len + 1));
xxread(fd, val, len);
val[len] = '\0';
return val;
}
void write_string(int fd, const char* val) {
if (fd < 0) return;
int len = strlen(val);
write_int(fd, len);
xwrite(fd, val, len);
}

View File

@@ -1,8 +1,9 @@
LOCAL_PATH:= $(call my-dir)
LOCAL_PATH := $(call my-dir)
# libsqlite.so (stub)
include $(CLEAR_VARS)
LOCAL_MODULE:= libsqlite
LOCAL_C_INCLUDES := $(EXT_PATH)/include
LOCAL_SRC_FILES := stubs/sqlite3_stub.c
include $(BUILD_SHARED_LIBRARY)
@@ -13,6 +14,30 @@ LOCAL_C_INCLUDES := $(LIBSELINUX)
LOCAL_SRC_FILES := stubs/selinux_stub.c
include $(BUILD_SHARED_LIBRARY)
# libmincrypt.a
include $(CLEAR_VARS)
LOCAL_MODULE:= libmincrypt
LOCAL_C_INCLUDES := $(EXT_PATH)/include
LOCAL_SRC_FILES := \
mincrypt/dsa_sig.c \
mincrypt/p256.c \
mincrypt/p256_ec.c \
mincrypt/p256_ecdsa.c \
mincrypt/rsa.c \
mincrypt/sha.c \
mincrypt/sha256.c
include $(BUILD_STATIC_LIBRARY)
# libnanopb.a
include $(CLEAR_VARS)
LOCAL_MODULE:= libnanopb
LOCAL_C_INCLUDES := $(LIBNANOPB)
LOCAL_SRC_FILES := \
nanopb/pb_common.c \
nanopb/pb_decode.c \
nanopb/pb_encode.c
include $(BUILD_STATIC_LIBRARY)
# libfdt.a
include $(CLEAR_VARS)
LOCAL_MODULE:= libfdt
@@ -58,7 +83,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liblzma
LOCAL_C_INCLUDES += \
$(EXT_PATH)/xz_config \
$(EXT_PATH)/include/xz_config \
$(EXT_PATH)/xz/src/common \
$(EXT_PATH)/xz/src/liblzma/api \
$(EXT_PATH)/xz/src/liblzma/check \
@@ -150,7 +175,7 @@ LOCAL_SRC_FILES := \
xz/src/liblzma/simple/simple_encoder.c \
xz/src/liblzma/simple/sparc.c \
xz/src/liblzma/simple/x86.c
LOCAL_CFLAGS += -DHAVE_CONFIG_H -std=c99
LOCAL_CFLAGS += -DHAVE_CONFIG_H -Wno-implicit-function-declaration
include $(BUILD_STATIC_LIBRARY)
# libsepol.a

1
native/jni/external/busybox vendored Submodule

1
native/jni/external/dtc vendored Submodule

Submodule native/jni/external/dtc added at e54388015a

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
#include "mincrypt/p256.h"
#ifdef __cplusplus
extern "C" {
#endif
// Returns 0 if input sig is not a valid ASN.1 sequence
int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int);
#ifdef __cplusplus
}
#endif
#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2007 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
struct HASH_CTX; // forward decl
typedef struct HASH_VTAB {
void (* const init)(struct HASH_CTX*);
void (* const update)(struct HASH_CTX*, const void*, int);
const uint8_t* (* const final)(struct HASH_CTX*);
const uint8_t* (* const hash)(const void*, int, uint8_t*);
int size;
} HASH_VTAB;
typedef struct HASH_CTX {
const HASH_VTAB * f;
uint64_t count;
uint8_t buf[64];
uint32_t state[8]; // upto SHA2
} HASH_CTX;
#define HASH_init(ctx) (ctx)->f->init(ctx)
#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
#define HASH_final(ctx) (ctx)->f->final(ctx)
#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
#define HASH_size(ctx) (ctx)->f->size
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_

View File

@@ -0,0 +1,162 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
// Collection of routines manipulating 256 bit unsigned integers.
// Just enough to implement ecdsa-p256 and related algorithms.
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define P256_BITSPERDIGIT 32
#define P256_NDIGITS 8
#define P256_NBYTES 32
typedef int p256_err;
typedef uint32_t p256_digit;
typedef int32_t p256_sdigit;
typedef uint64_t p256_ddigit;
typedef int64_t p256_sddigit;
// Defining p256_int as struct to leverage struct assigment.
typedef struct {
p256_digit a[P256_NDIGITS];
} p256_int;
extern const p256_int SECP256r1_n; // Curve order
extern const p256_int SECP256r1_p; // Curve prime
extern const p256_int SECP256r1_b; // Curve param
// Initialize a p256_int to zero.
void p256_init(p256_int* a);
// Clear a p256_int to zero.
void p256_clear(p256_int* a);
// Return bit. Index 0 is least significant.
int p256_get_bit(const p256_int* a, int index);
// b := a % MOD
void p256_mod(
const p256_int* MOD,
const p256_int* a,
p256_int* b);
// c := a * (top_b | b) % MOD
void p256_modmul(
const p256_int* MOD,
const p256_int* a,
const p256_digit top_b,
const p256_int* b,
p256_int* c);
// b := 1 / a % MOD
// MOD best be SECP256r1_n
void p256_modinv(
const p256_int* MOD,
const p256_int* a,
p256_int* b);
// b := 1 / a % MOD
// MOD best be SECP256r1_n
// Faster than p256_modinv()
void p256_modinv_vartime(
const p256_int* MOD,
const p256_int* a,
p256_int* b);
// b := a << (n % P256_BITSPERDIGIT)
// Returns the bits shifted out of most significant digit.
p256_digit p256_shl(const p256_int* a, int n, p256_int* b);
// b := a >> (n % P256_BITSPERDIGIT)
void p256_shr(const p256_int* a, int n, p256_int* b);
int p256_is_zero(const p256_int* a);
int p256_is_odd(const p256_int* a);
int p256_is_even(const p256_int* a);
// Returns -1, 0 or 1.
int p256_cmp(const p256_int* a, const p256_int *b);
// c: = a - b
// Returns -1 on borrow.
int p256_sub(const p256_int* a, const p256_int* b, p256_int* c);
// c := a + b
// Returns 1 on carry.
int p256_add(const p256_int* a, const p256_int* b, p256_int* c);
// c := a + (single digit)b
// Returns carry 1 on carry.
int p256_add_d(const p256_int* a, p256_digit b, p256_int* c);
// ec routines.
// {out_x,out_y} := nG
void p256_base_point_mul(const p256_int *n,
p256_int *out_x,
p256_int *out_y);
// {out_x,out_y} := n{in_x,in_y}
void p256_point_mul(const p256_int *n,
const p256_int *in_x,
const p256_int *in_y,
p256_int *out_x,
p256_int *out_y);
// {out_x,out_y} := n1G + n2{in_x,in_y}
void p256_points_mul_vartime(
const p256_int *n1, const p256_int *n2,
const p256_int *in_x, const p256_int *in_y,
p256_int *out_x, p256_int *out_y);
// Return whether point {x,y} is on curve.
int p256_is_valid_point(const p256_int* x, const p256_int* y);
// Outputs big-endian binary form. No leading zero skips.
void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]);
// Reads from big-endian binary form,
// thus pre-pad with leading zeros if short.
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst);
#define P256_DIGITS(x) ((x)->a)
#define P256_DIGIT(x,y) ((x)->a[y])
#define P256_ZERO {{0}}
#define P256_ONE {{1}}
#ifdef __cplusplus
}
#endif
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
// Using current directory as relative include path here since
// this code typically gets lifted into a variety of build systems
// and directory structures.
#include "p256.h"
#ifdef __cplusplus
extern "C" {
#endif
// Returns 0 if {r,s} is not a signature on message for
// public key {key_x,key_y}.
//
// Note: message is a p256_int.
// Convert from a binary string using p256_from_bin().
int p256_ecdsa_verify(const p256_int* key_x,
const p256_int* key_y,
const p256_int* message,
const p256_int* r, const p256_int* s);
#ifdef __cplusplus
}
#endif
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_

View File

@@ -0,0 +1,58 @@
/* rsa.h
**
** Copyright 2008, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of Google Inc. nor the names of its contributors may
** be used to endorse or promote products derived from this software
** without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RSANUMBYTES 256 /* 2048 bit key length */
#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
typedef struct RSAPublicKey {
int len; /* Length of n[] in number of uint32_t */
uint32_t n0inv; /* -1 / n[0] mod 2^32 */
uint32_t n[RSANUMWORDS]; /* modulus as little endian array */
uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
int exponent; /* 3 or 65537 */
} RSAPublicKey;
int RSA_verify(const RSAPublicKey *key,
const uint8_t* signature,
const int len,
const uint8_t* hash,
const int hash_len);
#ifdef __cplusplus
}
#endif
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2005 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
#include <stdint.h>
#include "hash-internal.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef HASH_CTX SHA_CTX;
void SHA_init(SHA_CTX* ctx);
void SHA_update(SHA_CTX* ctx, const void* data, int len);
const uint8_t* SHA_final(SHA_CTX* ctx);
// Convenience method. Returns digest address.
// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
#define SHA_DIGEST_SIZE 20
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2011 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
#include <stdint.h>
#include "hash-internal.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef HASH_CTX SHA256_CTX;
void SHA256_init(SHA256_CTX* ctx);
void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
const uint8_t* SHA256_final(SHA256_CTX* ctx);
// Convenience method. Returns digest address.
const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
#define SHA256_DIGEST_SIZE 32
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_

1
native/jni/external/lz4 vendored Submodule

Submodule native/jni/external/lz4 added at dfed9fa1d7

126
native/jni/external/mincrypt/dsa_sig.c vendored Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include "mincrypt/dsa_sig.h"
#include "mincrypt/p256.h"
/**
* Trims off the leading zero bytes and copy it to a buffer aligning it to the end.
*/
static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src,
int src_len) {
int dst_offset;
while (*src == '\0' && src_len > 0) {
src++;
src_len--;
}
if (src_len > P256_NBYTES || src_len < 1) {
return 0;
}
dst_offset = P256_NBYTES - src_len;
memset(dst, 0, dst_offset);
memcpy(dst + dst_offset, src, src_len);
return 1;
}
/**
* Unpacks the ASN.1 DSA signature sequence.
*/
int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) {
/*
* Structure is:
* 0x30 0xNN SEQUENCE + s_length
* 0x02 0xNN INTEGER + r_length
* 0xAA 0xBB .. r_length bytes of "r" (offset 4)
* 0x02 0xNN INTEGER + s_length
* 0xMM 0xNN .. s_length bytes of "s" (offset 6 + r_len)
*/
int seq_len;
unsigned char r_bytes[P256_NBYTES];
unsigned char s_bytes[P256_NBYTES];
int r_len;
int s_len;
memset(r_bytes, 0, sizeof(r_bytes));
memset(s_bytes, 0, sizeof(s_bytes));
/*
* Must have at least:
* 2 bytes sequence header and length
* 2 bytes R integer header and length
* 1 byte of R
* 2 bytes S integer header and length
* 1 byte of S
*
* 8 bytes total
*/
if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) {
return 0;
}
seq_len = sig[1];
if ((seq_len <= 0) || (seq_len + 2 != sig_len)) {
return 0;
}
r_len = sig[3];
/*
* Must have at least:
* 2 bytes for R header and length
* 2 bytes S integer header and length
* 1 byte of S
*/
if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) {
return 0;
}
s_len = sig[5 + r_len];
/**
* Must have:
* 2 bytes for R header and length
* r_len bytes for R
* 2 bytes S integer header and length
*/
if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) {
return 0;
}
/*
* ASN.1 encoded integers are zero-padded for positive integers. Make sure we have
* a correctly-sized buffer and that the resulting integer isn't too large.
*/
if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len)
|| !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) {
return 0;
}
p256_from_bin(r_bytes, r_int);
p256_from_bin(s_bytes, s_int);
return 1;
}

373
native/jni/external/mincrypt/p256.c vendored Normal file
View File

@@ -0,0 +1,373 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This is an implementation of the P256 elliptic curve group. It's written to
// be portable 32-bit, although it's still constant-time.
//
// WARNING: Implementing these functions in a constant-time manner is far from
// obvious. Be careful when touching this code.
//
// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "mincrypt/p256.h"
const p256_int SECP256r1_n = // curve order
{{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}};
const p256_int SECP256r1_p = // curve field size
{{-1, -1, -1, 0, 0, 0, 1, -1 }};
const p256_int SECP256r1_b = // curve b
{{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
void p256_init(p256_int* a) {
memset(a, 0, sizeof(*a));
}
void p256_clear(p256_int* a) { p256_init(a); }
int p256_get_bit(const p256_int* scalar, int bit) {
return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
>> (bit & (P256_BITSPERDIGIT - 1))) & 1;
}
int p256_is_zero(const p256_int* a) {
int i, result = 0;
for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i);
return !result;
}
// top, c[] += a[] * b
// Returns new top
static p256_digit mulAdd(const p256_int* a,
p256_digit b,
p256_digit top,
p256_digit* c) {
int i;
p256_ddigit carry = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += *c;
carry += (p256_ddigit)P256_DIGIT(a, i) * b;
*c++ = (p256_digit)carry;
carry >>= P256_BITSPERDIGIT;
}
return top + (p256_digit)carry;
}
// top, c[] -= top_a, a[]
static p256_digit subTop(p256_digit top_a,
const p256_digit* a,
p256_digit top_c,
p256_digit* c) {
int i;
p256_sddigit borrow = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += *c;
borrow -= *a++;
*c++ = (p256_digit)borrow;
borrow >>= P256_BITSPERDIGIT;
}
borrow += top_c;
borrow -= top_a;
top_c = (p256_digit)borrow;
assert((borrow >> P256_BITSPERDIGIT) == 0);
return top_c;
}
// top, c[] -= MOD[] & mask (0 or -1)
// returns new top.
static p256_digit subM(const p256_int* MOD,
p256_digit top,
p256_digit* c,
p256_digit mask) {
int i;
p256_sddigit borrow = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += *c;
borrow -= P256_DIGIT(MOD, i) & mask;
*c++ = (p256_digit)borrow;
borrow >>= P256_BITSPERDIGIT;
}
return top + (p256_digit)borrow;
}
// top, c[] += MOD[] & mask (0 or -1)
// returns new top.
static p256_digit addM(const p256_int* MOD,
p256_digit top,
p256_digit* c,
p256_digit mask) {
int i;
p256_ddigit carry = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += *c;
carry += P256_DIGIT(MOD, i) & mask;
*c++ = (p256_digit)carry;
carry >>= P256_BITSPERDIGIT;
}
return top + (p256_digit)carry;
}
// c = a * b mod MOD. c can be a and/or b.
void p256_modmul(const p256_int* MOD,
const p256_int* a,
const p256_digit top_b,
const p256_int* b,
p256_int* c) {
p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
p256_digit top = 0;
int i;
// Multiply/add into tmp.
for (i = 0; i < P256_NDIGITS; ++i) {
if (i) tmp[i + P256_NDIGITS - 1] = top;
top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i);
}
// Multiply/add top digit
tmp[i + P256_NDIGITS - 1] = top;
top = mulAdd(a, top_b, 0, tmp + i);
// Reduce tmp, digit by digit.
for (; i >= 0; --i) {
p256_digit reducer[P256_NDIGITS] = { 0 };
p256_digit top_reducer;
// top can be any value at this point.
// Guestimate reducer as top * MOD, since msw of MOD is -1.
top_reducer = mulAdd(MOD, top, 0, reducer);
// Subtract reducer from top | tmp.
top = subTop(top_reducer, reducer, top, tmp + i);
// top is now either 0 or 1. Make it 0, fixed-timing.
assert(top <= 1);
top = subM(MOD, top, tmp + i, ~(top - 1));
assert(top == 0);
// We have now reduced the top digit off tmp. Fetch new top digit.
top = tmp[i + P256_NDIGITS - 1];
}
// tmp might still be larger than MOD, yet same bit length.
// Make sure it is less, fixed-timing.
addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1));
memcpy(c, tmp, P256_NBYTES);
}
int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; }
int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); }
p256_digit p256_shl(const p256_int* a, int n, p256_int* b) {
int i;
p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
n %= P256_BITSPERDIGIT;
for (i = P256_NDIGITS - 1; i > 0; --i) {
p256_digit accu = (P256_DIGIT(a, i) << n);
accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
P256_DIGIT(b, i) = accu;
}
P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT);
return top;
}
void p256_shr(const p256_int* a, int n, p256_int* b) {
int i;
n %= P256_BITSPERDIGIT;
for (i = 0; i < P256_NDIGITS - 1; ++i) {
p256_digit accu = (P256_DIGIT(a, i) >> n);
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
P256_DIGIT(b, i) = accu;
}
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
}
static void p256_shr1(const p256_int* a, int highbit, p256_int* b) {
int i;
for (i = 0; i < P256_NDIGITS - 1; ++i) {
p256_digit accu = (P256_DIGIT(a, i) >> 1);
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
P256_DIGIT(b, i) = accu;
}
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
(highbit << (P256_BITSPERDIGIT - 1));
}
// Return -1, 0, 1 for a < b, a == b or a > b respectively.
int p256_cmp(const p256_int* a, const p256_int* b) {
int i;
p256_sddigit borrow = 0;
p256_digit notzero = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
// Track whether any result digit is ever not zero.
// Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1.
notzero |= !!((p256_digit)borrow);
borrow >>= P256_BITSPERDIGIT;
}
return (int)borrow | notzero;
}
// c = a - b. Returns borrow: 0 or -1.
int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) {
int i;
p256_sddigit borrow = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
if (c) P256_DIGIT(c, i) = (p256_digit)borrow;
borrow >>= P256_BITSPERDIGIT;
}
return (int)borrow;
}
// c = a + b. Returns carry: 0 or 1.
int p256_add(const p256_int* a, const p256_int* b, p256_int* c) {
int i;
p256_ddigit carry = 0;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i);
if (c) P256_DIGIT(c, i) = (p256_digit)carry;
carry >>= P256_BITSPERDIGIT;
}
return (int)carry;
}
// b = a + d. Returns carry, 0 or 1.
int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) {
int i;
p256_ddigit carry = d;
for (i = 0; i < P256_NDIGITS; ++i) {
carry += (p256_ddigit)P256_DIGIT(a, i);
if (b) P256_DIGIT(b, i) = (p256_digit)carry;
carry >>= P256_BITSPERDIGIT;
}
return (int)carry;
}
// b = 1/a mod MOD, binary euclid.
void p256_modinv_vartime(const p256_int* MOD,
const p256_int* a,
p256_int* b) {
p256_int R = P256_ZERO;
p256_int S = P256_ONE;
p256_int U = *MOD;
p256_int V = *a;
for (;;) {
if (p256_is_even(&U)) {
p256_shr1(&U, 0, &U);
if (p256_is_even(&R)) {
p256_shr1(&R, 0, &R);
} else {
// R = (R+MOD)/2
p256_shr1(&R, p256_add(&R, MOD, &R), &R);
}
} else if (p256_is_even(&V)) {
p256_shr1(&V, 0, &V);
if (p256_is_even(&S)) {
p256_shr1(&S, 0, &S);
} else {
// S = (S+MOD)/2
p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
}
} else { // U,V both odd.
if (!p256_sub(&V, &U, NULL)) {
p256_sub(&V, &U, &V);
if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S);
if (p256_is_zero(&V)) break; // done.
} else {
p256_sub(&U, &V, &U);
if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R);
}
}
}
p256_mod(MOD, &R, b);
}
void p256_mod(const p256_int* MOD,
const p256_int* in,
p256_int* out) {
if (out != in) *out = *in;
addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1));
}
// Verify y^2 == x^3 - 3x + b mod p
// and 0 < x < p and 0 < y < p
int p256_is_valid_point(const p256_int* x, const p256_int* y) {
p256_int y2, x3;
if (p256_cmp(&SECP256r1_p, x) <= 0 ||
p256_cmp(&SECP256r1_p, y) <= 0 ||
p256_is_zero(x) ||
p256_is_zero(y)) return 0;
p256_modmul(&SECP256r1_p, y, 0, y, &y2); // y^2
p256_modmul(&SECP256r1_p, x, 0, x, &x3); // x^2
p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); // x^3
if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - x
if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 2x
if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x
if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b
p256_sub(&x3, &SECP256r1_p, &x3);
return p256_cmp(&y2, &x3) == 0;
}
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) {
int i;
const uint8_t* p = &src[0];
for (i = P256_NDIGITS - 1; i >= 0; --i) {
P256_DIGIT(dst, i) =
(p[0] << 24) |
(p[1] << 16) |
(p[2] << 8) |
p[3];
p += 4;
}
}

1279
native/jni/external/mincrypt/p256_ec.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google Inc. nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include "mincrypt/p256_ecdsa.h"
#include "mincrypt/p256.h"
int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y,
const p256_int* message,
const p256_int* r, const p256_int* s) {
p256_int u, v;
// Check public key.
if (!p256_is_valid_point(key_x, key_y)) return 0;
// Check r and s are != 0 % n.
p256_mod(&SECP256r1_n, r, &u);
p256_mod(&SECP256r1_n, s, &v);
if (p256_is_zero(&u) || p256_is_zero(&v)) return 0;
p256_modinv_vartime(&SECP256r1_n, s, &v);
p256_modmul(&SECP256r1_n, message, 0, &v, &u); // message / s % n
p256_modmul(&SECP256r1_n, r, 0, &v, &v); // r / s % n
p256_points_mul_vartime(&u, &v,
key_x, key_y,
&u, &v);
p256_mod(&SECP256r1_n, &u, &u); // (x coord % p) % n
return p256_cmp(r, &u) == 0;
}

308
native/jni/external/mincrypt/rsa.c vendored Normal file
View File

@@ -0,0 +1,308 @@
/* rsa.c
**
** Copyright 2012, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of Google Inc. nor the names of its contributors may
** be used to endorse or promote products derived from this software
** without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"
// a[] -= mod
static void subM(const RSAPublicKey* key,
uint32_t* a) {
int64_t A = 0;
int i;
for (i = 0; i < key->len; ++i) {
A += (uint64_t)a[i] - key->n[i];
a[i] = (uint32_t)A;
A >>= 32;
}
}
// return a[] >= mod
static int geM(const RSAPublicKey* key,
const uint32_t* a) {
int i;
for (i = key->len; i;) {
--i;
if (a[i] < key->n[i]) return 0;
if (a[i] > key->n[i]) return 1;
}
return 1; // equal
}
// montgomery c[] += a * b[] / R % mod
static void montMulAdd(const RSAPublicKey* key,
uint32_t* c,
const uint32_t a,
const uint32_t* b) {
uint64_t A = (uint64_t)a * b[0] + c[0];
uint32_t d0 = (uint32_t)A * key->n0inv;
uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
int i;
for (i = 1; i < key->len; ++i) {
A = (A >> 32) + (uint64_t)a * b[i] + c[i];
B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
c[i - 1] = (uint32_t)B;
}
A = (A >> 32) + (B >> 32);
c[i - 1] = (uint32_t)A;
if (A >> 32) {
subM(key, c);
}
}
// montgomery c[] = a[] * b[] / R % mod
static void montMul(const RSAPublicKey* key,
uint32_t* c,
const uint32_t* a,
const uint32_t* b) {
int i;
for (i = 0; i < key->len; ++i) {
c[i] = 0;
}
for (i = 0; i < key->len; ++i) {
montMulAdd(key, c, a[i], b);
}
}
// In-place public exponentiation.
// Input and output big-endian byte array in inout.
static void modpow(const RSAPublicKey* key,
uint8_t* inout) {
uint32_t a[RSANUMWORDS];
uint32_t aR[RSANUMWORDS];
uint32_t aaR[RSANUMWORDS];
uint32_t* aaa = 0;
int i;
// Convert from big endian byte array to little endian word array.
for (i = 0; i < key->len; ++i) {
uint32_t tmp =
(inout[((key->len - 1 - i) * 4) + 0] << 24) |
(inout[((key->len - 1 - i) * 4) + 1] << 16) |
(inout[((key->len - 1 - i) * 4) + 2] << 8) |
(inout[((key->len - 1 - i) * 4) + 3] << 0);
a[i] = tmp;
}
if (key->exponent == 65537) {
aaa = aaR; // Re-use location.
montMul(key, aR, a, key->rr); // aR = a * RR / R mod M
for (i = 0; i < 16; i += 2) {
montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M
montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M
}
montMul(key, aaa, aR, a); // aaa = aR * a / R mod M
} else if (key->exponent == 3) {
aaa = aR; // Re-use location.
montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
}
// Make sure aaa < mod; aaa is at most 1x mod too large.
if (geM(key, aaa)) {
subM(key, aaa);
}
// Convert to bigendian byte array
for (i = key->len - 1; i >= 0; --i) {
uint32_t tmp = aaa[i];
*inout++ = tmp >> 24;
*inout++ = tmp >> 16;
*inout++ = tmp >> 8;
*inout++ = tmp >> 0;
}
}
// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
// other flavor which omits the optional parameter entirely). This code does not
// accept signatures without the optional parameter.
/*
static const uint8_t sha_padding[RSANUMBYTES] = {
0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
0x05, 0x00, 0x04, 0x14,
// 20 bytes of hash go here.
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
*/
// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
// At the location of the bytes of the hash all 00 are hashed.
static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
0x7c, 0xfb, 0xf1, 0x67
};
/*
static const uint8_t sha256_padding[RSANUMBYTES] = {
0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
// 32 bytes of hash go here.
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
*/
// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
// At the location of the bytes of the hash all 00 are hashed.
static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
};
// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
// Both e=3 and e=65537 are supported. hash_len may be
// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash. No other
// values are supported.
//
// Returns 1 on successful verification, 0 on failure.
int RSA_verify(const RSAPublicKey *key,
const uint8_t *signature,
const int len,
const uint8_t *hash,
const int hash_len) {
uint8_t buf[RSANUMBYTES];
int i;
const uint8_t* padding_hash;
if (key->len != RSANUMWORDS) {
return 0; // Wrong key passed in.
}
if (len != sizeof(buf)) {
return 0; // Wrong input length.
}
if (hash_len != SHA_DIGEST_SIZE &&
hash_len != SHA256_DIGEST_SIZE) {
return 0; // Unsupported hash.
}
if (key->exponent != 3 && key->exponent != 65537) {
return 0; // Unsupported exponent.
}
for (i = 0; i < len; ++i) { // Copy input to local workspace.
buf[i] = signature[i];
}
modpow(key, buf); // In-place exponentiation.
// Xor sha portion, so it all becomes 00 iff equal.
for (i = len - hash_len; i < len; ++i) {
buf[i] ^= *hash++;
}
// Hash resulting buf, in-place.
switch (hash_len) {
case SHA_DIGEST_SIZE:
padding_hash = kExpectedPadShaRsa2048;
SHA_hash(buf, len, buf);
break;
case SHA256_DIGEST_SIZE:
padding_hash = kExpectedPadSha256Rsa2048;
SHA256_hash(buf, len, buf);
break;
default:
return 0;
}
// Compare against expected hash value.
for (i = 0; i < hash_len; ++i) {
if (buf[i] != padding_hash[i]) {
return 0;
}
}
return 1; // All checked out OK.
}

155
native/jni/external/mincrypt/sha.c vendored Normal file
View File

@@ -0,0 +1,155 @@
/* sha.c
**
** Copyright 2013, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of Google Inc. nor the names of its contributors may
** be used to endorse or promote products derived from this software
** without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Optimized for minimal code size.
#include "mincrypt/sha.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
static void SHA1_Transform(SHA_CTX* ctx) {
uint32_t W[80];
uint32_t A, B, C, D, E;
uint8_t* p = ctx->buf;
int t;
for(t = 0; t < 16; ++t) {
uint32_t tmp = *p++ << 24;
tmp |= *p++ << 16;
tmp |= *p++ << 8;
tmp |= *p++;
W[t] = tmp;
}
for(; t < 80; t++) {
W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
for(t = 0; t < 80; t++) {
uint32_t tmp = rol(5,A) + E + W[t];
if (t < 20)
tmp += (D^(B&(C^D))) + 0x5A827999;
else if ( t < 40)
tmp += (B^C^D) + 0x6ED9EBA1;
else if ( t < 60)
tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
else
tmp += (B^C^D) + 0xCA62C1D6;
E = D;
D = C;
C = rol(30,B);
B = A;
A = tmp;
}
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
}
static const HASH_VTAB SHA_VTAB = {
SHA_init,
SHA_update,
SHA_final,
SHA_hash,
SHA_DIGEST_SIZE
};
void SHA_init(SHA_CTX* ctx) {
ctx->f = &SHA_VTAB;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
ctx->count = 0;
}
void SHA_update(SHA_CTX* ctx, const void* data, int len) {
int i = (int) (ctx->count & 63);
const uint8_t* p = (const uint8_t*)data;
ctx->count += len;
while (len--) {
ctx->buf[i++] = *p++;
if (i == 64) {
SHA1_Transform(ctx);
i = 0;
}
}
}
const uint8_t* SHA_final(SHA_CTX* ctx) {
uint8_t *p = ctx->buf;
uint64_t cnt = ctx->count * 8;
int i;
SHA_update(ctx, (uint8_t*)"\x80", 1);
while ((ctx->count & 63) != 56) {
SHA_update(ctx, (uint8_t*)"\0", 1);
}
for (i = 0; i < 8; ++i) {
uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
SHA_update(ctx, &tmp, 1);
}
for (i = 0; i < 5; i++) {
uint32_t tmp = ctx->state[i];
*p++ = tmp >> 24;
*p++ = tmp >> 16;
*p++ = tmp >> 8;
*p++ = tmp >> 0;
}
return ctx->buf;
}
/* Convenience function */
const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
SHA_CTX ctx;
SHA_init(&ctx);
SHA_update(&ctx, data, len);
memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
return digest;
}

184
native/jni/external/mincrypt/sha256.c vendored Normal file
View File

@@ -0,0 +1,184 @@
/* sha256.c
**
** Copyright 2013, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of Google Inc. nor the names of its contributors may
** be used to endorse or promote products derived from this software
** without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Optimized for minimal code size.
#include "mincrypt/sha256.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
#define shr(value, bits) ((value) >> (bits))
static const uint32_t K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
static void SHA256_Transform(SHA256_CTX* ctx) {
uint32_t W[64];
uint32_t A, B, C, D, E, F, G, H;
uint8_t* p = ctx->buf;
int t;
for(t = 0; t < 16; ++t) {
uint32_t tmp = *p++ << 24;
tmp |= *p++ << 16;
tmp |= *p++ << 8;
tmp |= *p++;
W[t] = tmp;
}
for(; t < 64; t++) {
uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
W[t] = W[t-16] + s0 + W[t-7] + s1;
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
F = ctx->state[5];
G = ctx->state[6];
H = ctx->state[7];
for(t = 0; t < 64; t++) {
uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
uint32_t t2 = s0 + maj;
uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
uint32_t ch = (E & F) ^ ((~E) & G);
uint32_t t1 = H + s1 + ch + K[t] + W[t];
H = G;
G = F;
F = E;
E = D + t1;
D = C;
C = B;
B = A;
A = t1 + t2;
}
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
ctx->state[5] += F;
ctx->state[6] += G;
ctx->state[7] += H;
}
static const HASH_VTAB SHA256_VTAB = {
SHA256_init,
SHA256_update,
SHA256_final,
SHA256_hash,
SHA256_DIGEST_SIZE
};
void SHA256_init(SHA256_CTX* ctx) {
ctx->f = &SHA256_VTAB;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
ctx->count = 0;
}
void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
int i = (int) (ctx->count & 63);
const uint8_t* p = (const uint8_t*)data;
ctx->count += len;
while (len--) {
ctx->buf[i++] = *p++;
if (i == 64) {
SHA256_Transform(ctx);
i = 0;
}
}
}
const uint8_t* SHA256_final(SHA256_CTX* ctx) {
uint8_t *p = ctx->buf;
uint64_t cnt = ctx->count * 8;
int i;
SHA256_update(ctx, (uint8_t*)"\x80", 1);
while ((ctx->count & 63) != 56) {
SHA256_update(ctx, (uint8_t*)"\0", 1);
}
for (i = 0; i < 8; ++i) {
uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
SHA256_update(ctx, &tmp, 1);
}
for (i = 0; i < 8; i++) {
uint32_t tmp = ctx->state[i];
*p++ = tmp >> 24;
*p++ = tmp >> 16;
*p++ = tmp >> 8;
*p++ = tmp >> 0;
}
return ctx->buf;
}
/* Convenience function */
const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
SHA256_CTX ctx;
SHA256_init(&ctx);
SHA256_update(&ctx, data, len);
memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
return digest;
}

1
native/jni/external/nanopb vendored Submodule

1
native/jni/external/selinux vendored Submodule

60
native/jni/include/cpio.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef _CPIO_H_
#define _CPIO_H_
#include <stdint.h>
#include "vector.h"
typedef struct cpio_entry {
// uint32_t ino;
uint32_t mode;
uint32_t uid;
uint32_t gid;
// uint32_t nlink;
// uint32_t mtime;
uint32_t filesize;
// uint32_t devmajor;
// uint32_t devminor;
// uint32_t rdevmajor;
// uint32_t rdevminor;
// uint32_t namesize;
// uint32_t check;
char *filename;
void *data;
int remove;
} cpio_entry;
typedef struct cpio_newc_header {
char magic[6];
char ino[8];
char mode[8];
char uid[8];
char gid[8];
char nlink[8];
char mtime[8];
char filesize[8];
char devmajor[8];
char devminor[8];
char rdevmajor[8];
char rdevminor[8];
char namesize[8];
char check[8];
} cpio_newc_header;
// Basic cpio functions
void cpio_free(cpio_entry *e);
int cpio_find(struct vector *v, const char *entry);
int cpio_cmp(const void *a, const void *b);
void parse_cpio(struct vector *v, const char *filename);
void dump_cpio(struct vector *v, const char *filename);
void cpio_vec_insert(struct vector *v, cpio_entry *n);
void cpio_vec_destroy(struct vector *v);
void cpio_rm(struct vector *v, int recursive, const char *entry);
void cpio_mkdir(struct vector *v, mode_t mode, const char *entry);
void cpio_ln(struct vector *v, const char *target, const char *entry);
void cpio_add(struct vector *v, mode_t mode, const char *entry, const char *filename);
int cpio_mv(struct vector *v, const char *from, const char *to);
int cpio_extract(struct vector *v, const char *entry, const char *filename);
void cpio_extract_all(struct vector *v);
#endif

View File

@@ -5,43 +5,62 @@
#define _DAEMON_H_
#include <pthread.h>
#include <sys/un.h>
#include <sys/socket.h>
extern pthread_t sepol_patch;
extern int is_restart;
extern int setup_done;
extern int seperate_vendor;
extern int full_patch_pid;
// Commands require connecting to daemon
typedef enum {
enum {
DO_NOTHING = 0,
SUPERUSER,
CHECK_VERSION,
CHECK_VERSION_CODE,
POST_FS_DATA,
LATE_START,
LAUNCH_MAGISKHIDE,
STOP_MAGISKHIDE,
ADD_HIDELIST,
RM_HIDELIST,
LS_HIDELIST,
SUPERUSER,
CHECK_VERSION,
CHECK_VERSION_CODE,
POST_FS,
POST_FS_DATA,
LATE_START,
TEST
} client_request;
HIDE_CONNECT,
HANDSHAKE
};
// Return codes for daemon
typedef enum {
enum {
DAEMON_ERROR = -1,
DAEMON_SUCCESS = 0,
ROOT_REQUIRED,
LOGCAT_DISABLED,
HIDE_IS_ENABLED,
HIDE_NOT_ENABLED,
HIDE_ITEM_EXIST,
HIDE_ITEM_NOT_EXIST,
} daemon_response;
};
typedef enum {
MAIN_DAEMON,
LOG_DAEMON
} daemon_t;
// daemon.c
void start_daemon();
void main_daemon();
int connect_daemon();
int connect_daemon2(daemon_t d, int *sockfd);
void auto_start_magiskhide();
// log_monitor.c
extern int loggable;
void log_daemon();
// socket.c
int setup_socket(struct sockaddr_un *sun, daemon_t d);
int recv_fd(int sockfd);
void send_fd(int sockfd, int fd);
int read_int(int fd);
@@ -53,10 +72,9 @@ void write_string(int fd, const char* val);
* Boot Stages *
***************/
void post_fs(int client);
void startup();
void post_fs_data(int client);
void late_start(int client);
void fix_filecon();
/**************
* MagiskHide *
@@ -72,6 +90,6 @@ void ls_hide_list(int client);
* Superuser *
*************/
void su_daemon_receiver(int client);
void su_daemon_receiver(int client, struct ucred *credential);
#endif

123
native/jni/include/db.h Normal file
View File

@@ -0,0 +1,123 @@
#ifndef DB_H
#define DB_H
#include <sqlite3.h>
#include <sys/stat.h>
/***************
* DB Settings *
***************/
#define DB_SETTING_KEYS ((char *[]) { \
"root_access", \
"multiuser_mode", \
"mnt_ns" \
})
#define DB_SETTINGS_NUM (sizeof(DB_SETTING_KEYS) / sizeof(char*))
// Settings indices
enum {
ROOT_ACCESS = 0,
SU_MULTIUSER_MODE,
SU_MNT_NS
};
// Values for root_access
enum {
ROOT_ACCESS_DISABLED = 0,
ROOT_ACCESS_APPS_ONLY,
ROOT_ACCESS_ADB_ONLY,
ROOT_ACCESS_APPS_AND_ADB
};
// Values for multiuser_mode
enum {
MULTIUSER_MODE_OWNER_ONLY = 0,
MULTIUSER_MODE_OWNER_MANAGED,
MULTIUSER_MODE_USER
};
// Values for mnt_ns
enum {
NAMESPACE_MODE_GLOBAL = 0,
NAMESPACE_MODE_REQUESTER,
NAMESPACE_MODE_ISOLATE
};
struct db_settings {
int v[DB_SETTINGS_NUM];
};
#define DEFAULT_DB_SETTINGS (struct db_settings) { .v = {\
ROOT_ACCESS_APPS_AND_ADB, \
MULTIUSER_MODE_OWNER_ONLY, \
NAMESPACE_MODE_REQUESTER \
}}
/**************
* DB Strings *
**************/
#define DB_STRING_KEYS ((char *[]) { \
"requester" \
})
#define DB_STRING_NUM (sizeof(DB_STRING_KEYS) / sizeof(char*))
// Strings indices
enum {
SU_MANAGER = 0
};
struct db_strings {
char s[DB_STRING_NUM][128];
};
void INIT_DB_STRINGS(struct db_strings *str);
/*************
* SU Access *
*************/
typedef enum {
QUERY = 0,
DENY = 1,
ALLOW = 2,
} policy_t;
struct su_access {
policy_t policy;
int log;
int notify;
};
#define DEFAULT_SU_ACCESS (struct su_access) { \
.policy = QUERY, \
.log = 1, \
.notify = 1 \
}
#define SILENT_SU_ACCESS (struct su_access) { \
.policy = ALLOW, \
.log = 0, \
.notify = 0 \
}
#define NO_SU_ACCESS (struct su_access) { \
.policy = DENY, \
.log = 0, \
.notify = 0 \
}
/********************
* Public Functions *
********************/
sqlite3 *get_magiskdb();
int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs);
int get_db_strings(sqlite3 *db, int key, struct db_strings *str);
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su);
int validate_manager(char *pkg, int userid, struct stat *st);
#endif //DB_H

View File

@@ -11,43 +11,58 @@
#define str(a) #a
#define xstr(a) str(a)
/**************
* No logging *
**************/
#define LOGD(...)
#define LOGI(...)
#define LOGW(...)
#define LOGE(...)
#define PLOGE(...)
/******************
* Daemon logging *
******************/
#ifdef IS_DAEMON
#undef LOGI
#undef LOGW
#undef LOGE
#undef PLOGE
#include <pthread.h>
#include <android/log.h>
#define LOG_TAG "Magisk"
#ifdef MAGISK_DEBUG
#undef LOGD
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#else
#define LOGD(...)
#endif
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno))
enum {
HIDE_EVENT,
LOG_EVENT,
DEBUG_EVENT
};
extern int logcat_events[];
#endif
void monitor_logs();
void start_debug_full_log();
void stop_debug_full_log();
void start_debug_log();
/********************
* Tools Log & Exit *
********************/
#else // IS_DAEMON
#ifdef XWRAP_EXIT
#undef LOGE
#undef PLOGE
#include <stdio.h>
#define LOGE(...) { fprintf(stderr, __VA_ARGS__); exit(1); }
#define PLOGE(fmt, args...) { fprintf(stderr, fmt " failed with %d: %s\n\n", ##args, errno, strerror(errno)); exit(1); }
#endif // IS_DAEMON
#endif
#endif // _LOGGING_H_

View File

@@ -0,0 +1,71 @@
/* magisk.h - Top header
*/
#ifndef _MAGISK_H_
#define _MAGISK_H_
#include "logging.h"
#define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK"
#define MAIN_SOCKET "d30138f2310a9fb9c54a3e0c21f58591"
#define LOG_SOCKET "5864cd77f2f8c59b3882e2d35dbf51e4"
#define JAVA_PACKAGE_NAME "com.topjohnwu.magisk"
#ifndef ARG_MAX
#define ARG_MAX 4096
#endif
#define LOGFILE "/cache/magisk.log"
#define UNBLOCKFILE "/dev/.magisk.unblock"
#define DISABLEFILE "/cache/.disable_magisk"
#define MAGISKTMP "/sbin/.core"
#define BLOCKDIR MAGISKTMP "/block"
#define MIRRDIR MAGISKTMP "/mirror"
#define BBPATH MAGISKTMP "/busybox"
#define MOUNTPOINT MAGISKTMP "/img"
#define COREDIR MOUNTPOINT "/.core"
#define HOSTSFILE COREDIR "/hosts"
#define HIDELIST COREDIR "/hidelist"
#define SECURE_DIR "/data/adb"
#define MAINIMG SECURE_DIR "/magisk.img"
#define DATABIN SECURE_DIR "/magisk"
#define MAGISKDB SECURE_DIR "/magisk.db"
#define SIMPLEMOUNT SECURE_DIR "/magisk_simple"
#define MANAGERAPK DATABIN "/magisk.apk"
#define MAGISKRC "/init.magisk.rc"
// selinuxfs paths
#define SELINUX_PATH "/sys/fs/selinux"
#define SELINUX_ENFORCE SELINUX_PATH "/enforce"
#define SELINUX_POLICY SELINUX_PATH "/policy"
#define SELINUX_LOAD SELINUX_PATH "/load"
#define SELINUX_CONTEXT SELINUX_PATH "/context"
// split policy paths
#define PLAT_POLICY_DIR "/system/etc/selinux/"
#define NONPLAT_POLICY_DIR "/vendor/etc/selinux/"
#define SPLIT_PLAT_CIL PLAT_POLICY_DIR "plat_sepolicy.cil"
#define SPLIT_PLAT_MAPPING PLAT_POLICY_DIR "mapping/%s.cil"
#define SPLIT_PRECOMPILE NONPLAT_POLICY_DIR "precompiled_sepolicy"
#define SPLIT_NONPLAT_VER NONPLAT_POLICY_DIR "plat_sepolicy_vers.txt"
#define MAGISKHIDE_PROP "persist.magisk.hide"
extern char *argv0; /* For changing process name */
#define applet ((char *[]) { "su", "resetprop", "magiskhide", "imgtool", NULL })
#define init_applet ((char *[]) { "magiskpolicy", "supolicy", NULL })
extern int (*applet_main[]) (int, char *[]), (*init_applet_main[]) (int, char *[]);
int create_links(const char *bin, const char *path);
// Multi-call entrypoints
int magiskhide_main(int argc, char *argv[]);
int magiskpolicy_main(int argc, char *argv[]);
int su_client_main(int argc, char *argv[]);
int resetprop_main(int argc, char *argv[]);
int imgtool_main(int argc, char *argv[]);
#endif

View File

@@ -0,0 +1,39 @@
#include "magisk.h"
#include "magiskpolicy.h"
const char magiskrc[] =
// Triggers
"on post-fs\n"
" start logd\n"
"\n"
"on post-fs-data\n"
" load_persist_props\n"
" rm "UNBLOCKFILE"\n"
" start magisk_startup\n"
" wait "UNBLOCKFILE" 10\n"
" rm /dev/.magisk.unblock\n"
"\n"
// Services
"service magisk_daemon /sbin/magisk --daemon\n"
" user root\n"
" seclabel u:r:"SEPOL_PROC_DOMAIN":s0\n"
" oneshot\n"
"\n"
"service magisk_startup /sbin/magisk --startup\n"
" user root\n"
" seclabel u:r:"SEPOL_PROC_DOMAIN":s0\n"
" oneshot\n"
"\n"
"service magisk_service /sbin/magisk --service\n"
" class late_start\n"
" user root\n"
" seclabel u:r:"SEPOL_PROC_DOMAIN":s0\n"
" oneshot\n"
;

View File

@@ -4,10 +4,6 @@
#ifndef _RESETPROP_H_
#define _RESETPROP_H_
#ifdef __cplusplus
extern "C" {
#endif
int prop_exist(const char *name);
int setprop(const char *name, const char *value);
int setprop2(const char *name, const char *value, const int trigger);
@@ -16,10 +12,6 @@ char *getprop2(const char *name, int persist);
int deleteprop(const char *name);
int deleteprop2(const char *name, const int persist);
int read_prop_file(const char* filename, const int trigger);
void getprop_all(void (*callback)(const char*, const char*));
#ifdef __cplusplus
}
#endif
void getprop_all(void (*callback)(const char *, const char *, void *), void *cookie);
#endif

View File

@@ -61,7 +61,7 @@ int xumount(const char *target);
int xumount2(const char *target, int flags);
int xrename(const char *oldpath, const char *newpath);
int xmkdir(const char *pathname, mode_t mode);
int xmkdir_p(const char *pathname, mode_t mode);
int xmkdirs(const char *pathname, mode_t mode);
int xmkdirat(int dirfd, const char *pathname, mode_t mode);
void *xmmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
@@ -70,7 +70,7 @@ pid_t xfork();
// misc.c
extern int quit_signals[];
#define quit_signals ((int []) { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 })
unsigned get_shell_uid();
unsigned get_system_uid();
@@ -83,15 +83,21 @@ void ps(void (*func)(int));
void ps_filter_proc_name(const char *filter, void (*func)(int));
void unlock_blocks();
void setup_sighandlers(void (*handler)(int));
int exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, ...);
int exec_array(int err, int *fd, void (*setenv)(struct vector *), char *const *argv);
int exec_command(int err, int *fd, void (*setenv)(struct vector*), const char *argv0, ...);
int exec_command_sync(char *const argv0, ...);
int bind_mount(const char *from, const char *to);
void get_client_cred(int fd, struct ucred *cred);
int switch_mnt_ns(int pid);
int fork_dont_care();
void wait_till_exists(const char *target);
void gen_rand_str(char *buf, int len);
// file.c
#define align(p, a) (((p) + (a) - 1) / (a) * (a))
#define align_off(p, a) (align(p, a) - (p))
extern char **excl_list;
struct file_attr {
@@ -100,12 +106,14 @@ struct file_attr {
};
int fd_getpath(int fd, char *path, size_t size);
int mkdir_p(const char *pathname, mode_t mode);
int mkdirs(const char *pathname, mode_t mode);
void in_order_walk(int dirfd, void (*callback)(int, struct dirent*));
void rm_rf(const char *path);
void frm_rf(int dirfd);
void mv_f(const char *source, const char *destination);
void mv_dir(int src, int dest);
void cp_afc(const char *source, const char *destination);
void link_dir(int src, int dest);
void clone_dir(int src, int dest);
int getattr(const char *path, struct file_attr *a);
int getattrat(int dirfd, const char *pathname, struct file_attr *a);
@@ -115,26 +123,28 @@ int setattrat(int dirfd, const char *pathname, struct file_attr *a);
int fsetattr(int fd, struct file_attr *a);
void fclone_attr(const int sourcefd, const int targetfd);
void clone_attr(const char *source, const char *target);
void restorecon(int dirfd, int force);
void mmap_ro(const char *filename, void **buf, size_t *size);
void mmap_rw(const char *filename, void **buf, size_t *size);
void full_read(int fd, void **buf, size_t *size);
void restorecon();
int mmap_ro(const char *filename, void **buf, size_t *size);
int mmap_rw(const char *filename, void **buf, size_t *size);
void fd_full_read(int fd, void **buf, size_t *size);
void full_read(const char *filename, void **buf, size_t *size);
void full_read_at(int dirfd, const char *filename, void **buf, size_t *size);
void stream_full_read(int fd, void **buf, size_t *size);
void write_zero(int fd, size_t size);
void mem_align(size_t *pos, size_t align);
void file_align(int fd, size_t align, int out);
// img.c
#define round_size(a) ((((a) / 32) + 2) * 32)
#define SOURCE_TMP "/dev/source"
#define TARGET_TMP "/dev/target"
int create_img(const char *img, int size);
int get_img_size(const char *img, int *used, int *total);
int resize_img(const char *img, int size);
char *mount_image(const char *img, const char *target);
void umount_image(const char *target, const char *device);
int umount_image(const char *target, const char *device);
int merge_img(const char *source, const char *target);
void trim_img(const char *img);
int trim_img(const char *img, const char *mount, char *loop);
// pattern.c
void patch_init_rc(void **buf, size_t *size);
int patch_verity(void **buf, uint32_t *size, int patch);
void patch_encryption(void **buf, uint32_t *size);
#endif

View File

@@ -7,18 +7,19 @@
#include <sys/types.h>
struct vector {
size_t size;
size_t cap;
unsigned size;
unsigned cap;
void **data;
};
void vec_init(struct vector *v);
void vec_push_back(struct vector *v, void *p);
void vec_push_back_all(struct vector *v, void *p, ...);
void *vec_pop_back(struct vector *v);
void vec_sort(struct vector *v, int (*compar)(const void *, const void *));
void vec_destroy(struct vector *v);
void vec_deep_destroy(struct vector *v);
struct vector *vec_dup(struct vector *v);
void vec_dup(struct vector *v, struct vector *vv);
#define vec_size(v) (v)->size
#define vec_cap(v) (v)->cap
@@ -26,11 +27,11 @@ struct vector *vec_dup(struct vector *v);
/* Usage: vec_for_each(vector *v, void *e) */
#define vec_for_each(v, e) \
e = v ? (v)->data[0] : NULL; \
for (size_t _ = 0; v && _ < (v)->size; ++_, e = (v)->data[_])
for (int _ = 0; v && _ < (v)->size; ++_, e = (v)->data[_])
#define vec_for_each_r(v, e) \
e = v ? (v)->data[(v)->size - 1] : NULL; \
for (size_t _ = (v)->size; v && _ > 0; --_, e = (v)->data[_ - 1])
e = (v && (v)->size > 0) ? (v)->data[(v)->size - 1] : NULL; \
for (int _ = ((int) (v)->size) - 1; v && _ >= 0; --_, e = (v)->data[_])
#define vec_cur(v) vec_entry(v)[_]

View File

@@ -0,0 +1,455 @@
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <libfdt.h>
#include <sys/mman.h>
#include "bootimg.h"
#include "magiskboot.h"
#include "utils.h"
#include "logging.h"
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"
#define INSUF_BLOCK_RET 2
#define CHROMEOS_RET 3
#define ELF32_RET 4
#define ELF64_RET 5
// Macros to determine header on-the-go
#define lheader(b, e, o) \
((b)->flags & PXA_FLAG) ? \
(((struct pxa_boot_img_hdr*) (b)->hdr)->e o) : \
(((struct boot_img_hdr*) (b)->hdr)->e o)
#define header(b, e) (lheader(b, e,))
static void dump(void *buf, size_t size, const char *filename) {
if (size == 0)
return;
int fd = creat(filename, 0644);
xwrite(fd, buf, size);
close(fd);
}
static size_t restore(const char *filename, int fd) {
int ifd = xopen(filename, O_RDONLY);
size_t size = lseek(ifd, 0, SEEK_END);
lseek(ifd, 0, SEEK_SET);
xsendfile(fd, ifd, NULL, size);
close(ifd);
return size;
}
static void restore_buf(int fd, const void *buf, size_t size) {
xwrite(fd, buf, size);
}
static void print_hdr(const boot_img *boot) {
fprintf(stderr, "KERNEL [%u]\n", header(boot, kernel_size));
fprintf(stderr, "RAMDISK [%u]\n", header(boot, ramdisk_size));
fprintf(stderr, "SECOND [%u]\n", header(boot, second_size));
fprintf(stderr, "EXTRA [%u]\n", header(boot, extra_size));
fprintf(stderr, "PAGESIZE [%u]\n", header(boot, page_size));
if (!(boot->flags & PXA_FLAG)) {
uint32_t os_version = ((boot_img_hdr*) boot->hdr)->os_version;
if (os_version) {
int a,b,c,y,m = 0;
int version, patch_level;
version = os_version >> 11;
patch_level = os_version & 0x7ff;
a = (version >> 14) & 0x7f;
b = (version >> 7) & 0x7f;
c = version & 0x7f;
fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c);
y = (patch_level >> 4) + 2000;
m = patch_level & 0xf;
fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m);
}
}
fprintf(stderr, "NAME [%s]\n", header(boot, name));
fprintf(stderr, "CMDLINE [%s]\n", header(boot, cmdline));
fprintf(stderr, "CHECKSUM [");
for (int i = 0; i < ((boot->flags & SHA256_FLAG) ? SHA256_DIGEST_SIZE : SHA_DIGEST_SIZE); ++i)
fprintf(stderr, "%02x", header(boot, id)[i]);
fprintf(stderr, "]\n");
}
static void clean_boot(boot_img *boot) {
munmap(boot->map_addr, boot->map_size);
free(boot->hdr);
free(boot->k_hdr);
free(boot->r_hdr);
free(boot->b_hdr);
memset(boot, 0, sizeof(*boot));
}
#define pos_align() pos = align(pos, header(boot, page_size))
int parse_img(const char *image, boot_img *boot) {
memset(boot, 0, sizeof(*boot));
int is_blk = mmap_ro(image, &boot->map_addr, &boot->map_size);
// Parse image
fprintf(stderr, "Parsing boot image: [%s]\n", image);
for (void *head = boot->map_addr; head < boot->map_addr + boot->map_size; ++head) {
size_t pos = 0;
switch (check_fmt(head, boot->map_size)) {
case CHROMEOS:
// The caller should know it's chromeos, as it needs additional signing
boot->flags |= CHROMEOS_FLAG;
continue;
case DHTB:
boot->flags |= DHTB_FLAG;
boot->flags |= SEANDROID_FLAG;
fprintf(stderr, "DHTB_HDR\n");
continue;
case ELF32:
exit(ELF32_RET);
case ELF64:
exit(ELF64_RET);
case BLOB:
boot->flags |= BLOB_FLAG;
fprintf(stderr, "TEGRA_BLOB\n");
boot->b_hdr = malloc(sizeof(blob_hdr));
memcpy(boot->b_hdr, head, sizeof(blob_hdr));
continue;
case AOSP:
// Read the header
if (((boot_img_hdr*) head)->page_size >= 0x02000000) {
boot->flags |= PXA_FLAG;
fprintf(stderr, "PXA_BOOT_HDR\n");
boot->hdr = malloc(sizeof(pxa_boot_img_hdr));
memcpy(boot->hdr, head, sizeof(pxa_boot_img_hdr));
} else if (memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_MAGIC, 12) == 0
|| memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_NEW_MAGIC, 26) == 0) {
boot->flags |= NOOKHD_FLAG;
fprintf(stderr, "NOOKHD_GREEN_LOADER\n");
head += NOOKHD_PRE_HEADER_SZ - 1;
continue;
} else if (memcmp(((boot_img_hdr*) head)->name, ACCLAIM_MAGIC, 10) == 0) {
boot->flags |= ACCLAIM_FLAG;
fprintf(stderr, "ACCLAIM_BAUWKSBOOT\n");
head += ACCLAIM_PRE_HEADER_SZ - 1;
continue;
} else {
boot->hdr = malloc(sizeof(boot_img_hdr));
memcpy(boot->hdr, head, sizeof(boot_img_hdr));
}
pos += header(boot, page_size);
for (int i = SHA_DIGEST_SIZE; i < SHA256_DIGEST_SIZE; ++i) {
if (header(boot, id)[i]) {
boot->flags |= SHA256_FLAG;
break;
}
}
print_hdr(boot);
boot->kernel = head + pos;
pos += header(boot, kernel_size);
pos_align();
boot->ramdisk = head + pos;
pos += header(boot, ramdisk_size);
pos_align();
boot->second = head + pos;
pos += header(boot, second_size);
pos_align();
boot->extra = head + pos;
pos += header(boot, extra_size);
pos_align();
if (pos < boot->map_size) {
boot->tail = head + pos;
boot->tail_size = boot->map_size - (boot->tail - boot->map_addr);
}
// Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE
if (boot->tail_size >= 16 && memcmp(boot->tail, SEANDROID_MAGIC, 16) == 0) {
boot->flags |= SEANDROID_FLAG;
} else if (boot->tail_size >= 16 && memcmp(boot->tail, LG_BUMP_MAGIC, 16) == 0) {
boot->flags |= LG_BUMP_FLAG;
}
// Search for dtb in kernel
for (uint32_t i = 0; i < header(boot, kernel_size); ++i) {
if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) {
// Check that fdt_header.totalsize does not overflow kernel image size
uint32_t dt_size = fdt32_to_cpu(*(uint32_t *)(boot->kernel + i + 4));
if (dt_size > header(boot, kernel_size) - i) {
fprintf(stderr, "Invalid DTB detection at 0x%x: size (%u) > remaining (%u)\n",
i, dt_size, header(boot, kernel_size) - i);
continue;
}
// Check that fdt_header.off_dt_struct does not overflow kernel image size
uint32_t dt_struct_offset = fdt32_to_cpu(*(uint32_t *)(boot->kernel + i + 8));
if (dt_struct_offset > header(boot, kernel_size) - i) {
fprintf(stderr, "Invalid DTB detection at 0x%x: struct offset (%u) > remaining (%u)\n",
i, dt_struct_offset, header(boot, kernel_size) - i);
continue;
}
// Check that fdt_node_header.tag of first node is FDT_BEGIN_NODE
uint32_t dt_begin_node = fdt32_to_cpu(*(uint32_t *)(boot->kernel + i + dt_struct_offset));
if (dt_begin_node != FDT_BEGIN_NODE) {
fprintf(stderr, "Invalid DTB detection at 0x%x: header tag of first node != FDT_BEGIN_NODE\n", i);
continue;
}
boot->dtb = boot->kernel + i;
boot->dt_size = header(boot, kernel_size) - i;
lheader(boot, kernel_size, = i);
fprintf(stderr, "DTB [%u]\n", boot->dt_size);
break;
}
}
boot->k_fmt = check_fmt(boot->kernel, header(boot, kernel_size));
boot->r_fmt = check_fmt(boot->ramdisk, header(boot, ramdisk_size));
// Check MTK
if (boot->k_fmt == MTK) {
fprintf(stderr, "MTK_KERNEL_HDR\n");
boot->flags |= MTK_KERNEL;
boot->k_hdr = malloc(sizeof(mtk_hdr));
memcpy(boot->k_hdr, boot->kernel, sizeof(mtk_hdr));
fprintf(stderr, "KERNEL [%u]\n", boot->k_hdr->size);
fprintf(stderr, "NAME [%s]\n", boot->k_hdr->name);
boot->kernel += 512;
lheader(boot, kernel_size, -= 512);
boot->k_fmt = check_fmt(boot->kernel, header(boot, kernel_size));
}
if (boot->r_fmt == MTK) {
fprintf(stderr, "MTK_RAMDISK_HDR\n");
boot->flags |= MTK_RAMDISK;
boot->r_hdr = malloc(sizeof(mtk_hdr));
memcpy(boot->r_hdr, boot->ramdisk, sizeof(mtk_hdr));
fprintf(stderr, "RAMDISK [%u]\n", boot->r_hdr->size);
fprintf(stderr, "NAME [%s]\n", boot->r_hdr->name);
boot->ramdisk += 512;
lheader(boot, ramdisk_size, -= 512);
boot->r_fmt = check_fmt(boot->ramdisk, header(boot, ramdisk_size));
}
char fmt[16];
get_fmt_name(boot->k_fmt, fmt);
fprintf(stderr, "KERNEL_FMT [%s]\n", fmt);
get_fmt_name(boot->r_fmt, fmt);
fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt);
return boot->flags & CHROMEOS_FLAG ? CHROMEOS_RET :
((is_blk && boot->tail_size < 500 * 1024) ? INSUF_BLOCK_RET : 0);
default:
continue;
}
}
LOGE("No boot image magic found!\n");
}
int unpack(const char *image) {
boot_img boot;
int ret = parse_img(image, &boot);
int fd;
// Dump kernel
if (COMPRESSED(boot.k_fmt)) {
fd = creat(KERNEL_FILE, 0644);
decomp(boot.k_fmt, fd, boot.kernel, header(&boot, kernel_size));
close(fd);
} else {
dump(boot.kernel, header(&boot, kernel_size), KERNEL_FILE);
}
// Dump dtb
dump(boot.dtb, boot.dt_size, DTB_FILE);
// Dump ramdisk
if (COMPRESSED(boot.r_fmt)) {
fd = creat(RAMDISK_FILE, 0644);
decomp(boot.r_fmt, fd, boot.ramdisk, header(&boot, ramdisk_size));
close(fd);
} else {
dump(boot.ramdisk, header(&boot, ramdisk_size), RAMDISK_FILE);
}
// Dump second
dump(boot.second, header(&boot, second_size), SECOND_FILE);
// Dump extra
dump(boot.extra, header(&boot, extra_size), EXTRA_FILE);
clean_boot(&boot);
return ret;
}
#define file_align() write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR) - header_off, header(&boot, page_size)))
void repack(const char* orig_image, const char* out_image) {
boot_img boot;
off_t header_off, kernel_off, ramdisk_off, second_off, extra_off;
// Parse original image
parse_img(orig_image, &boot);
// Reset all sizes
lheader(&boot, kernel_size, = 0);
lheader(&boot, ramdisk_size, = 0);
lheader(&boot, second_size, = 0);
lheader(&boot, extra_size, = 0);
boot.dt_size = 0;
fprintf(stderr, "Repack to boot image: [%s]\n", out_image);
// Create new image
int fd = creat(out_image, 0644);
if (boot.flags & DHTB_FLAG) {
// Skip DHTB header
write_zero(fd, 512);
} else if (boot.flags & BLOB_FLAG) {
// Skip blob header
write_zero(fd, sizeof(blob_hdr));
} else if (boot.flags & NOOKHD_FLAG) {
restore_buf(fd, boot.map_addr, NOOKHD_PRE_HEADER_SZ);
} else if (boot.flags & ACCLAIM_FLAG) {
restore_buf(fd, boot.map_addr, ACCLAIM_PRE_HEADER_SZ);
}
// Skip a page for header
header_off = lseek(fd, 0, SEEK_CUR);
write_zero(fd, header(&boot, page_size));
// kernel
kernel_off = lseek(fd, 0, SEEK_CUR);
if (boot.flags & MTK_KERNEL) {
// Skip MTK header
write_zero(fd, 512);
}
if (access(KERNEL_FILE, R_OK) == 0) {
if (COMPRESSED(boot.k_fmt)) {
size_t raw_size;
void *kernel_raw;
mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size);
lheader(&boot, kernel_size, = comp(boot.k_fmt, fd, kernel_raw, raw_size));
munmap(kernel_raw, raw_size);
} else {
lheader(&boot, kernel_size, = restore(KERNEL_FILE, fd));
}
}
// dtb
if (access(DTB_FILE, R_OK) == 0) {
lheader(&boot, kernel_size, += restore(DTB_FILE, fd));
}
file_align();
// ramdisk
ramdisk_off = lseek(fd, 0, SEEK_CUR);
if (boot.flags & MTK_RAMDISK) {
// Skip MTK header
write_zero(fd, 512);
}
if (access(RAMDISK_FILE, R_OK) == 0) {
if (COMPRESSED(boot.r_fmt)) {
size_t cpio_size;
void *cpio;
mmap_ro(RAMDISK_FILE, &cpio, &cpio_size);
lheader(&boot, ramdisk_size, = comp(boot.r_fmt, fd, cpio, cpio_size));
munmap(cpio, cpio_size);
} else {
lheader(&boot, ramdisk_size, = restore(RAMDISK_FILE, fd));
}
file_align();
}
// second
second_off = lseek(fd, 0, SEEK_CUR);
if (access(SECOND_FILE, R_OK) == 0) {
lheader(&boot, second_size, = restore(SECOND_FILE, fd));
file_align();
}
// extra
extra_off = lseek(fd, 0, SEEK_CUR);
if (access(EXTRA_FILE, R_OK) == 0) {
lheader(&boot, extra_size, = restore(EXTRA_FILE, fd));
file_align();
}
// Append tail info
if (boot.flags & SEANDROID_FLAG) {
restore_buf(fd, SEANDROID_MAGIC "\xFF\xFF\xFF\xFF", 20);
}
if (boot.flags & LG_BUMP_FLAG) {
restore_buf(fd, LG_BUMP_MAGIC, 16);
}
close(fd);
// Map output image as rw
munmap(boot.map_addr, boot.map_size);
mmap_rw(out_image, &boot.map_addr, &boot.map_size);
// MTK headers
if (boot.flags & MTK_KERNEL) {
boot.k_hdr->size = header(&boot, kernel_size);
lheader(&boot, kernel_size, += 512);
memcpy(boot.map_addr + kernel_off, boot.k_hdr, sizeof(mtk_hdr));
}
if (boot.flags & MTK_RAMDISK) {
boot.r_hdr->size = header(&boot, ramdisk_size);
lheader(&boot, ramdisk_size, += 512);
memcpy(boot.map_addr + ramdisk_off, boot.r_hdr, sizeof(mtk_hdr));
}
// Update checksum
HASH_CTX ctx;
(boot.flags & SHA256_FLAG) ? SHA256_init(&ctx) : SHA_init(&ctx);
uint32_t size = header(&boot, kernel_size);
HASH_update(&ctx, boot.map_addr + kernel_off, size);
HASH_update(&ctx, &size, sizeof(size));
size = header(&boot, ramdisk_size);
HASH_update(&ctx, boot.map_addr + ramdisk_off, size);
HASH_update(&ctx, &size, sizeof(size));
size = header(&boot, second_size);
HASH_update(&ctx, boot.map_addr + second_off, size);
HASH_update(&ctx, &size, sizeof(size));
size = header(&boot, extra_size);
if (size) {
HASH_update(&ctx, boot.map_addr + extra_off, size);
HASH_update(&ctx, &size, sizeof(size));
}
memset(header(&boot, id), 0, 32);
memcpy(header(&boot, id), HASH_final(&ctx),
(boot.flags & SHA256_FLAG) ? SHA256_DIGEST_SIZE : SHA_DIGEST_SIZE);
// Print new image info
print_hdr(&boot);
// Main header
memcpy(boot.map_addr + header_off, boot.hdr,
(boot.flags & PXA_FLAG) ? sizeof(pxa_boot_img_hdr) : sizeof(boot_img_hdr));
if (boot.flags & DHTB_FLAG) {
// DHTB header
dhtb_hdr *hdr = boot.map_addr;
memcpy(hdr, DHTB_MAGIC, 8);
hdr->size = boot.map_size - 512;
SHA256_hash(boot.map_addr + 512, hdr->size, hdr->checksum);
} else if (boot.flags & BLOB_FLAG) {
// Blob headers
boot.b_hdr->size = boot.map_size - sizeof(blob_hdr);
memcpy(boot.map_addr, boot.b_hdr, sizeof(blob_hdr));
}
clean_boot(&boot);
}

View File

@@ -0,0 +1,169 @@
#include <stdint.h>
#include "format.h"
#ifndef _BOOT_IMAGE_H_
#define _BOOT_IMAGE_H_
typedef struct boot_img_hdr {
char magic[8];
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
uint32_t extra_size; /* extra blob size in bytes */
/* operating system version and security patch level; for
* version "A.B.C" and patch level "Y-M-D":
* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
* lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
* os_version = ver << 11 | lvl */
uint32_t os_version;
char name[16]; /* asciiz product name */
char cmdline[512];
char id[32]; /* timestamp / checksum / sha1 / etc */
/* Supplemental command line data; kept here to maintain
* binary compatibility with older versions of mkbootimg */
char extra_cmdline[1024];
} __attribute__((packed)) boot_img_hdr ;
typedef struct pxa_boot_img_hdr {
char magic[8];
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
uint32_t extra_size; /* extra blob size in bytes */
uint32_t unknown; /* unknown value */
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
char name[24]; /* asciiz product name */
char cmdline[512];
char id[32]; /* timestamp / checksum / sha1 / etc */
/* Supplemental command line data; kept here to maintain
* binary compatibility with older versions of mkbootimg */
char extra_cmdline[1024];
} __attribute__((packed)) pxa_boot_img_hdr;
/*
** +-----------------+
** | boot header | 1 page
** +-----------------+
** | kernel | n pages
** +-----------------+
** | ramdisk | m pages
** +-----------------+
** | second stage | o pages
** +-----------------+
** | extra blob | p pages
** +-----------------+
**
** n = (kernel_size + page_size - 1) / page_size
** m = (ramdisk_size + page_size - 1) / page_size
** o = (second_size + page_size - 1) / page_size
** p = (extra_size + page_size - 1) / page_size
**
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
** 2. second is optional (second_size == 0 -> no second)
** 3. load each element (kernel, ramdisk, second) at
** the specified physical address (kernel_addr, etc)
** 4. prepare tags at tag_addr. kernel_args[] is
** appended to the kernel commandline in the tags.
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
** 6. if second_size != 0: jump to second_addr
** else: jump to kernel_addr
*/
typedef struct mtk_hdr {
uint32_t magic; /* MTK magic */
uint32_t size; /* Size of the content */
char name[32]; /* The type of the header */
} __attribute__((packed)) mtk_hdr;
typedef struct dhtb_hdr {
char magic[8]; /* DHTB magic */
char checksum[40]; /* Payload SHA256, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
uint32_t size; /* Payload size, whole image + SEANDROIDENFORCE + 0xFFFFFFFF */
} __attribute__((packed)) dhtb_hdr;
typedef struct blob_hdr {
char secure_magic[20]; /* "-SIGNED-BY-SIGNBLOB-" */
uint32_t datalen; /* 0x00000000 */
uint32_t signature; /* 0x00000000 */
char magic[16]; /* "MSM-RADIO-UPDATE" */
uint32_t hdr_version; /* 0x00010000 */
uint32_t hdr_size; /* Size of header */
uint32_t part_offset; /* Same as size */
uint32_t num_parts; /* Number of partitions */
uint32_t unknown[7]; /* All 0x00000000 */
char name[4]; /* Name of partition */
uint32_t offset; /* offset in blob where this partition starts */
uint32_t size; /* Size of data */
uint32_t version; /* 0x00000001 */
} __attribute__((packed)) blob_hdr;
// Flags
#define MTK_KERNEL 0x0001
#define MTK_RAMDISK 0x0002
#define CHROMEOS_FLAG 0x0004
#define PXA_FLAG 0x0008
#define DHTB_FLAG 0x0010
#define SEANDROID_FLAG 0x0020
#define LG_BUMP_FLAG 0x0040
#define SHA256_FLAG 0x0080
#define BLOB_FLAG 0x0100
#define NOOKHD_FLAG 0x0200
#define ACCLAIM_FLAG 0x0400
typedef struct boot_img {
// Memory map of the whole image
void *map_addr;
size_t map_size;
// Headers
void *hdr; /* Either boot_img_hdr or pxa_boot_img_hdr */
mtk_hdr *k_hdr; /* MTK kernel header */
mtk_hdr *r_hdr; /* MTK ramdisk header */
blob_hdr *b_hdr; /* Tegra blob header */
// Flags to indicate the state of current boot image
uint16_t flags;
// The format of kernel and ramdisk
format_t k_fmt;
format_t r_fmt;
// Pointer to dtb that is appended after kernel
void *dtb;
uint32_t dt_size;
// Pointer to end of image
void *tail;
size_t tail_size;
// Pointers to blocks defined in header
void *kernel;
void *ramdisk;
void *second;
void *extra;
} boot_img;
#endif

View File

@@ -343,7 +343,7 @@ done:
return total;
}
long long decomp(file_t type, int to, const void *from, size_t size) {
long long decomp(format_t type, int to, const void *from, size_t size) {
switch (type) {
case GZIP:
return gzip(0, to, from, size);
@@ -363,7 +363,7 @@ long long decomp(file_t type, int to, const void *from, size_t size) {
}
}
long long comp(file_t type, int to, const void *from, size_t size) {
long long comp(format_t type, int to, const void *from, size_t size) {
switch (type) {
case GZIP:
return gzip(1, to, from, size);
@@ -392,10 +392,10 @@ void decomp_file(char *from, const char *to) {
void *file;
size_t size = 0;
if (strcmp(from, "-") == 0)
full_read(STDIN_FILENO, &file, &size);
stream_full_read(STDIN_FILENO, &file, &size);
else
mmap_ro(from, &file, &size);
file_t type = check_type(file);
format_t type = check_fmt(file, size);
char *ext;
ext = strrchr(from, '.');
if (to == NULL)
@@ -437,7 +437,7 @@ void decomp_file(char *from, const char *to) {
fd = STDOUT_FILENO;
} else {
fd = creat(to, 0644);
fprintf(stderr, "Decompressing to [%s]\n\n", to);
fprintf(stderr, "Decompressing to [%s]\n", to);
}
decomp(type, fd, file, size);
@@ -453,7 +453,7 @@ void decomp_file(char *from, const char *to) {
}
void comp_file(const char *method, const char *from, const char *to) {
file_t type;
format_t type;
char *ext, dest[PATH_MAX];
if (strcmp(method, "gzip") == 0) {
type = GZIP;
@@ -483,7 +483,7 @@ void comp_file(const char *method, const char *from, const char *to) {
void *file;
size_t size;
if (strcmp(from, "-") == 0)
full_read(STDIN_FILENO, &file, &size);
stream_full_read(STDIN_FILENO, &file, &size);
else
mmap_ro(from, &file, &size);
if (to == NULL) {
@@ -498,7 +498,7 @@ void comp_file(const char *method, const char *from, const char *to) {
fd = STDOUT_FILENO;
} else {
fd = creat(dest, 0644);
fprintf(stderr, "Compressing to [%s]\n\n", dest);
fprintf(stderr, "Compressing to [%s]\n", dest);
}
comp(type, fd, file, size);
close(fd);

View File

@@ -5,8 +5,6 @@
#include "magiskboot.h"
#include "utils.h"
extern int check_verity_pattern(const char *s);
static void print_props(const void *fdt, int node, int depth) {
int prop;
fdt_for_each_property_offset(prop, fdt, node) {
@@ -51,7 +49,7 @@ static void dtb_dump(const char *file) {
for (int i = 0; i < size; ++i) {
if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) {
fdt = dtb + i;
fprintf(stderr, "Dumping dtb.%04d\n\n", dtb_num++);
fprintf(stderr, "Dumping dtb.%04d\n", dtb_num++);
print_subnode(fdt, 0, 0);
}
}
@@ -63,7 +61,7 @@ static void dtb_dump(const char *file) {
static void dtb_patch(const char *file, int patch) {
size_t size ;
void *dtb, *fdt;
fprintf(stderr, "Loading dtbs from [%s]\n\n", file);
fprintf(stderr, "Loading dtbs from [%s]\n", file);
if (patch)
mmap_rw(file, &dtb, &size);
else
@@ -79,26 +77,22 @@ static void dtb_patch(const char *file, int patch) {
int block;
fdt_for_each_subnode(block, fdt, fstab) {
fprintf(stderr, "Found block [%s] in fstab\n", fdt_get_name(fdt, block, NULL));
int skip, value_size;
char *value = (char *) fdt_getprop(fdt, block, "fsmgr_flags", &value_size);
for (int i = 0; i < value_size; ++i) {
if ((skip = check_verity_pattern(value + i)) > 0) {
if (patch) {
fprintf(stderr, "Remove pattern [%.*s] in [fsmgr_flags]\n", skip, value + i);
memcpy(value + i, value + i + skip, value_size - i - skip);
memset(value + value_size - skip, '\0', skip);
} else {
fprintf(stderr, "Found pattern [%.*s] in [fsmgr_flags]\n", skip, value + i);
i += skip - 1;
}
found = 1;
}
uint32_t value_size;
void *value = (void *) fdt_getprop(fdt, block, "fsmgr_flags", &value_size);
if (patch) {
void *dup = xmalloc(value_size);
memcpy(dup, value, value_size);
memset(value, 0, value_size);
found |= patch_verity(&dup, &value_size, 1);
memcpy(value, dup, value_size);
free(dup);
} else {
found |= patch_verity(&value, &value_size, 0);
}
}
}
}
}
fprintf(stderr, "\n");
munmap(dtb, size);
exit(!found);
}

Some files were not shown because too many files have changed in this diff Show More