Compare commits

...

254 Commits
v7 ... v13.0

Author SHA1 Message Date
topjohnwu
0b4baad78b Add mount namespace mode 2017-06-08 22:56:21 +08:00
topjohnwu
201e32d4c4 Fix daemon crashes in encrypted /data 2017-06-08 19:15:51 +08:00
topjohnwu
0980cb6eb5 Proper handle version string 2017-06-08 05:21:51 +08:00
topjohnwu
f75d23363b Update Magisk Manager 2017-06-08 05:21:27 +08:00
topjohnwu
6c0ba66f17 Add excessive logging for debug mode 2017-06-08 03:25:15 +08:00
topjohnwu
f32ce7392e Update sepolicy rules 2017-06-08 03:02:01 +08:00
topjohnwu
8bf382adad Apparently, not every device uses emmc 2017-06-07 11:32:35 +08:00
topjohnwu
541ba357bb Fix prop issues 2017-06-07 11:26:58 +08:00
topjohnwu
b6578b52e3 Update README.MD 2017-06-04 02:55:12 +08:00
topjohnwu
fb01c43ece Add Linux compatibility 2017-06-04 01:39:52 +08:00
topjohnwu
b9a012c6e3 Fix execution in Magisk binary for uninstallation 2017-06-04 00:35:45 +08:00
topjohnwu
17684ed8a8 Fix uninstaller and build with 'all' 2017-06-04 00:04:58 +08:00
topjohnwu
1b6b3b2cd5 Build in debug mode by default 2017-06-03 22:04:22 +08:00
topjohnwu
acd8567586 Adjust for Windows builds 2017-06-03 22:00:22 +08:00
topjohnwu
e780c76c93 Massive build script refactor 2017-06-03 20:31:02 +08:00
topjohnwu
532c6caddf Fix typo in cpio check 2017-06-03 18:52:02 +08:00
topjohnwu
ef8d9be633 More improvements and fixes 2017-06-03 05:52:49 +08:00
topjohnwu
2cdbcc5666 Add more checks for other patches 2017-06-03 05:08:52 +08:00
topjohnwu
c282a8f328 Loop for every for logging 2017-06-03 04:31:01 +08:00
topjohnwu
b9eab39541 Add ext4 img helper commands 2017-06-03 03:58:26 +08:00
topjohnwu
20903784a4 Support file based encryption and several small updates 2017-06-03 02:28:51 +08:00
topjohnwu
3ec9ff7467 Update MagiskSU 2017-06-01 03:20:51 +08:00
topjohnwu
17d3a87b1f Prevent resetprop function signature duplicate with libc 2017-05-30 23:34:39 +08:00
topjohnwu
14c5c60863 Improve excessive rapid root access performance 2017-05-29 18:56:00 +08:00
topjohnwu
70a80090c4 Improve multiuser su support 2017-05-28 01:33:58 +08:00
topjohnwu
b6cb5d09cb Add multiuser support 2017-05-27 02:43:55 +08:00
topjohnwu
69cfde4516 Add new function for vector (future proof) 2017-05-26 23:03:54 +08:00
topjohnwu
bdc83da098 Fix bug in magic mount 2017-05-26 23:03:54 +08:00
topjohnwu
f872a122a9 Preserve at least 32M free size 2017-05-26 23:03:45 +08:00
topjohnwu
aa92e4cbd0 Fix stupid bug in MagiskHide 2017-05-12 15:28:15 +08:00
topjohnwu
e603877a17 Install Magisk Manager APK with pm (Android O Compat.) 2017-05-09 01:16:58 +08:00
topjohnwu
bb96477779 Improve Magic Mount with proper precedence 2017-05-09 01:09:32 +08:00
topjohnwu
543ee79720 Prevent su logging tons of errors 2017-05-08 11:50:52 +08:00
topjohnwu
ea8cd98361 Cleanup file descriptors 2017-05-08 03:11:14 +08:00
topjohnwu
58849f28a8 Add daemon response code 2017-05-05 16:13:26 +08:00
topjohnwu
d66c284bed Fix several small issues 2017-05-05 04:39:09 +08:00
topjohnwu
693848280b Add systemless hosts support 2017-05-04 03:05:37 +08:00
topjohnwu
396afaa181 Improve magiskhide stability 2017-05-04 02:58:37 +08:00
topjohnwu
05ed29133b Finish post-fs simple mount 2017-05-04 02:39:53 +08:00
topjohnwu
a31c1e8084 post-fs-data mode done 2017-05-04 01:22:56 +08:00
topjohnwu
21891230f2 Typo fix 2017-05-02 05:00:01 +08:00
topjohnwu
47da76c5a5 Stupid bug, critical fix 2017-05-02 04:57:14 +08:00
topjohnwu
6017ff2318 Close files, cleanup resourses 2017-05-02 04:55:55 +08:00
topjohnwu
e16d604d0d Implement Magic Mount 2017-05-01 01:58:52 +08:00
topjohnwu
d3d5703f3f Reduce duplicate code for MagiskBoot 2017-04-28 21:53:44 +08:00
topjohnwu
62fe92d922 Update credits 2017-04-28 03:36:16 +08:00
topjohnwu
512e7be74f Add version info 2017-04-28 03:26:48 +08:00
topjohnwu
727abbea8f Cleanup magiskboot 2017-04-28 03:24:30 +08:00
topjohnwu
76f81ece62 Fix verbose output 2017-04-28 01:45:57 +08:00
topjohnwu
495654f9ff Small tweaks 2017-04-24 21:43:30 +08:00
topjohnwu
95fec2100e Use GPL v3 license and update copyright messages 2017-04-22 17:12:54 +08:00
topjohnwu
623a879797 Update scripts 2017-04-22 17:12:54 +08:00
topjohnwu
4c96d23f48 Some minor updates 2017-04-22 17:12:54 +08:00
topjohnwu
9bc8f6e9d7 Add common script support 2017-04-22 17:12:54 +08:00
topjohnwu
e00e6509ee Add error code for magiskhide 2017-04-22 17:12:54 +08:00
topjohnwu
be5739508b Isolate root daemon from requests 2017-04-22 17:12:54 +08:00
topjohnwu
38c867ea94 Some fixes 2017-04-22 17:12:54 +08:00
topjohnwu
2a985ce6c0 Add magiskhide list management 2017-04-22 17:12:54 +08:00
topjohnwu
e4f3fb36f3 Update build scripts 2017-04-22 17:12:54 +08:00
topjohnwu
b2f8792873 Add more Android O selinux stuff 2017-04-22 17:12:54 +08:00
topjohnwu
2065133e2d Update policy rules for Android O 2017-04-22 17:12:54 +08:00
topjohnwu
86da87f254 Update build script and tools 2017-04-22 17:12:54 +08:00
topjohnwu
102a7f8723 Change flags 2017-04-22 17:12:54 +08:00
topjohnwu
e9afc15719 Fix magiskhide daemon enable/disable 2017-04-22 17:12:54 +08:00
topjohnwu
08527dde9b Auto start magiskhide 2017-04-22 17:12:54 +08:00
topjohnwu
d9c3a3c9a9 Remove su_device auto transit 2017-04-22 17:12:54 +08:00
topjohnwu
fe89f9e55e Update to newer functions in resetprop 2017-04-22 17:12:54 +08:00
topjohnwu
73802aabac Fix compile issue when using NDK Unified Headers 2017-04-22 17:12:54 +08:00
topjohnwu
bc66733289 Add Android O sepolicy patches 2017-04-22 17:12:54 +08:00
topjohnwu
f4c93b2251 Update resetprop for Android O support
Updated to upstream https://android.googlesource.com/platform/bionic.git
2017-04-22 17:12:54 +08:00
topjohnwu
c079c598f2 Update scripts, MagiskSU now works fine 2017-04-22 17:12:54 +08:00
topjohnwu
8a2f0063d4 Improve magiskhide process/thread management 2017-04-22 17:12:54 +08:00
topjohnwu
dfe4b33f2f Integrate sepolicy patching with MagiskSU fixed 2017-04-22 17:12:54 +08:00
topjohnwu
2f7cfa7ab2 Link binaries when daemon started 2017-04-22 17:12:54 +08:00
topjohnwu
bdcb813ee6 Add block rw support 2017-04-22 17:12:54 +08:00
topjohnwu
f0751007f3 Update main function 2017-04-22 17:12:54 +08:00
topjohnwu
6ad993704c Integrate MagiskSU into Magisk daemon 2017-04-22 17:12:54 +08:00
topjohnwu
796c3009c7 Refactor resetprop 2017-04-22 17:12:54 +08:00
topjohnwu
144ff5e716 Integrate MagiskHide into Magisk Daemon 2017-04-22 17:12:54 +08:00
topjohnwu
054a1e5ea4 Add magisk daemon 2017-04-22 17:12:54 +08:00
topjohnwu
a223f6056e Add zygote namespace detection 2017-04-22 17:12:54 +08:00
topjohnwu
a1fd7704e0 Fix vector bug 2017-04-22 17:12:54 +08:00
topjohnwu
b94227efc9 Add process searching 2017-04-22 17:12:54 +08:00
topjohnwu
3a7e782c07 Remove separate binary support for tools rely on daemon 2017-04-22 17:12:54 +08:00
topjohnwu
8f6b33d790 Rewrite magiskhide 2017-04-22 17:12:54 +08:00
topjohnwu
f476daa041 Change parts of library to shared
libsqlite and libselinux are shipped with Android systems
We build them here for the compiler to link against it,
we actually use the one in /system/lib(64)
2017-04-22 17:12:54 +08:00
topjohnwu
acfde9458d Merge magiskpolicy, magiskhide, resetprop, magisksu 2017-04-22 17:12:54 +08:00
topjohnwu
82e969627a Start unifying with log monitor 2017-04-22 17:12:54 +08:00
topjohnwu
40766b3375 Do not use psuedo permissive, hide instead 2017-04-03 23:28:18 +08:00
topjohnwu
d274e45587 Fix SuperSU installation 2017-03-31 06:25:22 +08:00
topjohnwu
0a0eb3f710 Update policy rules 2017-03-31 02:54:39 +08:00
topjohnwu
81d054a525 Adjust scripts 2017-03-31 02:54:39 +08:00
topjohnwu
2e185f4ec9 Add core props support 2017-03-30 02:47:40 +08:00
topjohnwu
67f347f880 Live patch policy in service mode 2017-03-30 02:29:10 +08:00
topjohnwu
81542fc6a8 Fix MTK header support 2017-03-29 04:35:35 +08:00
topjohnwu
5aced279d6 Add legacy lz4 mode support 2017-03-29 04:35:35 +08:00
topjohnwu
3f016f785f Handle selinux for Samsung in binary 2017-03-29 02:23:10 +08:00
topjohnwu
a6427d081e Fix typo 2017-03-29 02:22:33 +08:00
topjohnwu
8c7fbe20f9 Daemons cannot run in /data on Samsung, move to magisk.img 2017-03-27 07:23:53 +08:00
Deiki-kun
469aba8ed0 Magisk Hide enable/disable scripts fix 2017-03-27 05:51:23 +08:00
topjohnwu
6e8e4ad5da Fix compile warnings 2017-03-26 23:40:34 +08:00
Jan Christian Grünhage
2f33d654e4 Fix Markdown headings 2017-03-26 21:49:24 +08:00
Jasmin Hassan
760b6385f1 list_monitor: use IN_CLOSE_WRITE instead of IN_MODIFY 2017-03-26 21:49:11 +08:00
Jasmin Hassan
91527500f9 proc_monitor: Support newer kernels am_proc_start format 2017-03-26 21:49:11 +08:00
Jasmin Hassan
e87d989ca3 Fix proccess monitor for lsskernel 6.0.1 (3.8UX) 2017-03-26 21:49:11 +08:00
topjohnwu
64d61bae08 Start MagiskHide even if disabled (MagiskSU only mode) 2017-03-26 21:47:54 +08:00
topjohnwu
9862265465 Add Samsung RKP hexpatch back 2017-03-26 21:44:44 +08:00
topjohnwu
624b7616d0 Another freakin stupid typo 2017-03-21 05:15:13 +08:00
topjohnwu
d53f33bed8 I shall test Samsung before release... 2017-03-21 04:25:49 +08:00
topjohnwu
02e039d792 Small fixes 2017-03-20 05:03:52 +08:00
topjohnwu
9f9333315e Update build script and remove redundant file 2017-03-19 05:02:20 +08:00
topjohnwu
0d10b812fe Handle MagiskSU and MagiskHide differently 2017-03-19 05:00:12 +08:00
topjohnwu
b4fe4f3d10 Rename sepolicy-inject 2017-03-18 17:26:30 +08:00
topjohnwu
ba93fcbda0 Prevent multirom crashes 2017-03-18 16:57:29 +08:00
topjohnwu
88d19a4ca4 Several fixes 2017-03-18 16:57:04 +08:00
topjohnwu
af7b9ea898 Update to MagiskSU 8 2017-03-16 06:58:43 +08:00
topjohnwu
09cd0468cf Stop after reading TRAILER!!! 2017-03-16 06:46:32 +08:00
topjohnwu
529aa754f5 Update scripts 2017-03-15 19:32:25 +08:00
topjohnwu
3c7e865555 The long awaited vendor mount fix 2017-03-15 03:43:28 +08:00
topjohnwu
7877ac0c3b Well, /dev/zero cannot be used like that... 2017-03-13 05:05:51 +08:00
topjohnwu
1442e29d0e Update size in MTK headers 2017-03-13 04:27:56 +08:00
topjohnwu
9a7e9b736e Typo 2017-03-13 04:17:39 +08:00
topjohnwu
c421e45fa0 Small improvements and bug fixes 2017-03-12 19:22:15 +08:00
topjohnwu
8833d21ac3 Update scripts for MagiskBoot 2017-03-12 18:21:50 +08:00
topjohnwu
1a3c522c94 Various improvements for Magisk installation 2017-03-12 18:12:16 +08:00
topjohnwu
c55aa92d4f Update build script 2017-03-12 01:24:30 +08:00
topjohnwu
212a303347 Add auto cpio backup and restore 2017-03-10 07:52:59 +08:00
topjohnwu
3f3568d8af More cpio features 2017-03-10 04:15:37 +08:00
topjohnwu
1e3bcfc8cd Add basic cpio features 2017-03-08 00:54:23 +08:00
topjohnwu
a4ce9f6f05 Add compress, decompress, cleanup command 2017-03-05 01:51:13 +08:00
topjohnwu
65dc99744e Use our own zlib for static link and ZLIB_CONST flag 2017-03-04 21:18:24 +08:00
topjohnwu
c6d4740b0c Separate utility functions 2017-03-04 21:16:59 +08:00
topjohnwu
9f91c8b59d Improvements 2017-03-04 00:04:15 +08:00
topjohnwu
2b3b087c29 Add bzip2 support 2017-03-02 05:23:31 +08:00
topjohnwu
e08d46aa76 Add lz4 support 2017-03-02 04:12:47 +08:00
topjohnwu
feccc97a14 Fix typo 2017-03-01 00:50:56 +08:00
topjohnwu
77eec3d21d Support legacy lzma 2017-03-01 00:47:59 +08:00
topjohnwu
ecaafd1b70 Fix header when repack from ELF 2017-03-01 00:15:38 +08:00
topjohnwu
0d51997e46 Add xz support 2017-02-28 21:56:13 +08:00
topjohnwu
463cbceb07 Cleanup Android.mk 2017-02-28 17:53:04 +08:00
topjohnwu
1437c5c63f Add ndk-compression with liblzma 2017-02-28 17:24:27 +08:00
topjohnwu
52f1d50902 Project restructure 2017-02-28 16:59:21 +08:00
topjohnwu
a839cb787e Rename bootimgtool to magiskboot 2017-02-28 05:43:49 +08:00
topjohnwu
f621fb2060 Add gzip native support 2017-02-28 05:40:27 +08:00
topjohnwu
2ccd8b8838 Cleanup hexpatch 2017-02-25 03:50:26 +08:00
topjohnwu
7ef0746c52 Add ELF support 2017-02-25 03:29:12 +08:00
topjohnwu
6f609f0dd7 Several improvements 2017-02-24 15:53:17 +08:00
topjohnwu
ee2a30470a Boot IMG tools complete re-write
Fix #27, Fix #35, Fix #68, Fix #70, Fix #71, Fix #72, Fix #75, Fix #87
2017-02-24 07:45:48 +08:00
topjohnwu
e11fb2c09e Fix compile errors 2017-02-20 11:55:32 +08:00
topjohnwu
c6e9270590 Add busybox to uninstaller and bug fixes 2017-02-14 07:13:36 +08:00
topjohnwu
3e2e171407 Update su 2017-02-14 06:41:52 +08:00
topjohnwu
332f531a10 Move binaries to seperate folder 2017-02-14 06:39:10 +08:00
Drgravy
bae2c9bc63 fix LG bump support for uninstaller 2017-02-14 03:39:53 +08:00
Drgravy
5ac68f8df8 fix up bump support for LG g2/g3 devices 2017-02-14 03:39:53 +08:00
topjohnwu
06d3b94804 Several improvements 2017-02-07 07:50:55 +08:00
topjohnwu
e7c314fefc Add sepolicy-inject back to PATH 2017-02-06 07:20:01 +08:00
topjohnwu
faab79b41a Update uninstaller 2017-02-06 07:20:01 +08:00
topjohnwu
14204c9bfc Busybox path changed; stock one is enough for detection 2017-02-06 00:14:03 +08:00
topjohnwu
45dbd4464b Add general purpose script execution 2017-02-06 00:13:25 +08:00
topjohnwu
472255924a Auto switch to pseudo enforced if permissive 2017-02-05 23:43:01 +08:00
topjohnwu
6d3ac2aa55 Check before enable/disable 2017-02-05 23:42:57 +08:00
topjohnwu
9ad03994d1 Handle disabling 2017-02-05 23:40:50 +08:00
topjohnwu
35228f80b8 Several minor fixes 2017-02-05 01:45:53 +08:00
topjohnwu
69ded881c6 Treat symlinks as new files 2017-02-05 01:36:07 +08:00
topjohnwu
d9bce45db4 Fix props not loading correctly 2017-02-05 00:37:30 +08:00
topjohnwu
5e92b4faa9 Update binaries 2017-02-04 18:59:52 +08:00
topjohnwu
db501822ef Update busybox handling 2017-02-04 18:44:07 +08:00
topjohnwu
ef9948a967 Move MagiskHide initialization to Magisk Manager 2017-02-01 23:22:26 +08:00
topjohnwu
298f09402f Introduce MagiskSU 2017-02-01 06:08:59 +08:00
topjohnwu
d4149d4b7a Update native parts 2017-02-01 06:03:05 +08:00
topjohnwu
3315228a90 Properly handle loading prop files
1. Add new trigger "load_magisk_props_action" in init.magisk.rc
2. Patch init*.rc with new trigger
3. Update resetprop to handle prop value with spaces
4. Handle the case when modules contains file/folder names with spaces
2017-01-09 02:23:00 +08:00
topjohnwu
f72205c401 Fix binary outdated complain 2017-01-03 09:37:45 +08:00
topjohnwu
11862bbaee Remove apps from whitelist, causes issues 2017-01-03 09:37:03 +08:00
topjohnwu
8d846993ee Load system.prop; longer waiting time 2017-01-03 01:55:19 +08:00
topjohnwu
1f84626278 Handle /cache/su.img 2017-01-02 17:48:50 +08:00
topjohnwu
b4cfe6e9c0 Proper vendor support 2017-01-02 17:48:34 +08:00
topjohnwu
94a861e318 Update uninstaller 2017-01-02 03:35:30 +08:00
topjohnwu
1421e775d2 Remove system root 2017-01-02 03:00:03 +08:00
topjohnwu
f8eab72c7a Install Magisk Manager stub if not installed 2017-01-02 02:31:59 +08:00
topjohnwu
2afd2f0d3b More SuperSU support 2017-01-02 02:00:53 +08:00
topjohnwu
2b72f40cec Upgrade phh su 2017-01-02 01:28:24 +08:00
topjohnwu
ff5c0d6361 MagiskHide small fix 2017-01-01 20:31:08 +08:00
topjohnwu
198b14e5fc Fixed various Magic Mount bugs 2017-01-01 19:45:06 +08:00
topjohnwu
f9fea265cf Small updates for MagiskHide 2017-01-01 18:54:13 +08:00
topjohnwu
668601ca23 Separate all binaries and makefile 2016-12-31 02:44:24 +08:00
topjohnwu
99406f2099 Separate all Android.mk files 2016-12-30 06:06:19 +08:00
topjohnwu
632b3cb9ae Higher priority; compare whole string instead substr 2016-12-30 06:05:33 +08:00
topjohnwu
0bf04c04f9 Final fix for MagiskHide, all is well! 2016-12-29 23:25:11 +08:00
topjohnwu
dc29018ec0 Reduce wait interval and various bug fixes 2016-12-28 15:28:42 +08:00
topjohnwu
b6412afe96 Fix Magisk Hide losing root issue
This is the issue that has been haunting since day 1. Root and mounted files randomly disappears, and only an reboot can fix it.
The issue is that Zygote requires some time to isolate the mount namespace for the children it forks (read: most processes), so in rare cases such as the CPU is on heavy load, or CPU is in deep sleep, it takes longer than usual to finish the mount namespace isolation. Magisk Hide kicks in before the isolation is done, and it will switch to Zygote's namespace and do the unmounting. All children will then lose the mounted files, which includes root.
The solution is to first find the namespace id of Zygote, and wait a small period of time and retry if the namespace isn't isolated yet.
2016-12-28 04:02:35 +08:00
topjohnwu
4e88186903 Move /sbin binaries to new location for root
Finally fix #12
2016-12-22 20:03:35 +08:00
Paulo d'Castro
f387378b69 Bump support 2016-12-22 20:02:29 +08:00
Paulo d'Castro
f894e6b4ea Uninstaller bump support 2016-12-22 20:02:29 +08:00
topjohnwu
e33f5996f3 Disable MagiskHide when SuperSU detected 2016-12-18 22:50:27 +08:00
topjohnwu
8f7f1ff7dd Fix boot image backup overwrites when upgrade 2016-12-18 22:45:31 +08:00
topjohnwu
54a0e52e05 Minor script fix 2016-12-18 19:05:18 +08:00
topjohnwu
b2431b982f Prettify code 2016-12-11 05:10:48 +08:00
topjohnwu
8d6d619eed Fork once only
Right now there are three threads (process)
1. Main thread in parent: monitor logcat
2. Second thread in parent: monitor hidelist
3. Children: switch namespace and unmounts
2016-12-11 04:56:01 +08:00
topjohnwu
70e332b9e8 MagiskHide small update 2016-12-11 03:41:29 +08:00
topjohnwu
0a53c42a8a Improve phh su installation 2016-12-10 23:48:24 +08:00
topjohnwu
0ccc92dc1e Minor restructure 2016-12-09 15:57:10 +08:00
topjohnwu
c9157cc13b Fix bug in clone dummy 2016-12-08 21:31:34 +08:00
topjohnwu
2b1270381d Install phh su if no SuperSU detected 2016-12-08 01:50:10 -08:00
topjohnwu
cdb8ee3946 Fix #19 uninstaller issues 2016-12-08 01:24:27 -08:00
topjohnwu
1e3586621b Magic Mount Total Re-factor Part 2
1. It seems that many part of the system is upset about symlinks, revert to bind mounts
2. New system and vendor mirror implementation found, no need to copy anything
3. Thanks to the new mirror implementation, adding new items to /system and /vendor is now possible
4. Re-written some coding style
2016-12-08 00:58:22 -08:00
topjohnwu
c07e9ac29d Magic Mount total re-factor
1. Remove stage 4 bind which mount files back, use symlinks instead
2. libs do not support symlink, make a copy to data if needed
3. Proper support for adding new files into /system/vendor on devices with separate vendor partition
2016-12-07 01:45:09 +08:00
topjohnwu
6e3bb48574 Add su binary into Magisk 2016-12-06 04:49:35 +08:00
topjohnwu
16d7ae62bd Move selinux submodule 2016-12-06 03:09:15 +08:00
topjohnwu
eea3cb32a5 Add Windows build scripts and fix script bugs 2016-12-06 02:45:51 +08:00
topjohnwu
670fe8590c Various fixes
Fixes #13 and #17
2016-11-29 04:19:36 +08:00
topjohnwu
30c048723c Update installer 2016-11-15 04:46:01 +08:00
topjohnwu
85dc669ddf Mount magisk.img with option suid
Should fix #12, hope so :)
2016-11-14 11:00:56 +08:00
topjohnwu
397c1a1c2b Magisk Hide won't play well with dummy lib 2016-11-14 05:02:57 +08:00
topjohnwu
f1d3e35aac Proper support for special mounts 2016-11-14 04:30:05 +08:00
topjohnwu
0e69201f05 Remove UID check, not reliable.... 2016-11-14 04:27:43 +08:00
topjohnwu
f8fdaf5c1f Initialize is not needed 2016-11-13 21:22:04 +08:00
topjohnwu
1f3b81338c Fix Moto DTB issue 2016-11-13 21:03:00 +08:00
topjohnwu
5921d3a42a Update scripts 2016-11-13 21:02:35 +08:00
topjohnwu
dbbc85719e MagiskHide: Unmount cache mounts and check UID 2016-11-13 19:27:01 +08:00
topjohnwu
0ddb6c3f10 Various small changes 2016-11-13 16:58:43 +08:00
topjohnwu
e13281726c Add bootanim, host, busybox 2016-11-09 05:17:14 +08:00
topjohnwu
0ddf4355a1 Update build.sh 2016-11-09 05:16:03 +08:00
topjohnwu
7c8a3ca1a8 Revert to 1.25.0 as 1.25.1 is faulty 2016-11-09 04:41:34 +08:00
topjohnwu
3068738a70 MagiskHide small tweak 2016-11-07 23:57:21 +08:00
topjohnwu
cfa0d8b7c0 gitmodule typo fix 2016-11-06 05:00:58 +08:00
topjohnwu
7ac41652f7 Brand new dummy cloning: No bugs and faster 2016-11-06 04:47:54 +08:00
topjohnwu
24a510bc2e Kill process after remove from list 2016-11-06 02:43:57 +08:00
topjohnwu
0498540439 Magisk Hide: Unmount dummy skeleton 2016-11-06 02:09:14 +08:00
topjohnwu
da94c2e1e5 Update build.sh to detect failures 2016-11-06 01:33:55 +08:00
topjohnwu
bcdd74514f Adjust scripts for resetprop 2016-11-05 02:38:10 +08:00
topjohnwu
1d0c36a0ab Add resetprop to Magisk 2016-11-05 02:38:10 +08:00
topjohnwu
a34ea8f131 Magisk Hide Massive Update 2016-11-01 04:21:43 +08:00
topjohnwu
7fbfa6a52b Remove custom patch script in uninstaller 2016-10-30 20:09:32 +08:00
topjohnwu
799ef3380d Update build script 2016-10-30 19:32:36 +08:00
topjohnwu
d5087858ca Add build scripts
Building through the build script will compile all binaries, and generate a properly signed zip
Should work on linux and macOS environments
2016-10-30 19:11:26 +08:00
Pierre-Hugues Husson
d9fc5650b8 Oops, MTK rootfs/recovery detection had wrong offset 2016-10-30 06:57:50 +08:00
topjohnwu
9ea028f5ab Various updates, prepare for Multirom support 2016-10-30 06:50:06 +08:00
topjohnwu
aa309087fd Update flash script 2016-10-30 06:50:06 +08:00
topjohnwu
57bdd9d3bf Update busybox to 1.25.1 2016-10-30 06:11:48 +08:00
topjohnwu
dc9871fe5b Update binaries 2016-10-30 06:11:22 +08:00
topjohnwu
3255ca3ea4 Remove unnecessary statics 2016-10-30 06:08:23 +08:00
topjohnwu
a06ef6fe25 Magisk v8 2016-10-19 06:22:00 +08:00
topjohnwu
696d256fa0 Move root helper location 2016-10-15 05:38:30 +08:00
topjohnwu
70e8ad7104 Add scripts / support for Magisk Hide to Magisk 2016-10-15 05:38:12 +08:00
topjohnwu
f785dcac3d Magisk Hide: Auto unmount necessary files 2016-10-15 05:18:16 +08:00
topjohnwu
aa54ef10ae Magisk Hide: Unmount everything 2016-10-06 17:53:52 +08:00
topjohnwu
14946da163 Magisk Hide done 2016-10-06 04:33:33 +08:00
topjohnwu
5f9bcfbefe Change the name to magiskhide 2016-10-06 02:21:12 +08:00
topjohnwu
aa2eed2c38 Make hidesu hide Magisk and read config file 2016-10-06 02:17:21 +08:00
Pierre-Hugues Husson
6bff6e9cff [hidesu] Don't suicide 2016-10-05 04:11:07 +08:00
Pierre-Hugues Husson
023d369b74 Move to android-21 NDK 2016-10-05 04:10:24 +08:00
Pierre-Hugues Husson
c9d4241afe PoC++ of hidesu
This uses logcat -b events to search for new process
2016-10-05 04:10:05 +08:00
Pierre-Hugues Husson
e1279c29c2 Add hidesu program.
This is a test program, this will probably be integrated into su daemon.
This hides su by bind-mounting something (/system) over /sbin, so that
there is no /sbin/su binary.
Usage:
hidesu /proc/<one pid of the namespace>/ns/mnt

This uses the fact that when a program wants access to /sdcard, zygote
does this using mount namespaces, so every program accessing /sdcard
will be in a custom mount namespace, that can be modified.
2016-10-05 04:07:48 +08:00
Tom Briden
2d6fb1c45e Only delete verity_key if ! $KEEPVERITY
otherwise the device can't boot
2016-10-04 14:56:02 -05:00
108 changed files with 231012 additions and 1722 deletions

16
.gitattributes vendored Normal file
View File

@@ -0,0 +1,16 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text eol=lf
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
# *.c text
# *.h text
# Declare files that will always have CRLF line endings on checkout.
*.cmd text eol=crlf
# Denote all files that are truly binary and should not be modified.
chromeos/** binary
*.jar binary
*.exe binary
*.apk binary

9
.gitignore vendored
View File

@@ -1,2 +1,7 @@
obj
libs
obj/
libs/
*.zip
*.jks
# Copied binaries
ziptools/zipadjust

21
.gitmodules vendored
View File

@@ -1,6 +1,15 @@
[submodule "selinux"]
path = selinux
url = https://github.com/topjohnwu/selinux
[submodule "jni/sepolicy-inject"]
path = jni/sepolicy-inject
url = https://github.com/topjohnwu/sepolicy-inject
[submodule "jni/selinux"]
path = jni/selinux
url = https://github.com/topjohnwu/selinux.git
[submodule "jni/su"]
path = jni/su
url = https://github.com/topjohnwu/MagiskSU.git
[submodule "jni/ndk-compression"]
path = jni/ndk-compression
url = https://github.com/topjohnwu/ndk-compression.git
[submodule "jni/magiskpolicy"]
path = jni/magiskpolicy
url = https://github.com/topjohnwu/magiskpolicy.git
[submodule "MagiskManager"]
path = MagiskManager
url = https://github.com/topjohnwu/MagiskManager.git

674
LICENSE Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

1
MagiskManager Submodule

Submodule MagiskManager added at d3ff482c9b

View File

@@ -1,4 +1,78 @@
# Magisk
Static binaries included:
* Busybox: http://forum.xda-developers.com/android/software-hacking/tool-busybox-flashable-archs-t3348543
* Open source su binary: https://github.com/seSuperuser/Superuser
## How to build Magisk
#### Building has been tested on 3 major platforms:
***macOS 10.12.5***
***Ubuntu 17.04 x64***
***Windows 10 Creators Update x64***
#### Environment Requirements
1. Python 3 **(>= 3.5)**: `python3` (or in some cases `python`) should be accessible
2. Java runtime: `java` should be accessible
3. (Unix only) C compiler: `gcc` should be accessible
4. Android SDK: `ANDROID_HOME` environment variable should point to the Android SDK folder
5. NDK: Install NDK using `sdkmanager`, or through Android SDK Manager
6. Android build-tools: Should have build-tools version matching `MagiskManager/app/build.gradle` installed
#### Instructions and Notes
1. The python build script uses ANSI color codes to change the color of the terminal output. For Windows, this **only** works on Windows 10, as previous Windows console do not support them. If you insist to use an older Windows version, a quick Google search should provide many workarounds
2. After installing the latest Python 3 on Windows (allow the installer to add Python to PATH, or you'll have to manually set the environment), instead of calling `python3` like most Unix environment, you should call `python` in shell (cmd or Powershell both OK). You can double check the version by `python --version`
3. The build script will do several checks, it will refuse to run if the environment doesn't meet the requirements
4. For further instructions, please check the built in help message by `python3 build.py -h`
(Unix users can simply `./build.py -h`, Windows users, as mentioned, call `python` instead)
5. Each action has its own help message, access them by commands like `python3 build.py all -h`
6. To build Magisk for release (enabled through the `--release` flag, the script builds in debug mode by default), you will need to provide a Java keystore file, and place it in `release_signature.jks` to sign Magisk Manager APK for release builds. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually)
7. To properly setup the Android SDK environment, the easiest way is to use Android Studio and open Magisk Manager. If gradle sync passed, your build-tools etc. should be set properly. You can also access SDK Manager GUI within Android Studio to download NDK. Don't forget to add Android Studio's SDK path into environment variable ANDROID_HOME.
## License
Magisk, including all subprojects (git submodule) is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
## Credits
**MagiskManager** (`MagiskManager`)
* Copyright 2016-2017, John Wu (@topjohnwu)
* All contributors and translators
**MagiskSU** (`jni/su`)
* Copyright 2016-2017, 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`)
* Copyright 2016-2017, John Wu (@topjohnwu)
* Copyright 2015, Pierre-Hugues Husson (phh@phh.me)
* Copyright 2015, Joshua Brindle (@joshua_brindle)
**MagiskHide** (`jni/magiskhide`)
* Copyright 2016-2017, John Wu (@topjohnwu)
* Copyright 2016, Pierre-Hugues Husson (phh@phh.me) (original hidesu)
**resetprop** (`jni/resetprop`)
* Copyright 2016-2017 John Wu (@topjohnwu)
* Copyright 2016 nkk71 (nkk71x@gmail.com)
**SELinux** (`jni/selinux`)
* Makefile for NDK: Copyright 2016-2017, John Wu (@topjohnwu)
* It is maintained by many developers in SELinux project, copyright belongs to them
**ndk-compression** (`jni/ndk-compression`)
* Makefile for NDK: Copyright 2017, John Wu (@topjohnwu)
* Each library has its own copyright message in each directories
**Others Not Mentioned**
* Copyright 2016-2017, John Wu (@topjohnwu)

270
build.py Executable file
View File

@@ -0,0 +1,270 @@
#!/usr/bin/env python3
import sys
import os
import subprocess
def error(str):
print('\n' + '\033[41m' + str + '\033[0m' + '\n')
sys.exit(1)
def header(str):
print('\n' + '\033[44m' + str + '\033[0m' + '\n')
# Environment checks
if not sys.version_info >= (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!')
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')
import argparse
import multiprocessing
import zipfile
import datetime
import errno
def silentremove(file):
try:
os.remove(file)
except OSError as e:
if e.errno != errno.ENOENT:
raise
def zip_with_msg(zipfile, source, target):
if not os.path.exists(source):
error('{} does not exist! Try build \'binary\' and \'apk\' before zipping!'.format(source))
print('zip: ' + source + ' -> ' + target)
zipfile.write(source, target)
def build_all(args):
build_binary(args)
build_apk(args)
zip_main(args)
zip_uninstaller(args)
def build_binary(args):
header('* Building Magisk binaries')
ndk_build = os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build')
debug_flag = '' if args.release else '-DDEBUG'
proc = subprocess.run('{} APP_CFLAGS=\"-DMAGISK_VERSION=\\\"{}\\\" -DMAGISK_VER_CODE={} {}\" -j{}'.format(
ndk_build, args.versionString, args.versionCode, debug_flag, multiprocessing.cpu_count()), shell=True)
if proc.returncode != 0:
error('Build Magisk binary failed!')
def build_apk(args):
header('* Building Magisk Manager')
os.chdir('MagiskManager')
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\'')
proc = subprocess.run('{} 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', 'app-release-unsigned.apk')
aligned = os.path.join('app', 'build', 'outputs', 'apk', 'app-release-aligned.apk')
release = os.path.join('app', 'build', 'outputs', 'apk', 'app-release.apk')
# Find the latest build tools
build_tool = sorted(os.listdir(os.path.join(os.environ['ANDROID_HOME'], 'build-tools')))[-1]
silentremove(aligned)
silentremove(release)
proc = subprocess.run([
os.path.join(os.environ['ANDROID_HOME'], 'build-tools', build_tool, 'zipalign'),
'-v', '-p', '4', unsigned, aligned])
if proc.returncode != 0:
error('Zipalign Magisk Manager failed!')
proc = subprocess.run('{} sign --ks {} --out {} {}'.format(
os.path.join(os.environ['ANDROID_HOME'], 'build-tools', build_tool, 'apksigner'),
os.path.join('..', 'release_signature.jks'),
release, aligned), shell=True)
if proc.returncode != 0:
error('Release sign Magisk Manager failed!')
silentremove(unsigned)
silentremove(aligned)
else:
proc = subprocess.run('{} assembleDebug'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build Magisk Manager failed!')
# Return to upper directory
os.chdir('..')
def sign_adjust_zip(unsigned, output):
header('* Signing / Adjusting Zip')
# Unsigned->signed
proc = subprocess.run(['java', '-jar', os.path.join('ziptools', 'signapk.jar'),
os.path.join('ziptools', 'test.certificate.x509.pem'),
os.path.join('ziptools', 'test.key.pk8'), unsigned, 'tmp_signed.zip'])
if proc.returncode != 0:
error('First sign flashable zip failed!')
if os.name != 'nt' and not os.path.exists(os.path.join('ziptools', 'zipadjust')):
# Compile zipadjust
proc = subprocess.run('gcc -o ziptools/zipadjust ziptools/src/*.c -lz', shell=True)
if proc.returncode != 0:
error('Build zipadjust failed!')
# Adjust zip
proc = subprocess.run([os.path.join('ziptools', 'zipadjust'), 'tmp_signed.zip', 'tmp_adjusted.zip'])
if proc.returncode != 0:
error('Adjust flashable zip failed!')
# Adjusted -> output
proc = subprocess.run(['java', '-jar', os.path.join('ziptools', 'minsignapk.jar'),
os.path.join('ziptools', 'test.certificate.x509.pem'),
os.path.join('ziptools', 'test.key.pk8'), 'tmp_adjusted.zip', output])
if proc.returncode != 0:
error('Second sign flashable zip failed!')
# Cleanup
silentremove(unsigned)
silentremove('tmp_signed.zip')
silentremove('tmp_adjusted.zip')
def zip_main(args):
header('* Packing Flashable Zip')
with zipfile.ZipFile('tmp_unsigned.zip', 'w', compression=zipfile.ZIP_DEFLATED) as zipf:
# Compiled Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
for binary in ['magisk', 'magiskboot']:
source = os.path.join('libs', lib_dir, binary)
target = os.path.join(zip_dir, binary)
zip_with_msg(zipf, source, target)
# APK
source = os.path.join('MagiskManager', 'app', 'build', 'outputs', 'apk', 'app-release.apk' if args.release else 'app-debug.apk')
target = os.path.join('common', 'magisk.apk')
zip_with_msg(zipf, source, target)
# Scripts
source = os.path.join('scripts', 'flash_script.sh')
with open(source, 'r') as flash_script:
# Add version info into flash script
update_binary = flash_script.read().replace(
'MAGISK_VERSION_STUB', 'Magisk v{} Installer'.format(args.versionString))
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
print('zip: ' + source + ' -> ' + target)
zipf.writestr(target, update_binary)
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
print('zip: ' + target)
zipf.writestr(target, '#MAGISK\n')
source = os.path.join('scripts', 'init.magisk.rc')
target = os.path.join('common', 'init.magisk.rc')
zip_with_msg(zipf, source, target)
source = os.path.join('scripts', 'boot_patch.sh')
target = os.path.join('common', 'boot_patch.sh')
zip_with_msg(zipf, source, target)
# Prebuilts
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
source = os.path.join('chromeos', chromeos)
zip_with_msg(zipf, source, source)
# End of zipping
output = 'Magisk-v{}.zip'.format(args.versionString)
sign_adjust_zip('tmp_unsigned.zip', output)
def zip_uninstaller(args):
header('* Packing Uninstaller Zip')
with zipfile.ZipFile('tmp_unsigned.zip', 'w', compression=zipfile.ZIP_DEFLATED) as zipf:
# Compiled Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
source = os.path.join('libs', 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)
source = os.path.join('scripts', 'uninstaller_loader.sh')
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
zip_with_msg(zipf, source, target)
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
print('zip: ' + target)
zipf.writestr(target, '#MAGISK\n')
output = 'Magisk-uninstaller-{}.zip'.format(datetime.datetime.now().strftime('%Y%m%d'))
sign_adjust_zip('tmp_unsigned.zip', output)
def cleanup(args):
if len(args.target) == 0:
args.target = ['binary', 'apk', 'zip']
if 'binary' in args.target:
header('* Cleaning Magisk binaries')
subprocess.run(os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build') + ' clean', shell=True)
if 'apk' in args.target:
header('* Cleaning Magisk Manager')
os.chdir('MagiskManager')
subprocess.run('{} clean'.format(os.path.join('.', 'gradlew')), shell=True)
os.chdir('..')
if 'zip' in args.target:
header('* Cleaning created zip files')
for f in os.listdir('.'):
if '.zip' in f:
print('rm {}'.format(f))
silentremove(f)
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.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.set_defaults(func=build_binary)
apk_parser = subparsers.add_parser('apk', help='build Magisk Manager APK')
apk_parser.set_defaults(func=build_apk)
zip_parser = subparsers.add_parser('zip', help='zip and sign Magisk into a flashable zip')
zip_parser.add_argument('versionString')
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 apk zip (default: all)')
clean_parser.add_argument('target', nargs='*')
clean_parser.set_defaults(func=cleanup)
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
args.func(args)

View File

@@ -1,26 +1,65 @@
my_path := $(call my-dir)
LOCAL_PATH := $(my_path)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := bootimgtools
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_LDFLAGS := -static
LOCAL_STATIC_LIBRARIES := libc libcutils
LOCAL_SRC_FILES := bootimgtools.c extract.c repack.c hexpatch.c
LOCAL_CFLAGS += -std=gnu11
LOCAL_MODULE := magisk
LOCAL_STATIC_LIBRARIES := libsepol
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/utils \
$(LOCAL_PATH)/daemon \
$(LOCAL_PATH)/resetprop \
$(LOCAL_PATH)/magiskpolicy \
$(LOCAL_PATH)/selinux/libselinux/include \
$(LOCAL_PATH)/selinux/libsepol/include \
$(LOCAL_PATH)/sqlite3
LOCAL_SRC_FILES := \
main.c \
utils/misc.c \
utils/vector.c \
utils/xwrap.c \
utils/list.c \
daemon/daemon.c \
daemon/socket_trans.c \
daemon/log_monitor.c \
daemon/bootstages.c \
magiskhide/magiskhide.c \
magiskhide/hide_daemon.c \
magiskhide/proc_monitor.c \
magiskhide/pre_process.c \
magiskhide/list_manager.c \
magiskpolicy/magiskpolicy.c \
magiskpolicy/rules.c \
magiskpolicy/sepolicy.c \
magiskpolicy/api.c \
resetprop/resetprop.cpp \
resetprop/system_properties.cpp \
su/su.c \
su/activity.c \
su/db.c \
su/misc.c \
su/pts.c \
su/su_daemon.c \
su/su_socket.c
LOCAL_CFLAGS := -Wno-implicit-exception-spec-mismatch
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE := sepolicy-inject
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_LDFLAGS := -static
LOCAL_STATIC_LIBRARIES := libc libcutils libsepol
LOCAL_SRC_FILES := sepolicy-inject/sepolicy-inject.c sepolicy-inject/builtin_rules.c
LOCAL_C_INCLUDES := selinux/libsepol/include/
LOCAL_CFLAGS += -std=gnu11
include $(BUILD_EXECUTABLE)
# Libraries
include jni/selinux/libselinux/Android.mk
include jni/selinux/libsepol/Android.mk
include jni/sqlite3/Android.mk
include selinux/libsepol/Android.mk
#####################################################################
# In order to build separate binaries, please comment out everything
# starting from line 3 (including the 3 lines for libraries)
# Then, uncomment the line you want below
#####################################################################
# include jni/resetprop/Android.mk
# include jni/magiskpolicy/Android.mk
# Build magiskboot
include jni/magiskboot/Android.mk

View File

@@ -1,2 +1,4 @@
APP_ABI := x86 armeabi
APP_PIE = true
APP_ABI := x86 x86_64 armeabi-v7a arm64-v8a
APP_PLATFORM := android-21
APP_UNIFIED_HEADERS := true
APP_CPPFLAGS += -std=c++11

View File

@@ -1,45 +0,0 @@
#include <getopt.h>
#include <stdio.h>
#include "bootimgtools.h"
/********************
Patch Boot Image
*********************/
int usage(char *arg0) {
fprintf(stderr, "Boot Image Unpack/Repack Tool\n");
fprintf(stderr, "%s --extract <bootimage>\n", arg0);
fprintf(stderr, " Unpack <bootimage> into current directory\n\n");
fprintf(stderr, "%s --repack <bootimage>\n", arg0);
fprintf(stderr, " Repack kernel, dt, ramdisk... from current directory to new-image.img\n <bootimage> is the image you've just unpacked\n\n");
fprintf(stderr, "%s --hexpatch <bootimage> <hexpattern1> <hexpattern2>\n", arg0);
fprintf(stderr, " Search <hexpattern1> in <bootimage>, and replace with <hexpattern2>\n\n");
return 1;
}
int main(int argc, char *argv[])
{
char ch;
struct option long_options[] = {
{"extract", required_argument, NULL, 'e'},
{"repack", required_argument, NULL, 'r'},
{"hexpatch", required_argument, NULL, 'p'},
{NULL, 0, NULL, 0}
};
while ((ch = getopt_long(argc, argv, "e:r:p:", long_options, NULL)) != -1) {
switch (ch) {
case 'e':
return extract(optarg);
case 'r':
return repack(optarg);
case 'p':
if (argc < 5) return usage(argv[0]);
optind += 2;
return hexpatch(argv[optind - 3], argv[optind - 2], argv[optind - 1]);
default:
return usage(argv[0]);
}
}
return 0;
}

773
jni/daemon/bootstages.c Normal file
View File

@@ -0,0 +1,773 @@
/* post_fs_data.c - post-fs-data actions
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#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 "utils.h"
#include "daemon.h"
#include "resetprop.h"
static char *buf, *buf2;
static struct vector module_list;
#ifdef DEBUG
static int debug_log_pid, debug_log_fd;
#endif
/******************
* Node structure *
******************/
// Precedence: MODULE > SKEL > DUMMY
#define DO_NOTHING 0x0 /* intermediate node */
#define IS_DUMMY 0x1 /* mount from mirror */
#define IS_SKEL 0x2 /* mount from skeleton */
#define IS_MODULE 0x4 /* mount from module */
struct node_entry {
const char *module; /* Only used when status & IS_MODULE */
char *name;
uint8_t type;
uint8_t status;
struct node_entry *parent;
struct vector *children;
};
#define IS_DIR(n) (n->type == DT_DIR)
#define IS_LNK(n) (n->type == DT_LNK)
#define IS_REG(n) (n->type == DT_REG)
/******************
* Image handling *
******************/
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);
}
static char *mount_image(const char *img, const char *target) {
char *device = loopsetup(img);
if (device)
xmount(device, target, "ext4", 0, NULL);
return device;
}
static void umount_image(const char *target, const char *device) {
xumount(target);
int fd = xopen(device, O_RDWR);
ioctl(fd, LOOP_CLR_FD);
close(fd);
}
#define round_size(a) ((((a) / 32) + 2) * 32)
static int merge_img(const char *source, const char *target) {
if (access(source, F_OK) == -1)
return 0;
if (access(target, F_OK) == -1) {
rename(source, target);
return 0;
}
// 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))
return 1;
xmkdir("/cache/source", 0755);
xmkdir("/cache/target", 0755);
char *s_loop, *t_loop;
s_loop = mount_image(source, "/cache/source");
if (s_loop == NULL) return 1;
t_loop = mount_image(target, "/cache/target");
if (t_loop == NULL) return 1;
DIR *dir;
struct dirent *entry;
if (!(dir = opendir("/cache/source")))
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
snprintf(buf, PATH_MAX, "/cache/target/%s", entry->d_name);
if (access(buf, F_OK) == 0) {
LOGI("merge module %s\n", entry->d_name);
rm_rf(buf);
}
}
}
closedir(dir);
clone_dir("/cache/source", "/cache/target");
// Unmount all loop devices
umount_image("/cache/source", s_loop);
umount_image("/cache/target", t_loop);
rmdir("/cache/source");
rmdir("/cache/target");
free(s_loop);
free(t_loop);
unlink(source);
return 0;
}
static 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);
}
/***********
* Scripts *
***********/
void exec_common_script(const char* stage) {
DIR *dir;
struct dirent *entry;
snprintf(buf, PATH_MAX, "%s/%s.d", COREDIR, stage);
if (!(dir = opendir(buf)))
return;
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_REG) {
snprintf(buf2, PATH_MAX, "%s/%s", buf, entry->d_name);
if (access(buf2, X_OK) == -1)
continue;
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
char *const command[] = { "sh", buf2, NULL };
int pid = run_command(0, NULL, "/system/bin/sh", command);
if (pid != -1)
waitpid(pid, NULL, 0);
}
}
closedir(dir);
}
void exec_module_script(const char* stage) {
char *module;
vec_for_each(&module_list, module) {
snprintf(buf, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage);
if (access(buf, F_OK) == -1)
continue;
LOGI("%s: exec [%s.sh]\n", module, stage);
char *const command[] = { "sh", buf, NULL };
int pid = run_command(0, NULL, "/system/bin/sh", command);
if (pid != -1)
waitpid(pid, NULL, 0);
}
}
/***************
* Magic Mount *
***************/
static char *get_full_path(struct node_entry *node) {
char buffer[PATH_MAX], temp[PATH_MAX];
// Concat the paths
struct node_entry *cur = node;
strcpy(buffer, node->name);
while (cur->parent) {
strcpy(temp, buffer);
snprintf(buffer, sizeof(buffer), "%s/%s", cur->parent->name, temp);
cur = cur->parent;
}
return strdup(buffer);
}
// Free the node
static void destroy_node(struct node_entry *node) {
free(node->name);
vec_destroy(node->children);
free(node->children);
free(node);
}
// Free the node and all children recursively
static void destroy_subtree(struct node_entry *node) {
// Never free parent, since it shall be freed by themselves
struct node_entry *e;
vec_for_each(node->children, e) {
destroy_subtree(e);
}
destroy_node(node);
}
// Return the child
static struct node_entry *insert_child(struct node_entry *p, struct node_entry *c) {
c->parent = p;
if (p->children == NULL) {
p->children = xmalloc(sizeof(struct vector));
vec_init(p->children);
}
struct node_entry *e;
vec_for_each(p->children, e) {
if (strcmp(e->name, c->name) == 0) {
// Exist duplicate
if (c->status > e->status) {
// Precedence is higher, replace with new node
c->children = e->children; // Preserve all children
free(e->name);
free(e);
vec_entry(p->children)[_] = c;
return c;
} else {
// Free the new entry, return old
destroy_node(c);
return e;
}
}
}
// New entry, push back
vec_push_back(p->children, c);
return c;
}
static void construct_tree(const char *module, struct node_entry *parent) {
DIR *dir;
struct dirent *entry;
struct node_entry *node;
char *parent_path = get_full_path(parent);
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, parent_path);
if (!(dir = opendir(buf)))
goto cleanup;
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Create new node
node = xcalloc(sizeof(*node), 1);
node->module = module;
node->name = strdup(entry->d_name);
node->type = entry->d_type;
snprintf(buf, PATH_MAX, "%s/%s", parent_path, node->name);
// Check if the entry has a correspond target
if (IS_LNK(node) || access(buf, F_OK) == -1) {
// Mark the parent folder as a skeleton
parent->status |= IS_SKEL;
node->status |= IS_MODULE;
} else if (IS_DIR(node)) {
// Check if marked as replace
snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf);
if (access(buf2, F_OK) == 0) {
// Replace everything, mark as leaf
node->status |= IS_MODULE;
}
} else if (IS_REG(node)) {
// This is a leaf, mark as target
node->status |= IS_MODULE;
}
node = insert_child(parent, node);
if (IS_DIR(node) && !(node->status & IS_MODULE)) {
// Intermediate node, travel deeper
construct_tree(module, node);
}
}
closedir(dir);
cleanup:
free(parent_path);
}
static void clone_skeleton(struct node_entry *node) {
DIR *dir;
struct dirent *entry;
struct node_entry *dummy, *child;
// Clone the structure
char *full_path = get_full_path(node);
if (!(dir = opendir(full_path)))
goto cleanup;
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Create dummy node
dummy = xcalloc(sizeof(*dummy), 1);
dummy->name = strdup(entry->d_name);
dummy->type = entry->d_type;
dummy->status |= IS_DUMMY;
insert_child(node, dummy);
}
closedir(dir);
snprintf(buf, PATH_MAX, "%s%s", DUMMDIR, full_path);
mkdir_p(buf, 0755);
clone_attr(full_path, buf);
bind_mount(buf, full_path);
vec_for_each(node->children, child) {
snprintf(buf, PATH_MAX, "%s%s/%s", DUMMDIR, full_path, child->name);
// Create the dummy file/directory
if (IS_DIR(child))
xmkdir(buf, 0755);
else if (IS_REG(child))
close(open_new(buf));
if (child->status & IS_MODULE) {
// Mount from module file to dummy file
snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, child->module, full_path, child->name);
} else if (child->status & IS_SKEL) {
// It's another skeleton, recursive call and end
clone_skeleton(child);
continue;
} else if (child->status & IS_DUMMY) {
// Mount from mirror to dummy file
snprintf(buf2, PATH_MAX, "%s%s/%s", MIRRDIR, full_path, child->name);
}
if (IS_LNK(child)) {
// Symlink special treatments
char *temp = xmalloc(PATH_MAX);
xreadlink(buf2, temp, PATH_MAX);
symlink(temp, buf);
free(temp);
LOGI("cplink: %s -> %s\n", buf2, buf);
} else {
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
bind_mount(buf2, buf);
}
}
cleanup:
free(full_path);
}
static void magic_mount(struct node_entry *node) {
char *real_path;
struct node_entry *child;
if (strcmp(node->name, "vendor") == 0 && strcmp(node->parent->name, "/system") == 0) {
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, node->module);
snprintf(buf2, PATH_MAX, "%s/%s/vendor", MOUNTPOINT, node->module);
unlink(buf2);
symlink(buf, buf2);
return;
}
if (node->status) {
if (node->status & IS_MODULE) {
// The real deal, mount module item
real_path = get_full_path(node);
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, node->module, real_path);
bind_mount(buf, real_path);
free(real_path);
} else if (node->status & IS_SKEL) {
// The node is labeled to be cloned with skeleton, lets do it
clone_skeleton(node);
}
// We should not see dummies, so no need to handle it here
} else {
// It's an intermediate node, travel deeper
vec_for_each(node->children, child)
magic_mount(child);
}
}
/****************
* Simple Mount *
****************/
static void simple_mount(const char *path) {
DIR *dir;
struct dirent *entry;
snprintf(buf, PATH_MAX, "%s%s", CACHEMOUNT, path);
if (!(dir = opendir(buf)))
return;
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Target file path
snprintf(buf2, PATH_MAX, "%s/%s", path, entry->d_name);
// Only mount existing file
if (access(buf2, F_OK) == -1)
continue;
if (entry->d_type == DT_DIR) {
char *new_path = strdup(buf2);
simple_mount(new_path);
free(new_path);
} else if (entry->d_type == DT_REG) {
// Actual file path
snprintf(buf, PATH_MAX, "%s/%s", buf, entry->d_name);
// Clone all attributes
clone_attr(buf2, buf);
// Finally, mount the file
bind_mount(buf, buf2);
}
}
closedir(dir);
}
/****************
* Entry points *
****************/
static void *start_magisk_hide(void *args) {
launch_magiskhide(-1);
return NULL;
}
static void unblock_boot_process() {
close(open(UNBLOCKFILE, O_RDONLY | O_CREAT));
pthread_exit(NULL);
}
void post_fs(int client) {
// Error handler
err_handler = unblock_boot_process;
// Start log monitor
monitor_logs();
LOGI("** post-fs mode running\n");
// ack
write_int(client, 0);
close(client);
// 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) {
// Error handler
err_handler = unblock_boot_process;
// ack
write_int(client, 0);
close(client);
if (!check_data())
goto unblock;
#ifdef DEBUG
// Start debug logs in new process
debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
char *const command[] = { "logcat", "-v", "brief", NULL };
debug_log_pid = run_command(0, &debug_log_fd, "/system/bin/logcat", command);
#endif
LOGI("** post-fs-data mode running\n");
// uninstaller
if (access(UNINSTALLER, F_OK) == 0) {
close(open(UNBLOCKFILE, O_RDONLY | O_CREAT));
system("(BOOTMODE=true sh " UNINSTALLER ") &");
return;
}
// Allocate buffer
if (buf == NULL) buf = xmalloc(PATH_MAX);
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
// Cache support
if (access("/cache/data_bin", F_OK) == 0) {
rm_rf(DATABIN);
rename("/cache/data_bin", DATABIN);
}
// Magisk Manual Injector support
if (access("/data/local/tmp/magisk", F_OK) == 0) {
rm_rf(DATABIN);
rename("/data/local/tmp/magisk", DATABIN);
}
// Lazy.... use shell blob
system("mv /data/magisk/stock_boot* /data;");
// Merge images
if (merge_img("/cache/magisk.img", MAINIMG))
goto unblock;
if (merge_img("/data/magisk_merge.img", MAINIMG))
goto unblock;
int new_img = 0;
if (access(MAINIMG, F_OK) == -1) {
if (create_img(MAINIMG, 64))
goto unblock;
new_img = 1;
}
// Initialize resetprop for the daemon
init_resetprop();
LOGI("* Mounting " MAINIMG "\n");
// Mounting magisk image
char *magiskloop = mount_image(MAINIMG, MOUNTPOINT);
if (magiskloop == NULL)
goto unblock;
if (new_img) {
mkdir(COREDIR, 0755);
mkdir(COREDIR "/post-fs-data.d", 0755);
mkdir(COREDIR "/service.d", 0755);
mkdir(COREDIR "/props", 0755);
}
// Run common scripts
LOGI("* Running post-fs-data.d scripts\n");
exec_common_script("post-fs-data");
// Core only mode
if (access(DISABLEFILE, F_OK) == 0)
goto unblock;
DIR *dir;
struct dirent *entry;
char *module;
struct node_entry *sys_root, *ven_root = NULL, *child;
dir = xopendir(MOUNTPOINT);
// Create the system root entry
sys_root = xcalloc(sizeof(*sys_root), 1);
sys_root->name = strdup("/system");
int has_modules = 0;
// Travel through each modules
vec_init(&module_list);
LOGI("* Loading modules\n");
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;
snprintf(buf, PATH_MAX, "%s/%s", MOUNTPOINT, entry->d_name);
// Check whether remove
snprintf(buf2, PATH_MAX, "%s/remove", buf);
if (access(buf2, F_OK) == 0) {
rm_rf(buf);
continue;
}
// Check whether disable
snprintf(buf2, PATH_MAX, "%s/disable", buf);
if (access(buf2, F_OK) == 0)
continue;
// Add the module to list
module = strdup(entry->d_name);
vec_push_back(&module_list, module);
// Read props
snprintf(buf2, PATH_MAX, "%s/system.prop", buf);
if (access(buf2, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module);
read_prop_file(buf2, 0);
}
// Check whether enable auto_mount
snprintf(buf2, PATH_MAX, "%s/auto_mount", buf);
if (access(buf2, F_OK) == -1)
continue;
// Double check whether the system folder exists
snprintf(buf2, PATH_MAX, "%s/system", buf);
if (access(buf2, F_OK) == -1)
continue;
// Construct structure
has_modules = 1;
LOGI("%s: constructing magic mount structure\n", module);
construct_tree(module, sys_root);
}
}
closedir(dir);
// Trim image
umount_image(MOUNTPOINT, magiskloop);
free(magiskloop);
trim_img(MAINIMG);
// Remount them back :)
magiskloop = mount_image(MAINIMG, MOUNTPOINT);
free(magiskloop);
if (has_modules) {
// Mount mirrors
LOGI("* Mounting system/vendor mirrors");
int seperate_vendor = 0;
struct vector mounts;
vec_init(&mounts);
file_to_vector("/proc/mounts", &mounts);
char *line;
vec_for_each(&mounts, line) {
if (strstr(line, " /system ")) {
sscanf(line, "%s", buf);
snprintf(buf2, PATH_MAX, "%s/system", MIRRDIR);
xmkdir_p(buf2, 0755);
xmount(buf, buf2, "ext4", MS_RDONLY, NULL);
LOGI("mount: %s -> %s\n", buf, buf2);
continue;
}
if (strstr(line, " /vendor ")) {
seperate_vendor = 1;
sscanf(line, "%s", buf);
snprintf(buf2, PATH_MAX, "%s/vendor", MIRRDIR);
xmkdir_p(buf2, 0755);
xmount(buf, buf2, "ext4", MS_RDONLY, NULL);
LOGI("mount: %s -> %s\n", buf, buf2);
continue;
}
}
vec_deep_destroy(&mounts);
if (!seperate_vendor) {
snprintf(buf, PATH_MAX, "%s/system/vendor", MIRRDIR);
snprintf(buf2, PATH_MAX, "%s/vendor", MIRRDIR);
symlink(buf, buf2);
LOGI("link: %s -> %s\n", buf, buf2);
}
// Magic!!
magic_mount(sys_root);
// Get the vendor node if exists
vec_for_each(sys_root->children, child) {
if (strcmp(child->name, "vendor") == 0) {
ven_root = child;
free(ven_root->name);
ven_root->name = strdup("/vendor");
ven_root->parent = NULL;
break;
}
}
if (ven_root)
magic_mount(ven_root);
}
// Cleanup memory
destroy_subtree(sys_root);
// Execute module scripts
LOGI("* Running module post-fs-data scripts\n");
exec_module_script("post-fs-data");
// Systemless hosts
if (access(HOSTSFILE, F_OK) == 0) {
LOGI("* Enabling systemless hosts file support");
bind_mount(HOSTSFILE, "/system/etc/hosts");
}
// Start magiskhide if enabled
char *hide_prop = getprop(MAGISKHIDE_PROP);
if (hide_prop) {
if (strcmp(hide_prop, "1") == 0) {
pthread_t thread;
xpthread_create(&thread, NULL, start_magisk_hide, NULL);
pthread_detach(thread);
}
free(hide_prop);
}
unblock:
unblock_boot_process();
}
void late_start(int client) {
LOGI("** late_start service mode running\n");
// ack
write_int(client, 0);
close(client);
// Allocate buffer
if (buf == NULL) buf = xmalloc(PATH_MAX);
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
// Wait till the full patch is done
pthread_join(sepol_patch, NULL);
// Run scripts after full patch, most reliable way to run scripts
LOGI("* Running service.d scripts\n");
exec_common_script("service");
LOGI("* Running module service scripts\n");
exec_module_script("service");
// Install Magisk Manager if exists
if (access(MANAGERAPK, F_OK) == 0) {
while(1) {
sleep(5);
char *const command[] = { "sh", "-c",
"CLASSPATH=/system/framework/pm.jar "
"/system/bin/app_process /system/bin "
"com.android.commands.pm.Pm install -r " MANAGERAPK, NULL };
int apk_res = 0, pid;
pid = run_command(1, &apk_res, "/system/bin/sh", command);
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;
}
unlink(MANAGERAPK);
}
// All boot stage done, cleanup everything
free(buf);
free(buf2);
vec_deep_destroy(&module_list);
#ifdef DEBUG
// Stop recording the boot logcat after every boot task is done
extern int debug_log_pid, debug_log_fd;
kill(debug_log_pid, SIGTERM);
waitpid(debug_log_pid, NULL, 0);
close(debug_log_fd);
#endif
}

208
jni/daemon/daemon.c Normal file
View File

@@ -0,0 +1,208 @@
/* 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 <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"
pthread_t sepol_patch;
int null_fd;
static void *request_handler(void *args) {
// Setup the default error handler for threads
err_handler = exit_thread;
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 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 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;
}
// Just in case
close(client);
return NULL;
}
/* Setup the address and return socket fd */
static int setup_socket(struct sockaddr_un *sun) {
int fd = xsocket(AF_LOCAL, SOCK_STREAM, 0);
if (fcntl(fd, F_SETFD, FD_CLOEXEC))
PLOGE("fcntl FD_CLOEXEC");
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_LOCAL;
memcpy(sun->sun_path, REQUESTOR_DAEMON_PATH, REQUESTOR_DAEMON_PATH_LEN);
return fd;
}
static void *large_sepol_patch(void *args) {
LOGD("sepol: Starting large patch thread\n");
// Patch su to everything
sepol_allow("su", ALL, ALL, ALL);
dump_policydb(SELINUX_LOAD);
LOGD("sepol: Large patch done\n");
destroy_policydb();
return NULL;
}
void start_daemon(int client) {
// Launch the daemon, create new session, set proper context
if (getuid() != UID_ROOT || getgid() != UID_ROOT) {
fprintf(stderr, "Starting daemon requires root: %s\n", strerror(errno));
PLOGE("start daemon");
}
switch (fork()) {
case -1:
PLOGE("fork");
case 0:
break;
default:
return;
}
// First close the client, it's useless for us
close(client);
xsetsid();
setcon("u:r:su:s0");
umask(022);
null_fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
xdup2(null_fd, STDIN_FILENO);
xdup2(null_fd, STDOUT_FILENO);
xdup2(null_fd, STDERR_FILENO);
// Patch selinux with medium patch before we do anything
load_policydb(SELINUX_POLICY);
sepol_med_rules();
dump_policydb(SELINUX_LOAD);
// Continue the larger patch in another thread, we will join later
pthread_create(&sepol_patch, NULL, large_sepol_patch, NULL);
struct sockaddr_un sun;
int fd = setup_socket(&sun);
xbind(fd, (struct sockaddr*) &sun, sizeof(sun));
xlisten(fd, 10);
// Change process name
strcpy(argv0, "magisk_daemon");
// The root daemon should not do anything if an error occurs
// It should stay intact under any circumstances
err_handler = do_nothing;
LOGI("Magisk v" xstr(MAGISK_VERSION) " daemon started\n");
// Unlock all blocks for rw
unlock_blocks();
// Setup links under /sbin
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
create_links(NULL, "/sbin");
xchmod("/sbin", 0755);
mkdir("/magisk", 0755);
xchmod("/magisk", 0755);
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
// Loop forever to listen for requests
while(1) {
int *client = xmalloc(sizeof(int));
*client = xaccept(fd, NULL, NULL);
// Just in case, set to close on exec
fcntl(*client, F_SETFD, FD_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);
// LOGD("client: trying to connect socket\n");
if (connect(fd, (struct sockaddr*) &sun, sizeof(sun))) {
/* If we cannot access the daemon, we start the daemon
* since there is no clear entry point when the daemon should be started
*/
LOGD("client: connect fail, try launching new daemon process\n");
start_daemon(fd);
do {
// Wait for 10ms
usleep(10);
} while (connect(fd, (struct sockaddr*) &sun, sizeof(sun)));
}
return fd;
}

79
jni/daemon/daemon.h Normal file
View File

@@ -0,0 +1,79 @@
/* daemon.h - Utility functions for daemon-client communication
*/
#ifndef _DAEMON_H_
#define _DAEMON_H_
#include <pthread.h>
extern pthread_t sepol_patch;
// Commands require connecting to daemon
typedef enum {
DO_NOTHING = 0,
LAUNCH_MAGISKHIDE,
STOP_MAGISKHIDE,
ADD_HIDELIST,
RM_HIDELIST,
SUPERUSER,
CHECK_VERSION,
CHECK_VERSION_CODE,
POST_FS,
POST_FS_DATA,
LATE_START,
TEST
} client_request;
// Return codes for daemon
typedef enum {
DAEMON_ERROR = -1,
DAEMON_SUCCESS = 0,
ROOT_REQUIRED,
HIDE_IS_ENABLED,
HIDE_NOT_ENABLED,
HIDE_ITEM_EXIST,
HIDE_ITEM_NOT_EXIST,
} daemon_response;
// daemon.c
void start_daemon(int client);
int connect_daemon();
// socket_trans.c
int recv_fd(int sockfd);
void send_fd(int sockfd, int fd);
int read_int(int fd);
void write_int(int fd, int val);
char* read_string(int fd);
void write_string(int fd, const char* val);
// log_monitor.c
void monitor_logs();
/***************
* Boot Stages *
***************/
void post_fs(int client);
void post_fs_data(int client);
void late_start(int client);
/**************
* MagiskHide *
**************/
void launch_magiskhide(int client);
void stop_magiskhide(int client);
void add_hide_list(int client);
void rm_hide_list(int client);
/*************
* Superuser *
*************/
void su_daemon_receiver(int client);
#endif

46
jni/daemon/log_monitor.c Normal file
View File

@@ -0,0 +1,46 @@
/* log_monitor.c - New thread to monitor logcat
*
* Open a new thread to call logcat and get logs with tag "Magisk"
* Also, write the logs to a log file for debugging purpose
*
*/
#include <stdio.h>
#include <limits.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include "magisk.h"
#include "utils.h"
#include "daemon.h"
static void *logger_thread(void *args) {
// Setup error handler
err_handler = exit_thread;
rename(LOGFILE, LASTLOG);
int log_fd, log_pid;
log_fd = xopen(LOGFILE, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
while (1) {
// Start logcat
char *const command[] = { "logcat", "-s", "Magisk", "-v", "thread", NULL };
log_pid = run_command(0, &log_fd, "/system/bin/logcat", command);
waitpid(log_pid, NULL, 0);
// For some reason it went here, clear buffer and restart
system("logcat -c");
}
// Should never be here, but well...
close(log_fd);
return NULL;
}
/* Start a new thread to monitor logcat and dump to logfile */
void monitor_logs() {
pthread_t thread;
xpthread_create(&thread, NULL, logger_thread, NULL);
pthread_detach(thread);
}

148
jni/daemon/socket_trans.c Normal file
View File

@@ -0,0 +1,148 @@
/* socket_trans.c - Functions to transfer data through socket
*/
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "magisk.h"
#include "utils.h"
#include "daemon.h"
/*
* 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,148 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include "bootimgtools.h"
void dump(uint8_t *ptr, size_t size, char* filename) {
unlink(filename);
int ofd = open(filename, O_WRONLY|O_CREAT, 0644);
assert(ofd >= 0);
int ret = write(ofd, ptr, size);
assert(ret == size);
close(ofd);
}
//TODO: Search for other header types
void dump_ramdisk(uint8_t *ptr, size_t size) {
//GZip header
if(memcmp(ptr, "\x1f\x8b\x08\x00", 4) == 0) {
dump(ptr, size, "ramdisk.gz");
//MTK header
} else if(memcmp(ptr, "\x88\x16\x88\x58", 4) == 0) {
if(memcmp(ptr+4, "RECOVERY", 8)==0) {
dump(ptr, 0, "ramdisk-mtk-recovery");
} else if(memcmp(ptr+4, "ROOTFS\0\0", 8)==0) {
dump(ptr, 0, "ramdisk-mtk-boot");
} else {
exit(1);
}
dump(ptr, 0, "ramdisk-mtk"); //Create an mtk flag
dump_ramdisk(ptr+512, size-512);
} else {
//Since our first aim is to extract/repack ramdisk
//Stop if we can't find it
//Still dump it for debug purposes
dump(ptr, size, "ramdisk");
fprintf(stderr, "Unknown ramdisk type\n");
abort();
}
}
void search_security_hdr(uint8_t *buf, size_t size) {
if(memcmp(buf, "CHROMEOS", 8) == 0) {
dump(buf, 0, "chromeos");
return;
}
}
int search_security(uint8_t *buf, size_t size, int pos) {
//Rockchip signature
if(memcmp(buf+1024, "SIGN", 4) == 0) {
//Rockchip signature AT LEAST means the bootloader will check the crc
dump(buf, 0, "rkcrc"); //Create an flag to tell it
//And it's possible there is a security too
return 1;
}
//If we didn't parse the whole file, it is highly likely there is a boot signature
if(pos < size) {
return 1;
}
return 0;
}
/*
* TODO:
* - At the moment we dump kernel + ramdisk + second + DT, it's likely we only want ramdisk
* - Error-handling via assert() is perhaps not the best
*/
int extract(char *image) {
int fd = open(image, O_RDONLY);
off_t size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
uint8_t *orig = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
uint8_t *base = orig;
assert(base);
search_security_hdr(base, size);
//We're searching for the header in the whole file, we could stop earlier.
//At least HTC and nVidia have a signature header
while(base<(orig+size)) {
if(memcmp(base, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0)
break;
//We're searching every 256bytes, is it ok?
base += 256;
}
assert(base < (orig+size));
struct boot_img_hdr *hdr = (struct boot_img_hdr*) base;
assert(
hdr->page_size == 2048 ||
hdr->page_size == 4096 ||
hdr->page_size == 16384
);
long pos = hdr->page_size;
dump(base+pos, hdr->kernel_size, "kernel");
pos += hdr->kernel_size + hdr->page_size-1;
pos &= ~(hdr->page_size-1L);
dump_ramdisk(base+pos, hdr->ramdisk_size);
pos += hdr->ramdisk_size + hdr->page_size-1;
pos &= ~(hdr->page_size-1L);
if(hdr->second_size) {
assert( (pos+hdr->second_size) <= size);
dump(base+pos, hdr->second_size, "second");
pos += hdr->second_size + hdr->page_size-1;
pos &= ~(hdr->page_size-1L);
}
//This is non-standard, so we triple check
if( hdr->unused[0] &&
pos < size &&
(pos+hdr->unused[0]) <= size) {
if(memcmp(base+pos, "QCDT", 4) == 0 ||
memcmp(base+pos, "SPRD", 4) == 0 ||
memcmp(base+pos, "DTBH", 4) == 0
) {
dump(base+pos, hdr->unused[0], "dt");
pos += hdr->unused[0] + hdr->page_size-1;
pos &= ~(hdr->page_size-1L);
}
}
//If we think we find some security-related infos in the boot.img
//create a "secure" flag to warn the user it is dangerous
if(search_security(base, size, pos)) {
dump(base, 0, "secure");
}
munmap(orig, size);
close(fd);
return 0;
}

View File

@@ -1,66 +0,0 @@
#include <getopt.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include "bootimgtools.h"
int hex2int(char c) {
int first = c / 16 - 3;
int second = c % 16;
int result = first * 10 + second;
if(result > 9) result--;
return result;
}
int hex2ascii(char c, char d) {
int high = hex2int(c) * 16;
int low = hex2int(d);
return high+low;
}
void hexstr2str(char *hex, char *str) {
char buf = 0;
for(int i = 0, length = strlen(hex); i < length; ++i){
if(i % 2){
str[i / 2] = hex2ascii(buf, hex[i]);
} else{
buf = hex[i];
}
}
}
int hexpatch(char * image, char *from, char *to) {
int fd = open(image, O_RDWR), patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
off_t filesize = lseek(fd, 0, SEEK_END);
char *file, *pattern, *patch, *start;
file = malloc(sizeof (char) * filesize);
pattern = malloc(sizeof (char) * patternsize);
patch = malloc(sizeof (char) * patchsize);
lseek(fd, 0, SEEK_SET);
read(fd, file, filesize);
hexstr2str(from, pattern);
hexstr2str(to, patch);
for (off_t i = 0; i < filesize;) {
int j;
for (j = 0; j < patternsize; ++j) {
if(file[i + j] != pattern[j]) break;
}
if (j == patternsize) {
fprintf(stderr, "Pattern %s found!\nPatching to %s\n", from, to);
lseek(fd, i, SEEK_SET);
write(fd, patch, patchsize);
}
if(j == 0) j = 1;
i += j;
}
free(file);
free(pattern);
free(patch);
close(fd);
return 0;
}

93
jni/magisk.h Normal file
View File

@@ -0,0 +1,93 @@
/* magisk.h - Top header
*/
#ifndef _MAGISK_H_
#define _MAGISK_H_
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <android/log.h>
#define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK"
#define str(a) #a
#define xstr(a) str(a)
#define REQUESTOR_DAEMON_PATH "\0MAGISK"
#define REQUESTOR_DAEMON_PATH_LEN 7
#define LOG_TAG "Magisk"
#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 DISABLEFILE "/cache/.disable_magisk"
#define UNINSTALLER "/cache/magisk_uninstaller.sh"
#define MOUNTPOINT "/magisk"
#define COREDIR MOUNTPOINT "/.core"
#define HOSTSFILE COREDIR "/hosts"
#define HIDELIST COREDIR "/hidelist"
#define MAINIMG "/data/magisk.img"
#define DATABIN "/data/magisk"
#define MANAGERAPK DATABIN "/magisk.apk"
#define MAGISKTMP "/dev/magisk"
#define MIRRDIR MAGISKTMP "/mirror"
#define DUMMDIR MAGISKTMP "/dummy"
#define CACHEMOUNT "/cache/magisk_mount"
#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"
// Global handler for PLOGE
extern __thread void (*err_handler)(void);
// Common error handlers
static inline void exit_proc() { exit(1); }
static inline void exit_thread() { pthread_exit(NULL); }
static inline void do_nothing() {}
// Dummy function to depress debug message
static inline void stub(const char *fmt, ...) {}
#ifdef DEBUG
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#else
#define LOGD(...) stub(__VA_ARGS__)
#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)); err_handler(); }
extern char *argv0; /* For changing process name */
extern char *applet[];
extern int (*applet_main[]) (int, char *[]);
extern int null_fd;
// 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

31
jni/magiskboot/Android.mk Normal file
View File

@@ -0,0 +1,31 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := magiskboot
LOCAL_STATIC_LIBRARIES := libz liblzma liblz4 libbz2
LOCAL_C_INCLUDES := \
jni/utils \
jni/ndk-compression/zlib/ \
jni/ndk-compression/xz/src/liblzma/api/ \
jni/ndk-compression/lz4/lib/ \
jni/ndk-compression/bzip2/
LOCAL_SRC_FILES := \
main.c \
unpack.c \
repack.c \
hexpatch.c \
parseimg.c \
compress.c \
utils.c \
cpio.c \
sha1.c \
../utils/xwrap.c \
../utils/vector.c
LOCAL_CFLAGS += -DZLIB_CONST
include $(BUILD_EXECUTABLE)
include jni/ndk-compression/zlib/Android.mk
include jni/ndk-compression/xz/src/liblzma/Android.mk
include jni/ndk-compression/lz4/lib/Android.mk
include jni/ndk-compression/bzip2/Android.mk

View File

@@ -43,7 +43,14 @@ struct boot_img_hdr
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
uint32_t unused[2]; /* future expansion: should be 0 */
uint32_t dt_size; /* device tree 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 */
@@ -66,10 +73,13 @@ struct boot_img_hdr
** +-----------------+
** | second stage | o pages
** +-----------------+
** | device tree | 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 = (dt_size + page_size - 1) / page_size
**
** 0. all entities are page_size aligned in flash
** 1. kernel and ramdisk are required (size != 0)
@@ -83,8 +93,10 @@ struct boot_img_hdr
** else: jump to kernel_addr
*/
int extract(char *image);
int repack(char *image);
int hexpatch(char *image, char *from, char *to);
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;
#endif

569
jni/magiskboot/compress.c Normal file
View File

@@ -0,0 +1,569 @@
#include <zlib.h>
#include <lzma.h>
#include <lz4.h>
#include <lz4frame.h>
#include <bzlib.h>
#include "magiskboot.h"
#define windowBits 15
#define ZLIB_GZIP 16
#define memLevel 8
#define CHUNK 0x40000
#define LZ4_HEADER_SIZE 19
#define LZ4_FOOTER_SIZE 4
#define LZ4_LEGACY_BLOCKSIZE 0x800000
static void write_file(const int fd, const void *buf, const size_t size, const char *filename) {
xwrite(fd, buf, size);
}
static void report(const int mode, const char* filename) {
switch(mode) {
case 0:
printf("Decompressing to [%s]\n\n", filename);
break;
default:
printf("Compressing to [%s]\n\n", filename);
break;
}
}
// Mode: 0 = decode; 1 = encode
void gzip(int mode, const char* filename, const unsigned char* buf, size_t size) {
size_t ret = 0, flush, have, pos = 0;
z_stream strm;
unsigned char out[CHUNK];
report(mode, filename);
int fd = open_new(filename);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
switch(mode) {
case 0:
ret = inflateInit2(&strm, windowBits | ZLIB_GZIP);
break;
case 1:
ret = deflateInit2(&strm, 9, Z_DEFLATED, windowBits | ZLIB_GZIP, memLevel, Z_DEFAULT_STRATEGY);
break;
default:
LOGE(1, "Unsupported gzip mode!\n");
}
if (ret != Z_OK)
LOGE(1, "Unable to init zlib stream\n");
do {
strm.next_in = buf + pos;
if (pos + CHUNK >= size) {
strm.avail_in = size - pos;
flush = Z_FINISH;
} else {
strm.avail_in = CHUNK;
flush = Z_NO_FLUSH;
}
pos += strm.avail_in;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
switch(mode) {
case 0:
ret = inflate(&strm, flush);
break;
case 1:
ret = deflate(&strm, flush);
break;
}
if (ret == Z_STREAM_ERROR)
LOGE(1, "Error when running gzip\n");
have = CHUNK - strm.avail_out;
write_file(fd, out, have, filename);
} while (strm.avail_out == 0);
} while(pos < size);
switch(mode) {
case 0:
inflateEnd(&strm);
break;
case 1:
deflateEnd(&strm);
break;
}
close(fd);
}
// Mode: 0 = decode xz/lzma; 1 = encode xz; 2 = encode lzma
void lzma(int mode, const char* filename, const unsigned char* buf, size_t size) {
size_t have, pos = 0;
lzma_ret ret = 0;
lzma_stream strm = LZMA_STREAM_INIT;
lzma_options_lzma opt;
lzma_action action;
unsigned char out[BUFSIZ];
report(mode, filename);
int fd = open_new(filename);
// Initialize preset
lzma_lzma_preset(&opt, LZMA_PRESET_DEFAULT);
lzma_filter filters[] = {
{ .id = LZMA_FILTER_LZMA2, .options = &opt },
{ .id = LZMA_VLI_UNKNOWN, .options = NULL },
};
switch(mode) {
case 0:
ret = lzma_auto_decoder(&strm, UINT64_MAX, 0);
break;
case 1:
ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC64);
break;
case 2:
ret = lzma_alone_encoder(&strm, &opt);
break;
default:
LOGE(1, "Unsupported lzma mode!\n");
}
if (ret != LZMA_OK)
LOGE(1, "Unable to init lzma stream\n");
do {
strm.next_in = buf + pos;
if (pos + BUFSIZ >= size) {
strm.avail_in = size - pos;
action = LZMA_FINISH;
} else {
strm.avail_in = BUFSIZ;
action = LZMA_RUN;
}
pos += strm.avail_in;
do {
strm.avail_out = BUFSIZ;
strm.next_out = out;
ret = lzma_code(&strm, action);
have = BUFSIZ - strm.avail_out;
write_file(fd, out, have, filename);
} while (strm.avail_out == 0 && ret == LZMA_OK);
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
LOGE(1, "LZMA error %d!\n", ret);
} while (pos < size);
lzma_end(&strm);
close(fd);
}
// Mode: 0 = decode; 1 = encode
void lz4(int mode, const char* filename, const unsigned char* buf, size_t size) {
LZ4F_decompressionContext_t dctx;
LZ4F_compressionContext_t cctx;
LZ4F_frameInfo_t info;
size_t outCapacity, avail_in, ret = 0, pos = 0;
size_t have, read;
unsigned char *out = NULL;
report(mode, filename);
int fd = open_new(filename);
// Initialize context
switch(mode) {
case 0:
ret = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
break;
case 1:
ret = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
break;
default:
LOGE(1, "Unsupported lz4 mode!\n");
}
if (LZ4F_isError(ret))
LOGE(1, "Context creation error: %s\n", LZ4F_getErrorName(ret));
// Allocate out buffer
switch(mode) {
case 0:
// Read header
read = CHUNK;
ret = LZ4F_getFrameInfo(dctx, &info, buf, &read);
if (LZ4F_isError(ret))
LOGE(1, "LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(ret));
switch (info.blockSizeID) {
case LZ4F_default:
case LZ4F_max64KB: outCapacity = 1 << 16; break;
case LZ4F_max256KB: outCapacity = 1 << 18; break;
case LZ4F_max1MB: outCapacity = 1 << 20; break;
case LZ4F_max4MB: outCapacity = 1 << 22; break;
default:
LOGE(1, "Impossible unless more block sizes are allowed\n");
}
pos += read;
break;
case 1:
outCapacity = LZ4F_compressBound(CHUNK, NULL) + LZ4_HEADER_SIZE + LZ4_FOOTER_SIZE;
break;
}
out = xmalloc(outCapacity);
// Write header
if (mode == 1) {
have = ret = LZ4F_compressBegin(cctx, out, size, NULL);
if (LZ4F_isError(ret))
LOGE(1, "Failed to start compression: error %s\n", LZ4F_getErrorName(ret));
write_file(fd, out, have, filename);
}
do {
if (pos + CHUNK >= size) {
avail_in = size - pos;
} else {
avail_in = CHUNK;
}
do {
switch(mode) {
case 0:
have = outCapacity, read = avail_in;
ret = LZ4F_decompress(dctx, out, &have, buf + pos, &read, NULL);
break;
case 1:
read = avail_in;
have = ret = LZ4F_compressUpdate(cctx, out, outCapacity, buf + pos, avail_in, NULL);
break;
}
if (LZ4F_isError(ret))
LOGE(1, "LZ4 coding error: %s\n", LZ4F_getErrorName(ret));
write_file(fd, out, have, filename);
// Update status
pos += read;
avail_in -= read;
} while(avail_in != 0 && ret != 0);
} while(pos < size && ret != 0);
switch(mode) {
case 0:
LZ4F_freeDecompressionContext(dctx);
break;
case 1:
have = ret = LZ4F_compressEnd(cctx, out, outCapacity, NULL);
if (LZ4F_isError(ret))
LOGE(1, "Failed to end compression: error %s\n", LZ4F_getErrorName(ret));
write_file(fd, out, have, filename);
LZ4F_freeCompressionContext(cctx);
break;
}
free(out);
close(fd);
}
// Mode: 0 = decode; 1 = encode
void bzip2(int mode, const char* filename, const unsigned char* buf, size_t size) {
size_t ret = 0, action, have, pos = 0;
bz_stream strm;
char out[CHUNK];
report(mode, filename);
int fd = open_new(filename);
strm.bzalloc = NULL;
strm.bzfree = NULL;
strm.opaque = NULL;
switch(mode) {
case 0:
ret = BZ2_bzDecompressInit(&strm, 0, 0);
break;
case 1:
ret = BZ2_bzCompressInit(&strm, 9, 0, 0);
break;
default:
LOGE(1, "Unsupported bzip2 mode!\n");
}
if (ret != BZ_OK)
LOGE(1, "Unable to init bzlib stream\n");
do {
strm.next_in = (char *) buf + pos;
if (pos + CHUNK >= size) {
strm.avail_in = size - pos;
action = BZ_FINISH;
} else {
strm.avail_in = CHUNK;
action = BZ_RUN;
}
pos += strm.avail_in;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
switch(mode) {
case 0:
ret = BZ2_bzDecompress(&strm);
break;
case 1:
ret = BZ2_bzCompress(&strm, action);
break;
}
have = CHUNK - strm.avail_out;
write_file(fd, out, have, filename);
} while (strm.avail_out == 0);
} while(pos < size);
switch(mode) {
case 0:
BZ2_bzDecompressEnd(&strm);
break;
case 1:
BZ2_bzCompressEnd(&strm);
break;
}
close(fd);
}
// Mode: 0 = decode; 1 = encode
void lz4_legacy(int mode, const char* filename, const unsigned char* buf, size_t size) {
size_t pos = 0;
int have;
char *out;
unsigned block_size, insize;
unsigned char block_size_le[4];
report(mode, filename);
int fd = open_new(filename);
switch(mode) {
case 0:
out = xmalloc(LZ4_LEGACY_BLOCKSIZE);
// Skip magic
pos += 4;
break;
case 1:
out = xmalloc(LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE));
// Write magic
write_file(fd, "\x02\x21\x4c\x18", 4, filename);
break;
default:
LOGE(1, "Unsupported lz4_legacy mode!\n");
}
do {
switch(mode) {
case 0:
block_size = buf[pos];
block_size += (buf[pos + 1]<<8);
block_size += (buf[pos + 2]<<16);
block_size += ((unsigned)buf[pos + 3])<<24;
pos += 4;
if (block_size > LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE))
LOGE(1, "lz4_legacy block size too large!\n");
have = LZ4_decompress_safe((const char*) (buf + pos), out, block_size, LZ4_LEGACY_BLOCKSIZE);
if (have < 0)
LOGE(1, "Cannot decode lz4_legacy block\n");
pos += block_size;
break;
case 1:
if (pos + LZ4_LEGACY_BLOCKSIZE >= size)
insize = size - pos;
else
insize = LZ4_LEGACY_BLOCKSIZE;
have = LZ4_compress_default((const char*) (buf + pos), out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE));
if (have == 0)
LOGE(1, "lz4_legacy compression error\n");
pos += insize;
block_size_le[0] = (unsigned char)have;
block_size_le[1] = (unsigned char)(have >> 8);
block_size_le[2] = (unsigned char)(have >> 16);
block_size_le[3] = (unsigned char)(have >> 24);
write_file(fd, block_size_le, 4, filename);
break;
}
// Write main data
write_file(fd, out, have, filename);
} while(pos < size);
free(out);
close(fd);
}
int decomp(file_t type, const char *to, const unsigned char *from, size_t size) {
switch (type) {
case GZIP:
gzip(0, to, from, size);
break;
case XZ:
lzma(0, to, from, size);
break;
case LZMA:
lzma(0, to, from, size);
break;
case BZIP2:
bzip2(0, to, from, size);
break;
case LZ4:
lz4(0, to, from, size);
break;
case LZ4_LEGACY:
lz4_legacy(0, to, from, size);
break;
default:
// Unsupported
return 1;
}
return 0;
}
// Output will be to.ext
int comp(file_t type, const char *to, const unsigned char *from, size_t size) {
char name[PATH_MAX];
const char *ext = strrchr(to, '.');
if (ext == NULL) ext = to;
strcpy(name, to);
switch (type) {
case GZIP:
if (strcmp(ext, ".gz") != 0)
sprintf(name, "%s.%s", to, "gz");
gzip(1, name, from, size);
break;
case XZ:
if (strcmp(ext, ".xz") != 0)
sprintf(name, "%s.%s", to, "xz");
lzma(1, name, from, size);
break;
case LZMA:
if (strcmp(ext, ".lzma") != 0)
sprintf(name, "%s.%s", to, "lzma");
lzma(2, name, from, size);
break;
case BZIP2:
if (strcmp(ext, ".bz2") != 0)
sprintf(name, "%s.%s", to, "bz2");
bzip2(1, name, from, size);
break;
case LZ4:
if (strcmp(ext, ".lz4") != 0)
sprintf(name, "%s.%s", to, "lz4");
lz4(1, name, from, size);
break;
case LZ4_LEGACY:
if (strcmp(ext, ".lz4") != 0)
sprintf(name, "%s.%s", to, "lz4");
lz4_legacy(1, name, from, size);
break;
default:
// Unsupported
return 1;
}
return 0;
}
void decomp_file(char *from, const char *to) {
int ok = 1;
unsigned char *file;
size_t size;
mmap_ro(from, &file, &size);
file_t type = check_type(file);
char *ext;
ext = strrchr(from, '.');
if (ext == NULL)
LOGE(1, "Bad filename extention\n");
// File type and extension should match
switch (type) {
case GZIP:
if (strcmp(ext, ".gz") != 0)
ok = 0;
break;
case XZ:
if (strcmp(ext, ".xz") != 0)
ok = 0;
break;
case LZMA:
if (strcmp(ext, ".lzma") != 0)
ok = 0;
break;
case BZIP2:
if (strcmp(ext, ".bz2") != 0)
ok = 0;
break;
case LZ4_LEGACY:
case LZ4:
if (strcmp(ext, ".lz4") != 0)
ok = 0;
break;
default:
LOGE(1, "Provided file \'%s\' is not a supported archive format\n", from);
}
if (ok) {
// If all match, strip out the suffix
if (!to) {
*ext = '\0';
to = from;
}
decomp(type, to, file, size);
if (to == from) {
*ext = '.';
unlink(from);
}
} else {
LOGE(1, "Bad filename extention \'%s\'\n", ext);
}
munmap(file, size);
}
void comp_file(const char *method, const char *from, const char *to) {
file_t type;
if (strcmp(method, "gzip") == 0) {
type = GZIP;
} else if (strcmp(method, "xz") == 0) {
type = XZ;
} else if (strcmp(method, "lzma") == 0) {
type = LZMA;
} else if (strcmp(method, "lz4") == 0) {
type = LZ4;
} else if (strcmp(method, "lz4_legacy") == 0) {
type = LZ4_LEGACY;
} else if (strcmp(method, "bzip2") == 0) {
type = BZIP2;
} else {
fprintf(stderr, "Only support following methods: ");
for (int i = 0; SUP_LIST[i]; ++i)
fprintf(stderr, "%s ", SUP_LIST[i]);
fprintf(stderr, "\n");
exit(1);
}
unsigned char *file;
size_t size;
mmap_ro(from, &file, &size);
if (!to)
to = from;
comp(type, to, file, size);
munmap(file, size);
if (to == from)
unlink(from);
}

480
jni/magiskboot/cpio.c Normal file
View File

@@ -0,0 +1,480 @@
#include "magiskboot.h"
#include "cpio.h"
#include "vector.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(1, "bad cpio header\n");
return val;
}
static void cpio_free(cpio_file *f) {
if (f) {
free(f->filename);
free(f->data);
free(f);
}
}
static void cpio_vec_insert(struct vector *v, cpio_file *n) {
cpio_file *f, *t;
int shift = 0;
// Insert in alphabet order
vec_for_each(v, f) {
if (shift) {
vec_entry(v)[_] = t;
t = f;
continue;
}
t = f;
if (strcmp(f->filename, n->filename) == 0) {
// Replace, then all is done
cpio_free(f);
vec_entry(v)[_] = n;
return;
} else if (strcmp(f->filename, n->filename) > 0) {
// Insert, then start shifting
vec_entry(v)[_] = n;
t = f;
shift = 1;
}
}
if (shift)
vec_push_back(v, t);
else
vec_push_back(v, n);
}
static int cpio_compare(const void *a, const void *b) {
return strcmp((*(cpio_file **) a)->filename, (*(cpio_file **) b)->filename);
}
// Parse cpio file to a vector of cpio_file
static void parse_cpio(const char *filename, struct vector *v) {
printf("Loading cpio: [%s]\n\n", filename);
int fd = xopen(filename, O_RDONLY);
cpio_newc_header header;
cpio_file *f;
while(read(fd, &header, 110) == 110) {
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 = malloc(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);
// Sort by name
vec_sort(v, cpio_compare);
}
static void dump_cpio(const char *filename, struct vector *v) {
printf("\nDump cpio: [%s]\n\n", filename);
int fd = open_new(filename);
unsigned inode = 300000;
char header[111];
cpio_file *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_file
cpio_file *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_file *f;
vec_for_each(v, f) {
if ((recursive && strncmp(f->filename, entry, strlen(entry)) == 0)
|| (strcmp(f->filename, entry) == 0) ) {
if (!f->remove) {
printf("Remove [%s]\n", entry);
f->remove = 1;
}
if (!recursive) return;
}
}
}
static void cpio_mkdir(mode_t mode, const char *entry, struct vector *v) {
cpio_file *f = xcalloc(sizeof(*f), 1);
f->mode = S_IFDIR | mode;
f->namesize = strlen(entry) + 1;
f->filename = xmalloc(f->namesize);
memcpy(f->filename, entry, f->namesize);
cpio_vec_insert(v, f);
printf("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_file *f = xcalloc(sizeof(*f), 1);
f->mode = S_IFREG | mode;
f->namesize = strlen(entry) + 1;
f->filename = xmalloc(f->namesize);
memcpy(f->filename, entry, f->namesize);
f->filesize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
f->data = malloc(f->filesize);
xxread(fd, f->data, f->filesize);
close(fd);
cpio_vec_insert(v, f);
printf("Add entry [%s] (%04o)\n", entry, mode);
}
static void cpio_test(struct vector *v) {
#define MAGISK_PATCH 0x1
#define OTHER_PATCH 0x2
int ret = 0;
cpio_file *f;
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "init.supersu.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;
}
if (strcmp(f->filename, "init.magisk.rc") == 0)
ret |= MAGISK_PATCH;
}
cpio_vec_destroy(v);
exit((ret & OTHER_PATCH) ? OTHER_PATCH : (ret & MAGISK_PATCH));
}
static int check_verity_pattern(const char *s) {
int pos = 0;
if (s[0] == ',') ++pos;
if (strncmp(s + pos, "verify", 6) != 0) return -1;
pos += 6;
if (s[pos] == '=') {
while (s[pos] != ' ' && s[pos] != '\n' && s[pos] != ',') ++pos;
}
return pos;
}
static void cpio_dmverity(struct vector *v) {
cpio_file *f;
size_t read, write;
int skip;
vec_for_each(v, f) {
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
for (read = 0, write = 0; read < f->filesize; ++read, ++write) {
skip = check_verity_pattern(f->data + read);
if (skip > 0) {
printf("Remove pattern [%.*s] in [%s]\n", (int) 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) {
f->remove = 1;
break;
}
}
}
static void cpio_forceencrypt(struct vector *v) {
cpio_file *f;
size_t read, write;
const char *ENCRYPT_LIST[] = { "forceencrypt", "forcefdeorfbe", "fileencryptioninline", NULL };
vec_for_each(v, f) {
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
for (read = 0, write = 0; read < f->filesize; ++read, ++write) {
for (int i = 0 ; ENCRYPT_LIST[i]; ++i) {
if (strncmp(f->data + read, ENCRYPT_LIST[i], strlen(ENCRYPT_LIST[i])) == 0) {
memcpy(f->data + write, "encryptable", 11);
printf("Replace [%s] with [%s] in [%s]\n", ENCRYPT_LIST[i], "encryptable", f->filename);
write += 11;
read += strlen(ENCRYPT_LIST[i]);
break;
}
}
f->data[write] = f->data[read];
}
f->filesize = write;
}
}
}
static void cpio_extract(const char *entry, const char *filename, struct vector *v) {
cpio_file *f;
vec_for_each(v, f) {
if (strcmp(f->filename, entry) == 0 && S_ISREG(f->mode)) {
printf("Extracting [%s] to [%s]\n\n", entry, filename);
int fd = open_new(filename);
xwrite(fd, f->data, f->filesize);
fchmod(fd, f->mode);
fchown(fd, f->uid, f->gid);
close(fd);
exit(0);
}
}
LOGE(1, "Cannot find the file entry [%s]\n", entry);
}
static void cpio_backup(const char *orig, struct vector *v) {
struct vector o_body, *o = &o_body, bak;
cpio_file *m, *n, *dir, *rem;
char buf[PATH_MAX];
int res, doBak;
dir = xcalloc(sizeof(*dir), 1);
rem = xcalloc(sizeof(*rem), 1);
vec_init(o);
vec_init(&bak);
// First push back the directory and the rmlist
vec_push_back(&bak, dir);
vec_push_back(&bak, rem);
parse_cpio(orig, o);
// Remove possible backups in original ramdisk
cpio_rm(1, ".backup", o);
cpio_rm(1, ".backup", v);
// Init the directory and rmlist
dir->filename = strdup(".backup");
dir->namesize = strlen(dir->filename) + 1;
dir->mode = S_IFDIR;
rem->filename = strdup(".backup/.rmlist");
rem->namesize = strlen(rem->filename) + 1;
rem->mode = S_IFREG;
// 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;
printf("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;
printf("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;
printf("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);
printf("[%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);
}
// Don't include if empty
if (rem->filesize == 0) {
rem->remove = 1;
if (bak.size == 2)
dir->remove = 1;
}
// Sort
vec_sort(v, cpio_compare);
// Cleanup
cpio_vec_destroy(o);
}
static int cpio_restore(struct vector *v) {
cpio_file *f, *n;
int ret = 1;
vec_for_each(v, f) {
if (strstr(f->filename, ".backup") != NULL) {
ret = 0;
f->remove = 1;
if (strcmp(f->filename, ".backup") == 0) continue;
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;
}
n = xcalloc(sizeof(*n), 1);
memcpy(n, f, sizeof(*f));
n->namesize -= 8;
n->filename = xmalloc(n->namesize);
memcpy(n->filename, f->filename + 8, n->namesize);
n->data = xmalloc(n->filesize);
memcpy(n->data, f->data, n->filesize);
n->remove = 0;
printf("Restoring [%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;
}
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, "patch-dmverity") == 0) {
cmd = DMVERITY;
} else if (strcmp(command, "patch-forceencrypt") == 0) {
cmd = FORCEENCRYPT;
} else if (strcmp(command, "restore") == 0) {
cmd = RESTORE;
} 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, "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;
return 1;
}
struct vector v;
vec_init(&v);
parse_cpio(incpio, &v);
switch(cmd) {
case TEST:
cpio_test(&v);
break;
case DMVERITY:
cpio_dmverity(&v);
break;
case FORCEENCRYPT:
cpio_forceencrypt(&v);
break;
case RESTORE:
ret = cpio_restore(&v);
break;
case BACKUP:
cpio_backup(argv[0], &v);
case RM:
cpio_rm(recursive, argv[0], &v);
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;
default:
// Never happen
break;
}
dump_cpio(incpio, &v);
cpio_vec_destroy(&v);
exit(ret);
}

42
jni/magiskboot/cpio.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef _CPIO_H_
#define _CPIO_H_
#include <stdint.h>
typedef struct cpio_file {
// 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_file;
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;
#endif

32
jni/magiskboot/hexpatch.c Normal file
View File

@@ -0,0 +1,32 @@
#include "magiskboot.h"
static void hex2byte(const char *hex, unsigned char *str) {
char high, low;
for (int i = 0, length = strlen(hex); i < length; i += 2) {
high = toupper(hex[i]) - '0';
low = toupper(hex[i + 1]) - '0';
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
}
}
void hexpatch(const char *image, const char *from, const char *to) {
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
size_t filesize;
unsigned char *file, *pattern, *patch;
mmap_rw(image, &file, &filesize);
pattern = xmalloc(patternsize);
patch = xmalloc(patchsize);
hex2byte(from, pattern);
hex2byte(to, patch);
for (size_t i = 0; i < filesize - patternsize; ++i) {
if (memcmp(file + i, pattern, patternsize) == 0) {
printf("Pattern %s found!\nPatching to %s\n", from, to);
memset(file + i, 0, patternsize);
memcpy(file + i, patch, patchsize);
i += patternsize - 1;
}
}
munmap(file, filesize);
free(pattern);
free(patch);
}

10
jni/magiskboot/magisk.h Normal file
View File

@@ -0,0 +1,10 @@
/* magisk.h - Let MagiskBoot use the same error handling API as main magisk program
*/
#ifndef _MAGISK_H_
#define _MAGISK_H_
#define LOGE(err, ...) { fprintf(stderr, __VA_ARGS__); exit(err); }
#define PLOGE(fmt, args...) { fprintf(stderr, fmt " failed with %d: %s\n\n", ##args, errno, strerror(errno)); exit(1); }
#endif

101
jni/magiskboot/magiskboot.h Normal file
View File

@@ -0,0 +1,101 @@
#ifndef _MAGISKBOOT_H_
#define _MAGISKBOOT_H_
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include "bootimg.h"
#include "sha1.h"
#include "magisk.h"
#include "utils.h"
#define CHROMEOS_MAGIC "CHROMEOS"
#define ELF32_MAGIC "\x7f""ELF\x01"
#define ELF64_MAGIC "\x7f""ELF\x02"
#define KERNEL_FILE "kernel"
#define RAMDISK_FILE "ramdisk.cpio"
#define SECOND_FILE "second"
#define DTB_FILE "dtb"
#define NEW_BOOT "new-boot.img"
#define str(a) #a
#define xstr(a) str(a)
typedef enum {
UNKNOWN,
CHROMEOS,
AOSP,
ELF32,
ELF64,
GZIP,
LZOP,
XZ,
LZMA,
BZIP2,
LZ4,
LZ4_LEGACY,
MTK
} file_t;
typedef enum {
NONE,
RM,
MKDIR,
ADD,
EXTRACT,
TEST,
DMVERITY,
FORCEENCRYPT,
BACKUP,
RESTORE
} command_t;
extern char *SUP_LIST[];
extern char *SUP_EXT_LIST[];
extern file_t SUP_TYPE_LIST[];
// Global variables
extern unsigned char *kernel, *ramdisk, *second, *dtb, *extra;
extern boot_img_hdr hdr;
extern file_t ramdisk_type;
extern int mtk_kernel, mtk_ramdisk;
// Main entries
void unpack(const char *image);
void repack(const char* orig_image, const char* out_image);
void hexpatch(const char *image, const char *from, const char *to);
void parse_img(unsigned char *orig, size_t size);
int cpio_commands(const char *command, int argc, char *argv[]);
void cleanup();
// Compressions
void gzip(int mode, const char* filename, const unsigned char* buf, size_t size);
void lzma(int mode, const char* filename, const unsigned char* buf, size_t size);
void lz4(int mode, const char* filename, const unsigned char* buf, size_t size);
void bzip2(int mode, const char* filename, const unsigned char* buf, size_t size);
void lz4_legacy(int mode, const char* filename, const unsigned char* buf, size_t size);
int comp(file_t type, const char *to, const unsigned char *from, size_t size);
void comp_file(const char *method, const char *from, const char *to);
int decomp(file_t type, const char *to, const unsigned char *from, size_t size);
void decomp_file(char *from, const char *to);
// Utils
void mmap_ro(const char *filename, unsigned char **buf, size_t *size);
void mmap_rw(const char *filename, unsigned char **buf, size_t *size);
file_t check_type(const unsigned char *buf);
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);
int open_new(const char *filename);
void print_info();
#endif

100
jni/magiskboot/main.c Normal file
View File

@@ -0,0 +1,100 @@
#include "magiskboot.h"
/********************
Patch Boot Image
*********************/
static void usage(char *arg0) {
fprintf(stderr,
"%s --unpack <bootimg>\n"
" Unpack <bootimg> to kernel, ramdisk.cpio, (second), (dtb) into the\n current directory\n"
"\n"
"%s --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"
"%s --hexpatch <file> <hexpattern1> <hexpattern2>\n"
" Search <hexpattern1> in <file>, and replace with <hexpattern2>\n"
"\n"
"%s --cpio-<cmd> <incpio> [flags...] [params...]\n"
" Do cpio related cmds to <incpio> (modifications are done directly)\n Supported commands:\n"
" --cpio-rm <incpio> [-r] <entry>\n Remove entry from cpio, flag -r to remove recursively\n"
" --cpio-mkdir <incpio> <mode> <entry>\n Create directory as an <entry>\n"
" --cpio-add <incpio> <mode> <entry> <infile>\n Add <infile> as an <entry>; replaces <entry> if already exists\n"
" --cpio-extract <incpio> <entry> <outfile>\n Extract <entry> to <outfile>\n"
" --cpio-test <incpio>\n Return value: 0/not patched 1/Magisk 2/SuperSU\n"
" --cpio-patch-dmverity <incpio>\n Remove dm-verity\n"
" --cpio-patch-forceencrypt <incpio>\n Change forceencrypt flag to encryptable\n"
" --cpio-backup <incpio> <origcpio>\n Create ramdisk backups into <incpio> from <origcpio>\n"
" --cpio-restore <incpio>\n Restore ramdisk from ramdisk backup within <incpio>\n"
"\n"
"%s --compress[=method] <infile> [outfile]\n"
" Compress <infile> with [method] (default: gzip), optionally to [outfile]\n Supported methods: "
, arg0, arg0, arg0, arg0, arg0);
for (int i = 0; SUP_LIST[i]; ++i)
fprintf(stderr, "%s ", SUP_LIST[i]);
fprintf(stderr,
"\n"
"\n"
"%s --decompress <infile> [outfile]\n"
" Detect method and decompress <infile>, optionally to [outfile]\n Supported methods: "
, arg0);
for (int i = 0; SUP_LIST[i]; ++i)
fprintf(stderr, "%s ", SUP_LIST[i]);
fprintf(stderr,
"\n"
"\n"
"%s --sha1 <file>\n"
" Print the SHA1 checksum for <file>\n"
"\n"
"%s --cleanup\n"
" Cleanup the current working directory\n"
"\n"
, arg0, arg0);
exit(1);
}
int main(int argc, char *argv[]) {
printf("MagiskBoot v" xstr(MAGISK_VERSION) " (by topjohnwu) - Boot Image Modification Tool\n\n");
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
cleanup();
} else if (argc > 2 && strcmp(argv[1], "--sha1") == 0) {
char sha1[21], *buf;
size_t size;
mmap_ro(argv[2], (unsigned char **) &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 *command;
command = strchr(argv[1] + 2, '-');
if (command == NULL) usage(argv[0]);
else ++command;
if (cpio_commands(command, argc - 2, argv + 2)) usage(argv[0]);
} else {
usage(argv[0]);
}
return 0;
}

91
jni/magiskboot/parseimg.c Normal file
View File

@@ -0,0 +1,91 @@
#include "bootimg.h"
#include "magiskboot.h"
unsigned char *kernel, *ramdisk, *second, *dtb, *extra;
boot_img_hdr hdr;
int mtk_kernel = 0, mtk_ramdisk = 0;
file_t ramdisk_type;
static void check_headers() {
// Check ramdisk compression type
ramdisk_type = check_type(ramdisk);
// Check MTK
if (check_type(kernel) == MTK) {
printf("MTK header found in kernel\n");
mtk_kernel = 1;
}
if (ramdisk_type == MTK) {
printf("MTK header found in ramdisk\n");
mtk_ramdisk = 1;
ramdisk_type = check_type(ramdisk + 512);
}
// Print info
print_info();
}
static void parse_aosp(unsigned char *base, size_t size) {
// printf("IMG [AOSP]\n");
size_t pos = 0;
// Read the header
memcpy(&hdr, base, sizeof(hdr));
pos += hdr.page_size;
// Kernel position
kernel = base + pos;
pos += hdr.kernel_size;
mem_align(&pos, hdr.page_size);
// Ramdisk position
ramdisk = base + pos;
pos += hdr.ramdisk_size;
mem_align(&pos, hdr.page_size);
if (hdr.second_size) {
// Second position
second = base + pos;
pos += hdr.second_size;
mem_align(&pos, hdr.page_size);
}
if (hdr.dt_size) {
// dtb position
dtb = base + pos;
pos += hdr.dt_size;
mem_align(&pos, hdr.page_size);
}
if (pos < size) {
extra = base + pos;
}
check_headers();
}
void parse_img(unsigned char *orig, size_t size) {
unsigned char *base, *end;
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
close(open_new("chromeos"));
continue;
case ELF32:
exit(2);
return;
case ELF64:
exit(3);
return;
case AOSP:
parse_aosp(base, size);
return;
default:
continue;
}
}
LOGE(1, "No boot image magic found!\n");
}

136
jni/magiskboot/repack.c Normal file
View File

@@ -0,0 +1,136 @@
#include "magiskboot.h"
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);
}
void repack(const char* orig_image, const char* out_image) {
size_t size;
unsigned char *orig;
char name[PATH_MAX];
// There are possible two MTK headers
mtk_hdr mtk_kernel_hdr, mtk_ramdisk_hdr;
size_t mtk_kernel_off, mtk_ramdisk_off;
// Load original image
mmap_ro(orig_image, &orig, &size);
// Parse original image
printf("Parsing boot image: [%s]\n\n", orig_image);
parse_img(orig, size);
printf("Repack to boot image: [%s]\n\n", out_image);
// Create new image
int fd = open_new(out_image);
// Set all sizes to 0
hdr.kernel_size = 0;
hdr.ramdisk_size = 0;
hdr.second_size = 0;
hdr.dt_size = 0;
// Skip a page for header
write_zero(fd, hdr.page_size);
// Restore kernel
if (mtk_kernel) {
mtk_kernel_off = lseek(fd, 0, SEEK_CUR);
restore_buf(fd, kernel, 512);
memcpy(&mtk_kernel_hdr, kernel, sizeof(mtk_kernel_hdr));
}
hdr.kernel_size = restore(KERNEL_FILE, fd);
file_align(fd, hdr.page_size, 1);
// Restore ramdisk
if (mtk_ramdisk) {
mtk_ramdisk_off = lseek(fd, 0, SEEK_CUR);
restore_buf(fd, ramdisk, 512);
memcpy(&mtk_ramdisk_hdr, ramdisk, sizeof(mtk_ramdisk_hdr));
}
if (access(RAMDISK_FILE, R_OK) == 0) {
// If we found raw cpio, compress to original format
// Before we start, clean up previous compressed files
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
unlink(name);
}
size_t cpio_size;
unsigned char *cpio;
mmap_ro(RAMDISK_FILE, &cpio, &cpio_size);
if (comp(ramdisk_type, RAMDISK_FILE, cpio, cpio_size))
LOGE(1, "Unsupported ramdisk format!\n");
munmap(cpio, cpio_size);
}
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) {
ramdisk_type = SUP_TYPE_LIST[i];
found = 1;
break;
}
}
if (!found)
LOGE(1, "No ramdisk exists!\n");
hdr.ramdisk_size = restore(name, fd);
file_align(fd, hdr.page_size, 1);
// Restore second
if (access(SECOND_FILE, R_OK) == 0) {
hdr.second_size = restore(SECOND_FILE, fd);
file_align(fd, hdr.page_size, 1);
}
// Restore dtb
if (access(DTB_FILE, R_OK) == 0) {
hdr.dt_size = restore(DTB_FILE, fd);
file_align(fd, hdr.page_size, 1);
}
// Check extra info, currently only for LG Bump and Samsung SEANDROIDENFORCE
if (extra) {
if (memcmp(extra, "SEANDROIDENFORCE", 16) == 0 ||
memcmp(extra, "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79", 16) == 0 ) {
restore_buf(fd, extra, 16);
}
}
// Write headers back
if (mtk_kernel) {
lseek(fd, mtk_kernel_off, SEEK_SET);
mtk_kernel_hdr.size = hdr.kernel_size;
hdr.kernel_size += 512;
restore_buf(fd, &mtk_kernel_hdr, sizeof(mtk_kernel_hdr));
}
if (mtk_ramdisk) {
lseek(fd, mtk_ramdisk_off, SEEK_SET);
mtk_ramdisk_hdr.size = hdr.ramdisk_size;
hdr.ramdisk_size += 512;
restore_buf(fd, &mtk_ramdisk_hdr, sizeof(mtk_ramdisk_hdr));
}
// Main header
lseek(fd, 0, SEEK_SET);
restore_buf(fd, &hdr, sizeof(hdr));
// Print new image info
print_info();
munmap(orig, size);
close(fd);
}

295
jni/magiskboot/sha1.c Normal file
View File

@@ -0,0 +1,295 @@
/*
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';
}

44
jni/magiskboot/sha1.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef SHA1_H
#define SHA1_H
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
*/
#include "stdint.h"
typedef struct
{
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
void SHA1Transform(
uint32_t state[5],
const unsigned char buffer[64]
);
void SHA1Init(
SHA1_CTX * context
);
void SHA1Update(
SHA1_CTX * context,
const unsigned char *data,
uint32_t len
);
void SHA1Final(
unsigned char digest[20],
SHA1_CTX * context
);
void SHA1(
char *hash_out,
const char *str,
int len);
#endif /* SHA1_H */

48
jni/magiskboot/unpack.c Normal file
View File

@@ -0,0 +1,48 @@
#include "magiskboot.h"
static void dump(unsigned char *buf, size_t size, const char *filename) {
int fd = open_new(filename);
xwrite(fd, buf, size);
close(fd);
}
void unpack(const char* image) {
size_t size;
unsigned char *orig;
mmap_ro(image, &orig, &size);
// Parse image
printf("Parsing boot image: [%s]\n\n", image);
parse_img(orig, size);
// Dump kernel
if (mtk_kernel) {
kernel += 512;
hdr.kernel_size -= 512;
}
dump(kernel, hdr.kernel_size, KERNEL_FILE);
// Dump ramdisk
if (mtk_ramdisk) {
ramdisk += 512;
hdr.ramdisk_size -= 512;
}
if (decomp(ramdisk_type, RAMDISK_FILE, ramdisk, hdr.ramdisk_size)) {
// Dump the compressed ramdisk
dump(ramdisk, hdr.ramdisk_size, RAMDISK_FILE ".unsupport");
LOGE(1, "Unsupported ramdisk format! Dumped to %s\n", RAMDISK_FILE ".unsupport");
}
if (hdr.second_size) {
// Dump second
dump(second, hdr.second_size, SECOND_FILE);
}
if (hdr.dt_size) {
// Dump dtb
dump(dtb, hdr.dt_size, DTB_FILE);
}
munmap(orig, size);
}

146
jni/magiskboot/utils.c Normal file
View File

@@ -0,0 +1,146 @@
#include "magiskboot.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 };
void mmap_ro(const char *filename, unsigned char **buf, size_t *size) {
int fd = xopen(filename, O_RDONLY);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = xmmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0);
close(fd);
}
void mmap_rw(const char *filename, unsigned char **buf, size_t *size) {
int fd = xopen(filename, O_RDWR);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = xmmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
}
file_t check_type(const unsigned char *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, "\x1f\x8b\x08\x00", 4) == 0) {
return GZIP;
} else if (memcmp(buf, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9) == 0) {
return LZOP;
} else if (memcmp(buf, "\xfd""7zXZ\x00", 6) == 0) {
return XZ;
} else if (memcmp(buf, "\x5d\x00\x00", 3) == 0
&& (buf[12] == (unsigned char) '\xff' || buf[12] == (unsigned char) '\x00')) {
return LZMA;
} else if (memcmp(buf, "BZh", 3) == 0) {
return BZIP2;
} else if (memcmp(buf, "\x04\x22\x4d\x18", 4) == 0) {
return LZ4;
} else if (memcmp(buf, "\x02\x21\x4c\x18", 4) == 0) {
return LZ4_LEGACY;
} else if (memcmp(buf, "\x88\x16\x88\x58", 4) == 0) {
return MTK;
} else {
return UNKNOWN;
}
}
void write_zero(int fd, size_t size) {
size_t pos = lseek(fd, 0, SEEK_CUR);
ftruncate(fd, pos + size);
lseek(fd, pos + size, SEEK_SET);
}
void mem_align(size_t *pos, size_t align) {
size_t mask = align - 1;
if (*pos & mask) {
*pos += align - (*pos & mask);
}
}
void file_align(int fd, size_t align, int out) {
size_t pos = lseek(fd, 0, SEEK_CUR);
size_t mask = align - 1;
size_t off;
if (pos & mask) {
off = align - (pos & mask);
if (out) {
write_zero(fd, off);
} else {
lseek(fd, pos + off, SEEK_SET);
}
}
}
int open_new(const char *filename) {
return xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
}
void print_info() {
printf("KERNEL [%d] @ 0x%08x\n", hdr.kernel_size, hdr.kernel_addr);
printf("RAMDISK [%d] @ 0x%08x\n", hdr.ramdisk_size, hdr.ramdisk_addr);
printf("SECOND [%d] @ 0x%08x\n", hdr.second_size, hdr.second_addr);
printf("DTB [%d] @ 0x%08x\n", hdr.dt_size, hdr.tags_addr);
printf("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;
printf("OS_VERSION [%d.%d.%d]\n", a, b, c);
y = (os_patch_level >> 4) + 2000;
m = os_patch_level & 0xf;
printf("PATCH_LEVEL [%d-%02d]\n", y, m);
}
printf("NAME [%s]\n", hdr.name);
printf("CMDLINE [%s]\n", hdr.cmdline);
switch (ramdisk_type) {
case GZIP:
printf("COMPRESSION [%s]\n", "gzip");
break;
case XZ:
printf("COMPRESSION [%s]\n", "xz");
break;
case LZMA:
printf("COMPRESSION [%s]\n", "lzma");
break;
case BZIP2:
printf("COMPRESSION [%s]\n", "bzip2");
break;
case LZ4:
printf("COMPRESSION [%s]\n", "lz4");
break;
case LZ4_LEGACY:
printf("COMPRESSION [%s]\n", "lz4_legacy");
break;
default:
fprintf(stderr, "Unknown ramdisk format!\n");
}
printf("\n");
}
void cleanup() {
printf("Cleaning up...\n");
char name[PATH_MAX];
unlink(KERNEL_FILE);
unlink(RAMDISK_FILE);
unlink(RAMDISK_FILE ".unsupport");
unlink(SECOND_FILE);
unlink(DTB_FILE);
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
unlink(name);
}
}

View File

@@ -0,0 +1,127 @@
/* hide_daemon.c - MagiskHide daemon
*
* A dedicated process to join the target namespace,
* and hide all traces in that particular namespace
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include "magisk.h"
#include "utils.h"
#include "magiskhide.h"
static int pid;
static void lazy_unmount(const char* mountpoint) {
if (umount2(mountpoint, MNT_DETACH) != -1)
LOGI("hide_daemon: Unmounted (%s)\n", mountpoint);
else
LOGI("hide_daemon: Unmount Failed (%s)\n", mountpoint);
}
static void hide_daemon_err() {
LOGD("hide_daemon: error occured, stopping magiskhide services\n");
// Resume process if possible
kill(pid, SIGCONT);
int err = 1;
write(sv[1], &err, sizeof(err));
_exit(-1);
}
int hide_daemon() {
// Fork to a new process
hide_pid = fork();
switch(hide_pid) {
case -1:
PLOGE("fork");
return 1;
case 0:
break;
default:
return 0;
}
close(sv[0]);
// Set the process name
strcpy(argv0, "magiskhide_daemon");
// When an error occurs, report its failure to main process
err_handler = hide_daemon_err;
char buffer[4096], cache_block[256], *line;
struct vector mount_list;
cache_block[0] = '\0';
while(1) {
xxread(sv[1], &pid, sizeof(pid));
// Termination called
if(pid == -1) {
LOGD("hide_daemon: received termination request\n");
_exit(0);
}
manage_selinux();
relink_sbin();
if (switch_mnt_ns(pid))
continue;
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 (strlen(cache_block) == 0) {
vec_for_each(&mount_list, line) {
if (strstr(line, " /cache ")) {
sscanf(line, "%256s", cache_block);
break;
}
}
}
// First unmount the dummy skeletons, cache mounts, and /sbin links
vec_for_each_r(&mount_list, line) {
if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin")
|| (strstr(line, cache_block) && strstr(line, "/system/")) ) {
sscanf(line, "%*s %512s", 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 loop mounts
vec_for_each_r(&mount_list, line) {
if (strstr(line, "/dev/block/loop") && !strstr(line, DUMMDIR)) {
sscanf(line, "%*s %512s", buffer);
lazy_unmount(buffer);
}
free(line);
}
vec_destroy(&mount_list);
// All done, send resume signal
kill(pid, SIGCONT);
// Tell main process all is well
pid = 0;
xwrite(sv[1], &pid, sizeof(pid));
}
// Should never go here
}

View File

@@ -0,0 +1,148 @@
/* list_manager.c - Hide list management
*/
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "magisk.h"
#include "utils.h"
#include "daemon.h"
#include "magiskhide.h"
int add_list(char *proc) {
if (!hideEnabled) {
free(proc);
return HIDE_NOT_ENABLED;
}
char *line;
struct vector *new_list = xmalloc(sizeof(*new_list));
if (new_list == NULL)
return DAEMON_ERROR;
vec_init(new_list);
vec_for_each(hide_list, line) {
// They should be unique
if (strcmp(line, proc) == 0) {
free(proc);
vec_destroy(new_list);
free(new_list);
return HIDE_ITEM_EXIST;
}
vec_push_back(new_list, line);
}
vec_push_back(new_list, proc);
LOGI("hide_list add: [%s]\n", proc);
ps_filter_proc_name(proc, kill_proc);
// Critical region
pthread_mutex_lock(&hide_lock);
vec_destroy(hide_list);
free(hide_list);
hide_list = new_list;
pthread_mutex_unlock(&hide_lock);
pthread_mutex_lock(&file_lock);
if (vector_to_file(HIDELIST, hide_list)) {
pthread_mutex_unlock(&file_lock);
return DAEMON_ERROR;
}
pthread_mutex_unlock(&file_lock);
return DAEMON_SUCCESS;
}
int rm_list(char *proc) {
if (!hideEnabled) {
free(proc);
return HIDE_NOT_ENABLED;
}
daemon_response ret = DAEMON_ERROR;
char *line;
int do_rm = 0;
struct vector *new_list = xmalloc(sizeof(*new_list));
if (new_list == NULL)
goto error;
vec_init(new_list);
vec_for_each(hide_list, line) {
if (strcmp(line, proc) == 0) {
free(proc);
proc = line;
do_rm = 1;
continue;
}
vec_push_back(new_list, line);
}
if (do_rm) {
LOGI("hide_list rm: [%s]\n", proc);
ps_filter_proc_name(proc, kill_proc);
// Critical region
pthread_mutex_lock(&hide_lock);
vec_destroy(hide_list);
free(hide_list);
hide_list = new_list;
pthread_mutex_unlock(&hide_lock);
ret = DAEMON_SUCCESS;
pthread_mutex_lock(&file_lock);
if (vector_to_file(HIDELIST, hide_list))
ret = DAEMON_ERROR;
pthread_mutex_unlock(&file_lock);
} else {
ret = HIDE_ITEM_NOT_EXIST;
vec_destroy(new_list);
free(new_list);
}
error:
free(proc);
return ret;
}
int init_list() {
LOGD("hide_list: initialize...\n");
if ((hide_list = xmalloc(sizeof(*hide_list))) == NULL)
return 1;
vec_init(hide_list);
// Might error if file doesn't exist, no need to report
file_to_vector(HIDELIST, hide_list);
char *line;
vec_for_each(hide_list, line) {
LOGI("hide_list: [%s]\n", line);
ps_filter_proc_name(line, kill_proc);
}
return 0;
}
int destroy_list() {
char *line;
vec_for_each(hide_list, line) {
ps_filter_proc_name(line, kill_proc);
}
vec_deep_destroy(hide_list);
free(hide_list);
hide_list = NULL;
return 0;
}
void add_hide_list(int client) {
err_handler = do_nothing;
char *proc = read_string(client);
// ack
write_int(client, add_list(proc));
close(client);
}
void rm_hide_list(int client) {
err_handler = do_nothing;
char *proc = read_string(client);
// ack
write_int(client, rm_list(proc));
close(client);
}

184
jni/magiskhide/magiskhide.c Normal file
View File

@@ -0,0 +1,184 @@
/* magiskhide.c - initialize the environment for Magiskhide
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "magisk.h"
#include "utils.h"
#include "magiskhide.h"
#include "daemon.h"
#include "resetprop.h"
int sv[2], hide_pid = -1;
struct vector *hide_list = NULL;
int hideEnabled = 0;
static pthread_t proc_monitor_thread;
pthread_mutex_t hide_lock, file_lock;
void kill_proc(int pid) {
kill(pid, SIGTERM);
}
static void usage(char *arg0) {
fprintf(stderr,
"MagiskHide v" xstr(MAGISK_VERSION) " (by topjohnwu) - Hide Magisk!\n\n"
"%s [--options [arguments...] ]\n\n"
"Options:\n"
" --enable: Start the magiskhide daemon\n"
" --disable: Stop the magiskhide daemon\n"
" --add <process name>: Add <process name> to the list\n"
" --rm <process name>: Remove <process name> from the list\n"
" --ls: Print out the current hide list\n"
, arg0);
exit(1);
}
void launch_magiskhide(int client) {
// We manually handle crashes
err_handler = do_nothing;
if (hideEnabled) {
write_int(client, HIDE_IS_ENABLED);
close(client);
return;
}
LOGI("* Starting MagiskHide\n");
hideEnabled = 1;
if (client != -1) {
if (setprop(MAGISKHIDE_PROP, "1"))
goto error;
}
hide_sensitive_props();
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) == -1)
goto error;
/*
* The setns system call do not support multithread processes
* We have to fork a new process, and communicate with sockets
*/
if (hide_daemon())
goto error;
close(sv[1]);
// Initialize the mutex lock
pthread_mutex_init(&hide_lock, NULL);
pthread_mutex_init(&file_lock, NULL);
// Initialize the hide list
if (init_list())
goto error;
// Add SafetyNet by default
add_list(strdup("com.google.android.gms.unstable"));
write_int(client, DAEMON_SUCCESS);
close(client);
// Get thread reference
proc_monitor_thread = pthread_self();
// Start monitoring
proc_monitor();
return;
error:
hideEnabled = 0;
write_int(client, DAEMON_ERROR);
close(client);
if (hide_pid != -1) {
int kill = -1;
// Kill hide daemon
write(sv[0], &kill, sizeof(kill));
close(sv[0]);
waitpid(hide_pid, NULL, 0);
hide_pid = -1;
}
return;
}
void stop_magiskhide(int client) {
if (!hideEnabled) {
write_int(client, HIDE_NOT_ENABLED);
close(client);
return;
}
LOGI("* Stopping MagiskHide\n");
hideEnabled = 0;
setprop(MAGISKHIDE_PROP, "0");
pthread_kill(proc_monitor_thread, SIGUSR1);
write_int(client, DAEMON_SUCCESS);
close(client);
}
int magiskhide_main(int argc, char *argv[]) {
if (argc < 2) {
usage(argv[0]);
}
client_request req = DO_NOTHING;
if (strcmp(argv[1], "--enable") == 0) {
req = LAUNCH_MAGISKHIDE;
} else if (strcmp(argv[1], "--disable") == 0) {
req = STOP_MAGISKHIDE;
} else if (strcmp(argv[1], "--add") == 0 && argc > 2) {
req = ADD_HIDELIST;
} else if (strcmp(argv[1], "--rm") == 0 && argc > 2) {
req = RM_HIDELIST;
} else if (strcmp(argv[1], "--ls") == 0) {
FILE *fp = fopen(HIDELIST, "r");
if (fp == NULL)
return 1;
char buffer[512];
while (fgets(buffer, sizeof(buffer), fp)) {
printf("%s", buffer);
}
fclose(fp);
return 0;
}
int fd = connect_daemon();
write_int(fd, req);
if (req == ADD_HIDELIST || req == RM_HIDELIST) {
write_string(fd, argv[2]);
}
daemon_response code = read_int(fd);
close(fd);
switch (code) {
case DAEMON_ERROR:
fprintf(stderr, "Error occured in daemon...\n");
break;
case DAEMON_SUCCESS:
break;
case ROOT_REQUIRED:
fprintf(stderr, "Root is required for this operation\n");
break;
case HIDE_NOT_ENABLED:
fprintf(stderr, "Magisk hide is not enabled yet\n");
break;
case HIDE_IS_ENABLED:
fprintf(stderr, "Magisk hide is already enabled\n");
break;
case HIDE_ITEM_EXIST:
fprintf(stderr, "Process [%s] already exists in hide list\n", argv[2]);
break;
case HIDE_ITEM_NOT_EXIST:
fprintf(stderr, "Process [%s] does not exist in hide list\n", argv[2]);
break;
}
return code;
}

View File

@@ -0,0 +1,30 @@
#ifndef MAGISK_HIDE_H
#define MAGISK_HIDE_H
#include <pthread.h>
// Kill process
void kill_proc(int pid);
// Hide daemon
int hide_daemon();
// Process monitor
void proc_monitor();
// Preprocess
void manage_selinux();
void hide_sensitive_props();
void relink_sbin();
// List managements
int add_list(char *proc);
int rm_list(char *proc);
int init_list();
int destroy_list();
extern int sv[2], hide_pid, hideEnabled;
extern struct vector *hide_list;
extern pthread_mutex_t hide_lock, file_lock;
#endif

View File

@@ -0,0 +1,90 @@
/* pre_process.c - Some pre-processes for MagiskHide to hide properly
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <selinux/selinux.h>
#include "magisk.h"
#include "utils.h"
#include "resetprop.h"
#include "magiskhide.h"
static char *prop_key[] =
{ "ro.boot.verifiedbootstate", "ro.boot.flash.locked", "ro.boot.veritymode", "ro.boot.warranty_bit", "ro.warranty_bit",
"ro.debuggable", "ro.secure", NULL };
static char *prop_value[] =
{ "green", "1", "enforcing", "0", "0", "0", "1", NULL };
static int isMocked = 0;
void manage_selinux() {
if (isMocked) return;
char val[1];
int fd = xopen(SELINUX_ENFORCE, O_RDONLY);
xxread(fd, val, 1);
close(fd);
// Permissive
if (val[0] == '0') {
LOGI("hide_daemon: Permissive detected, hide the state\n");
chmod(SELINUX_ENFORCE, 0640);
chmod(SELINUX_POLICY, 0440);
isMocked = 1;
}
}
void hide_sensitive_props() {
LOGI("hide_pre_proc: Hiding sensitive props\n");
// Hide all sensitive props
char *value;
for (int i = 0; prop_key[i]; ++i) {
value = getprop(prop_key[i]);
if (value) {
if (strcmp(value, prop_value[i]) != 0)
setprop2(prop_key[i], prop_value[i], 0);
free(value);
}
}
}
void relink_sbin() {
struct stat st;
if (stat("/sbin_orig", &st) == -1 && errno == ENOENT) {
// Re-link all binaries and bind mount
DIR *dir;
struct dirent *entry;
char from[PATH_MAX], to[PATH_MAX];
LOGI("hide_pre_proc: Re-linking /sbin\n");
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
xrename("/sbin", "/sbin_orig");
xmkdir("/sbin", 0755);
xchmod("/sbin", 0755);
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
xmkdir("/dev/sbin_bind", 0755);
xchmod("/dev/sbin_bind", 0755);
dir = xopendir("/sbin_orig");
while ((entry = xreaddir(dir))) {
snprintf(from, sizeof(from), "%s/%s", "/sbin_orig", entry->d_name);
snprintf(to, sizeof(to), "%s/%s", "/dev/sbin_bind", entry->d_name);
symlink(from, to);
lsetfilecon(to, "u:object_r:system_file:s0");
}
closedir(dir);
xmount("/dev/sbin_bind", "/sbin", NULL, MS_BIND, NULL);
}
}

View File

@@ -0,0 +1,182 @@
/* proc_monitor.c - Monitor am_proc_start events
*
* We monitor the logcat am_proc_start events, pause it,
* and send the target PID to hide daemon ASAP
*/
#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 "magisk.h"
#include "utils.h"
#include "magiskhide.h"
static int zygote_num = 0;
static char init_ns[32], zygote_ns[2][32];
static int log_pid = 0, log_fd = 0;
static char *buffer;
static void read_namespace(const int pid, char* target, const size_t size) {
char path[32];
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
xreadlink(path, target, size);
}
// Workaround for the lack of pthread_cancel
static void quit_pthread(int sig) {
err_handler = do_nothing;
LOGD("proc_monitor: running cleanup\n");
destroy_list();
free(buffer);
hideEnabled = 0;
// Kill the logging if needed
if (log_pid) {
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
close(log_fd);
log_fd = log_pid = 0;
}
int kill = -1;
// If process monitor dies, kill hide daemon too
write(sv[0], &kill, sizeof(kill));
close(sv[0]);
waitpid(hide_pid, NULL, 0);
pthread_mutex_destroy(&hide_lock);
pthread_mutex_destroy(&file_lock);
LOGD("proc_monitor: terminating...\n");
pthread_exit(NULL);
}
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 proc_monitor_err() {
LOGD("proc_monitor: error occured, stopping magiskhide services\n");
quit_pthread(SIGUSR1);
}
void proc_monitor() {
// Register the cancel signal
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = quit_pthread;
sigaction(SIGUSR1, &act, NULL);
// The error handler should stop magiskhide services
err_handler = proc_monitor_err;
int pid;
buffer = xmalloc(PATH_MAX);
// Get the mount namespace of init
read_namespace(1, init_ns, 32);
LOGI("proc_monitor: init ns=%s\n", init_ns);
// Get the mount namespace of zygote
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 (32-bit) ns=%s (64-bit) ns=%s\n", zygote_ns[0], zygote_ns[1]);
break;
}
while (1) {
// Clear previous buffer
system("logcat -b events -c");
// Monitor am_proc_start
char *const command[] = { "logcat", "-b", "events", "-v", "raw", "-s", "am_proc_start", NULL };
log_pid = run_command(0, &log_fd, "/system/bin/logcat", command);
while(fdgets(buffer, PATH_MAX, log_fd)) {
int ret, comma = 0;
char *pos = buffer, *line, processName[256];
while(1) {
pos = strchr(pos, ',');
if(pos == NULL)
break;
pos[0] = ' ';
++comma;
}
if (comma == 6)
ret = sscanf(buffer, "[%*d %d %*d %*d %256s", &pid, processName);
else
ret = sscanf(buffer, "[%*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, buffer, 32);
if (strcmp(buffer, zygote_ns[i]) == 0) {
usleep(50);
ret = 0;
break;
}
}
if (ret) break;
}
ret = 0;
// Send pause signal ASAP
if (kill(pid, SIGSTOP) == -1) continue;
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, pid, buffer);
// Unmount start
xwrite(sv[0], &pid, sizeof(pid));
// Get the hide daemon return code
xxread(sv[0], &ret, sizeof(ret));
LOGD("proc_monitor: hide daemon response code: %d\n", ret);
break;
}
}
pthread_mutex_unlock(&hide_lock);
if (ret) {
// Wait hide process to kill itself
waitpid(hide_pid, NULL, 0);
quit_pthread(SIGUSR1);
}
}
// For some reason it went here, restart logging
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
close(log_fd);
log_pid = 0;
}
}

1
jni/magiskpolicy Submodule

Submodule jni/magiskpolicy added at 193d160bed

145
jni/main.c Normal file
View File

@@ -0,0 +1,145 @@
/* main.c - The multicall entry point
*/
#include <stdlib.h>
#include <stdio.h>
#include "utils.h"
#include "magisk.h"
#include "daemon.h"
char *argv0;
char *applet[] =
{ "su", "resetprop", "magiskpolicy", "supolicy", "sepolicy-inject", "magiskhide", NULL };
int (*applet_main[]) (int, char *[]) =
{ su_client_main, resetprop_main, magiskpolicy_main, magiskpolicy_main, magiskpolicy_main, magiskhide_main, NULL };
// Global error hander function
// Should be changed each thread/process
__thread void (*err_handler)(void);
static void usage() {
fprintf(stderr,
"Magisk v" xstr(MAGISK_VERSION) " multi-call binary\n"
"\n"
"Usage: %s [applet [arguments]...]\n"
" or: %s --install [SOURCE] <DIR> \n"
" or: %s --list\n"
" or: %s --createimg <PATH> <SIZE>\n"
" create ext4 image, SIZE is interpreted in MB\n"
" or: %s --imgsize <PATH>\n"
" or: %s --resizeimg <PATH> <SIZE>\n"
" SIZE is interpreted in MB\n"
" or: %s --[boot stage]\n"
" start boot stage service\n"
" or: %s [options]\n"
" or: applet [arguments]...\n"
"\n"
"Supported boot stages:\n"
" post-fs, post-fs-data, service\n"
"\n"
"Options:\n"
" -c print client version\n"
" -v print daemon version\n"
" -V print daemon version code\n"
"\n"
"Supported applets:\n"
, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0);
for (int i = 0; applet[i]; ++i) {
fprintf(stderr, i ? ", %s" : " %s", applet[i]);
}
fprintf(stderr, "\n");
exit(1);
}
int main(int argc, char *argv[]) {
argv0 = argv[0];
// Exit the whole app if error occurs by default
err_handler = exit_proc;
char * arg = strrchr(argv[0], '/');
if (arg) ++arg;
else arg = argv[0];
if (strcmp(arg, "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("Used: %dM\tTotal: %dM\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], "--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;
arg = argv[0];
}
}
// Applets
for (int i = 0; applet[i]; ++i) {
if (strcmp(arg, applet[i]) == 0)
return (*applet_main[i])(argc, argv);
}
fprintf(stderr, "%s: applet not found\n", arg);
return 1;
}

1
jni/ndk-compression Submodule

Submodule jni/ndk-compression added at 278ea80348

View File

@@ -1,144 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
#include <string.h>
#include "bootimgtools.h"
off_t file_size(char *filename) {
struct stat st;
if(stat(filename, &st))
exit(1);
return st.st_size;
}
int append_file(int ofd, char *filename, off_t pos) {
lseek(ofd, pos, SEEK_SET);
int fd = open(filename, O_RDONLY);
int size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
sendfile(ofd, fd, NULL, size);
close(fd);
return size;
}
int append_ramdisk(int ofd, off_t pos) {
if(access("ramdisk-mtk", R_OK) == 0) {
char buf[512];
off_t size = file_size("ramdisk.gz");
memcpy(buf, "\x88\x16\x88\x58", 4);
uint32_t v = size;
memcpy(buf+4, &v, sizeof(v)); //Should convert to LE
//TODO: RECOVERY OR ROOTFS?
char str[32];
memset(str, 0, sizeof(str));
if(access("ramdisk-mtk-boot", R_OK)==0) {
strcpy(str, "ROOTFS");
} else if(access("ramdisk-mtk-recovery", R_OK)==0) {
strcpy(str, "RECOVERY");
} else {
exit(1);
}
memcpy(buf+8, str, sizeof(str));
memset(buf+8+sizeof(str), 0xff, 512-8-sizeof(str));
pwrite(ofd, buf, sizeof(buf), pos);
return append_file(ofd, "ramdisk.gz", pos + 512) + 512;
} else if(access("ramdisk.gz", R_OK) == 0) {
return append_file(ofd, "ramdisk.gz", pos);
} else {
return append_file(ofd, "ramdisk", pos);
}
}
void post_process(struct boot_img_hdr *hdr, int ofd, int pos) {
if(access("rkcrc", R_OK) == 0) {
fprintf(stderr, "Rockchip CRCs not supported yet\n");
exit(1);
}
//Round up the file size
ftruncate(ofd, pos);
}
int repack(char *image) {
//TODO: Merge with extract.c?
//{
int ifd = open(image, O_RDONLY);
off_t isize = lseek(ifd, 0, SEEK_END);
lseek(ifd, 0, SEEK_SET);
uint8_t *iorig = mmap(NULL, isize, PROT_READ, MAP_SHARED, ifd, 0);
uint8_t *ibase = iorig;
assert(ibase);
while(ibase<(iorig+isize)) {
if(memcmp(ibase, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0)
break;
ibase += 256;
}
assert(ibase < (iorig+isize));
//}
//
struct boot_img_hdr *ihdr = (struct boot_img_hdr*) ibase;
assert(
ihdr->page_size == 2048 ||
ihdr->page_size == 4096 ||
ihdr->page_size == 16384
);
unlink("new-boot.img");
int ofd = open("new-boot.img", O_RDWR|O_CREAT, 0644);
ftruncate(ofd, ihdr->page_size);
//Write back original header, we'll change it later
write(ofd, ihdr, sizeof(*ihdr));
struct boot_img_hdr *hdr = mmap(NULL, sizeof(*ihdr), PROT_READ|PROT_WRITE, MAP_SHARED, ofd, 0);
//First set everything to zero, so we know where we are at.
hdr->kernel_size = 0;
hdr->ramdisk_size = 0;
hdr->second_size = 0;
hdr->unused[0] = 0;
memset(hdr->id, 0, sizeof(hdr->id)); //Setting id to 0 might be wrong?
int pos = hdr->page_size;
int size = 0;
size = append_file(ofd, "kernel", pos);
pos += size + hdr->page_size - 1;
pos &= ~(hdr->page_size-1);
hdr->kernel_size = size;
size = append_ramdisk(ofd, pos);
pos += size + hdr->page_size - 1;
pos &= ~(hdr->page_size-1);
hdr->ramdisk_size = size;
if(access("second", R_OK) == 0) {
size = append_file(ofd, "second", pos);
pos += size + hdr->page_size - 1;
pos &= ~(hdr->page_size-1);
hdr->second_size = size;
}
if(access("dt", R_OK) == 0) {
size = append_file(ofd, "dt", pos);
pos += size + hdr->page_size - 1;
pos &= ~(hdr->page_size-1);
hdr->unused[0] = size;
}
post_process(hdr, ofd, pos);
munmap(hdr, sizeof(*ihdr));
close(ofd);
return 0;
}

8
jni/resetprop/Android.mk Normal file
View File

@@ -0,0 +1,8 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := resetprop
LOCAL_SRC_FILES := resetprop.cpp system_properties.cpp libc_logging.cpp
LOCAL_LDLIBS += -latomic
LOCAL_CFLAGS := -Wno-implicit-exception-spec-mismatch -DINDEP_BINARY
include $(BUILD_EXECUTABLE)

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef ERRNO_RESTORER_H
#define ERRNO_RESTORER_H
#include <errno.h>
#include "bionic_macros.h"
class ErrnoRestorer {
public:
explicit ErrnoRestorer() : saved_errno_(errno) {
}
~ErrnoRestorer() {
errno = saved_errno_;
}
void override(int new_errno) {
saved_errno_ = new_errno;
}
private:
int saved_errno_;
DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer);
};
#endif // ERRNO_RESTORER_H

View File

@@ -0,0 +1,144 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 THE
* COPYRIGHT OWNER OR CONTRIBUTORS 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 _INCLUDE_SYS__SYSTEM_PROPERTIES_H
#define _INCLUDE_SYS__SYSTEM_PROPERTIES_H
#include <sys/cdefs.h>
#include <stdint.h>
#ifndef _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#error you should #include <sys/system_properties.h> instead
#endif
// #include <sys/system_properties.h>
#include "system_properties.h"
__BEGIN_DECLS
#define PROP_SERVICE_NAME "property_service"
#define PROP_FILENAME "/dev/__properties__"
#define PROP_MSG_SETPROP 1
#define PROP_MSG_SETPROP2 0x00020001
#define PROP_SUCCESS 0
#define PROP_ERROR_READ_CMD 0x0004
#define PROP_ERROR_READ_DATA 0x0008
#define PROP_ERROR_READ_ONLY_PROPERTY 0x000B
#define PROP_ERROR_INVALID_NAME 0x0010
#define PROP_ERROR_INVALID_VALUE 0x0014
#define PROP_ERROR_PERMISSION_DENIED 0x0018
#define PROP_ERROR_INVALID_CMD 0x001B
#define PROP_ERROR_HANDLE_CONTROL_MESSAGE 0x0020
#define PROP_ERROR_SET_FAILED 0x0024
/*
** Map the property area from the specified filename. This
** method is for testing only.
*/
int __system_property_set_filename2(const char *filename);
/*
** Initialize the area to be used to store properties. Can
** only be done by a single process that has write access to
** the property area.
*/
int __system_property_area_init2();
/* Read the global serial number of the system properties
**
** Called to predict if a series of cached __system_property_find2
** objects will have seen __system_property_serial2 values change.
** But also aids the converse, as changes in the global serial can
** also be used to predict if a failed __system_property_find2
** could in-turn now find a new object; thus preventing the
** cycles of effort to poll __system_property_find2.
**
** Typically called at beginning of a cache cycle to signal if _any_ possible
** changes have occurred since last. If there is, one may check each individual
** __system_property_serial2 to confirm dirty, or __system_property_find2
** to check if the property now exists. If a call to __system_property_add2
** or __system_property_update2 has completed between two calls to
** __system_property_area_serial2 then the second call will return a larger
** value than the first call. Beware of race conditions as changes to the
** properties are not atomic, the main value of this call is to determine
** whether the expensive __system_property_find2 is worth retrying to see if
** a property now exists.
**
** Returns the serial number on success, -1 on error.
*/
uint32_t __system_property_area_serial2();
/* Add a new system property. Can only be done by a single
** process that has write access to the property area, and
** that process must handle sequencing to ensure the property
** does not already exist and that only one property is added
** or updated at a time.
**
** Returns 0 on success, -1 if the property area is full.
*/
int __system_property_add2(const char *name, unsigned int namelen, const char *value, unsigned int valuelen);
/* Delete a new system property. Added in resetprop
**
** Returns 0 on success, -1 if the property area is full.
*/
int __system_property_del(const char *name);
/* Update the value of a system property returned by
** __system_property_find2. Can only be done by a single process
** that has write access to the property area, and that process
** must handle sequencing to ensure that only one property is
** updated at a time.
**
** Returns 0 on success, -1 if the parameters are incorrect.
*/
int __system_property_update2(prop_info *pi, const char *value, unsigned int len);
/* Read the serial number of a system property returned by
** __system_property_find2.
**
** Returns the serial number on success, -1 on error.
*/
uint32_t __system_property_serial2(const prop_info* pi);
/* Initialize the system properties area in read only mode.
* Should be done by all processes that need to read system
* properties.
*
* Returns 0 on success, -1 otherwise.
*/
int __system_properties_init2();
/* Deprecated: use __system_property_wait2 instead. */
uint32_t __system_property_wait_any2(uint32_t old_serial);
__END_DECLS
#endif

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 THE
* COPYRIGHT OWNER OR CONTRIBUTORS 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 _BIONIC_FUTEX_H
#define _BIONIC_FUTEX_H
#include <errno.h>
#include <linux/futex.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/syscall.h>
#include <unistd.h>
__BEGIN_DECLS
struct timespec;
static inline __always_inline int __futex(volatile void* ftx, int op, int value,
const struct timespec* timeout,
int bitset) {
// Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
int saved_errno = errno;
int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
if (__predict_false(result == -1)) {
result = -errno;
errno = saved_errno;
}
return result;
}
static inline int __futex_wake(volatile void* ftx, int count) {
return __futex(ftx, FUTEX_WAKE, count, NULL, 0);
}
static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
}
static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
}
static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
bool use_realtime_clock, const struct timespec* abs_timeout) {
return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
(use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
FUTEX_BITSET_MATCH_ANY);
}
__END_DECLS
#endif /* _BIONIC_FUTEX_H */

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 THE
* COPYRIGHT OWNER OR CONTRIBUTORS 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 _BIONIC_LOCK_H
#define _BIONIC_LOCK_H
#include <stdatomic.h>
#include "bionic_futex.h"
#include "bionic_macros.h"
// Lock is used in places like pthread_rwlock_t, which can be initialized without calling
// an initialization function. So make sure Lock can be initialized by setting its memory to 0.
class Lock {
private:
enum LockState {
Unlocked = 0,
LockedWithoutWaiter,
LockedWithWaiter,
};
_Atomic(LockState) state;
bool process_shared;
public:
void init(bool process_shared) {
atomic_init(&state, Unlocked);
this->process_shared = process_shared;
}
bool trylock() {
LockState old_state = Unlocked;
return __predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed));
}
void lock() {
LockState old_state = Unlocked;
if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed))) {
return;
}
while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
// TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
__futex_wait_ex(&state, process_shared, LockedWithWaiter, false, nullptr);
}
return;
}
void unlock() {
if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
__futex_wake_ex(&state, process_shared, 1);
}
}
};
#endif // _BIONIC_LOCK_H

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2010 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.
*/
#ifndef _BIONIC_MACROS_H_
#define _BIONIC_MACROS_H_
// Frameworks OpenGL code currently leaks this header and allows
// collisions with other declarations, e.g., from libnativehelper.
// TODO: Remove once cleaned up. b/18334516
#if !defined(DISALLOW_COPY_AND_ASSIGN)
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
// It goes in the private: declarations in a class.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#endif // !defined(DISALLOW_COPY_AND_ASSIGN)
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName() = delete; \
DISALLOW_COPY_AND_ASSIGN(TypeName)
#define BIONIC_ALIGN(value, alignment) \
(((value) + (alignment) - 1) & ~((alignment) - 1))
#define BIONIC_ROUND_UP_POWER_OF_2(value) \
((sizeof(value) == 8) \
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
#endif // _BIONIC_MACROS_H_

291
jni/resetprop/resetprop.cpp Normal file
View File

@@ -0,0 +1,291 @@
/* resetprop.cpp - Manipulate any system props
*
* Copyright 2016 nkk71 <nkk71x@gmail.com>
* Copyright 2016 topjohnwu <topjohnwu@gmail.com>
*
* Info:
*
* all changes are in
*
* bionic/libc/bionic/system_properties.cpp
*
* Functions that need to be patched/added in system_properties.cpp
*
* int __system_properties_init2()
* on android 7, first tear down the everything then let it initialize again:
* if (initialized) {
* //list_foreach(contexts, [](context_node* l) { l->reset_access(); });
* //return 0;
* free_and_unmap_contexts();
* initialized = false;
* }
*
*
* static prop_area* map_prop_area(const char* filename, bool is_legacy)
* we dont want this read only so change: 'O_RDONLY' to 'O_RDWR'
*
* static prop_area* map_fd_ro(const int fd)
* we dont want this read only so change: 'PROT_READ' to 'PROT_READ | PROT_WRITE'
*
*
* Copy the code of prop_info *prop_area::find_property, and modify to delete props
* const prop_info *prop_area::find_property_and_del(prop_bt *const trie, const char *name)
* {
* ...
* ... Do not alloc a new prop_bt here, remove all code involve alloc_if_needed
* ...
*
* if (prop_offset != 0) {
* atomic_store_explicit(&current->prop, 0, memory_order_release); // Add this line to nullify the prop entry
* return to_prop_info(&current->prop);
* } else {
*
* ....
* }
*
*
* by patching just those functions directly, all other functions should be ok
* as is.
*
*
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include "_system_properties.h"
#include <sys/system_properties.h>
#ifdef INDEP_BINARY
int resetprop_main(int argc, char *argv[]);
int main(int argc, char *argv[]) {
return resetprop_main(argc, argv);
}
#define PRINT_D(...) if (verbose) printf(__VA_ARGS__)
#define PRINT_E(...) fprintf(stderr, __VA_ARGS__)
#else
#include "magisk.h"
#define PRINT_D(...) { LOGD(__VA_ARGS__); if (verbose) printf(__VA_ARGS__); }
#define PRINT_E(...) { LOGE(__VA_ARGS__); fprintf(stderr, __VA_ARGS__); }
#endif
#include "resetprop.h"
static int verbose = 0;
static bool is_legal_property_name(const char* name, size_t namelen) {
if (namelen < 1) return false;
if (name[0] == '.') return false;
if (name[namelen - 1] == '.') return false;
/* Only allow alphanumeric, plus '.', '-', or '_' */
/* Don't allow ".." to appear in a property name */
for (size_t i = 0; i < namelen; i++) {
if (name[i] == '.') {
// i=0 is guaranteed to never have a dot. See above.
if (name[i - 1] == '.') return false;
continue;
}
if (name[i] == '_' || name[i] == '-') continue;
if (name[i] >= 'a' && name[i] <= 'z') continue;
if (name[i] >= 'A' && name[i] <= 'Z') continue;
if (name[i] >= '0' && name[i] <= '9') continue;
return false;
}
return true;
}
static int usage(char* arg0) {
fprintf(stderr,
"resetprop v" xstr(MAGISK_VERSION) " (by topjohnwu & nkk71) - System Props Modification Tool\n\n"
"Usage: %s [options] [args...]\n"
"%s <name> <value>: Set property entry <name> with <value>\n"
"%s --file <prop file>: Load props from <prop file>\n"
"%s --delete <name>: Remove prop entry <name>\n"
"\n"
"Options:\n"
" -v verbose output\n"
" -n don't trigger events when changing props\n"
, arg0, arg0, arg0, arg0);
return 1;
}
int init_resetprop() {
PRINT_D("resetprop: Initializing...\n");
if (__system_properties_init2()) {
PRINT_E("resetprop: Initialize error\n");
return -1;
}
return 0;
}
static void read_prop_info(void* cookie, const char *name, const char *value, uint32_t serial) {
strcpy((char *) cookie, value);
}
// Get prop by name, return string (should free manually!)
char *getprop(const char *name) {
const prop_info *pi = __system_property_find2(name);
if (pi == NULL) {
PRINT_D("resetprop: failed to get [%s]\n", name);
return NULL;
}
char value[PROP_VALUE_MAX];
__system_property_read_callback2(pi, read_prop_info, value);
PRINT_D("resetprop: getprop [%s]: [%s]\n", name, value);
return strdup(value);
}
int setprop(const char *name, const char *value) {
return setprop2(name, value, 1);
}
int setprop2(const char *name, const char *value, const int trigger) {
int ret;
char *check = getprop(name);
if (check) {
free(check);
if (trigger) {
if (!strncmp(name, "ro.", 3)) deleteprop(name);
ret = __system_property_set2(name, value);
} else {
ret = __system_property_update2((prop_info*) __system_property_find2(name), value, strlen(value));
}
} else {
PRINT_D("resetprop: New prop [%s]\n", name);
if (trigger) {
ret = __system_property_set2(name, value);
} else {
ret = __system_property_add2(name, strlen(name), value, strlen(value));
}
}
PRINT_D("resetprop: setprop [%s]: [%s] by %s\n", name, value,
trigger ? "property_service" : "modifing prop data structure");
if (ret)
PRINT_E("resetprop: setprop error\n");
return ret;
}
int deleteprop(const char *name) {
PRINT_D("resetprop: deleteprop [%s]\n", name);
if (__system_property_del(name)) {
PRINT_E("resetprop: delete prop: [%s] error\n", name);
return -1;
}
return 0;
}
int read_prop_file(const char* filename, const int trigger) {
PRINT_D("resetprop: Load prop file [%s]\n", filename);
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
PRINT_E("Cannot open [%s]\n", filename);
return 1;
}
char *line = NULL, *pch;
size_t len;
ssize_t read;
int comment = 0, i;
while ((read = getline(&line, &len, fp)) != -1) {
// Remove the trailing newline
if (line[read - 1] == '\n') {
line[read - 1] = '\0';
--read;
}
comment = 0;
for (i = 0; i < read; ++i) {
// Ignore starting spaces
if (line[i] == ' ') continue;
else {
// A line starting with # is ignored
if (line[i] == '#') comment = 1;
break;
}
}
if (comment) continue;
pch = strchr(line, '=');
// Ignore ivalid formats
if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
// Separate the string
*pch = '\0';
setprop2(line + i, pch + 1, trigger);
}
free(line);
fclose(fp);
return 0;
}
int resetprop_main(int argc, char *argv[]) {
int del = 0, file = 0, trigger = 1;
int exp_arg = 2;
char *name, *value, *filename;
if (argc < 3) {
return usage(argv[0]);
}
for (int i = 1; i < argc; ++i) {
if (!strcmp("-v", argv[i])) {
verbose = 1;
} else if (!strcmp("-n", argv[i])) {
trigger = 0;
} else if (!strcmp("--file", argv[i])) {
file = 1;
exp_arg = 1;
} else if (!strcmp("--delete", argv[i])) {
del = 1;
exp_arg = 1;
} else {
if (i + exp_arg > argc) {
return usage(argv[0]);
}
if (file) {
filename = argv[i];
break;
} else {
if(!is_legal_property_name(argv[i], strlen(argv[i]))) {
PRINT_E("Illegal property name: [%s]\n", argv[i]);
return 1;
}
name = argv[i];
if (exp_arg > 1) {
if (strlen(argv[i + 1]) >= PROP_VALUE_MAX) {
PRINT_E("Value too long: [%s]\n", argv[i + 1]);
return 1;
}
value = argv[i + 1];
}
break;
}
}
}
init_resetprop();
if (file) {
return read_prop_file(filename, trigger);
} else if (del) {
return deleteprop(name);
} else {
return setprop2(name, value, trigger);
}
return 0;
}

22
jni/resetprop/resetprop.h Normal file
View File

@@ -0,0 +1,22 @@
/* resetprop.h - API for resetprop
*/
#ifndef _RESETPROP_H_
#define _RESETPROP_H_
#ifdef __cplusplus
extern "C" {
#endif
int init_resetprop();
int setprop(const char *name, const char *value);
int setprop2(const char *name, const char *value, const int trigger);
char *getprop(const char *name);
int deleteprop(const char *name);
int read_prop_file(const char* filename, const int trigger);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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 THE
* COPYRIGHT OWNER OR CONTRIBUTORS 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 _INCLUDE_SYS_SYSTEM_PROPERTIES_H
#define _INCLUDE_SYS_SYSTEM_PROPERTIES_H
#include <sys/cdefs.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
__BEGIN_DECLS
typedef struct prop_info prop_info;
#define PROP_VALUE_MAX 92
/*
* Sets system property `key` to `value`, creating the system property if it doesn't already exist.
*/
int __system_property_set2(const char* key, const char* value) __INTRODUCED_IN(12);
/*
* Returns a `prop_info` corresponding system property `name`, or nullptr if it doesn't exist.
* Use __system_property_read_callback2 to query the current value.
*
* Property lookup is expensive, so it can be useful to cache the result of this function.
*/
const prop_info* __system_property_find2(const char* name);
/*
* Calls `callback` with a consistent trio of name, value, and serial number for property `pi`.
*/
void __system_property_read_callback2(const prop_info *pi,
void (*callback)(void* cookie, const char *name, const char *value, uint32_t serial),
void* cookie) __INTRODUCED_IN(26);
/*
* Passes a `prop_info` for each system property to the provided
* callback. Use __system_property_read_callback2() to read the value.
*
* This method is for inspecting and debugging the property system, and not generally useful.
*/
int __system_property_foreach2(void (*propfn)(const prop_info* pi, void* cookie), void* cookie)
__INTRODUCED_IN(19);
/*
* Waits for the specific system property identified by `pi` to be updated
* past `old_serial`. Waits no longer than `relative_timeout`, or forever
* if `relaive_timeout` is null.
*
* If `pi` is null, waits for the global serial number instead.
*
* If you don't know the current serial, use 0.
*
* Returns true and updates `*new_serial_ptr` on success, or false if the call
* timed out.
*/
struct timespec;
bool __system_property_wait2(const prop_info* pi,
uint32_t old_serial,
uint32_t* new_serial_ptr,
const struct timespec* relative_timeout)
__INTRODUCED_IN(26);
/* Deprecated. In Android O and above, there's no limit on property name length. */
#define PROP_NAME_MAX 32
/* Deprecated. Use __system_property_read_callback2 instead. */
int __system_property_read2(const prop_info* pi, char* name, char* value);
/* Deprecated. Use __system_property_read_callback2 instead. */
int __system_property_get2(const char* name, char* value);
/* Deprecated. Use __system_property_foreach2 instead. */
const prop_info* __system_property_find_nth2(unsigned n);
__END_DECLS
#endif

1
jni/selinux Submodule

Submodule jni/selinux added at 0b14ed89aa

10
jni/sqlite3/Android.mk Normal file
View File

@@ -0,0 +1,10 @@
LOCAL_PATH:= $(call my-dir)
##
# libsqlite.so
#
include $(CLEAR_VARS)
LOCAL_MODULE:= libsqlite
LOCAL_SRC_FILES := sqlite3.c shell.c
include $(BUILD_SHARED_LIBRARY)

7387
jni/sqlite3/shell.c Normal file

File diff suppressed because it is too large Load Diff

202113
jni/sqlite3/sqlite3.c Normal file

File diff suppressed because it is too large Load Diff

10491
jni/sqlite3/sqlite3.h Normal file

File diff suppressed because it is too large Load Diff

564
jni/sqlite3/sqlite3ext.h Normal file
View File

@@ -0,0 +1,564 @@
/*
** 2006 June 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#include "sqlite3.h"
/*
** The following structure holds pointers to all of the SQLite API
** routines.
**
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each other's shared
** libraries!
*/
struct sqlite3_api_routines {
void * (*aggregate_context)(sqlite3_context*,int nBytes);
int (*aggregate_count)(sqlite3_context*);
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
int (*bind_double)(sqlite3_stmt*,int,double);
int (*bind_int)(sqlite3_stmt*,int,int);
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
int (*bind_null)(sqlite3_stmt*,int);
int (*bind_parameter_count)(sqlite3_stmt*);
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
int (*column_count)(sqlite3_stmt*pStmt);
const char * (*column_database_name)(sqlite3_stmt*,int);
const void * (*column_database_name16)(sqlite3_stmt*,int);
const char * (*column_decltype)(sqlite3_stmt*,int i);
const void * (*column_decltype16)(sqlite3_stmt*,int);
double (*column_double)(sqlite3_stmt*,int iCol);
int (*column_int)(sqlite3_stmt*,int iCol);
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
const char * (*column_name)(sqlite3_stmt*,int);
const void * (*column_name16)(sqlite3_stmt*,int);
const char * (*column_origin_name)(sqlite3_stmt*,int);
const void * (*column_origin_name16)(sqlite3_stmt*,int);
const char * (*column_table_name)(sqlite3_stmt*,int);
const void * (*column_table_name16)(sqlite3_stmt*,int);
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
const void * (*column_text16)(sqlite3_stmt*,int iCol);
int (*column_type)(sqlite3_stmt*,int iCol);
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
int (*declare_vtab)(sqlite3*,const char*);
int (*enable_shared_cache)(int);
int (*errcode)(sqlite3*db);
const char * (*errmsg)(sqlite3*);
const void * (*errmsg16)(sqlite3*);
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
int (*expired)(sqlite3_stmt*);
int (*finalize)(sqlite3_stmt*pStmt);
void (*free)(void*);
void (*free_table)(char**result);
int (*get_autocommit)(sqlite3*);
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
void *(*malloc)(int);
char * (*mprintf)(const char*,...);
int (*open)(const char*,sqlite3**);
int (*open16)(const void*,sqlite3**);
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
void *(*realloc)(void*,int);
int (*reset)(sqlite3_stmt*pStmt);
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_double)(sqlite3_context*,double);
void (*result_error)(sqlite3_context*,const char*,int);
void (*result_error16)(sqlite3_context*,const void*,int);
void (*result_int)(sqlite3_context*,int);
void (*result_int64)(sqlite3_context*,sqlite_int64);
void (*result_null)(sqlite3_context*);
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
int (*value_bytes16)(sqlite3_value*);
double (*value_double)(sqlite3_value*);
int (*value_int)(sqlite3_value*);
sqlite_int64 (*value_int64)(sqlite3_value*);
int (*value_numeric_type)(sqlite3_value*);
const unsigned char * (*value_text)(sqlite3_value*);
const void * (*value_text16)(sqlite3_value*);
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
char *(*vmprintf)(const char*,va_list);
/* Added ??? */
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
/* Added by 3.3.13 */
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*),
void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
sqlite3_mutex *(*mutex_alloc)(int);
void (*mutex_enter)(sqlite3_mutex*);
void (*mutex_free)(sqlite3_mutex*);
void (*mutex_leave)(sqlite3_mutex*);
int (*mutex_try)(sqlite3_mutex*);
int (*open_v2)(const char*,sqlite3**,int,const char*);
int (*release_memory)(int);
void (*result_error_nomem)(sqlite3_context*);
void (*result_error_toobig)(sqlite3_context*);
int (*sleep)(int);
void (*soft_heap_limit)(int);
sqlite3_vfs *(*vfs_find)(const char*);
int (*vfs_register)(sqlite3_vfs*,int);
int (*vfs_unregister)(sqlite3_vfs*);
int (*xthreadsafe)(void);
void (*result_zeroblob)(sqlite3_context*,int);
void (*result_error_code)(sqlite3_context*,int);
int (*test_control)(int, ...);
void (*randomness)(int,void*);
sqlite3 *(*context_db_handle)(sqlite3_context*);
int (*extended_result_codes)(sqlite3*,int);
int (*limit)(sqlite3*,int,int);
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
int (*backup_finish)(sqlite3_backup*);
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
int (*backup_pagecount)(sqlite3_backup*);
int (*backup_remaining)(sqlite3_backup*);
int (*backup_step)(sqlite3_backup*,int);
const char *(*compileoption_get)(int);
int (*compileoption_used)(const char*);
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*));
int (*db_config)(sqlite3*,int,...);
sqlite3_mutex *(*db_mutex)(sqlite3*);
int (*db_status)(sqlite3*,int,int*,int*,int);
int (*extended_errcode)(sqlite3*);
void (*log)(int,const char*,...);
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
const char *(*sourceid)(void);
int (*stmt_status)(sqlite3_stmt*,int,int);
int (*strnicmp)(const char*,const char*,int);
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
int (*wal_autocheckpoint)(sqlite3*,int);
int (*wal_checkpoint)(sqlite3*,const char*);
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
int (*vtab_config)(sqlite3*,int op,...);
int (*vtab_on_conflict)(sqlite3*);
/* Version 3.7.16 and later */
int (*close_v2)(sqlite3*);
const char *(*db_filename)(sqlite3*,const char*);
int (*db_readonly)(sqlite3*,const char*);
int (*db_release_memory)(sqlite3*);
const char *(*errstr)(int);
int (*stmt_busy)(sqlite3_stmt*);
int (*stmt_readonly)(sqlite3_stmt*);
int (*stricmp)(const char*,const char*);
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*vsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
void(*)(void*));
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
void(*)(void*),unsigned char);
int (*cancel_auto_extension)(void(*)(void));
int (*load_extension)(sqlite3*,const char*,const char*,char**);
void *(*malloc64)(sqlite3_uint64);
sqlite3_uint64 (*msize)(void*);
void *(*realloc64)(void*,sqlite3_uint64);
void (*reset_auto_extension)(void);
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
void(*)(void*));
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
/* Version 3.8.11 and later */
sqlite3_value *(*value_dup)(const sqlite3_value*);
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
/* Version 3.9.0 and later */
unsigned int (*value_subtype)(sqlite3_value*);
void (*result_subtype)(sqlite3_context*,unsigned int);
/* Version 3.10.0 and later */
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
/* Version 3.18.0 and later */
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
sqlite3 *db, /* Handle to the database. */
char **pzErrMsg, /* Used to set error string on failure. */
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
);
/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition. But the main library does not want to redefine
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob sqlite3_api->bind_blob
#define sqlite3_bind_double sqlite3_api->bind_double
#define sqlite3_bind_int sqlite3_api->bind_int
#define sqlite3_bind_int64 sqlite3_api->bind_int64
#define sqlite3_bind_null sqlite3_api->bind_null
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
#define sqlite3_bind_text sqlite3_api->bind_text
#define sqlite3_bind_text16 sqlite3_api->bind_text16
#define sqlite3_bind_value sqlite3_api->bind_value
#define sqlite3_busy_handler sqlite3_api->busy_handler
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
#define sqlite3_changes sqlite3_api->changes
#define sqlite3_close sqlite3_api->close
#define sqlite3_collation_needed sqlite3_api->collation_needed
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
#define sqlite3_column_blob sqlite3_api->column_blob
#define sqlite3_column_bytes sqlite3_api->column_bytes
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
#define sqlite3_column_count sqlite3_api->column_count
#define sqlite3_column_database_name sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype sqlite3_api->column_decltype
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
#define sqlite3_column_double sqlite3_api->column_double
#define sqlite3_column_int sqlite3_api->column_int
#define sqlite3_column_int64 sqlite3_api->column_int64
#define sqlite3_column_name sqlite3_api->column_name
#define sqlite3_column_name16 sqlite3_api->column_name16
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
#define sqlite3_column_table_name sqlite3_api->column_table_name
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
#define sqlite3_column_text sqlite3_api->column_text
#define sqlite3_column_text16 sqlite3_api->column_text16
#define sqlite3_column_type sqlite3_api->column_type
#define sqlite3_column_value sqlite3_api->column_value
#define sqlite3_commit_hook sqlite3_api->commit_hook
#define sqlite3_complete sqlite3_api->complete
#define sqlite3_complete16 sqlite3_api->complete16
#define sqlite3_create_collation sqlite3_api->create_collation
#define sqlite3_create_collation16 sqlite3_api->create_collation16
#define sqlite3_create_function sqlite3_api->create_function
#define sqlite3_create_function16 sqlite3_api->create_function16
#define sqlite3_create_module sqlite3_api->create_module
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
#define sqlite3_data_count sqlite3_api->data_count
#define sqlite3_db_handle sqlite3_api->db_handle
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
#define sqlite3_errcode sqlite3_api->errcode
#define sqlite3_errmsg sqlite3_api->errmsg
#define sqlite3_errmsg16 sqlite3_api->errmsg16
#define sqlite3_exec sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired sqlite3_api->expired
#endif
#define sqlite3_finalize sqlite3_api->finalize
#define sqlite3_free sqlite3_api->free
#define sqlite3_free_table sqlite3_api->free_table
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover sqlite3_api->global_recover
#endif
#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
#define sqlite3_malloc sqlite3_api->malloc
#define sqlite3_mprintf sqlite3_api->mprintf
#define sqlite3_open sqlite3_api->open
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
#define sqlite3_reset sqlite3_api->reset
#define sqlite3_result_blob sqlite3_api->result_blob
#define sqlite3_result_double sqlite3_api->result_double
#define sqlite3_result_error sqlite3_api->result_error
#define sqlite3_result_error16 sqlite3_api->result_error16
#define sqlite3_result_int sqlite3_api->result_int
#define sqlite3_result_int64 sqlite3_api->result_int64
#define sqlite3_result_null sqlite3_api->result_null
#define sqlite3_result_text sqlite3_api->result_text
#define sqlite3_result_text16 sqlite3_api->result_text16
#define sqlite3_result_text16be sqlite3_api->result_text16be
#define sqlite3_result_text16le sqlite3_api->result_text16le
#define sqlite3_result_value sqlite3_api->result_value
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
#define sqlite3_total_changes sqlite3_api->total_changes
#define sqlite3_trace sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook sqlite3_api->update_hook
#define sqlite3_user_data sqlite3_api->user_data
#define sqlite3_value_blob sqlite3_api->value_blob
#define sqlite3_value_bytes sqlite3_api->value_bytes
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
#define sqlite3_value_double sqlite3_api->value_double
#define sqlite3_value_int sqlite3_api->value_int
#define sqlite3_value_int64 sqlite3_api->value_int64
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
#define sqlite3_value_text sqlite3_api->value_text
#define sqlite3_value_text16 sqlite3_api->value_text16
#define sqlite3_value_text16be sqlite3_api->value_text16be
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
#define sqlite3_blob_close sqlite3_api->blob_close
#define sqlite3_blob_open sqlite3_api->blob_open
#define sqlite3_blob_read sqlite3_api->blob_read
#define sqlite3_blob_write sqlite3_api->blob_write
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
#define sqlite3_file_control sqlite3_api->file_control
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
#define sqlite3_memory_used sqlite3_api->memory_used
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
#define sqlite3_mutex_free sqlite3_api->mutex_free
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
#define sqlite3_mutex_try sqlite3_api->mutex_try
#define sqlite3_open_v2 sqlite3_api->open_v2
#define sqlite3_release_memory sqlite3_api->release_memory
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
#define sqlite3_sleep sqlite3_api->sleep
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find sqlite3_api->vfs_find
#define sqlite3_vfs_register sqlite3_api->vfs_register
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
#define sqlite3_result_error_code sqlite3_api->result_error_code
#define sqlite3_test_control sqlite3_api->test_control
#define sqlite3_randomness sqlite3_api->randomness
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
#define sqlite3_limit sqlite3_api->limit
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
#define sqlite3_backup_finish sqlite3_api->backup_finish
#define sqlite3_backup_init sqlite3_api->backup_init
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
#define sqlite3_backup_step sqlite3_api->backup_step
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
#define sqlite3_db_config sqlite3_api->db_config
#define sqlite3_db_mutex sqlite3_api->db_mutex
#define sqlite3_db_status sqlite3_api->db_status
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
#define sqlite3_log sqlite3_api->log
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
#define sqlite3_sourceid sqlite3_api->sourceid
#define sqlite3_stmt_status sqlite3_api->stmt_status
#define sqlite3_strnicmp sqlite3_api->strnicmp
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook sqlite3_api->wal_hook
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
#define sqlite3_vtab_config sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
/* Version 3.7.16 and later */
#define sqlite3_close_v2 sqlite3_api->close_v2
#define sqlite3_db_filename sqlite3_api->db_filename
#define sqlite3_db_readonly sqlite3_api->db_readonly
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
#define sqlite3_errstr sqlite3_api->errstr
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
#define sqlite3_stricmp sqlite3_api->stricmp
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
#define sqlite3_bind_text64 sqlite3_api->bind_text64
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
#define sqlite3_load_extension sqlite3_api->load_extension
#define sqlite3_malloc64 sqlite3_api->malloc64
#define sqlite3_msize sqlite3_api->msize
#define sqlite3_realloc64 sqlite3_api->realloc64
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
/* Version 3.8.11 and later */
#define sqlite3_value_dup sqlite3_api->value_dup
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
/* Version 3.9.0 and later */
#define sqlite3_value_subtype sqlite3_api->value_subtype
#define sqlite3_result_subtype sqlite3_api->result_subtype
/* Version 3.10.0 and later */
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
/* Version 3.18.0 and later */
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
# define SQLITE_EXTENSION_INIT3 \
extern const sqlite3_api_routines *sqlite3_api;
#else
/* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* SQLITE3EXT_H */

1
jni/su Submodule

Submodule jni/su added at 1bbf96a0a7

38
jni/utils/list.c Normal file
View File

@@ -0,0 +1,38 @@
/* list.h - Double link list implementation
*/
#include <stdlib.h>
#include <string.h>
#include "list.h"
void init_list_head(struct list_head *head) {
head->next = head;
head->prev = head;
}
void list_insert(struct list_head *pos, struct list_head *node) {
// First construct our new node
node->next = pos->next;
node->prev = pos;
// Maintain the list
pos->next->prev = node;
pos->next = node;
}
void list_insert_end(struct list_head *head, struct list_head *node) {
list_insert(head->prev, node);
}
void list_pop(struct list_head *pos) {
// Maintain the list
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
// Remove references
pos->next = pos;
pos->prev = pos;
}
void list_pop_end(struct list_head *head) {
return list_pop(head->prev);
}

30
jni/utils/list.h Normal file
View File

@@ -0,0 +1,30 @@
/* list.h - Double link list implementation
*/
#ifndef _LIST_H_
#define _LIST_H_
#include <stddef.h>
struct list_head {
struct list_head *next;
struct list_head *prev;
};
void init_list_head(struct list_head *head);
void list_insert(struct list_head *pos, struct list_head *node);
void list_insert_end(struct list_head *head, struct list_head *node);
void list_pop(struct list_head *pos);
void list_pop_end(struct list_head *head);
#define list_entry(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_r(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
#endif

475
jni/utils/misc.c Normal file
View File

@@ -0,0 +1,475 @@
/* misc.c - Store all functions that are unable to be catagorized clearly
*/
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <errno.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <selinux/selinux.h>
#include "magisk.h"
#include "utils.h"
int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 };
unsigned get_shell_uid() {
struct passwd* ppwd = getpwnam("shell");
if (NULL == ppwd)
return 2000;
return ppwd->pw_uid;
}
unsigned get_system_uid() {
struct passwd* ppwd = getpwnam("system");
if (NULL == ppwd)
return 1000;
return ppwd->pw_uid;
}
unsigned get_radio_uid() {
struct passwd* ppwd = getpwnam("radio");
if (NULL == ppwd)
return 1001;
return ppwd->pw_uid;
}
int check_data() {
int ret = 0;
char buffer[4096];
FILE *fp = xfopen("/proc/mounts", "r");
while (fgets(buffer, sizeof(buffer), fp)) {
if (strstr(buffer, " /data ")) {
if (strstr(buffer, "tmpfs") == NULL)
ret = 1;
break;
}
}
fclose(fp);
return ret;
}
/* All the string should be freed manually!! */
int file_to_vector(const char* filename, struct vector *v) {
char *line = NULL;
size_t len = 0;
ssize_t read;
FILE *fp = fopen(filename, "r");
if (fp == NULL)
return 1;
while ((read = getline(&line, &len, fp)) != -1) {
// Remove end newline
if (line[read - 1] == '\n')
line[read - 1] = '\0';
vec_push_back(v, line);
line = NULL;
}
fclose(fp);
return 0;
}
int vector_to_file(const char *filename, struct vector *v) {
FILE *fp = xfopen(filename, "w");
if (fp == NULL)
return 1;
char *line;
vec_for_each(v, line) {
fprintf(fp, "%s\n", line);
}
fclose(fp);
return 0;
}
/* Check if the string only contains digits */
int isNum(const char *s) {
int len = strlen(s);
for (int i = 0; i < len; ++i)
if (s[i] < '0' || s[i] > '9')
return 0;
return 1;
}
/* Read a whole line from file descriptor */
ssize_t fdgets(char *buf, const size_t size, int fd) {
ssize_t len = 0;
buf[0] = '\0';
while (read(fd, buf + len, 1) >= 0 && len < size - 1) {
if (buf[len] == '\0' || buf[len++] == '\n') {
buf[len] = '\0';
break;
}
}
buf[size - 1] = '\0';
return len;
}
/* Call func for each process */
void ps(void (*func)(int)) {
DIR *dir;
struct dirent *entry;
if (!(dir = xopendir("/proc")))
return;
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) {
if (isNum(entry->d_name))
func(atoi(entry->d_name));
}
}
closedir(dir);
}
// Internal usage
static void (*ps_filter_cb)(int);
static const char *ps_filter_pattern;
static void proc_name_filter(int pid) {
char buf[64];
int fd;
snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
if ((fd = open(buf, O_RDONLY)) == -1)
return;
if (fdgets(buf, sizeof(buf), fd) == 0) {
snprintf(buf, sizeof(buf), "/proc/%d/comm", pid);
close(fd);
if ((fd = open(buf, O_RDONLY)) == -1)
return;
fdgets(buf, sizeof(buf), fd);
}
if (strcmp(buf, ps_filter_pattern) == 0) {
ps_filter_cb(pid);
}
close(fd);
}
/* Call func with process name filtered with pattern */
void ps_filter_proc_name(const char *pattern, void (*func)(int)) {
ps_filter_cb = func;
ps_filter_pattern = ((pattern == NULL) ? "" : pattern);
ps(proc_name_filter);
}
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;
}
#define DEV_BLOCK "/dev/block"
void unlock_blocks() {
char path[PATH_MAX];
DIR *dir;
struct dirent *entry;
int fd, OFF = 0;
if (!(dir = xopendir(DEV_BLOCK)))
return;
while((entry = readdir(dir))) {
if (entry->d_type == DT_BLK &&
strstr(entry->d_name, "ram") == NULL &&
strstr(entry->d_name, "loop") == NULL &&
strstr(entry->d_name, "dm-0") == NULL) {
snprintf(path, sizeof(path), "%s/%s", DEV_BLOCK, entry->d_name);
if ((fd = xopen(path, O_RDONLY)) < 0)
continue;
if (ioctl(fd, BLKROSET, &OFF) == -1)
PLOGE("unlock %s", path);
close(fd);
}
}
closedir(dir);
}
void setup_sighandlers(void (*handler)(int)) {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = handler;
for (int i = 0; quit_signals[i]; ++i) {
sigaction(quit_signals[i], &act, NULL);
}
}
/*
fd == NULL -> Ignore output
*fd == 0 -> Open pipe and set *fd to the read end
*fd != 0 -> STDOUT (or STDERR) will be redirected to *fd
*/
int run_command(int err, int *fd, const char *path, char *const argv[]) {
int pipefd[2], writeEnd = 0;
if (fd) {
if (*fd == 0) {
if (pipe(pipefd) == -1)
return -1;
writeEnd = pipefd[1];
// Give the read end of the pipe
*fd = pipefd[0];
}
}
int pid = fork();
if (pid != 0) {
if (writeEnd) close(writeEnd);
return pid;
}
if (fd) {
if (writeEnd == 0) writeEnd = *fd;
xdup2(writeEnd, STDOUT_FILENO);
if (err) xdup2(writeEnd, STDERR_FILENO);
}
execv(path, argv);
PLOGE("execv");
return -1;
}
int mkdir_p(const char *pathname, mode_t mode) {
char *path = strdup(pathname), *p;
errno = 0;
for (p = path + 1; *p; ++p) {
if (*p == '/') {
*p = '\0';
if (mkdir(path, mode) == -1) {
if (errno != EEXIST)
return -1;
}
*p = '/';
}
}
if (mkdir(path, mode) == -1) {
if (errno != EEXIST)
return -1;
}
free(path);
return 0;
}
int bind_mount(const char *from, const char *to) {
int ret = xmount(from, to, NULL, MS_BIND, NULL);
#ifdef DEBUG
LOGD("bind_mount: %s -> %s\n", from, to);
#else
LOGI("bind_mount: %s\n", to);
#endif
return ret;
}
int open_new(const char *filename) {
return xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
}
// file/link -> file/link only!!
int cp_afc(const char *source, const char *target) {
struct stat buf;
xlstat(source, &buf);
unlink(target);
char *con;
if (S_ISREG(buf.st_mode)) {
int sfd, tfd;
sfd = xopen(source, O_RDONLY);
tfd = xopen(target, O_WRONLY | O_CREAT | O_TRUNC);
xsendfile(tfd, sfd, NULL, buf.st_size);
fchmod(tfd, buf.st_mode & 0777);
fchown(tfd, buf.st_uid, buf.st_gid);
fgetfilecon(sfd, &con);
fsetfilecon(tfd, con);
free(con);
close(sfd);
close(tfd);
} else if (S_ISLNK(buf.st_mode)) {
char buffer[PATH_MAX];
xreadlink(source, buffer, sizeof(buffer));
xsymlink(buffer, target);
lgetfilecon(source, &con);
lsetfilecon(target, con);
free(con);
} else {
return 1;
}
return 0;
}
int clone_dir(const char *source, const char *target) {
DIR *dir;
struct dirent *entry;
char *s_path, *t_path;
if (!(dir = xopendir(source)))
return 1;
s_path = xmalloc(PATH_MAX);
t_path = xmalloc(PATH_MAX);
mkdir_p(target, 0755);
clone_attr(source, target);
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
snprintf(s_path, PATH_MAX, "%s/%s", source, entry->d_name);
snprintf(t_path, PATH_MAX, "%s/%s", target, entry->d_name);
switch (entry->d_type) {
case DT_DIR:
clone_dir(s_path, t_path);
break;
case DT_REG:
case DT_LNK:
cp_afc(s_path, t_path);
break;
}
}
free(s_path);
free(t_path);
closedir(dir);
return 0;
}
int rm_rf(const char *target) {
if (access(target, F_OK) == -1)
return 0;
struct stat buf;
xlstat(target, &buf);
char *next;
if (S_ISDIR(buf.st_mode)) {
DIR *dir;
struct dirent *entry;
if (!(dir = xopendir(target)))
return 1;
next = xmalloc(PATH_MAX);
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
snprintf(next, PATH_MAX, "%s/%s", target, entry->d_name);
switch (entry->d_type) {
case DT_DIR:
rm_rf(next);
break;
case DT_REG:
case DT_LNK:
unlink(next);
break;
}
}
free(next);
closedir(dir);
rmdir(target);
} else if (S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) {
unlink(target);
} else {
return 1;
}
return 0;
}
void clone_attr(const char *source, const char *target) {
struct stat buf;
xstat(source, &buf);
chmod(target, buf.st_mode & 0777);
chown(target, buf.st_uid, buf.st_gid);
char *con;
lgetfilecon(source, &con);
lsetfilecon(target, con);
free(con);
}
void get_client_cred(int fd, struct ucred *cred) {
socklen_t ucred_length = sizeof(*cred);
if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length))
PLOGE("getsockopt");
}
int create_img(const char *img, int size) {
unlink(img);
LOGI("Create %s with size %dM\n", img, size);
// Create a temp file with the file contexts
char file_contexts[] = "/magisk(/.*)? u:object_r:system_file:s0\n";
int fd = xopen("/dev/file_contexts_image", O_WRONLY | O_CREAT | O_TRUNC, 0644);
xwrite(fd, file_contexts, sizeof(file_contexts));
close(fd);
char command[PATH_MAX];
snprintf(command, sizeof(command),
"make_ext4fs -l %dM -a /magisk -S /dev/file_contexts_image %s", size, img);
int ret = system(command);
unlink("/dev/file_contexts_image");
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];
snprintf(buffer, sizeof(buffer), "e2fsck -n %s 2>/dev/null | tail -n 1", img);
char *const command[] = { "sh", "-c", buffer, NULL };
int pid, fd = 0;
pid = run_command(0, &fd, "/system/bin/sh", command);
fdgets(buffer, sizeof(buffer), fd);
close(fd);
if (pid == -1)
return 1;
waitpid(pid, NULL, 0);
char *tok;
tok = strtok(buffer, ",");
while(tok != NULL) {
if (strstr(tok, "blocks"))
break;
tok = strtok(NULL, ",");
}
sscanf(tok, "%d/%d", used, total);
*used = *used / 256 + 1;
*total /= 256;
return 0;
}
int resize_img(const char *img, int size) {
LOGI("Resize %s to %dM\n", img, size);
char buffer[PATH_MAX];
snprintf(buffer, PATH_MAX, "e2fsck -yf %s; resize2fs %s %dM;", img, img, size);
return system(buffer);
}
int switch_mnt_ns(int pid) {
char mnt[32];
snprintf(mnt, sizeof(mnt), "/proc/%d/ns/mnt", pid);
if(access(mnt, R_OK) == -1) return 1; // Maybe process died..
int fd, ret;
fd = xopen(mnt, O_RDONLY);
if (fd < 0) return 1;
// Switch to its namespace
ret = setns(fd, 0);
close(fd);
return ret;
}

99
jni/utils/utils.h Normal file
View File

@@ -0,0 +1,99 @@
/* util.h - Header for all utility functions
*/
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stdio.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include "vector.h"
#define UID_SHELL (get_shell_uid())
#define UID_ROOT 0
#define UID_SYSTEM (get_system_uid())
#define UID_RADIO (get_radio_uid())
extern int quit_signals[];
// xwrap.c
FILE *xfopen(const char *pathname, const char *mode);
FILE *xfdopen(int fd, const char *mode);
#define GET_MACRO(_1, _2, _3, NAME, ...) NAME
#define xopen(...) GET_MACRO(__VA_ARGS__, xopen3, xopen2)(__VA_ARGS__)
int xopen2(const char *pathname, int flags);
int xopen3(const char *pathname, int flags, mode_t mode);
ssize_t xwrite(int fd, const void *buf, size_t count);
ssize_t xread(int fd, void *buf, size_t count);
ssize_t xxread(int fd, void *buf, size_t count);
int xpipe(int pipefd[2]);
int xsetns(int fd, int nstype);
DIR *xopendir(const char *name);
struct dirent *xreaddir(DIR *dirp);
pid_t xsetsid();
int xsocket(int domain, int type, int protocol);
int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int xconnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int xlisten(int sockfd, int backlog);
int xaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
void *xmalloc(size_t size);
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t size);
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags);
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
int xsocketpair(int domain, int type, int protocol, int sv[2]);
int xstat(const char *pathname, struct stat *buf);
int xlstat(const char *pathname, struct stat *buf);
int xdup2(int oldfd, int newfd);
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz);
int xsymlink(const char *target, const char *linkpath);
int xmount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);
int xumount(const char *target);
int xumount2(const char *target, int flags);
int xchmod(const char *pathname, mode_t mode);
int xrename(const char *oldpath, const char *newpath);
int xmkdir(const char *pathname, mode_t mode);
void *xmmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count);
int xmkdir_p(const char *pathname, mode_t mode);
// misc.c
unsigned get_shell_uid();
unsigned get_system_uid();
unsigned get_radio_uid();
int check_data();
int file_to_vector(const char* filename, struct vector *v);
int vector_to_file(const char* filename, struct vector *v);
int isNum(const char *s);
ssize_t fdgets(char *buf, size_t size, int fd);
void ps(void (*func)(int));
void ps_filter_proc_name(const char *filter, void (*func)(int));
int create_links(const char *bin, const char *path);
void unlock_blocks();
void setup_sighandlers(void (*handler)(int));
int run_command(int err, int *fd, const char *path, char *const argv[]);
int mkdir_p(const char *pathname, mode_t mode);
int bind_mount(const char *from, const char *to);
int open_new(const char *filename);
int cp_afc(const char *source, const char *target);
int clone_dir(const char *source, const char *target);
int rm_rf(const char *target);
void clone_attr(const char *source, const char *target);
void get_client_cred(int fd, struct ucred *cred);
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);
int switch_mnt_ns(int pid);
#endif

67
jni/utils/vector.c Normal file
View File

@@ -0,0 +1,67 @@
/* vector.c - A simple vector implementation in c
*/
#include <stdlib.h>
#include <string.h>
#include "vector.h"
void vec_init(struct vector *v) {
if (v == NULL) return;
vec_size(v) = 0;
vec_cap(v) = 1;
vec_entry(v) = malloc(sizeof(void*));
}
void vec_push_back(struct vector *v, void *p) {
if (v == NULL) return;
if (vec_size(v) == vec_cap(v)) {
vec_cap(v) *= 2;
vec_entry(v) = realloc(vec_entry(v), sizeof(void*) * vec_cap(v));
}
vec_entry(v)[vec_size(v)] = p;
++vec_size(v);
}
void *vec_pop_back(struct vector *v) {
void *ret = vec_entry(v)[vec_size(v) - 1];
--vec_size(v);
return ret;
}
void vec_sort(struct vector *v, int (*compar)(const void *, const void *)) {
if (v == NULL) return;
qsort(vec_entry(v), vec_size(v), sizeof(void*), compar);
}
/* Will cleanup only the vector itself
* use in cases when each element requires special cleanup
*/
void vec_destroy(struct vector *v) {
if (v == NULL) return;
vec_size(v) = 0;
vec_cap(v) = 0;
free(vec_entry(v));
vec_entry(v) = NULL; // Prevent double destroy segfault
}
/* Will cleanup each element AND the vector itself
* Shall be the general case
*/
void vec_deep_destroy(struct vector *v) {
if (v == NULL) return;
void *e;
vec_for_each(v, e) {
free(e);
}
vec_destroy(v);
}
struct vector *vec_dup(struct vector *v) {
struct vector *ret = malloc(sizeof(*ret));
vec_size(ret) = vec_size(v);
vec_cap(ret) = vec_cap(v);
vec_entry(v) = malloc(sizeof(void*) * vec_cap(ret));
memcpy(vec_entry(ret), vec_entry(v), sizeof(void*) * vec_cap(ret));
return ret;
}

35
jni/utils/vector.h Normal file
View File

@@ -0,0 +1,35 @@
/* vector.h - A simple vector implementation in c
*/
#ifndef _VECTOR_H_
#define _VECTOR_H_
#include <sys/types.h>
struct vector {
size_t size;
size_t cap;
void **data;
};
void vec_init(struct vector *v);
void vec_push_back(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);
#define vec_size(v) (v)->size
#define vec_cap(v) (v)->cap
#define vec_entry(v) (v)->data
/* 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[_])
#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])
#endif

339
jni/utils/xwrap.c Normal file
View File

@@ -0,0 +1,339 @@
/* xwrap.c - wrappers around existing library functions.
*
* Functions with the x prefix are wrappers that either succeed or kill the
* program with an error message, but never return failure. They usually have
* the same arguments and return value as the function they wrap.
*
*/
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/sendfile.h>
#include "magisk.h"
#include "utils.h"
FILE *xfopen(const char *pathname, const char *mode) {
FILE *fp = fopen(pathname, mode);
if (fp == NULL) {
PLOGE("fopen: %s", pathname);
}
return fp;
}
FILE *xfdopen(int fd, const char *mode) {
FILE *fp = fdopen(fd, mode);
if (fp == NULL) {
PLOGE("fopen");
}
return fp;
}
int xopen2(const char *pathname, int flags) {
int fd = open(pathname, flags);
if (fd < 0) {
PLOGE("open: %s", pathname);
}
return fd;
}
int xopen3(const char *pathname, int flags, mode_t mode) {
int fd = open(pathname, flags, mode);
if (fd < 0) {
PLOGE("open: %s", pathname);
}
return fd;
}
ssize_t xwrite(int fd, const void *buf, size_t count) {
int ret = write(fd, buf, count);
if (count != ret) {
PLOGE("write");
}
return ret;
}
// Read error other than EOF
ssize_t xread(int fd, void *buf, size_t count) {
int ret = read(fd, buf, count);
if (ret < 0) {
PLOGE("read");
}
return ret;
}
// Read exact same size as count
ssize_t xxread(int fd, void *buf, size_t count) {
int ret = read(fd, buf, count);
if (count != ret) {
PLOGE("read");
}
return ret;
}
int xpipe(int pipefd[2]) {
int ret = pipe(pipefd);
if (ret == -1) {
PLOGE("pipe");
}
return ret;
}
int xsetns(int fd, int nstype) {
int ret = setns(fd, nstype);
if (ret == -1) {
PLOGE("setns");
}
return ret;
}
DIR *xopendir(const char *name) {
DIR *d = opendir(name);
if (d == NULL) {
PLOGE("opendir: %s", name);
}
return d;
}
struct dirent *xreaddir(DIR *dirp) {
errno = 0;
struct dirent *e = readdir(dirp);
if (errno && e == NULL) {
PLOGE("readdir");
}
return e;
}
pid_t xsetsid() {
pid_t pid = setsid();
if (pid == -1) {
PLOGE("setsid");
}
return pid;
}
int xsocket(int domain, int type, int protocol) {
int fd = socket(domain, type, protocol);
if (fd == -1) {
PLOGE("socket");
}
return fd;
}
int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int ret = bind(sockfd, addr, addrlen);
if (ret == -1) {
PLOGE("bind");
}
return ret;
}
int xconnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int ret = connect(sockfd, addr, addrlen);
if (ret == -1) {
PLOGE("bind");
}
return ret;
}
int xlisten(int sockfd, int backlog) {
int ret = listen(sockfd, backlog);
if (ret == -1) {
PLOGE("listen");
}
return ret;
}
int xaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
int fd = accept(sockfd, addr, addrlen);
if (fd == -1) {
PLOGE("accept");
}
return fd;
}
void *xmalloc(size_t size) {
void *p = malloc(size);
if (p == NULL) {
PLOGE("malloc");
}
return p;
}
void *xcalloc(size_t nmemb, size_t size) {
void *p = calloc(nmemb, size);
if (p == NULL) {
PLOGE("calloc");
}
return p;
}
void *xrealloc(void *ptr, size_t size) {
void *p = realloc(ptr, size);
if (p == NULL) {
PLOGE("realloc");
}
return p;
}
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) {
int sent = sendmsg(sockfd, msg, flags);
if (sent == -1) {
PLOGE("sendmsg");
}
return sent;
}
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
int rec = recvmsg(sockfd, msg, flags);
if (rec == -1) {
PLOGE("recvmsg");
}
return rec;
}
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg) {
errno = pthread_create(thread, attr, start_routine, arg);
if (errno) {
PLOGE("pthread_create");
}
return errno;
}
int xsocketpair(int domain, int type, int protocol, int sv[2]) {
int ret = socketpair(domain, type, protocol, sv);
if (ret == -1) {
PLOGE("socketpair");
}
return ret;
}
int xstat(const char *pathname, struct stat *buf) {
int ret = stat(pathname, buf);
if (ret == -1) {
PLOGE("stat %s", pathname);
}
return ret;
}
int xlstat(const char *pathname, struct stat *buf) {
int ret = lstat(pathname, buf);
if (ret == -1) {
PLOGE("lstat %s", pathname);
}
return ret;
}
int xdup2(int oldfd, int newfd) {
int ret = dup2(oldfd, newfd);
if (ret == -1) {
PLOGE("dup2");
}
return ret;
}
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) {
ssize_t ret = readlink(pathname, buf, bufsiz);
if (ret == -1) {
PLOGE("readlink %s", pathname);
} else {
buf[ret] = '\0';
++ret;
}
return ret;
}
int xsymlink(const char *target, const char *linkpath) {
int ret = symlink(target, linkpath);
if (ret == -1) {
PLOGE("symlink %s->%s", target, linkpath);
}
return ret;
}
int xmount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data) {
int ret = mount(source, target, filesystemtype, mountflags, data);
if (ret == -1) {
PLOGE("mount %s->%s", source, target);
}
return ret;
}
int xumount(const char *target) {
int ret = umount(target);
if (ret == -1) {
PLOGE("umount %s", target);
}
return ret;
}
int xumount2(const char *target, int flags) {
int ret = umount2(target, flags);
if (ret == -1) {
PLOGE("umount2 %s", target);
}
return ret;
}
int xchmod(const char *pathname, mode_t mode) {
int ret = chmod(pathname, mode);
if (ret == -1) {
PLOGE("chmod %s %u", pathname, mode);
}
return ret;
}
int xrename(const char *oldpath, const char *newpath) {
int ret = rename(oldpath, newpath);
if (ret == -1) {
PLOGE("rename %s->%s", oldpath, newpath);
}
return ret;
}
int xmkdir(const char *pathname, mode_t mode) {
int ret = mkdir(pathname, mode);
if (ret == -1) {
PLOGE("mkdir %s %u", pathname, mode);
}
return ret;
}
void *xmmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset) {
void *ret = mmap(addr, length, prot, flags, fd, offset);
if (ret == MAP_FAILED) {
PLOGE("mmap");
}
return ret;
}
ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
ssize_t ret = sendfile(out_fd, in_fd, offset, count);
if (count != ret) {
PLOGE("sendfile");
}
return ret;
}
int xmkdir_p(const char *pathname, mode_t mode) {
int ret = mkdir_p(pathname, mode);
if (ret == -1) {
PLOGE("mkdir_p %s", pathname);
}
return ret;
}

220
scripts/boot_patch.sh Normal file
View File

@@ -0,0 +1,220 @@
#!/system/bin/sh
##########################################################################################
#
# Magisk Boot Image Patcher
# by topjohnwu
#
# This script should be placed in a directory with at least the following files:
#
# File name type Description
#
# boot_patch.sh script A script to patch boot. Expect path to boot image as parameter.
# (this file) The script will use binaries and files in its same directory
# to complete the patching process
# magisk binary The main binary for all Magisk operations.
# It is also used to patch the sepolicy in the ramdisk.
# magiskboot binary A tool to unpack boot image, decompress ramdisk, extract ramdisk
# and patch common patches such as forceencrypt, remove dm-verity.
# init.magisk.rc script A new line will be added to init.rc to import this script.
# All magisk entrypoints are defined here
#
# If the script is not running as root, then the input boot image should be a stock image
# or have a backup included in ramdisk internally, since we cannot access the stock boot
# image placed under /data we've created when previously installing
#
##########################################################################################
CWD=`pwd`
cd `dirname $1`
BOOTIMAGE="`pwd`/`basename $1`"
cd "$CWD"
if [ -z $BOOTIMAGE ]; then
ui_print_wrap "This script requires a boot image as a parameter"
exit 1
fi
# Presets
[ -z $KEEPVERITY ] && KEEPVERITY=false
[ -z $KEEPFORCEENCRYPT ] && KEEPFORCEENCRYPT=false
# Detect whether running as root
[ `id -u` -eq 0 ] && ROOT=true || ROOT=false
# Call ui_print_wrap if exists, or else simply use echo
# Useful when wrapped in flashable zip
ui_print_wrap() {
type ui_print >/dev/null 2>&1 && ui_print "$1" || echo "$1"
}
grep_prop() {
REGEX="s/^$1=//p"
shift
FILES=$@
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
}
# --cpio-add <incpio> <mode> <entry> <infile>
cpio_add() {
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-add ramdisk.cpio $1 $2 $3
}
# --cpio-extract <incpio> <entry> <outfile>
cpio_extract() {
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-extract ramdisk.cpio $1 $2
}
# --cpio-mkdir <incpio> <mode> <entry>
cpio_mkdir() {
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-mkdir ramdisk.cpio $1 $2
}
##########################################################################################
# Prework
##########################################################################################
# Switch to the location of the script file
[ -z $SOURCEDMODE ] && cd "`dirname "${BASH_SOURCE:-$0}"`"
chmod +x ./*
# Detect ARCH
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64 || SYSTEMLIB=/system/lib
ui_print_wrap "- Unpacking boot image"
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --unpack $BOOTIMAGE
case $? in
1 )
ui_print_wrap "! Unable to unpack boot image"
exit 1
;;
2 )
ui_print_wrap "! Sony ELF32 format detected"
ui_print_wrap "! Please use BootBridge from @AdrianDC to flash Magisk"
exit 1
;;
3 )
ui_print_wrap "! Sony ELF64 format detected"
ui_print_wrap "! Stock kernel cannot be patched, please use a custom kernel"
exit 1
esac
##########################################################################################
# Ramdisk restores
##########################################################################################
# Test patch status and do restore, after this section, ramdisk.cpio.orig is guaranteed to exist
ui_print_wrap "- Checking ramdisk status"
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-test ramdisk.cpio
case $? in
0 ) # Stock boot
ui_print_wrap "- Stock boot image detected!"
ui_print_wrap "- Backing up stock boot image"
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --sha1 $BOOTIMAGE | tail -n 1`
STOCKDUMP=stock_boot_${SHA1}.img
dd if=$BOOTIMAGE of=$STOCKDUMP
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --compress $STOCKDUMP
cp -af ramdisk.cpio ramdisk.cpio.orig
;;
1 ) # Magisk patched
ui_print_wrap "- Magisk patched image detected!"
# Find SHA1 of stock boot image
if [ -z $SHA1 ]; then
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc.old
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc.old`
rm -f init.magisk.rc.old
fi
OK=false
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-restore ramdisk.cpio
if [ $? -eq 0 ]; then
ui_print_wrap "- Ramdisk restored from internal backup"
OK=true
else
# Restore failed
ui_print_wrap "! Cannot restore from internal backup"
# If we are root and SHA1 known, we try to find the stock backup
if $ROOT && [ ! -z $SHA1 ]; then
STOCKDUMP=/data/stock_boot_${SHA1}.img
if [ -f ${STOCKDUMP}.gz ]; then
ui_print_wrap "- Stock boot image backup found"
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --unpack stock_boot.img
rm -f stock_boot.img
OK=true
fi
fi
fi
if ! $OK; then
ui_print_wrap "! Ramdisk restoration incomplete"
ui_print_wrap "! Will still try to continue installation"
fi
cp -af ramdisk.cpio ramdisk.cpio.orig
;;
2 ) # Other patched
ui_print_wrap "! Boot image patched by other programs!"
ui_print_wrap "! Please restore stock boot image"
exit 1
;;
esac
##########################################################################################
# Ramdisk patches
##########################################################################################
ui_print_wrap "- Patching ramdisk"
# The common patches
$KEEPVERITY || LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-patch-dmverity ramdisk.cpio
$KEEPFORCEENCRYPT || LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-patch-forceencrypt ramdisk.cpio
# Add magisk entrypoint
cpio_extract init.rc init.rc
grep "import /init.magisk.rc" init.rc >/dev/null || sed -i '1,/.*import.*/s/.*import.*/import \/init.magisk.rc\n&/' init.rc
sed -i "/selinux.reload_policy/d" init.rc
cpio_add 750 init.rc init.rc
rm -f init.rc
# sepolicy patches
cpio_extract sepolicy sepolicy
LD_LIBRARY_PATH=$SYSTEMLIB ./magisk magiskpolicy --load sepolicy --save sepolicy --minimal
cpio_add 644 sepolicy sepolicy
rm -f sepolicy
# Add new items
if [ ! -z $SHA1 ]; then
cp init.magisk.rc init.magisk.rc.bak
echo "# STOCKSHA1=$SHA1" >> init.magisk.rc
fi
cpio_add 750 init.magisk.rc init.magisk.rc
[ -f init.magisk.rc.bak ] && mv init.magisk.rc.bak init.magisk.rc
cpio_add 755 sbin/magisk magisk
# Create ramdisk backups
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig
rm -f ramdisk.cpio.orig
##########################################################################################
# Repack and flash
##########################################################################################
# Hexpatches
# Remove Samsung RKP in stock kernel
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --hexpatch kernel \
49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
ui_print_wrap "- Repacking boot image"
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --repack $BOOTIMAGE
if [ $? -ne 0 ]; then
ui_print_wrap "! Unable to repack boot image!"
exit 1
fi
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cleanup

346
scripts/flash_script.sh Normal file
View File

@@ -0,0 +1,346 @@
#!/sbin/sh
##########################################################################################
#
# Magisk Flash Script
# by topjohnwu
#
# This script will detect, construct the environment for Magisk
# It will then call boot_patch.sh to patch the boot image
#
##########################################################################################
# Detect whether in boot mode
ps | grep zygote | grep -v grep >/dev/null && BOOTMODE=true || BOOTMODE=false
$BOOTMODE || ps -A | grep zygote | grep -v grep >/dev/null && BOOTMODE=true
# This path should work in any cases
TMPDIR=/dev/tmp
INSTALLER=$TMPDIR/magisk
COMMONDIR=$INSTALLER/common
BOOTTMP=$TMPDIR/boottmp
COREDIR=/magisk/.core
CHROMEDIR=$INSTALLER/chromeos
# Default permissions
umask 022
##########################################################################################
# Flashable update-binary preparation
##########################################################################################
OUTFD=$2
ZIP=$3
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=0
for FD in `ls /proc/$$/fd`; do
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
if [ "$?" -eq "0" ]; then
ps | grep " 3 $FD " | grep -v grep >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=$FD
break
fi
fi
done
fi
mkdir -p $INSTALLER
cd $INSTALLER
unzip -o "$ZIP"
##########################################################################################
# Functions
##########################################################################################
ui_print() {
if $BOOTMODE; then
echo "$1"
else
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
fi
}
getvar() {
local VARNAME=$1
local VALUE=$(eval echo \$"$VARNAME");
for FILE in /dev/.magisk /data/.magisk /cache/.magisk /system/.magisk; do
if [ -z "$VALUE" ]; then
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
if [ ! -z "$LINE" ]; then
VALUE=${LINE#*=}
fi
fi
done
eval $VARNAME=\$VALUE
}
find_boot_image() {
if [ -z "$BOOTIMAGE" ]; then
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION`
if [ ! -z "$BOOTIMAGE" ]; then break; fi
done
fi
if [ -z "$BOOTIMAGE" ]; then
FSTAB="/etc/recovery.fstab"
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
[ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
fi
}
is_mounted() {
if [ ! -z "$2" ]; then
cat /proc/mounts | grep $1 | grep $2, >/dev/null
else
cat /proc/mounts | grep $1 >/dev/null
fi
return $?
}
mount_image() {
if [ ! -d "$2" ]; then
mount -o rw,remount rootfs /
mkdir -p $2 2>/dev/null
($BOOTMODE) && mount -o ro,remount rootfs /
[ ! -d "$2" ] && return 1
fi
if (! is_mounted $2); then
LOOPDEVICE=
for LOOP in 0 1 2 3 4 5 6 7; do
if (! is_mounted $2); then
LOOPDEVICE=/dev/block/loop$LOOP
if [ ! -f "$LOOPDEVICE" ]; then
mknod $LOOPDEVICE b 7 $LOOP 2>/dev/null
fi
losetup $LOOPDEVICE $1
if [ "$?" -eq "0" ]; then
mount -t ext4 -o loop $LOOPDEVICE $2
if (! is_mounted $2); then
/system/bin/toolbox mount -t ext4 -o loop $LOOPDEVICE $2
fi
if (! is_mounted $2); then
/system/bin/toybox mount -t ext4 -o loop $LOOPDEVICE $2
fi
fi
if (is_mounted $2); then
ui_print "- Mounting $1 to $2"
break;
fi
fi
done
fi
}
grep_prop() {
REGEX="s/^$1=//p"
shift
FILES=$@
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
}
remove_system_su() {
if [ -f /system/bin/su -o -f /system/xbin/su ] && [ ! -f /su/bin/su ]; then
ui_print "! System installed root detected, mount rw :("
mount -o rw,remount /system
# SuperSU
if [ -e /system/bin/.ext/.su ]; then
mv -f /system/bin/app_process32_original /system/bin/app_process32 2>/dev/null
mv -f /system/bin/app_process64_original /system/bin/app_process64 2>/dev/null
mv -f /system/bin/install-recovery_original.sh /system/bin/install-recovery.sh 2>/dev/null
cd /system/bin
if [ -e app_process64 ]; then
ln -sf app_process64 app_process
else
ln -sf app_process32 app_process
fi
fi
rm -rf /system/.pin /system/bin/.ext /system/etc/.installed_su_daemon /system/etc/.has_su_daemon \
/system/xbin/daemonsu /system/xbin/su /system/xbin/sugote /system/xbin/sugote-mksh /system/xbin/supolicy \
/system/bin/app_process_init /system/bin/su /cache/su /system/lib/libsupol.so /system/lib64/libsupol.so \
/system/su.d /system/etc/install-recovery.sh /system/etc/init.d/99SuperSUDaemon /cache/install-recovery.sh \
/system/.supersu /cache/.supersu /data/.supersu \
/system/app/Superuser.apk /system/app/SuperSU /cache/Superuser.apk 2>/dev/null
fi
}
##########################################################################################
# Detection
##########################################################################################
ui_print "************************"
ui_print "* MAGISK_VERSION_STUB"
ui_print "************************"
if [ ! -d "$COMMONDIR" ]; then
ui_print "! Failed: Unable to extract zip file!"
exit 1
fi
ui_print "- Mounting /system(ro), /cache, /data"
mount -o ro /system 2>/dev/null
mount /cache 2>/dev/null
mount /data 2>/dev/null
if [ ! -f '/system/build.prop' ]; then
ui_print "! Failed: /system could not be mounted!"
exit 1
fi
# read override variables
getvar KEEPVERITY
getvar KEEPFORCEENCRYPT
getvar BOOTIMAGE
# Check if system root is installed and remove
remove_system_su
API=`grep_prop ro.build.version.sdk`
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
ABILONG=`grep_prop ro.product.cpu.abi`
ARCH=arm
IS64BIT=false
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
if [ "$API" -lt "21" ]; then
ui_print "! Magisk is only for Lollipop 5.0+ (SDK 21+)"
exit 1
fi
ui_print "- Device platform: $ARCH"
BINDIR=$INSTALLER/$ARCH
chmod -R 755 $CHROMEDIR $BINDIR
$IS64BIT && SYSTEMLIB=/system/lib64 || SYSTEMLIB=/system/lib
find_boot_image
if [ -z $BOOTIMAGE ]; then
ui_print "! Unable to detect boot image"
exit 1
fi
##########################################################################################
# Environment
##########################################################################################
ui_print "- Constructing environment"
is_mounted /data && MAGISKBIN=/data/magisk || MAGISKBIN=/cache/data_bin
# Copy required files
rm -rf $MAGISKBIN 2>/dev/null
mkdir -p $MAGISKBIN
cp -af $BINDIR/. $COMMONDIR/. $MAGISKBIN
chmod -R 755 $MAGISKBIN
chcon -hR u:object_r:system_file:s0 $MAGISKBIN
##########################################################################################
# Magisk Image
##########################################################################################
# Fix SuperSU.....
$BOOTMODE && $BINDIR/magiskpolicy --live "allow fsck * * *"
if (is_mounted /data); then
IMG=/data/magisk.img
else
IMG=/cache/magisk.img
ui_print "- Data unavailable, use cache workaround"
fi
if [ -f $IMG ]; then
ui_print "- $IMG detected!"
else
ui_print "- Creating $IMG"
$BINDIR/magisk --createimg $IMG 64M
fi
mount_image $IMG /magisk
if (! is_mounted /magisk); then
ui_print "! Magisk image mount failed..."
exit 1
fi
MAGISKLOOP=$LOOPDEVICE
# Core folders
mkdir -p $COREDIR/props $COREDIR/post-fs-data.d $COREDIR/service.d 2>/dev/null
chmod -R 755 $COREDIR/post-fs-data.d $COREDIR/service.d
chown -R 0.0 $COREDIR/post-fs-data.d $COREDIR/service.d
# Legacy cleanup
mv $COREDIR/magiskhide/hidelist $COREDIR/hidelist 2>/dev/null
rm -rf $COREDIR/magiskhide $COREDIR/bin
##########################################################################################
# Unpack boot
##########################################################################################
ui_print "- Found Boot Image: $BOOTIMAGE"
# Update our previous backup to new format if exists
if [ -f /data/stock_boot.img ]; then
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --sha1 /data/stock_boot.img | tail -n 1`
STOCKDUMP=/data/stock_boot_${SHA1}.img
mv /data/stock_boot.img $STOCKDUMP
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --compress $STOCKDUMP
fi
SOURCEDMODE=true
cd $MAGISKBIN
# Source the boot patcher
. $COMMONDIR/boot_patch.sh $BOOTIMAGE
# Sign chromeos boot
if [ -f chromeos ]; then
echo > empty
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed \
--keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk \
--version 1 --vmlinuz new-boot.img --config empty --arch arm --bootloader empty --flags 0x1
rm -f empty new-boot.img
mv new-boot.img.signed new-boot.img
fi
if is_mounted /data; then
rm -f /data/stock_boot*
mv stock_boot* /data
fi
ui_print "- Flashing new boot image"
if [ -L $BOOTIMAGE ]; then
dd if=new-boot.img of=$BOOTIMAGE bs=4096
else
cat new-boot.img /dev/zero | dd of=$BOOTIMAGE bs=4096
fi
rm -f new-boot.img
cd /
if ! $BOOTMODE; then
ui_print "- Unmounting partitions"
umount /magisk
losetup -d $MAGISKLOOP 2>/dev/null
rmdir /magisk
umount /system
fi
ui_print "- Done"
exit 0

View File

@@ -1,38 +1,34 @@
# Triggers
on post-fs
# Paths
export PATH /magisk/.core/bin:/sbin:/vendor/bin:/system/sbin:/system/bin:/magisk/.core/busybox:/system/xbin
start magisk_pfs
wait /dev/.magisk.unblock 20
rm /dev/.magisk.unblock
on post-fs-data
start magisk_pfsd
wait /dev/.magisk.unblock 40
rm /dev/.magisk.unblock
load_persist_props
start magisk_pfsd
wait /dev/.magisk.unblock 60
on property:magisk.root=*
start magisk_root
on property:magisk.restart_pfsd=1
trigger post-fs-data
# Services
# launch post-fs script
service magisk_pfs /sbin/magic_mask.sh post-fs
service magisk_pfs /sbin/magisk --post-fs
user root
seclabel u:r:su:s0
oneshot
# launch post-fs-data script
service magisk_pfsd /sbin/magic_mask.sh post-fs-data
service magisk_pfsd /sbin/magisk --post-fs-data
user root
seclabel u:r:su:s0
oneshot
# launch late_start script
service magisk_service /sbin/magic_mask.sh service
service magisk_service /sbin/magisk --service
class late_start
user root
seclabel u:r:su:s0

View File

@@ -0,0 +1,154 @@
#!/system/bin/sh
##########################################################################################
#
# Magisk Uninstaller
# by topjohnwu
#
# This script can be placed in /cache/magisk_uninstaller.sh
# The Magisk main binary will pick up the script, and uninstall itself, following a reboot
# This script can also be used in flashable zip with the uninstaller_loader.sh
#
# This script will try to do restoration in the following order:
# 1. Find and restore the original stock boot image dump (OTA proof)
# 2. Restore ramdisk from the internal backup (ramdisk fully restored, not OTA friendly)
# 3. Remove added files in ramdisk, modified files are remained intact. By doing so, Magisk
# will not be started at boot, but not removed clean enough
#
# Finally, this uninstaller will remove all Magisk related files
# (The list is LARGE, most likely due to bad decision in early versions
# the latest versions has much less bloat to cleanup)
#
##########################################################################################
[ -z $BOOTMODE ] && BOOTMODE=false
MAGISKBIN=/data/magisk
CHROMEDIR=$MAGISKBIN/chromeos
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64 || SYSTEMLIB=/system/lib
# Default permissions
umask 022
# Call ui_print_wrap if exists, or else simply use echo
# Useful when wrapped in flashable zip
ui_print_wrap() {
type ui_print >/dev/null 2>&1 && ui_print "$1" || echo "$1"
}
grep_prop() {
REGEX="s/^$1=//p"
shift
FILES=$@
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n "$REGEX" | head -n 1
}
find_boot_image() {
if [ -z "$BOOTIMAGE" ]; then
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
BOOTIMAGE=`readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION`
if [ ! -z "$BOOTIMAGE" ]; then break; fi
done
fi
if [ -z "$BOOTIMAGE" ]; then
FSTAB="/etc/recovery.fstab"
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
[ -f "$FSTAB" ] && BOOTIMAGE=`grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*'`
fi
}
# Environments
# Set permissions
chmod -R 755 $CHROMEDIR/futility $MAGISKBIN 2>/dev/null
# Find the boot image
find_boot_image
if [ -z "$BOOTIMAGE" ]; then
ui_print_wrap "! Unable to detect boot image"
exit 1
fi
ui_print_wrap "- Found Boot Image: $BOOTIMAGE"
cd $MAGISKBIN
ui_print_wrap "- Unpacking boot image"
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --unpack $BOOTIMAGE
if [ $? -ne 0 ]; then
ui_print_wrap "! Unable to unpack boot image"
exit 1
fi
# Update our previous backups to new format if exists
if [ -f /data/stock_boot.img ]; then
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --sha1 /data/stock_boot.img | tail -n 1`
STOCKDUMP=/data/stock_boot_${SHA1}.img
mv /data/stock_boot.img $STOCKDUMP
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --compress $STOCKDUMP
fi
# Detect boot image state
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-test ramdisk.cpio
case $? in
0 )
ui_print_wrap "- Stock boot image detected!"
ui_print_wrap "! Magisk is not installed!"
exit
;;
1 )
ui_print_wrap "- Magisk patched image detected!"
# Find SHA1 of stock boot image
if [ -z $SHA1 ]; then
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc.old
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc.old`
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
rm -f init.magisk.rc.old
fi
if [ -f ${STOCKDUMP}.gz ]; then
ui_print_wrap "- Boot image backup found!"
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
else
ui_print_wrap "! Boot image backup unavailable"
ui_print_wrap "- Restoring ramdisk with backup"
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --cpio-restore ramdisk.cpio
LD_LIBRARY_PATH=$SYSTEMLIB ./magiskboot --repack $BOOTIMAGE stock_boot.img
fi
;;
2 ) # Other patched
ui_print_wrap "! Boot image patched by other programs!"
ui_print_wrap "! Cannot uninstall with this uninstaller"
exit 1
;;
esac
# Sign chromeos boot
if [ -f chromeos ]; then
echo > empty
LD_LIBRARY_PATH=$SYSTEMLIB $CHROMEDIR/futility vbutil_kernel --pack stock_boot.img.signed \
--keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk \
--version 1 --vmlinuz stock_boot.img --config empty --arch arm --bootloader empty --flags 0x1
rm -f empty stock_boot.img
mv stock_boot.img.signed stock_boot.img
fi
ui_print_wrap "- Flashing stock/reverted image"
if [ -L $BOOTIMAGE ]; then
dd if=stock_boot.img of=$BOOTIMAGE bs=4096
else
cat stock_boot.img /dev/zero | dd of=$BOOTIMAGE bs=4096
fi
rm -f stock_boot.img
ui_print_wrap "- Removing Magisk files"
rm -rf /cache/magisk.log /cache/last_magisk.log /cache/magiskhide.log /cache/.disable_magisk \
/cache/magisk /cache/magisk_merge /cache/magisk_mount /cache/unblock /cache/magisk_uninstaller.sh \
/data/Magisk.apk /data/magisk.apk /data/magisk.img /data/magisk_merge.img /data/magisk_debug.log \
/data/busybox /data/magisk /data/custom_ramdisk_patch.sh 2>/dev/null
$BOOTMODE && reboot

View File

@@ -0,0 +1,133 @@
#!/sbin/sh
##########################################################################################
#
# Magisk Uninstaller (used in recovery)
# by topjohnwu
#
# This script will load the real uninstaller in a flashable zip
#
##########################################################################################
INSTALLER=/tmp/uninstall
# Default permissions
umask 022
##########################################################################################
# Flashable update-binary preparation
##########################################################################################
OUTFD=$2
ZIP=$3
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=0
for FD in `ls /proc/$$/fd`; do
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
if [ "$?" -eq "0" ]; then
ps | grep " 3 $FD " | grep -v grep >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=$FD
break
fi
fi
done
fi
mkdir -p $INSTALLER
cd $INSTALLER
unzip -o "$ZIP"
##########################################################################################
# Functions
##########################################################################################
ui_print() {
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
}
is_mounted() {
if [ ! -z "$2" ]; then
cat /proc/mounts | grep $1 | grep $2, >/dev/null
else
cat /proc/mounts | grep $1 >/dev/null
fi
return $?
}
grep_prop() {
REGEX="s/^$1=//p"
shift
FILES=$@
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
}
##########################################################################################
# Main
##########################################################################################
ui_print "*****************************"
ui_print " Magisk Uninstaller "
ui_print "*****************************"
if [ ! -d "$INSTALLER/arm" ]; then
ui_print "! Failed: Unable to extract zip file!"
exit 1
fi
ui_print "- Mounting /system(ro), /cache, /data"
mount -o ro /system 2>/dev/null
mount /cache 2>/dev/null
mount /data 2>/dev/null
if [ ! -f '/system/build.prop' ]; then
ui_print "! Failed: /system could not be mounted!"
exit 1
fi
API=`grep_prop ro.build.version.sdk`
ABI=`grep_prop ro.product.cpu.abi | cut -c-3`
ABI2=`grep_prop ro.product.cpu.abi2 | cut -c-3`
ABILONG=`grep_prop ro.product.cpu.abi`
ARCH=arm
IS64BIT=false
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
ui_print "- Device platform: $ARCH"
CHROMEDIR=$INSTALLER/chromeos
BINDIR=$INSTALLER/$ARCH
##########################################################################################
# Detection all done, start installing
##########################################################################################
if (is_mounted /data); then
# Copy the binaries to /data/magisk, in case they do not exist
rm -rf /data/magisk 2>/dev/null
mkdir -p /data/magisk 2>/dev/null
cp -af $BINDIR/. $CHROMEDIR /data/magisk
. $INSTALLER/magisk_uninstaller.sh
else
ui_print "! Data unavailable"
ui_print "! Placing uninstall script to /cache"
ui_print "! The device might reboot multiple times"
cp -af $INSTALLER/magisk_uninstaller.sh /cache/magisk_uninstaller.sh
umount /system
ui_print "- Rebooting....."
sleep 5
reboot
fi
umount /system
ui_print "- Done"
exit 0

Submodule selinux deleted from df7346cd5b

View File

@@ -1,265 +0,0 @@
#!/sbin/sh
##########################################################################################
#
# Magisk Uninstaller
# by topjohnwu
#
# This zip will remove all Magisk related files and revert boot image
#
##########################################################################################
INSTALLER=/tmp/uninstall
##########################################################################################
# Flashable update-binary preparation
##########################################################################################
OUTFD=$2
ZIP=$3
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=0
for FD in `ls /proc/$$/fd`; do
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
if [ "$?" -eq "0" ]; then
ps | grep " 3 $FD " | grep -v grep >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=$FD
break
fi
fi
done
fi
mkdir -p $INSTALLER
cd $INSTALLER
unzip -o "$ZIP"
##########################################################################################
# Functions
##########################################################################################
ui_print() {
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
}
getvar() {
local VARNAME=$1
local VALUE=$(eval echo \$"$VARNAME");
for FILE in /data/.magisk /cache/.magisk /system/.magisk; do
if [ -z "$VALUE" ]; then
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
if [ ! -z "$LINE" ]; then
VALUE=${LINE#*=}
fi
fi
done
eval $VARNAME=\$VALUE
}
find_boot_image() {
if [ -z "$BOOTIMAGE" ]; then
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION)
if [ ! -z "$BOOTIMAGE" ]; then break; fi
done
fi
if [ -z "$BOOTIMAGE" ]; then
FSTAB="/etc/recovery.fstab"
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
BOOTIMAGE=$(grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*')
fi
}
is_mounted() {
if [ ! -z "$2" ]; then
cat /proc/mounts | grep $1 | grep $2, >/dev/null
else
cat /proc/mounts | grep $1 >/dev/null
fi
return $?
}
grep_prop() {
REGEX="s/^$1=//p"
shift
FILES=$@
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
}
unpack_boot() {
rm -rf $UNPACKDIR $RAMDISK 2>/dev/null
mkdir -p $UNPACKDIR
mkdir -p $RAMDISK
cd $UNPACKDIR
$BINDIR/bootimgtools --extract $1
find $TMPDIR/boottmp -type d -exec chmod 755 {} \;
find $TMPDIR/boottmp -type f -exec chmod 644 {} \;
chmod 755 $(find $TMPDIR/boottmp -type d)
chmod 644 $(find $TMPDIR/boottmp -type f)
cd $RAMDISK
gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i
}
repack_boot() {
cd $RAMDISK
find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz
cd $UNPACKDIR
$BINDIR/bootimgtools --repack $ORIGBOOT
if [ -f chromeos ]; then
echo " " > config
echo " " > bootloader
$CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1
rm -f new-boot.img
mv new-boot.img.signed new-boot.img
fi
if ($SAMSUNG); then
SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE)
if [ $? -ne 0 ]; then
echo -n "SEANDROIDENFORCE" >> new-boot.img
fi
fi
mv new-boot.img $NEWBOOT
}
revert_boot() {
rm -rf $TMPDIR/boottmp 2>/dev/null
mkdir -p $TMPDIR/boottmp
CHROMEDIR=$INSTALLER/chromeos
ORIGBOOT=$TMPDIR/boottmp/boot.img
NEWBOOT=$TMPDIR/boottmp/new-boot.img
UNPACKDIR=$TMPDIR/boottmp/bootunpack
RAMDISK=$TMPDIR/boottmp/ramdisk
chmod 777 $CHROMEDIR/futility $BINDIR/*
ui_print "- Dumping boot image"
dd if=$BOOTIMAGE of=$ORIGBOOT
ui_print "- Unpacking boot image"
unpack_boot $ORIGBOOT
if [ -d ".backup" ]; then
ui_print "- Restoring ramdisk with backup"
cp -af .backup/* .
rm -rf magisk init.magisk.rc sbin/magic_mask.sh 2>/dev/null
rm -rf .backup
else
ui_print "! No ramdisk backup found"
ui_print "! Unable to revert completely"
ui_print "! Will still remove Magisk additions"
# Removing boot image modifications
rm -rf magisk init.magisk.rc sbin/magic_mask.sh 2>/dev/null
fi
ui_print "- Repacking boot image"
repack_boot
}
##########################################################################################
# Main
##########################################################################################
ui_print "*****************************"
ui_print " Magisk Uninstaller "
ui_print "*****************************"
if [ ! -d "$INSTALLER/arm" ]; then
ui_print "! Failed: Unable to extract zip file!"
exit 1
fi
ui_print "- Mounting /system(ro), /cache, /data"
mount -o ro /system 2>/dev/null
mount /cache 2>/dev/null
mount /data 2>/dev/null
if [ ! -f '/system/build.prop' ]; then
ui_print "! Failed: /system could not be mounted!"
exit 1
fi
API=$(grep_prop ro.build.version.sdk)
ABI=$(grep_prop ro.product.cpu.abi | cut -c-3)
ABI2=$(grep_prop ro.product.cpu.abi2 | cut -c-3)
ABILONG=$(grep_prop ro.product.cpu.abi)
ARCH=arm
IS64BIT=
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=1; fi;
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=1; fi;
ui_print "- Device platform: $ARCH"
BINDIR=$INSTALLER/arm
if [ "$ARCH" = "x86" -o "$ARCH" = "x64" ]; then
BINDIR=$INSTALLER/x86
fi
find_boot_image
if [ -z "$BOOTIMAGE" ]; then
ui_print "! Unable to detect boot image"
exit 1
fi
SAMSUNG=false
SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung")
if [ $? -eq 0 ]; then
SAMSUNG=true
fi
##########################################################################################
# Detection all done, start installing
##########################################################################################
umount /magisk 2>/dev/null
if (is_mounted /data); then
cp -af /data/stock_boot_*.gz /data/stock_boot.img.gz 2>/dev/null
gzip -d /data/stock_boot.img.gz 2>/dev/null
rm -rf /data/stock_boot.img.gz 2>/dev/null
if [ -f "/data/stock_boot.img" ]; then
ui_print "- Boot image backup found!"
NEWBOOT=/data/stock_boot.img
else
ui_print "! Boot image backup unavalible, try using ramdisk backup"
revert_boot
fi
ui_print "- Removing Magisk files"
rm -rf /cache/magisk /cache/magisk_merge /cache/magisk.log /cache/last_magisk.log /cache/unblock /data/Magisk.apk /data/magisk.img /data/magisk_merge.img /data/busybox /data/magisk 2>/dev/null
else
ui_print "! Data unavalible"
ui_print "! Impossible to restore original boot image"
ui_print "! Try using ramdisk backup"
revert_boot
ui_print "- Removing Magisk files"
rm -rf /cache/magisk* /cache/last_magisk.log /cache/unblock 2>/dev/null
ui_print "*****************************************"
ui_print " Magisk is not fully removed yet "
ui_print " Please manually remove /data/magisk.img "
ui_print "*****************************************"
fi
if [ -L "$BOOTIMAGE" ]; then
ui_print "- Block symlink detected!"
else
dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
fi
ui_print "- Flashing reverted image"
dd if=$NEWBOOT of=$BOOTIMAGE bs=4096
umount /system
ui_print "- Done"
exit 0

View File

@@ -1 +0,0 @@
# this is a dummy file, the magic is in update-binary

Binary file not shown.

Binary file not shown.

View File

@@ -1,500 +0,0 @@
#!/sbin/sh
##########################################################################################
#
# Magisk Boot Image Patcher
# by topjohnwu
#
# This zip will patch your boot image with Magisk support
#
##########################################################################################
if [ -z "$BOOTMODE" ]; then
BOOTMODE=false
fi
TMPDIR=/tmp
($BOOTMODE) && TMPDIR=/dev/tmp
INSTALLER=$TMPDIR/magisk
COREDIR=/magisk/.core
##########################################################################################
# Flashable update-binary preparation
##########################################################################################
OUTFD=$2
ZIP=$3
readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=0
for FD in `ls /proc/$$/fd`; do
readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
if [ "$?" -eq "0" ]; then
ps | grep " 3 $FD " | grep -v grep >/dev/null
if [ "$?" -eq "0" ]; then
OUTFD=$FD
break
fi
fi
done
fi
mkdir -p $INSTALLER
cd $INSTALLER
unzip -o "$ZIP"
##########################################################################################
# Functions
##########################################################################################
ui_print() {
if ($BOOTMODE); then
echo "$1"
else
echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD
echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD
fi
}
getvar() {
local VARNAME=$1
local VALUE=$(eval echo \$"$VARNAME");
for FILE in /data/.magisk /cache/.magisk /system/.magisk; do
if [ -z "$VALUE" ]; then
LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=")
if [ ! -z "$LINE" ]; then
VALUE=${LINE#*=}
fi
fi
done
eval $VARNAME=\$VALUE
}
find_boot_image() {
if [ -z "$BOOTIMAGE" ]; then
for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do
BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION)
if [ ! -z "$BOOTIMAGE" ]; then break; fi
done
fi
if [ -z "$BOOTIMAGE" ]; then
FSTAB="/etc/recovery.fstab"
[ ! -f "$FSTAB" ] && FSTAB="/etc/recovery.fstab.bak"
BOOTIMAGE=$(grep -E '\b/boot\b' "$FSTAB" | grep -oE '/dev/[a-zA-Z0-9_./-]*')
fi
}
is_mounted() {
if [ ! -z "$2" ]; then
cat /proc/mounts | grep $1 | grep $2, >/dev/null
else
cat /proc/mounts | grep $1 >/dev/null
fi
return $?
}
mount_image() {
if [ ! -d "$2" ]; then
mount -o rw,remount rootfs /
mkdir -p $2 2>/dev/null
($BOOTMODE) && mount -o ro,remount rootfs /
[ ! -d "$2" ] && return 1
fi
if (! is_mounted $2); then
LOOPDEVICE=
for LOOP in 0 1 2 3 4 5 6 7; do
if (! is_mounted $2); then
LOOPDEVICE=/dev/block/loop$LOOP
if [ ! -f "$LOOPDEVICE" ]; then
mknod $LOOPDEVICE b 7 $LOOP
fi
losetup $LOOPDEVICE $1
if [ "$?" -eq "0" ]; then
mount -t ext4 -o loop $LOOPDEVICE $2
if (! is_mounted $2); then
/system/bin/toolbox mount -t ext4 -o loop $LOOPDEVICE $2
fi
if (! is_mounted $2); then
/system/bin/toybox mount -t ext4 -o loop $LOOPDEVICE $2
fi
fi
if (is_mounted $2); then
ui_print "- Mounting $1 to $2"
break;
fi
fi
done
fi
}
grep_prop() {
REGEX="s/^$1=//p"
shift
FILES=$@
if [ -z "$FILES" ]; then
FILES='/system/build.prop'
fi
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
}
unpack_boot() {
rm -rf $UNPACKDIR $RAMDISK 2>/dev/null
mkdir -p $UNPACKDIR
mkdir -p $RAMDISK
cd $UNPACKDIR
$BINDIR/bootimgtools --extract $1
find $TMPDIR/boottmp -type d -exec chmod 755 {} \;
find $TMPDIR/boottmp -type f -exec chmod 644 {} \;
chmod 755 $(find $TMPDIR/boottmp -type d)
chmod 644 $(find $TMPDIR/boottmp -type f)
cd $RAMDISK
gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i
}
repack_boot() {
cd $RAMDISK
find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz
cd $UNPACKDIR
$BINDIR/bootimgtools --repack $ORIGBOOT
if [ -f chromeos ]; then
echo " " > config
echo " " > bootloader
$CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1
rm -f new-boot.img
mv new-boot.img.signed new-boot.img
fi
if ($SAMSUNG); then
SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE)
if [ $? -ne 0 ]; then
echo -n "SEANDROIDENFORCE" >> new-boot.img
fi
fi
mv new-boot.img $NEWBOOT
$BINDIR/bootimgtools --hexpatch $NEWBOOT \
49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
}
##########################################################################################
# Detection
##########################################################################################
ui_print "****************************"
ui_print "Magisk v7 Boot Image Patcher"
ui_print "****************************"
if [ ! -d "$INSTALLER/common" ]; then
ui_print "! Failed: Unable to extract zip file!"
exit 1
fi
ui_print "- Mounting /system(ro), /cache, /data"
mount -o ro /system 2>/dev/null
mount /cache 2>/dev/null
mount /data 2>/dev/null
if [ ! -f '/system/build.prop' ]; then
ui_print "! Failed: /system could not be mounted!"
exit 1
fi
API=$(grep_prop ro.build.version.sdk)
ABI=$(grep_prop ro.product.cpu.abi | cut -c-3)
ABI2=$(grep_prop ro.product.cpu.abi2 | cut -c-3)
ABILONG=$(grep_prop ro.product.cpu.abi)
ARCH=arm
IS64BIT=false
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
if [ "$API" -lt "21" ]; then
ui_print "! Magisk is only for Lollipop 5.0+ (SDK 21+)"
exit 1
fi
ui_print "- Device platform: $ARCH"
BINDIR=$INSTALLER/arm
if [ "$ARCH" = "x86" -o "$ARCH" = "x64" ]; then
BINDIR=$INSTALLER/x86
fi
find_boot_image
if [ -z "$BOOTIMAGE" ]; then
ui_print "! Unable to detect boot image"
exit 1
fi
if [ -z "$NOOVERRIDE" ]; then
# read override variables
getvar KEEPVERITY
getvar KEEPFORCEENCRYPT
getvar NORESTORE
fi
if [ -z "$KEEPVERITY" ]; then
# we don't keep dm-verity by default
KEEPVERITY=false
fi
if [ -z "$KEEPFORCEENCRYPT" ]; then
# we don't keep forceencrypt by default
KEEPFORCEENCRYPT=false
fi
if [ -z "$NORESTORE" ]; then
# we don't keep ramdisk by default
NORESTORE=false
fi
SAMSUNG=false
SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung")
if [ $? -eq 0 ]; then
SAMSUNG=true
fi
##########################################################################################
# Environment
##########################################################################################
ui_print "- Constructing environment"
if (is_mounted /data); then
rm -rf /data/busybox /data/magisk 2>/dev/null
mkdir -p /data/busybox
cp -af $BINDIR /data/magisk
chmod 755 /data/busybox /data/magisk /data/magisk/*
chcon 'u:object_r:system_file:s0' /data/busybox /data/magisk /data/magisk/*
/data/magisk/busybox --install -s /data/busybox
# Prevent issues
rm -f /data/busybox/su /data/busybox/sh
else
rm -rf /cache/data_bin 2>/dev/null
mkdir -p /cache/data_bin
cp -af $BINDIR /cache/data_bin
fi
##########################################################################################
# Image
##########################################################################################
# Fix SuperSU.....
($BOOTMODE) && /data/magisk/sepolicy-inject -s fsck --live
if (is_mounted /data); then
IMG=/data/magisk.img
else
IMG=/cache/magisk.img
ui_print "- Data unavalible, use cache workaround"
fi
if [ -f "$IMG" ]; then
ui_print "- $IMG detected!"
else
ui_print "- Creating $IMG"
make_ext4fs -l 64M -a /magisk -S $INSTALLER/common/file_contexts_image $IMG
fi
mount_image $IMG /magisk
if (! is_mounted /magisk); then
ui_print "! Image mount failed... abort"
exit 1
fi
MAGISKLOOP=$LOOPDEVICE
##########################################################################################
# Boot image patch
##########################################################################################
ui_print "- Found Boot Image: $BOOTIMAGE"
rm -rf $TMPDIR/boottmp 2>/dev/null
mkdir -p $TMPDIR/boottmp
CHROMEDIR=$INSTALLER/chromeos
ORIGBOOT=$TMPDIR/boottmp/boot.img
NEWBOOT=$TMPDIR/boottmp/new-boot.img
UNPACKDIR=$TMPDIR/boottmp/bootunpack
RAMDISK=$TMPDIR/boottmp/ramdisk
chmod 777 $CHROMEDIR/futility $BINDIR/*
ui_print "- Dumping boot image"
dd if=$BOOTIMAGE of=$ORIGBOOT
ui_print "- Unpacking boot image"
unpack_boot $ORIGBOOT
SUPERSU=false
if (! $NORESTORE); then
# Backups
if [ -d ".backup" ]; then
ui_print "- Restoring ramdisk with backup"
cp -af .backup/* .
rm -rf magisk init.magisk.rc sbin/magic_mask.sh 2>/dev/null
else
if [ -f "sbin/launch_daemonsu.sh" ]; then
SUPERSU=true
# Save it for helper module
mkdir -p /magisk/zzsupersu
touch /magisk/zzsupersu/stub
cp -af sbin/launch_daemonsu.sh $INSTALLER/roothelper/launch_daemonsu.sh
fi
# Non-standard boot image restores
if ($SUPERSU); then
ui_print "- SuperSU patched boot detected"
# Restore with SuperSU's backup
MOUNTSU=false
(! is_mounted /su) && (is_mounted /data) && mount_image /data/su.img /su && MOUNTSU=true
if (is_mounted /su); then
# Use sukernel's built-in functions
ui_print "- Using sukernel to restore boot image"
cd $UNPACKDIR
gunzip -c < $UNPACKDIR/ramdisk.gz > suramdisk
/su/bin/sukernel --restore suramdisk /data/stock_boot.img
if [ "$?" -ne "0" ]; then
# No boot backup found, use ramdisk backup
ui_print "- Restoring ramdisk with backup"
/su/bin/sukernel --cpio-restore suramdisk suramdisk
rm -rf $RAMDISK
mkdir -p $RAMDISK
cd $RAMDISK
cpio -i < $UNPACKDIR/suramdisk
rm -f $UNPACKDIR/suramdisk
else
ui_print "- Restoring boot image with backup"
cp -af /data/stock_boot.img $ORIGBOOT
unpack_boot $ORIGBOOT
fi
if ($MOUNTSU); then
ui_print "- Unmounting su.img"
umount /su
losetup -d $LOOPDEVICE
fi
else
# Find the boot backup ourselves
ui_print "! su.img mount failed... find the backup ourselves"
cp -af /data/stock_boot_*.gz /data/stock_boot.img.gz 2>/dev/null
gzip -d /data/stock_boot.img.gz 2>/dev/null
rm -rf /data/stock_boot.img.gz 2>/dev/null
if [ -f "/data/stock_boot.img" ]; then
ui_print "- Restoring boot image with backup"
cp -af /data/stock_boot.img $ORIGBOOT
unpack_boot $ORIGBOOT
else
ui_print "! No backups found"
ui_print "! Installer will still proceed, but might cause issues"
ui_print "! If possible, please restore to stock boot then flash Magisk again"
# Force removing SuperSU parts
rm -rf su init.supersu.rc sbin/launch_daemonsu.sh 2>/dev/null
fi
fi
else
# Magisk's own situation
if [ -d "magisk" ]; then
cp -af /data/stock_boot_*.gz /data/stock_boot.img.gz 2>/dev/null
gzip -d /data/stock_boot.img.gz 2>/dev/null
if [ -f "/data/stock_boot.img" ]; then
ui_print "- Restoring boot image with backup"
cp -af /data/stock_boot.img $ORIGBOOT
unpack_boot $ORIGBOOT
else
ui_print "! No backups found"
ui_print "! Installer will still proceed, but might cause issues"
ui_print "! If possible, please restore to stock boot then flash Magisk again"
# Removing other boot image modifications
rm -rf sbin/su init.xposed.rc sbin/mount_xposed.sh 2>/dev/null
fi
fi
fi
ui_print "- Creating backups"
mkdir .backup
cp -af init.rc *fstab* verity_key sepolicy .backup 2>/dev/null
if (is_mounted /data); then
cp -af $ORIGBOOT /data/stock_boot.img
else
cp -af $ORIGBOOT /cache/stock_boot.img
fi
fi
fi
ui_print "- Installing root helper module"
cp -af $INSTALLER/roothelper /magisk/00roothelper
chmod 755 /magisk/00roothelper /magisk/00roothelper/*
# Patch ramdisk
ui_print "- Patching ramdisk"
if [ $(grep -c "import /init.magisk.rc" init.rc) -eq "0" ]; then
sed -i "/import \/init\.environ\.rc/iimport /init.magisk.rc" init.rc
fi
sed -i "/selinux.reload_policy/d" init.rc
find . -type f -name "*fstab*" 2>/dev/null | while read FSTAB ; do
if (! $KEEPVERITY); then
sed -i "s/,support_scfs//g" $FSTAB
sed -i 's;,\{0,1\}verify\(=[^,]*\)\{0,1\};;g' $FSTAB
fi
if (! $KEEPFORCEENCRYPT); then
sed -i "s/forceencrypt/encryptable/g" $FSTAB
sed -i "s/forcefdeorfbe/encryptable/g" $FSTAB
fi
done
rm verity_key 2>/dev/null
# sepolicy patches
$BINDIR/sepolicy-inject --magisk -P sepolicy
# Add new items
mkdir -p magisk 2>/dev/null
cp -af $INSTALLER/common/init.magisk.rc init.magisk.rc
cp -af $INSTALLER/common/magic_mask.sh sbin/magic_mask.sh
chmod 0755 magisk
chmod 0750 init.magisk.rc sbin/magic_mask.sh
ui_print "- Repacking boot image"
repack_boot
ORIGSIZE=$(ls -l $ORIGBOOT | awk '{print $5}')
NEWSIZE=$(ls -l $NEWBOOT | awk '{print $5}')
if [ "$NEWSIZE" -gt "$ORIGSIZE" ]; then
ui_print "! Boot partition space insufficient"
ui_print "! Try to remove ramdisk backups"
rm -rf $RAMDISK/.backup $NEWBOOT 2>/dev/null
repack_boot
NEWSIZE=$(ls -l $NEWBOOT | awk '{print $5}')
if [ "$NEWSIZE" -gt "$ORIGSIZE" ]; then
ui_print "! Boot partition size still too small..."
ui_print "! Unable to install Magisk"
exit 1
fi
fi
chmod 644 $NEWBOOT
if [ -L "$BOOTIMAGE" ]; then
ui_print "- Block symlink detected!"
else
dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
fi
ui_print "- Flashing new boot image"
dd if=$NEWBOOT of=$BOOTIMAGE bs=4096
if (! $BOOTMODE); then
ui_print "- Unmounting partitions"
umount /magisk
losetup -d $MAGISKLOOP
umount /system
fi
ui_print "- Done"
exit 0

View File

@@ -1 +0,0 @@
#MAGISK

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
/magisk(/.*)? u:object_r:system_file:s0

View File

@@ -1,403 +0,0 @@
#!/system/bin/sh
LOGFILE=/cache/magisk.log
IMG=/data/magisk.img
COREDIR=/magisk/.core
DUMMDIR=$COREDIR/dummy
MIRRDIR=$COREDIR/mirror
TMPDIR=/dev/tmp
# Use the included busybox to do everything for maximum compatibility
# We also do so because we rely on the option "-c" for cp (reserve contexts)
# Reserve the original PATH
export OLDPATH=$PATH
export PATH="/data/busybox:$PATH"
log_print() {
echo $1
echo $1 >> $LOGFILE
log -p i -t Magisk "$1"
}
mktouch() {
mkdir -p ${1%/*} 2>/dev/null
if [ -z "$2" ]; then
touch $1 2>/dev/null
else
echo $2 > $1 2>/dev/null
fi
}
unblock() {
touch /dev/.magisk.unblock
exit
}
run_scripts() {
BASE=/magisk
if [ "$1" = "post-fs" ]; then
BASE=/cache/magisk
fi
for MOD in $BASE/* ; do
if [ ! -f "$MOD/disable" ]; then
if [ -f "$MOD/$1.sh" ]; then
chmod 755 $MOD/$1.sh
chcon 'u:object_r:system_file:s0' $MOD/$1.sh
log_print "$1: $MOD/$1.sh"
$MOD/$1.sh
fi
fi
done
}
loopsetup() {
LOOPDEVICE=
for DEV in $(ls /dev/block/loop*); do
if [ `losetup $DEV $1 >/dev/null 2>&1; echo $?` -eq 0 ]; then
LOOPDEVICE=$DEV
break
fi
done
}
target_size_check() {
e2fsck -p -f $1
curBlocks=`e2fsck -n $1 2>/dev/null | cut -d, -f3 | cut -d\ -f2`;
curUsedM=$((`echo "$curBlocks" | cut -d/ -f1` * 4 / 1024));
curSizeM=$((`echo "$curBlocks" | cut -d/ -f2` * 4 / 1024));
curFreeM=$((curSizeM - curUsedM));
}
travel() {
cd $1/$2
if [ -f ".replace" ]; then
rm -rf $TMPDIR/$2
mktouch $TMPDIR/$2 $1
else
for ITEM in * ; do
if [ ! -e "/$2/$ITEM" ]; then
# New item found
if [ $2 = "system" ]; then
# We cannot add new items to /system root, delete it
rm -rf $ITEM
else
if [ -d "$TMPDIR/dummy/$2" ]; then
# We are in a higher level, delete the lower levels
rm -rf $TMPDIR/dummy/$2
fi
# Mount the dummy parent
mktouch $TMPDIR/dummy/$2
mkdir -p $DUMMDIR/$2 2>/dev/null
if [ -d "$ITEM" ]; then
# Create new dummy directory
mkdir -p $DUMMDIR/$2/$ITEM
elif [ -L "$ITEM" ]; then
# Symlinks are small, copy them
cp -afc $ITEM $DUMMDIR/$2/$ITEM
else
# Create new dummy file
mktouch $DUMMDIR/$2/$ITEM
fi
# Clone the original /system structure (depth 1)
if [ -e "/$2" ]; then
for DUMMY in /$2/* ; do
if [ -d "$DUMMY" ]; then
# Create dummy directory
mkdir -p $DUMMDIR$DUMMY
elif [ -L "$DUMMY" ]; then
# Symlinks are small, copy them
cp -afc $DUMMY $DUMMDIR$DUMMY
else
# Create dummy file
mktouch $DUMMDIR$DUMMY
fi
done
fi
fi
fi
if [ -d "$ITEM" ]; then
# It's an directory, travel deeper
(travel $1 $2/$ITEM)
elif [ ! -L "$ITEM" ]; then
# Mount this file
mktouch $TMPDIR/$2/$ITEM $1
fi
done
fi
}
bind_mount() {
if [ -e "$1" -a -e "$2" ]; then
mount -o bind $1 $2
if [ "$?" -eq "0" ]; then log_print "Mount: $1";
else log_print "Mount Fail: $1"; fi
fi
}
merge_image() {
if [ -f "$1" ]; then
log_print "$1 found"
if [ -f "$IMG" ]; then
log_print "$IMG found, attempt to merge"
# Handle large images
target_size_check $1
MERGEUSED=$curUsedM
target_size_check $IMG
if [ "$MERGEUSED" -gt "$curFreeM" ]; then
NEWDATASIZE=$((((MERGEUSED + curUsedM) / 32 + 2) * 32))
log_print "Expanding $IMG to ${NEWDATASIZE}M..."
resize2fs $IMG ${NEWDATASIZE}M
fi
# Start merging
mkdir /cache/data_img
mkdir /cache/merge_img
# setup loop devices
loopsetup $IMG
LOOPDATA=$LOOPDEVICE
log_print "$LOOPDATA $IMG"
loopsetup $1
LOOPMERGE=$LOOPDEVICE
log_print "$LOOPMERGE $1"
if [ ! -z "$LOOPDATA" ]; then
if [ ! -z "$LOOPMERGE" ]; then
# if loop devices have been setup, mount images
OK=true
if [ `mount -t ext4 -o rw,noatime $LOOPDATA /cache/data_img >/dev/null 2>&1; echo $?` -ne 0 ]; then
OK=false
fi
if [ `mount -t ext4 -o rw,noatime $LOOPMERGE /cache/merge_img >/dev/null 2>&1; echo $?` -ne 0 ]; then
OK=false
fi
if ($OK); then
# Merge (will reserve selinux contexts)
cd /cache/merge_img
for MOD in *; do
rm -rf /cache/data_img/$MOD
cp -afc $MOD /cache/data_img/
done
log_print "Merge complete"
fi
umount /cache/data_img
umount /cache/merge_img
fi
fi
losetup -d $LOOPDATA
losetup -d $LOOPMERGE
rmdir /cache/data_img
rmdir /cache/merge_img
else
log_print "Moving $1 to $IMG "
mv $1 $IMG
fi
rm -f $1
fi
}
case $1 in
post-fs )
mv $LOGFILE /cache/last_magisk.log
touch $LOGFILE
chmod 644 $LOGFILE
log_print "Magisk post-fs mode running..."
if [ -d "/cache/magisk_merge" ]; then
cd /cache/magisk_merge
for MOD in *; do
rm -rf /cache/magisk/$MOD
cp -afc $MOD /cache/magisk/
done
rm -rf /cache/magisk_merge
fi
for MOD in /cache/magisk/* ; do
if [ -f "$MOD/remove" ]; then
log_print "Remove module: $MOD"
rm -rf $MOD
elif [ -f "$MOD/auto_mount" -a ! -f "$MOD/disable" ]; then
find $MOD/system -type f 2>/dev/null | while read ITEM ; do
TARGET=${ITEM#$MOD}
bind_mount $ITEM $TARGET
done
fi
done
run_scripts post-fs
unblock
;;
post-fs-data )
if [ `mount | grep " /data " >/dev/null 2>&1; echo $?` -ne 0 ]; then
# /data not mounted yet, we will be called again later
unblock
fi
if [ `mount | grep " /data " | grep "tmpfs" >/dev/null 2>&1; echo $?` -eq 0 ]; then
# /data not mounted yet, we will be called again later
unblock
fi
log_print "Magisk post-fs-data mode running..."
# Live patch sepolicy
/data/magisk/sepolicy-inject --live -s su
# Cache support
if [ -d "/cache/data_bin" ]; then
rm -rf /data/busybox /data/magisk
mkdir -p /data/busybox
mv /cache/data_bin /data/magisk
chmod 755 /data/busybox /data/magisk /data/magisk/*
chcon 'u:object_r:system_file:s0' /data/busybox /data/magisk /data/magisk/*
/data/magisk/busybox --install -s /data/busybox
# Prevent issues
rm -f /data/busybox/su /data/busybox/sh
fi
mv /cache/stock_boot.img /data 2>/dev/null
chmod 644 $IMG /cache/magisk.img /data/magisk_merge.img 2>/dev/null
# Handle image merging
merge_image /cache/magisk.img
merge_image /data/magisk_merge.img
# Mount magisk.img
if [ `cat /proc/mounts | grep /magisk >/dev/null 2>&1; echo $?` -ne 0 ]; then
loopsetup $IMG
if [ ! -z "$LOOPDEVICE" ]; then
mount -t ext4 -o rw,noatime $LOOPDEVICE /magisk
fi
fi
if [ `cat /proc/mounts | grep /magisk >/dev/null 2>&1; echo $?` -ne 0 ]; then
log_print "magisk.img mount failed, nothing to do :("
unblock
fi
log_print "Preparing modules"
# First do cleanups
rm -rf $DUMMDIR
rmdir $(find /magisk -type d -depth ! -path "*core*" ) 2>/dev/null
rm -rf $COREDIR/bin
mkdir -p $DUMMDIR
mkdir -p $MIRRDIR/system
# Travel through all mods
for MOD in /magisk/* ; do
if [ -f "$MOD/remove" ]; then
log_print "Remove module: $MOD"
rm -rf $MOD
elif [ -f "$MOD/auto_mount" -a -d "$MOD/system" -a ! -f "$MOD/disable" ]; then
(travel $MOD system)
fi
done
# Proper permissions for generated items
chmod 755 $(find $COREDIR -type d)
chmod 644 $(find $COREDIR -type f)
find $COREDIR -type d -exec chmod 755 {} \;
find $COREDIR -type f -exec chmod 644 {} \;
# linker(64), t*box, and app_process* are required if we need to dummy mount bin folder
if [ -f "$TMPDIR/dummy/system/bin" ]; then
rm -f $DUMMDIR/system/bin/linker* $DUMMDIR/system/bin/t*box $DUMMDIR/system/bin/app_process*
cd /system/bin
cp -afc linker* t*box app_process* $DUMMDIR/system/bin/
fi
# Unmount, shrink, remount
if [ `umount /magisk >/dev/null 2>&1; echo $?` -eq 0 ]; then
losetup -d $LOOPDEVICE
target_size_check $IMG
NEWDATASIZE=$(((curUsedM / 32 + 2) * 32))
if [ "$curSizeM" -gt "$NEWDATASIZE" ]; then
log_print "Shrinking $IMG to ${NEWDATASIZE}M..."
resize2fs $IMG ${NEWDATASIZE}M
fi
loopsetup $IMG
if [ ! -z "$LOOPDEVICE" ]; then
mount -t ext4 -o rw,noatime $LOOPDEVICE /magisk
fi
fi
if [ `cat /proc/mounts | grep /magisk >/dev/null 2>&1; echo $?` -ne 0 ]; then
log_print "magisk.img mount failed, nothing to do :("
unblock
fi
# Remove crap folder
rm -rf /magisk/lost+found
# Start doing tasks
# Stage 1
log_print "Bind mount dummy system"
find $TMPDIR/dummy -type f 2>/dev/null | while read ITEM ; do
TARGET=${ITEM#$TMPDIR/dummy}
ORIG=$DUMMDIR$TARGET
bind_mount $ORIG $TARGET
done
# Stage 2
log_print "Bind mount module items"
find $TMPDIR/system -type f 2>/dev/null | while read ITEM ; do
TARGET=${ITEM#$TMPDIR}
ORIG=`cat $ITEM`$TARGET
bind_mount $ORIG $TARGET
rm -f $DUMMDIR${TARGET%/*}/.dummy 2>/dev/null
done
# Run scripts
run_scripts post-fs-data
# Bind hosts for Adblock apps
[ ! -f "$COREDIR/hosts" ] && cp -afc /system/etc/hosts $COREDIR/hosts
log_print "Enabling systemless hosts file support"
bind_mount $COREDIR/hosts /system/etc/hosts
# Stage 3
log_print "Bind mount system mirror"
bind_mount /system $MIRRDIR/system
# Stage 4
log_print "Bind mount mirror items"
# Find all empty directores and dummy files, they should be mounted by original files in /system
find $DUMMDIR -type d -exec sh -c '[ -z "$(ls -A $1)" ] && echo $1' -- {} \; -o \( -type f -size 0 -print \) | while read ITEM ; do
ORIG=${ITEM/dummy/mirror}
TARGET=${ITEM#$DUMMDIR}
bind_mount $ORIG $TARGET
done
# All done
rm -rf $TMPDIR
unblock
;;
service )
# Version info
setprop magisk.version 7
log_print "Magisk late_start service mode running..."
run_scripts service
;;
esac

View File

@@ -1,9 +0,0 @@
id=phh
name=phh's SuperUser
version=Root Helper
versionCode=1
author=phhusson, topjohnwu
description=This is a helper, please upgrade from downloads section :)
support=http://forum.xda-developers.com/showthread.php?t=3216394
donate=http://forum.xda-developers.com/donatetome.php?u=1915408
cacheModule=false

View File

@@ -1,40 +0,0 @@
#!/system/bin/sh
LOGFILE=/cache/magisk.log
log_print() {
echo $1
echo "phh: $1" >> $LOGFILE
log -p i -t phh "$1"
}
launch_daemonsu() {
export PATH=$OLDPATH
# Switch contexts
echo "u:r:su_daemon:s0" > /proc/self/attr/current
# Start daemon
exec /magisk/phh/bin/su --daemon
}
# Disable the other root
[ -d "/magisk/zzsupersu" ] && touch /magisk/zzsupersu/disable
log_print "Live patching sepolicy"
/magisk/phh/bin/sepolicy-inject --live
# Expose the root path
log_print "Linking supath"
rm -rf /magisk/.core/bin
ln -s /magisk/phh/bin /magisk/.core/bin
# Run su.d
for script in /magisk/phh/su.d/* ; do
if [ -f "$script" ]; then
chmod 755 $script
log_print "su.d: $script"
$script
fi
done
log_print "Starting su daemon"
(launch_daemonsu &)

View File

@@ -1,29 +0,0 @@
#!/system/bin/sh
cd /magisk/00roothelper
if [ -f "launch_daemonsu.sh" ]; then
# SuperSU mode
rm -rf /magisk/supersu /magisk/zzsupersu
mkdir -p /magisk/zzsupersu
cp supersu.sh /magisk/zzsupersu/post-fs-data.sh
cp supersu.prop /magisk/zzsupersu/module.prop
cp launch_daemonsu.sh /magisk/zzsupersu/launch_daemonsu.sh
chmod 755 /magisk/zzsupersu /magisk/zzsupersu/*
else
# phh mode
if [ -f "/magisk/phh/su" ]; then
# Old version detected
cp /magisk/phh/su su
rm -rf /magisk/phh
mkdir -p /magisk/phh/bin
mkdir -p /magisk/phh/su.d
cp su /magisk/phh/bin/su
cp /data/magisk/sepolicy-inject /magisk/phh/bin/sepolicy-inject
cp phh.sh /magisk/phh/post-fs-data.sh
cp phh.prop /magisk/phh/module.prop
chmod 755 /magisk/phh /magisk/phh/* /magisk/phh/bin/*
fi
fi
rm -rf /magisk/00roothelper

View File

@@ -1,7 +0,0 @@
id=supersu
name=SuperSU Helper
version=v1
versionCode=1
author=topjohnwu
description=This is a helper module for Chainfire's SuperSU to work with Magisk
cacheModule=false

View File

@@ -1,11 +0,0 @@
#!/system/bin/sh
mount -o rw,remount rootfs /
mkdir /su 2>/dev/null
mount -o ro,remount rootfs /
chmod 755 /magisk/zzsupersu/launch_daemonsu.sh
/magisk/zzsupersu/launch_daemonsu.sh post-fs-data
rm -rf /magisk/.core/bin
ln -s /su/bin /magisk/.core/bin

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ziptools/minsignapk.jar Normal file

Binary file not shown.

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