Compare commits

...

207 Commits
v12.0 ... v14.0

Author SHA1 Message Date
topjohnwu
44b93e7cc4 Bump Magisk Manager version 2017-09-06 23:33:46 +08:00
topjohnwu
0eb79e5acd Update scripts 2017-09-06 23:33:46 +08:00
topjohnwu
eceba26894 Make MagiskHide work without magisk.img 2017-09-06 02:25:40 +08:00
topjohnwu
0bf404f75e Bump busybox to 1.27.2 2017-09-05 21:45:13 +08:00
topjohnwu
cd8dd65a65 chcon on Android 5.0 doesn't support -h options 2017-09-05 21:44:53 +08:00
topjohnwu
50c56f8b50 Simplify flash scripts 2017-09-05 21:44:22 +08:00
topjohnwu
9e9f8ca8f3 Restore cwd 2017-09-02 23:28:17 +08:00
topjohnwu
f63af0601c Support Magisk Manager boot image file patch 2017-08-31 03:08:09 +08:00
topjohnwu
189c671ce2 Rewrite environment setup 2017-08-31 02:20:06 +08:00
topjohnwu
bb39a01361 Minor adjust magiskpolicy 2017-08-28 02:14:14 +08:00
topjohnwu
764999704a Collect va_list before fork 2017-08-27 02:17:37 +08:00
topjohnwu
ecfa4aafc1 Fix clone_attr 2017-08-26 23:19:56 +08:00
topjohnwu
a1e33c4d2f Build everything ourselves 2017-08-24 12:14:17 +08:00
topjohnwu
7f8ba74dac Add hide Magisk Manager feature 2017-08-22 03:02:08 +08:00
topjohnwu
e3df62d812 Refactor several utility functions 2017-08-20 21:36:32 +08:00
topjohnwu
1913125881 Update README.MD 2017-08-20 15:03:26 +08:00
topjohnwu
e8e58f3fed Adjust run_command 2017-08-19 19:27:51 +08:00
topjohnwu
1ca9ec384b Fix typo in cloning attribute 2017-08-19 18:59:06 +08:00
topjohnwu
9522255e3a Proper magisk manual injection support 2017-08-17 03:46:01 +08:00
topjohnwu
2a22fa694e Fix removing modules from images 2017-08-17 02:19:14 +08:00
topjohnwu
1591f5a0ca Update magiskpolicy help message 2017-08-17 00:58:02 +08:00
topjohnwu
3bc4e9a724 Finalize docs 2017-08-17 00:41:50 +08:00
topjohnwu
f7a6bb0723 Add more details and tips 2017-08-15 10:13:19 +08:00
topjohnwu
e9c17a3ef7 Add bootstages docs 2017-08-15 02:27:07 +08:00
topjohnwu
29bb5840b5 Fix duplicate in applets.md 2017-08-15 01:38:22 +08:00
topjohnwu
c9d8d860f6 Update diagram link 2017-08-15 01:32:24 +08:00
topjohnwu
cc18096882 Update docs 2017-08-15 01:28:45 +08:00
topjohnwu
15f2a664d1 Update help messages 2017-08-15 01:25:54 +08:00
topjohnwu
70b4f62ddc Update links 2017-08-14 03:54:05 +08:00
topjohnwu
e1023fdfaf Fix typo in procedure chart 2017-08-14 03:52:37 +08:00
topjohnwu
5e9648387a Merge module and repo docs 2017-08-14 03:46:23 +08:00
topjohnwu
2ba8b4df67 Complete module.md 2017-08-14 03:25:11 +08:00
topjohnwu
3a084c5d7b Add docs 2017-08-14 02:41:27 +08:00
topjohnwu
f7200e39c3 Bump MagiskManager version 2017-08-13 01:50:36 +08:00
topjohnwu
a7dfc20967 Adjust several operation orders 2017-08-13 01:15:18 +08:00
topjohnwu
6eb7c0b5d6 Add new util functions for new template version 2017-08-12 23:15:39 +08:00
topjohnwu
0b3c078aeb Fix README.MD 2017-08-12 19:17:06 +08:00
topjohnwu
750872cc37 Add boot actions 2017-08-12 17:03:31 +08:00
topjohnwu
29895ff474 Fix multiuser in user independent mode 2017-08-12 01:09:20 +08:00
topjohnwu
44adccc147 Add magisk binary mirror 2017-08-11 17:43:36 +08:00
topjohnwu
2a7e2c70b5 Extract functions 2017-08-11 14:53:24 +08:00
topjohnwu
8d431b6762 Remove IS_VENDOR flag (not needed) 2017-08-11 14:53:17 +08:00
topjohnwu
273849c0c8 Reorganize functions 2017-08-11 11:07:58 +08:00
topjohnwu
5cc14405c7 Combine image related functions 2017-08-10 17:26:37 +08:00
topjohnwu
f0cfd60e62 Fix multiuser 2017-08-07 00:32:04 +08:00
topjohnwu
d6547f0701 Fix installer options not read properly 2017-08-04 23:49:22 +08:00
topjohnwu
3b68905037 Swap buffer to fix module scripts 2017-08-03 18:07:34 +08:00
topjohnwu
eae611c54d Add b64xz to handle busybox decode/decompress in scripts 2017-08-02 18:25:24 +08:00
topjohnwu
b37bad35c2 Fuse busybox into update-binary and remove from Magisk Manager APK 2017-08-02 02:22:33 +08:00
topjohnwu
5fab15fee5 Add busybox into PATH for scripts 2017-08-01 15:34:16 +08:00
topjohnwu
10c8ea17aa Fix debug message 2017-08-01 01:24:27 +08:00
topjohnwu
7058c8ff5a Force main binaries recompile everytime 2017-07-31 23:52:50 +08:00
topjohnwu
64e85da59f Merge Android.mk 2017-07-31 23:47:50 +08:00
topjohnwu
f79fad64aa Fix several script issues 2017-07-31 23:31:40 +08:00
topjohnwu
cb70eebb08 Update scripts 2017-07-31 03:03:52 +08:00
topjohnwu
edaf8787d1 Provide external files to Magisk Manager with build script 2017-07-31 00:59:41 +08:00
topjohnwu
24164c8580 Add busybox to source 2017-07-30 20:14:12 +08:00
topjohnwu
9fca7011aa Move headers 2017-07-30 18:15:00 +08:00
topjohnwu
b13eb3fd40 Force start logd ASAP 2017-07-25 05:33:25 +08:00
topjohnwu
b7986a351c Overcome some quirks in Android Lollipop 2017-07-25 05:33:25 +08:00
topjohnwu
ce87591c62 Fix unable to get SHA1 value issue 2017-07-25 02:40:26 +08:00
topjohnwu
25c289ad3e Fix typo in uninstaller 2017-07-19 03:24:07 +08:00
topjohnwu
8c5f11b7dd Update Magisk Manager 2017-07-19 02:34:23 +08:00
topjohnwu
7f7dda9ec2 Update uninstaller 2017-07-19 02:22:07 +08:00
topjohnwu
9c1005ff0c Update to Google CTS (2017.7.17) 2017-07-19 02:22:07 +08:00
topjohnwu
5b36b4472c Update and add new resetprop features 2017-07-19 02:22:07 +08:00
topjohnwu
a3fcc64aaa MagiskBoot log to stderr 2017-07-18 11:53:28 +08:00
topjohnwu
f3078bc903 Update MagiskSU 2017-07-16 23:39:27 +08:00
topjohnwu
6072744f7e Prevent logcat monitors crashing 2017-07-16 23:39:27 +08:00
topjohnwu
a87ad35a50 Check Android version before actually doing anything
Close #233
2017-07-14 01:13:49 +08:00
topjohnwu
cf56d7e4ed Let core-only mode run hosts and magiskhide 2017-07-14 00:54:43 +08:00
topjohnwu
e33a5eb307 Set proper selinux context for /sbin re-link 2017-07-14 00:51:42 +08:00
topjohnwu
e5b704eb32 Several cleanups 2017-07-13 23:42:01 +08:00
topjohnwu
56457bd325 Fix lzma compressed ramdisk
Fix issue #222
2017-07-13 10:22:55 +08:00
topjohnwu
bdbb3c6657 Eliminate a potential segfault in magiskpolicy
Huge props to @jenslody for finding out the issue!
Fix #278
2017-07-13 10:13:14 +08:00
topjohnwu
c4d7001489 Fix Pixel C flashing errors
Use return values instead of creating a file to indicate a chromeos image
Fix #264
2017-07-13 02:14:10 +08:00
topjohnwu
c07bac9a63 Bump MagiskManager version 2017-07-11 01:54:26 +08:00
topjohnwu
d27d04783f Add version info into util_functions 2017-07-11 01:54:11 +08:00
topjohnwu
58de5a7ec7 Prevent a slight chance to crash 2017-07-11 01:53:45 +08:00
topjohnwu
504a9b4746 MagiskHide refactor 2017-07-10 23:41:21 +08:00
topjohnwu
cccb5a3e08 Update comments 2017-07-10 22:48:14 +08:00
topjohnwu
d75fa62cab Adjust run_command function 2017-07-10 22:29:53 +08:00
topjohnwu
3d43c3c5bc Update scripts 2017-07-10 00:17:34 +08:00
topjohnwu
b570b363d9 Cleanup file descriptors and add more info 2017-07-08 23:51:58 +08:00
topjohnwu
b9968aa1e6 Add mount-master option to su 2017-07-08 01:13:12 +08:00
topjohnwu
c0d77808f6 Update selinux from upstream 2017-07-07 23:08:18 +08:00
topjohnwu
9679492c28 Match resetprop files with AOSP 2017-07-07 22:29:55 +08:00
topjohnwu
f3b68e6543 Seperate external shared libraries 2017-07-07 22:11:00 +08:00
topjohnwu
0dcfaaf5ff Adjust hide policies 2017-07-07 17:52:25 +08:00
topjohnwu
ba513dcb9a Use sqlite stub 2017-07-07 17:14:37 +08:00
topjohnwu
ebabc60477 Update Magisk Manager 2017-07-03 01:19:15 +08:00
topjohnwu
cf565d0145 Add mount ns kernel support detection 2017-07-03 01:19:15 +08:00
topjohnwu
52a23e7904 Add more props for hiding 2017-07-03 01:19:15 +08:00
topjohnwu
9e22b80714 Update unmounting policies 2017-07-03 01:19:15 +08:00
topjohnwu
7eed9c4a6d Several improvements 2017-07-03 01:19:15 +08:00
topjohnwu
bf42fce17e Update boot patch method and scripts 2017-07-03 01:19:15 +08:00
topjohnwu
9d421226a7 Update list implementation 2017-07-03 01:15:11 +08:00
topjohnwu
7b9be8369e Enable magiskhide by default 2017-07-01 15:45:22 +08:00
topjohnwu
7cf4b819ae Several small tweaks 2017-07-01 14:05:54 +08:00
topjohnwu
9e1aea33c3 Improve xmkdir 2017-06-30 23:22:51 +08:00
topjohnwu
8767a88854 Check/fix ext4 image before mounting 2017-06-30 23:22:26 +08:00
topjohnwu
47c0084641 Fix cache mount bug 2017-06-30 21:49:35 +08:00
topjohnwu
54e6a790cf Update Magisk Manager 2017-06-24 23:46:44 +09:00
topjohnwu
2a86bc8695 Update scripts 2017-06-24 23:39:24 +09:00
topjohnwu
04538372c6 Add more image commands 2017-06-24 23:37:45 +09:00
topjohnwu
9430ed66cd Add addon.d survival script 2017-06-19 00:15:44 +08:00
topjohnwu
96f8efc27a Several small fixes 2017-06-16 15:27:28 +08:00
topjohnwu
a90e8b6112 Only use binaries/libs in /system 2017-06-16 04:09:36 +08:00
topjohnwu
561c1fb798 Update MagiskManager 2017-06-16 04:07:45 +08:00
topjohnwu
806fec7017 Add new rules to unmount 2017-06-15 18:32:24 +08:00
topjohnwu
b3da28eade Don't compile shell.c for sqlite 2017-06-14 03:29:59 +08:00
topjohnwu
166f6412c2 Fix a flaw in mounting logic 2017-06-14 00:55:41 +08:00
topjohnwu
1e877808bc Fix link errors for flash scripts 2017-06-13 00:46:20 +08:00
topjohnwu
1777d9f751 Magic Mount algorithm massive bug fix 2017-06-12 03:29:01 +08:00
topjohnwu
309b99eac0 Always init for resetprop 2017-06-11 20:22:10 +08:00
topjohnwu
a5aa1b3917 Don't use system and collect logs 2017-06-11 20:20:24 +08:00
topjohnwu
aced0632ec Improve image merging 2017-06-11 16:51:44 +08:00
topjohnwu
4e801788d7 Fix shared library linking error 2017-06-11 01:40:08 +08:00
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
136 changed files with 23594 additions and 5855 deletions

4
.gitattributes vendored
View File

@@ -8,9 +8,11 @@
# Declare files that will always have CRLF line endings on checkout.
*.cmd text eol=crlf
*.bat text eol=crlf
# Denote all files that are truly binary and should not be modified.
binaries/** binary
chromeos/** binary
*.jar binary
*.exe binary
*.apk binary
*.png binary

17
.gitignore vendored
View File

@@ -1,22 +1,7 @@
obj/
libs/
*.zip
*.jks
# Copied binaries
zip_static/arm/*
zip_static/arm64/*
zip_static/x86/*
zip_static/x64/*
zip_static/chromeos/*
uninstaller/arm/*
uninstaller/arm64/*
uninstaller/x86/*
uninstaller/x64/*
uninstaller/chromeos/*
ziptools/zipadjust
# Generated scripts
uninstaller/common/
zip_static/common/*.sh
zip_static/common/*.rc
zip_static/META-INF/com/google/android/update-binary

6
.gitmodules vendored
View File

@@ -10,3 +10,9 @@
[submodule "jni/magiskpolicy"]
path = jni/magiskpolicy
url = https://github.com/topjohnwu/magiskpolicy.git
[submodule "MagiskManager"]
path = MagiskManager
url = https://github.com/topjohnwu/MagiskManager.git
[submodule "jni/busybox"]
path = jni/busybox
url = https://github.com/topjohnwu/ndk-busybox.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 b362c0ef38

102
README.MD
View File

@@ -1,11 +1,95 @@
# Magisk
### Static binaries included:
* Busybox: http://forum.xda-developers.com/android/software-hacking/tool-busybox-flashable-archs-t3348543
### How to build Magisk
1. Download and install NDK
2. Add the NDK directory into PATH
To check if the PATH is set correctly, try calling `which ndk-build` (`where ndk-build` on Windows) and see if it shows the NDK directory
3. Unix-like users (e.g. Linux & MacOS) please execute `build.sh` through shell
Windows users please execute `build.cmd` through cmd
4. The scripts will show you further details
## How to build Magisk
#### Building has been tested on 3 major platforms:
**macOS 10.12**
**Ubuntu 17.04 x64**
**Windows 10 x64**
#### Environment Requirements
1. A 64-bit machine: `cmake` for Android is only available in 64-bit
2. Python 3.5+: to run the build script
3. Java Development Kit (JDK) 8: To compile Magisk Manager and sign zips
4. C compiler (Unix only): To build `zipadjust`. Windows users can use the pre-built `zipadjust.exe`
5. Android SDK: `ANDROID_HOME` environment variable should point to the Android SDK folder
6. Android NDK: Install NDK via `sdkmanager`, or via Android SDK Manager in Android Studio
#### Instructions and Notes
1. The easiest way to setup a working environment is to open Magisk Manager with Android Studio. The IDE will download required components and construct the environment for you. Don't forget to set `ANDROID_HOME` environment variable to the SDK path.
2. Windows users: while installing Python 3 on Windows, allow the installer to add Python to `PATH`, or you'll have to add it manually afterwards. By default, the Python executable is setup as `python`, not `python3` like most Unix environment. If you have both Python 2 and Python 3 installed, you'll have to deal with the executable name and `PATH` yourself. To double check the Python version, call `python --version`.
3. To run the script, on Windows call `python build.py [args...]`; on Unix call `python3 build.py [args...]`, or simply `./build.py [args...]`. To see the built-in help message, call the script with `-h` as an argument. The `-h` option also works for each supported actions to see the help message for the specific action.
4. By default, the script will build binaries and Magisk Manager in debug mode, which will enable verbose debugging messages. If you want to build Magisk Manager in release mode (through the flag `--release`), you will need to place your Java Keystore file in `release_signature.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
5. 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 use an older Windows version, a quick Google search should provide many workarounds.
## 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)
* Maintained by many developers in SELinux project
**ndk-compression** (`jni/ndk-compression`)
* Makefile for NDK: Copyright 2017, John Wu (@topjohnwu)
* Each library has its own copyright message in corresponding directories
**ndk-busybox** (`jni/busybox`)
* Makefile for NDK, generated by [ndk-busybox-kitchen](https://github.com/topjohnwu/ndk-busybox-kitchen): Copyright 2017, John Wu (@topjohnwu)
* Patches for NDK: Many contributors along the way, all placed in [osm0sis/android-busybox-ndk](https://github.com/osm0sis/android-busybox-ndk)
* The copyright message for busybox should be included in its own directory
**Others Not Mentioned**
* Copyright 2016-2017, John Wu (@topjohnwu)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

182
build.cmd
View File

@@ -1,182 +0,0 @@
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
SET me=%~nx0
SET parent=%~dp0
SET tab=
SET OK=
CD %parent%
call :%~1 "%~2"
IF NOT DEFINED OK CALL :usage
EXIT /B %ERRORLEVEL%
:usage
ECHO %me% all ^<version name^>
ECHO %tab%Build binaries, zip, and sign Magisk
ECHO %tab%This is equlivant to first ^<build^>, then ^<zip^>
ECHO %me% clean
ECHO %tab%Cleanup compiled / generated files
ECHO %me% build
ECHO %tab%Build the binaries with ndk
ECHO %me% zip ^<version name^>
ECHO %tab%Zip and sign Magisk
ECHO %me% uninstaller
ECHO %tab%Zip and sign the uninstaller
EXIT /B 1
:all
SET OK=y
IF [%~1] == [] (
CALL :error "Missing version number"
CALL :usage
EXIT /B %ERRORLEVEL%
)
CALL :build
CALL :zip "%~1"
EXIT /B %ERRORLEVEL%
:build
SET OK=y
ECHO ************************
ECHO * Building binaries
ECHO ************************
FOR /F "tokens=* USEBACKQ" %%F IN (`where ndk-build`) DO (
IF [%%F] == [] (
CALL :error "Please add ndk-build to PATH!"
EXIT /B 1
)
)
CALL ndk-build -j4 || CALL :error "Magisk binary tools build failed...."
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
ECHO ************************
ECHO * Copying binaries
ECHO ************************
CALL :mkcp libs\armeabi-v7a\* zip_static\arm
CALL :mkcp libs\arm64-v8a\* zip_static\arm64
CALL :mkcp libs\x86\* zip_static\x86
CALL :mkcp libs\x86_64\* zip_static\x64
CALL :mkcp libs\armeabi-v7a\magiskboot uninstaller\arm
CALL :mkcp libs\arm64-v8a\magiskboot uninstaller\arm64
CALL :mkcp libs\x86\magiskboot uninstaller\x86
CALL :mkcp libs\x86_64\magiskboot uninstaller\x64
EXIT /B %ERRORLEVEL%
:clean
SET OK=y
ECHO ************************
ECHO * Cleaning up
ECHO ************************
CALL ndk-build clean
2>NUL RMDIR /S /Q zip_static\arm
2>NUL RMDIR /S /Q zip_static\arm64
2>NUL RMDIR /S /Q zip_static\x86
2>NUL RMDIR /S /Q zip_static\x64
2>NUL RMDIR /S /Q zip_static\chromeos
2>NUL DEL zip_static\META-INF\com\google\android\update-binary
2>NUL DEL zip_static\common\*.sh
2>NUL DEL zip_static\common\*.rc
2>NUL RMDIR /S /Q uninstaller\common
2>NUL RMDIR /S /Q uninstaller\arm
2>NUL RMDIR /S /Q uninstaller\arm64
2>NUL RMDIR /S /Q uninstaller\x86
2>NUL RMDIR /S /Q uninstaller\x64
2>NUL RMDIR /S /Q uninstaller\chromeos
EXIT /B 0
:zip
SET OK=y
IF [%~1] == [] (
CALL :error "Missing version number"
CALL :usage
EXIT /B %ERRORLEVEL%
)
IF NOT EXIST "zip_static\arm\magiskboot" CALL :error "Missing binaries! Please run '%me% build' before zipping!"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
ECHO ************************
ECHO * Adding version info
ECHO ************************
powershell.exe -nologo -noprofile -command "(gc -Raw scripts\flash_script.sh) -replace 'MAGISK_VERSION_STUB', 'Magisk v%~1 Boot Image Patcher' | sc zip_static\META-INF\com\google\android\update-binary"
powershell.exe -nologo -noprofile -command "(gc -Raw scripts\magic_mask.sh) -replace 'MAGISK_VERSION_STUB', 'setprop magisk.version \"%~1\"' | sc zip_static\common\magic_mask.sh"
ECHO ************************
ECHO * Copying Files
ECHO ************************
COPY /Y scripts\custom_ramdisk_patch.sh zip_static\common\custom_ramdisk_patch.sh
COPY /Y scripts\init.magisk.rc zip_static\common\init.magisk.rc
COPY /Y binaries\busybox-arm zip_static\arm\busybox
COPY /Y binaries\busybox-arm64 zip_static\arm64\busybox
COPY /Y binaries\busybox-x86 zip_static\x86\busybox
COPY /Y binaries\busybox-x64 zip_static\x64\busybox
CALL :mkcp binaries\chromeos zip_static\chromeos
ECHO ************************
ECHO * Zipping Magisk v%~1
ECHO ************************
CD zip_static
2>NUL DEL "..\Magisk-v%~1.zip"
..\ziptools\win_bin\zip "..\Magisk-v%~1.zip" -r .
CD ..\
CALL :sign_zip "Magisk-v%~1.zip"
EXIT /B %ERRORLEVEL%
:uninstaller
SET OK=y
IF NOT EXIST "uninstaller\arm\magiskboot" CALL :error "Missing binaries! Please run '%me% build' before zipping!"
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
ECHO ************************
ECHO * Copying Files
ECHO ************************
CALL :mkcp scripts\magisk_uninstaller.sh uninstaller\common
COPY /Y binaries\busybox-arm uninstaller\arm\busybox
COPY /Y binaries\busybox-arm64 uninstaller\arm64\busybox
COPY /Y binaries\busybox-x86 uninstaller\x86\busybox
COPY /Y binaries\busybox-x64 uninstaller\x64\busybox
CALL :mkcp binaries\chromeos uninstaller\chromeos
ECHO ************************
ECHO * Zipping uninstaller
ECHO ************************
FOR /F "tokens=* USEBACKQ" %%F IN (`ziptools\win_bin\date "+%%Y%%m%%d"`) DO (set timestamp=%%F)
CD uninstaller
2>NUL DEL "../Magisk-uninstaller-%timestamp%.zip"
..\ziptools\win_bin\zip "../Magisk-uninstaller-%timestamp%.zip" -r .
CD ..\
CALL :sign_zip "Magisk-uninstaller-%timestamp%.zip"
EXIT /B %ERRORLEVEL%
:sign_zip
IF NOT EXIST "ziptools\win_bin\zipadjust.exe" (
ECHO ************************
ECHO * Compiling ZipAdjust
ECHO ************************
gcc -o ziptools\win_bin\zipadjust ziptools\src\*.c -lz || CALL :error "ZipAdjust Build failed...."
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%
)
SET basename="%~1"
SET basename="%basename:.zip=%"
ECHO ************************
ECHO * First sign %~1
ECHO ************************
java -jar "ziptools\signapk.jar" "ziptools\test.certificate.x509.pem" "ziptools\test.key.pk8" "%~1" "%basename:"=%-firstsign.zip"
ECHO ************************
ECHO * Adjusting %~1
ECHO ************************
ziptools\win_bin\zipadjust "%basename:"=%-firstsign.zip" "%basename:"=%-adjusted.zip"
ECHO ************************
ECHO * Final sign %~1
ECHO ************************
java -jar "ziptools\minsignapk.jar" "ziptools\test.certificate.x509.pem" "ziptools\test.key.pk8" "%basename:"=%-adjusted.zip" "%basename:"=%-signed.zip"
MOVE /Y "%basename:"=%-signed.zip" "%~1"
DEL "%basename:"=%-adjusted.zip" "%basename:"=%-firstsign.zip"
EXIT /B %ERRORLEVEL%
:mkcp
2>NUL MKDIR "%~2"
2>NUL COPY /Y "%~1" "%~2"
EXIT /B 0
:error
ECHO.
ECHO ! %~1
ECHO.
EXIT /B 1

382
build.py Executable file
View File

@@ -0,0 +1,382 @@
#!/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
import shutil
import lzma
import base64
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: {} -> {}'.format(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')
# Force update Android.mk timestamp to trigger recompilation
os.utime(os.path.join('jni', 'Android.mk'))
ndk_build = os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build')
debug_flag = '' if args.release else '-DMAGISK_DEBUG'
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')
for key in ['public.certificate.x509.pem', 'private.key.pk8']:
source = os.path.join('ziptools', key)
target = os.path.join('MagiskManager', 'app', 'src', 'main', 'assets', key)
print('cp: {} -> {}'.format(source, target))
shutil.copyfile(source, target)
for script in ['magisk_uninstaller.sh', 'util_functions.sh']:
source = os.path.join('scripts', script)
target = os.path.join('MagiskManager', 'app', 'src', 'main', 'assets', script)
print('cp: {} -> {}'.format(source, target))
shutil.copyfile(source, target)
os.chdir('MagiskManager')
# Build unhide app and place in assets
proc = subprocess.run('{} unhide::assembleRelease'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build Magisk Manager failed!')
source = os.path.join('unhide', 'build', 'outputs', 'apk', 'release', 'unhide-release-unsigned.apk')
target = os.path.join('app', 'src', 'main', 'assets', 'unhide.apk')
print('cp: {} -> {}'.format(source, target))
shutil.copyfile(source, target)
print('')
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('{} app::assembleRelease'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build Magisk Manager failed!')
unsigned = os.path.join('app', 'build', 'outputs', 'apk', 'release', 'app-release-unsigned.apk')
aligned = os.path.join('app', 'build', 'outputs', 'apk', 'release', 'app-release-aligned.apk')
release = os.path.join('app', 'build', 'outputs', 'apk', 'release', 'app-release.apk')
# Find the latest build tools
build_tool = sorted(os.listdir(os.path.join(os.environ['ANDROID_HOME'], 'build-tools')))[-1]
silentremove(aligned)
silentremove(release)
proc = subprocess.run([
os.path.join(os.environ['ANDROID_HOME'], 'build-tools', build_tool, 'zipalign'),
'-v', '-p', '4', unsigned, aligned], stdout=subprocess.DEVNULL)
if proc.returncode != 0:
error('Zipalign Magisk Manager failed!')
# Find apksigner.jar
apksigner = ''
for root, dirs, files in os.walk(os.path.join(os.environ['ANDROID_HOME'], 'build-tools', build_tool)):
if 'apksigner.jar' in files:
apksigner = os.path.join(root, 'apksigner.jar')
break
if not apksigner:
error('Cannot find apksigner.jar in Android SDK build tools')
proc = subprocess.run('java -jar {} sign --ks {} --out {} {}'.format(
apksigner,
os.path.join('..', 'release_signature.jks'),
release, aligned), shell=True)
if proc.returncode != 0:
error('Release sign Magisk Manager failed!')
silentremove(unsigned)
silentremove(aligned)
else:
proc = subprocess.run('{} app::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):
zipsigner = os.path.join('ziptools', 'zipsigner', 'build', 'libs', 'zipsigner.jar')
if os.name != 'nt' and not os.path.exists(os.path.join('ziptools', 'zipadjust')):
header('* Building zipadjust')
# Compile zipadjust
proc = subprocess.run('gcc -o ziptools/zipadjust ziptools/zipadjust_src/*.c -lz', shell=True)
if proc.returncode != 0:
error('Build zipadjust failed!')
if not os.path.exists(zipsigner):
header('* Building zipsigner.jar')
os.chdir(os.path.join('ziptools', 'zipsigner'))
proc = subprocess.run('{} shadowJar'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0:
error('Build zipsigner.jar failed!')
os.chdir(os.path.join('..', '..'))
header('* Signing / Adjusting Zip')
publicKey = os.path.join('ziptools', 'public.certificate.x509.pem')
privateKey = os.path.join('ziptools', 'private.key.pk8')
# Unsigned->signed
proc = subprocess.run(['java', '-jar', zipsigner,
publicKey, privateKey, unsigned, 'tmp_signed.zip'])
if proc.returncode != 0:
error('First sign flashable zip 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', zipsigner,
"-m", publicKey, privateKey, '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 gen_update_binary():
update_bin = []
binary = os.path.join('libs', 'armeabi-v7a', 'b64xz')
if not os.path.exists(binary):
error('Please build \'binary\' before zipping!')
with open(binary, 'rb') as b64xz:
update_bin.append('#! /sbin/sh\nEX_ARM=')
update_bin.append(''.join("\\\\x{:02X}".format(c) for c in b64xz.read()))
binary = os.path.join('libs', 'x86', 'b64xz')
with open(binary, 'rb') as b64xz:
update_bin.append('\nEX_X86=')
update_bin.append(''.join("\\\\x{:02X}".format(c) for c in b64xz.read()))
binary = os.path.join('libs', 'armeabi-v7a', 'busybox')
with open(binary, 'rb') as busybox:
update_bin.append('\nBB_ARM=')
update_bin.append(base64.b64encode(lzma.compress(busybox.read())).decode('ascii'))
binary = os.path.join('libs', 'x86', 'busybox')
with open(binary, 'rb') as busybox:
update_bin.append('\nBB_X86=')
update_bin.append(base64.b64encode(lzma.compress(busybox.read())).decode('ascii'))
update_bin.append('\n')
with open(os.path.join('scripts', 'update_binary.sh'), 'r') as script:
update_bin.append(script.read())
return ''.join(update_bin)
def zip_main(args):
header('* Packing Flashable Zip')
with zipfile.ZipFile('tmp_unsigned.zip', 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
# META-INF
# update-binary
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
print('zip: ' + target)
zipf.writestr(target, gen_update_binary())
# updater-script
source = os.path.join('scripts', 'flash_script.sh')
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
zip_with_msg(zipf, source, target)
# Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
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',
'release' if args.release else 'debug', 'app-release.apk' if args.release else 'app-debug.apk')
target = os.path.join('common', 'magisk.apk')
zip_with_msg(zipf, source, target)
# Scripts
# boot_patch.sh
source = os.path.join('scripts', 'boot_patch.sh')
target = os.path.join('common', 'boot_patch.sh')
zip_with_msg(zipf, source, target)
# util_functions.sh
source = os.path.join('scripts', 'util_functions.sh')
with open(source, 'r') as script:
# Add version info util_functions.sh
util_func = script.read().replace(
'MAGISK_VERSION_STUB', 'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(args.versionString, args.versionCode))
target = os.path.join('common', 'util_functions.sh')
print('zip: ' + source + ' -> ' + target)
zipf.writestr(target, util_func)
# addon.d.sh
source = os.path.join('scripts', 'addon.d.sh')
target = os.path.join('addon.d', '99-magisk.sh')
zip_with_msg(zipf, source, target)
# init.magisk.rc
source = os.path.join('scripts', 'init.magisk.rc')
target = os.path.join('common', 'init.magisk.rc')
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, allowZip64=False) as zipf:
# META-INF
# update-binary
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
print('zip: ' + target)
zipf.writestr(target, gen_update_binary())
# updater-script
source = os.path.join('scripts', 'uninstaller_loader.sh')
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
zip_with_msg(zipf, source, target)
# Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
source = os.path.join('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)
# Scripts
# util_functions.sh
source = os.path.join('scripts', 'util_functions.sh')
with open(source, 'r') as script:
# Remove the stub
util_func = script.read().replace(
'MAGISK_VERSION_STUB', '')
target = os.path.join('util_functions.sh')
print('zip: ' + source + ' -> ' + target)
zipf.writestr(target, util_func)
# 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-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.add_argument('versionCode', type=int)
zip_parser.set_defaults(func=zip_main)
uninstaller_parser = subparsers.add_parser('uninstaller', help='create flashable uninstaller')
uninstaller_parser.set_defaults(func=zip_uninstaller)
clean_parser = subparsers.add_parser('clean', help='clean [target...] targets: binary apk zip')
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)

172
build.sh
View File

@@ -1,172 +0,0 @@
#!/bin/bash
usage() {
echo "$0 all <version name>"
echo -e "\tBuild binaries, zip, and sign Magisk"
echo -e "\tThis is equlivant to first <build>, then <zip>"
echo "$0 clean"
echo -e "\tCleanup compiled / generated files"
echo "$0 build"
echo -e "\tBuild the binaries with ndk"
echo "$0 zip <version name>"
echo -e "\tZip and sign Magisk"
echo "$0 uninstaller"
echo -e "\tZip and sign the uninstaller"
exit 1
}
cleanup() {
echo "************************"
echo "* Cleaning up"
echo "************************"
ndk-build clean 2>/dev/null
rm -rfv zip_static/arm
rm -rfv zip_static/arm64
rm -rfv zip_static/x86
rm -rfv zip_static/x64
rm -rfv zip_static/chromeos
rm -rfv zip_static/META-INF/com/google/android/update-binary
rm -rfv zip_static/common/*.sh
rm -rfv zip_static/common/*.rc
rm -rfv uninstaller/common
rm -rfv uninstaller/arm
rm -rfv uninstaller/arm64
rm -rfv uninstaller/x86
rm -rfv uninstaller/x64
rm -rfv uninstaller/chromeos
}
mkcp() {
[ ! -d "$2" ] && mkdir -p "$2"
cp -afv $1 $2
}
error() {
echo -e "\n! $1\n"
exit 1
}
build_bin() {
echo "************************"
echo "* Building binaries"
echo "************************"
[ -z `which ndk-build` ] && error "Please add ndk-build to PATH!"
ndk-build -j4 || error "Magisk binary tools build failed...."
echo "************************"
echo "* Copying binaries"
echo "************************"
mkcp "libs/armeabi-v7a/*" zip_static/arm
mkcp libs/armeabi-v7a/magiskboot uninstaller/arm
mkcp "libs/arm64-v8a/*" zip_static/arm64
mkcp libs/arm64-v8a/magiskboot uninstaller/arm64
mkcp "libs/x86/*" zip_static/x86
mkcp libs/x86/magiskboot uninstaller/x86
mkcp "libs/x86_64/*" zip_static/x64
mkcp libs/x86_64/magiskboot uninstaller/x64
}
zip_package() {
[ ! -f "zip_static/arm/magiskboot" ] && error "Missing binaries!! Please run '$0 build' before zipping"
echo "************************"
echo "* Adding version info"
echo "************************"
sed "s/MAGISK_VERSION_STUB/Magisk v$1 Boot Image Patcher/g" scripts/flash_script.sh > zip_static/META-INF/com/google/android/update-binary
sed "s/MAGISK_VERSION_STUB/setprop magisk.version \"$1\"/g" scripts/magic_mask.sh > zip_static/common/magic_mask.sh
echo "************************"
echo "* Copying files"
echo "************************"
cp -afv scripts/custom_ramdisk_patch.sh zip_static/common/custom_ramdisk_patch.sh
cp -afv scripts/init.magisk.rc zip_static/common/init.magisk.rc
cp -afv binaries/busybox-arm zip_static/arm/busybox
cp -afv binaries/busybox-arm64 zip_static/arm64/busybox
cp -afv binaries/busybox-x86 zip_static/x86/busybox
cp -afv binaries/busybox-x64 zip_static/x64/busybox
cp -afv binaries/chromeos/. zip_static/chromeos
echo "************************"
echo "* Zipping Magisk v$1"
echo "************************"
cd zip_static
find . -type f -exec chmod 644 {} \;
find . -type d -exec chmod 755 {} \;
rm -rf "../Magisk-v$1.zip"
zip "../Magisk-v$1.zip" -r .
cd ../
sign_zip "Magisk-v$1.zip"
}
zip_uninstaller() {
[ ! -f "uninstaller/arm/magiskboot" ] && error "Missing binaries!! Please run '$0 build' before zipping"
echo "************************"
echo "* Copying files"
echo "************************"
mkcp scripts/magisk_uninstaller.sh uninstaller/common
cp -afv binaries/busybox-arm uninstaller/arm/busybox
cp -afv binaries/busybox-arm64 uninstaller/arm64/busybox
cp -afv binaries/busybox-x86 uninstaller/x86/busybox
cp -afv binaries/busybox-x64 uninstaller/x64/busybox
cp -afv binaries/chromeos/. zip_static/chromeos
echo "************************"
echo "* Zipping uninstaller"
echo "************************"
mkcp scripts/magisk_uninstaller.sh uninstaller/common
cd uninstaller
find . -type f -exec chmod 644 {} \;
find . -type d -exec chmod 755 {} \;
TIMESTAMP=`date "+%Y%m%d"`
rm -rf "../Magisk-uninstaller-$TIMESTAMP.zip"
zip "../Magisk-uninstaller-$TIMESTAMP.zip" -r .
cd ../
sign_zip "Magisk-uninstaller-$TIMESTAMP.zip"
}
sign_zip() {
if [ ! -f "ziptools/zipadjust" ]; then
echo "************************"
echo "* Compiling ZipAdjust"
echo "************************"
gcc -o ziptools/zipadjust ziptools/src/*.c -lz || error "ZipAdjust Build failed...."
chmod 755 ziptools/zipadjust
fi
echo "************************"
echo "* First sign $1"
echo "************************"
java -jar "ziptools/signapk.jar" "ziptools/test.certificate.x509.pem" "ziptools/test.key.pk8" "$1" "${1%.*}-firstsign.zip"
echo "************************"
echo "* Adjusting $1"
echo "************************"
ziptools/zipadjust "${1%.*}-firstsign.zip" "${1%.*}-adjusted.zip"
echo "************************"
echo "* Final sign $1"
echo "************************"
java -jar "ziptools/minsignapk.jar" "ziptools/test.certificate.x509.pem" "ziptools/test.key.pk8" "${1%.*}-adjusted.zip" "${1%.*}-signed.zip"
mv "${1%.*}-signed.zip" "$1"
rm "${1%.*}-adjusted.zip" "${1%.*}-firstsign.zip"
}
DIR="$(cd "$(dirname "$0")"; pwd)"
cd "$DIR"
case $1 in
"all" )
[ -z "$2" ] && echo -e "! Missing version number\n" && usage
build_bin
zip_package $2
;;
"clean" )
cleanup
;;
"build" )
build_bin
;;
"zip" )
[ -z "$2" ] && echo -e "! Missing version number\n" && usage
zip_package $2
;;
"uninstaller" )
zip_uninstaller
;;
* )
usage
;;
esac

27
docs/README.MD Normal file
View File

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

171
docs/applets.md Normal file
View File

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

3
docs/changelog.md Normal file
View File

@@ -0,0 +1,3 @@
# Changelog
- 2017.8.16
- Initial version for Magisk v13.5+

60
docs/details.md Normal file
View File

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

76
docs/module_repo.md Normal file
View File

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

11
docs/procedures.html Normal file

File diff suppressed because one or more lines are too long

BIN
docs/repo_description.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

6
docs/tips.md Normal file
View File

@@ -0,0 +1,6 @@
# Tips and Tricks
## Remove Files
How to efficiently remove a file systemless-ly? To actually make the file **disappear** within the folder is complicated (possible, not worth the effort). **Replacing it with a dummy file should be good enough**! Create an empty file with the same name and place it in the same path within a module, then you're basically done!
## Remove Folders
Same as mentioned above, actually making the folder to **disappear** is not worth the effort. **Replacing it with an empty folder should be good enough**! A handy trick for module developers using [Magisk Module Template](https://github.com/topjohnwu/magisk-module-template) is to add the folder you want to remove into the `REPLACE` list within `config.sh`. If your module doesn't provide a correspond folder, it will create an empty folder, and automatically add `.replace` into the empty folder so the dummy folder will properly replace the one in `/system`.

View File

@@ -1,7 +1,107 @@
LOCAL_PATH := $(call my-dir)
include jni/magiskboot/Android.mk
include jni/magiskhide/Android.mk
include jni/resetprop/Android.mk
include jni/magiskpolicy/Android.mk
include jni/su/Android.mk
########################
# Binaries
########################
# magisk main binary
include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_STATIC_LIBRARIES := libsepol
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/external \
$(LOCAL_PATH)/selinux/libsepol/include
LOCAL_SRC_FILES := \
daemon/magisk.c \
daemon/daemon.c \
daemon/socket_trans.c \
daemon/log_monitor.c \
daemon/bootstages.c \
utils/misc.c \
utils/vector.c \
utils/xwrap.c \
utils/list.c \
utils/img.c \
magiskhide/magiskhide.c \
magiskhide/proc_monitor.c \
magiskhide/hide_utils.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_CPPFLAGS := -std=c++11
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)
# magiskboot
include $(CLEAR_VARS)
LOCAL_MODULE := magiskboot
LOCAL_STATIC_LIBRARIES := libz liblzma liblz4 libbz2
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/magiskboot \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/ndk-compression/zlib \
$(LOCAL_PATH)/ndk-compression/xz/src/liblzma/api \
$(LOCAL_PATH)/ndk-compression/lz4/lib \
$(LOCAL_PATH)/ndk-compression/bzip2
LOCAL_SRC_FILES := \
magiskboot/main.c \
magiskboot/bootimg.c \
magiskboot/hexpatch.c \
magiskboot/compress.c \
magiskboot/boot_utils.c \
magiskboot/cpio.c \
magiskboot/sha1.c \
utils/xwrap.c \
utils/vector.c \
utils/list.c
LOCAL_CFLAGS := -DZLIB_CONST
include $(BUILD_EXECUTABLE)
# 32-bit static binaries
ifneq ($(TARGET_ARCH_ABI), x86_64)
ifneq ($(TARGET_ARCH_ABI), arm64-v8a)
# b64xz
include $(CLEAR_VARS)
LOCAL_MODULE := b64xz
LOCAL_STATIC_LIBRARIES := liblzma
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ndk-compression/xz/src/liblzma/api
LOCAL_SRC_FILES := b64xz.c
LOCAL_LDFLAGS := -static
include $(BUILD_EXECUTABLE)
# Busybox
include jni/busybox/Android.mk
endif
endif
########################
# Libraries
########################
# External shared libraries, include stub libselinux and libsqlite
include jni/external/Android.mk
# libsepol, static library
include jni/selinux/libsepol/Android.mk
# Compression libraries for magiskboot
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

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

83
jni/b64xz.c Normal file
View File

@@ -0,0 +1,83 @@
/* b64xz.c - Base64-XZ Extractor
*
* This program expects data from stdin. The data should be compressed with xz and
* then encoded into base64 format. What b64xz does is basically the reverse of the
* mentioned process: decode base64 to uint8_ts, decompress xz, then dump to stdout
*
* The compiled binary will be hex-dumped into update-binary
* Busybox will be xz-compressed, base64 encoded and dumped into update-binary
* This program is to recover busybox for Magisk installation environment
*
* I intentionally removed stdio. This will result in a smaller binary size because
* all I/O are handled by system calls (read/write) instead of libc wrappers
*/
#include <unistd.h>
#include <lzma.h>
#define BUFSIZE 8192
static const char trans_tbl[] =
"|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
static void decodeblock(uint8_t* in, uint8_t* out) {
out[0] = (uint8_t)(in[0] << 2 | in[1] >> 4);
out[1] = (uint8_t)(in[1] << 4 | in[2] >> 2);
out[2] = (uint8_t)(((in[2] << 6) & 0xc0) | in[3]);
}
static int unxz(lzma_stream *strm, void *buf, size_t size) {
lzma_ret ret = 0;
uint8_t out[BUFSIZE];
strm->next_in = buf;
strm->avail_in = size;
do {
strm->next_out = out;
strm->avail_out = sizeof(out);
ret = lzma_code(strm, LZMA_RUN);
write(STDOUT_FILENO, out, sizeof(out) - strm->avail_out);
} while (strm->avail_out == 0 && ret == LZMA_OK);
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
write(STDERR_FILENO, "LZMA error!\n", 13);
return ret;
}
int main(int argc, char const* argv[]) {
if (argc > 1)
return 0;
uint8_t in[4], buf[BUFSIZE];
int len = 0, pos = 0;
char c;
// Setup lzma stream
lzma_stream strm = LZMA_STREAM_INIT;
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK) {
write(STDERR_FILENO, "Unable to init lzma stream\n", 28);
return 1;
}
while (read(STDIN_FILENO, &c, sizeof(c)) == 1) {
c = ((c < 43 || c > 122) ? -1 : (trans_tbl[c - 43] == '$' ? -1 : trans_tbl[c - 43] - 62));
if (c >= 0)
in[len++] = c;
if (len < 4)
continue;
len = 0;
decodeblock(in, buf + pos);
pos += 3;
if (pos > sizeof(buf) - 3) {
// Buffer is full, unxz
if (unxz(&strm, buf, pos))
return 1;
pos = 0;
}
}
if (pos) {
if (unxz(&strm, buf, pos))
return 1;
}
lzma_end(&strm);
return 0;
}

1
jni/busybox Submodule

Submodule jni/busybox added at 90c9c4fd96

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

@@ -0,0 +1,749 @@
/* bootstages.c - Core bootstage operations
*
* All bootstage operations, including simple mount in post-fs,
* magisk mount in post-fs-data, various image handling, script
* execution, load modules, install Magisk Manager etc.
*/
#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;
static int seperate_vendor = 0;
extern char **environ;
#ifdef MAGISK_DEBUG
static int debug_log_pid, debug_log_fd;
#endif
/******************
* Node structure *
******************/
// Precedence: MODULE > SKEL > INTER > DUMMY
#define IS_DUMMY 0x01 /* mount from mirror */
#define IS_INTER 0x02 /* intermediate node */
#define IS_SKEL 0x04 /* mount from skeleton */
#define IS_MODULE 0x08 /* mount from module */
#define IS_DIR(n) (n->type == DT_DIR)
#define IS_LNK(n) (n->type == DT_LNK)
#define IS_REG(n) (n->type == DT_REG)
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;
};
static void concat_path(struct node_entry *node) {
if (node->parent)
concat_path(node->parent);
int len = strlen(buf);
buf[len] = '/';
strcpy(buf + len + 1, node->name);
}
static char *get_full_path(struct node_entry *node) {
buf[0] = '\0';
concat_path(node);
return strdup(buf);
}
// 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
destroy_subtree(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;
}
/***********
* setenvs *
***********/
static void bb_setenv(struct vector *v) {
for (int i = 0; environ[i]; ++i) {
if (strncmp(environ[i], "PATH=", 5) == 0) {
snprintf(buf, PATH_MAX, "PATH=%s:%s", BBPATH, strchr(environ[i], '=') + 1);
vec_push_back(v, strdup(buf));
} else {
vec_push_back(v, strdup(environ[i]));
}
}
vec_push_back(v, NULL);
}
static void pm_setenv(struct vector *v) {
for (int i = 0; environ[i]; ++i) {
if (strncmp(environ[i], "CLASSPATH=", 10) != 0)
vec_push_back(v, strdup(environ[i]));
}
vec_push_back(v, strdup("CLASSPATH=/system/framework/pm.jar"));
vec_push_back(v, NULL);
}
/***********
* Scripts *
***********/
static 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);
int pid = exec_command(0, NULL, bb_setenv, "sh", buf2, NULL);
if (pid != -1)
waitpid(pid, NULL, 0);
}
}
closedir(dir);
}
static void exec_module_script(const char* stage) {
char *module;
vec_for_each(&module_list, module) {
snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage);
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, module);
if (access(buf2, F_OK) == -1 || access(buf, F_OK) == 0)
continue;
LOGI("%s: exec [%s.sh]\n", module, stage);
int pid = exec_command(0, NULL, bb_setenv, "sh", buf2, NULL);
if (pid != -1)
waitpid(pid, NULL, 0);
}
}
/***************
* Magic Mount *
***************/
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);
/*
* Clone the parent in the following condition:
* 1. File in module is a symlink
* 2. Target file do not exist
* 3. Target file is a symlink, but not /system/vendor
*/
int clone = 0;
if (IS_LNK(node) || access(buf, F_OK) == -1) {
clone = 1;
} else if (parent->parent != NULL || strcmp(node->name, "vendor") != 0) {
struct stat s;
xstat(buf, &s);
if (S_ISLNK(s.st_mode))
clone = 1;
}
if (clone) {
// Mark the parent folder as a skeleton
parent->status |= IS_SKEL; /* This will not overwrite if parent is module */
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 {
// This will be an intermediate node
node->status = IS_INTER;
}
} else if (IS_REG(node)) {
// This is a leaf, mark as target
node->status = IS_MODULE;
}
node = insert_child(parent, node);
if (node->status & (IS_SKEL | IS_INTER)) {
// Intermediate folder, 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);
snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path);
if (!(dir = opendir(buf)))
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);
if (node->status & IS_SKEL)
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));
// Links will be handled later
if (child->parent->parent == NULL && strcmp(child->name, "vendor") == 0) {
if (IS_LNK(child)) {
cp_afc(MIRRDIR "/system/vendor", "/system/vendor");
LOGI("cplink: %s -> %s\n", MIRRDIR "/system/vendor", "/system/vendor");
}
// Skip
continue;
} else 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 | IS_INTER)) {
// It's a intermediate folder, recursive clone
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)) {
// Copy symlinks directly
cp_afc(buf2, buf);
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 (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);
} else if (node->status & IS_INTER) {
// It's an intermediate node, travel deeper
vec_for_each(node->children, child)
magic_mount(child);
}
// The only thing goes here should be vendor placeholder
// There should be no dummies, so don't need to handle it here
}
/****************
* 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", CACHEMOUNT, buf2);
// Clone all attributes
clone_attr(buf2, buf);
// Finally, mount the file
bind_mount(buf, buf2);
}
}
closedir(dir);
}
/*****************
* Miscellaneous *
*****************/
static void mount_mirrors() {
LOGI("* Mounting mirrors");
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);
xmkdir_p(MIRRDIR "/system", 0755);
xmount(buf, MIRRDIR "/system", "ext4", MS_RDONLY, NULL);
LOGI("mount: %s -> %s\n", buf, MIRRDIR "/system");
continue;
}
if (strstr(line, " /vendor ")) {
seperate_vendor = 1;
sscanf(line, "%s", buf);
xmkdir_p(MIRRDIR "/vendor", 0755);
xmount(buf, MIRRDIR "/vendor", "ext4", MS_RDONLY, NULL);
LOGI("mount: %s -> %s\n", buf, MIRRDIR "/vendor");
continue;
}
}
vec_deep_destroy(&mounts);
if (!seperate_vendor) {
symlink(MIRRDIR "/system/vendor", MIRRDIR "/vendor");
LOGI("link: %s -> %s\n", MIRRDIR "/system/vendor", MIRRDIR "/vendor");
}
mkdir_p(MIRRDIR "/bin", 0755);
bind_mount(DATABIN, MIRRDIR "/bin");
}
static void link_busybox() {
mkdir_p(BBPATH, 0755);
exec_command_sync(MIRRDIR "/bin/busybox", "--install", "-s", BBPATH, NULL);
symlink(MIRRDIR "/bin/busybox", BBPATH "/busybox");
}
static int prepare_img() {
int new_img = 0;
if (access(MAINIMG, F_OK) == -1) {
if (create_img(MAINIMG, 64))
return 1;
new_img = 1;
}
LOGI("* Mounting " MAINIMG "\n");
// Mounting magisk image
char *magiskloop = mount_image(MAINIMG, MOUNTPOINT);
if (magiskloop == NULL)
return 1;
vec_init(&module_list);
if (new_img) {
xmkdir(COREDIR, 0755);
xmkdir(COREDIR "/post-fs-data.d", 0755);
xmkdir(COREDIR "/service.d", 0755);
xmkdir(COREDIR "/props", 0755);
} else {
DIR *dir = xopendir(MOUNTPOINT);
struct dirent *entry;
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/remove", MOUNTPOINT, entry->d_name);
if (access(buf, F_OK) == 0) {
snprintf(buf, PATH_MAX, "%s/%s", MOUNTPOINT, entry->d_name);
exec_command_sync(BBPATH "/rm", "-rf", buf, NULL);
continue;
}
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, entry->d_name);
if (access(buf, F_OK) == 0)
continue;
vec_push_back(&module_list, strdup(entry->d_name));
}
}
closedir(dir);
// Trim image
umount_image(MOUNTPOINT, magiskloop);
free(magiskloop);
trim_img(MAINIMG);
// Remount them back :)
magiskloop = mount_image(MAINIMG, MOUNTPOINT);
free(magiskloop);
}
return 0;
}
/****************
* 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 MAGISK_DEBUG
// Start debug logs in new process
debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", "-v", "brief", NULL);
close(debug_log_fd);
#endif
LOGI("** post-fs-data mode running\n");
// Allocate buffer
if (buf == NULL) buf = xmalloc(PATH_MAX);
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
// Magisk binaries
char *bin_path = NULL;
if (access("/cache/data_bin", F_OK) == 0)
bin_path = "/cache/data_bin";
else if (access("/data/data/com.topjohnwu.magisk/install", F_OK) == 0)
bin_path = "/data/data/com.topjohnwu.magisk/install";
if (bin_path) {
exec_command_sync("rm", "-rf", DATABIN, NULL);
exec_command_sync("cp", "-r", bin_path, DATABIN, NULL);
exec_command_sync("rm", "-rf", bin_path, NULL);
exec_command_sync("chmod", "-R", "755", bin_path, NULL);
// Lazy.... use shell blob to match files
exec_command_sync("sh", "-c", "mv /data/magisk/stock_boot* /data", NULL);
}
// Link busybox
mount_mirrors();
link_busybox();
// Merge images
if (merge_img("/cache/magisk.img", MAINIMG)) {
LOGE("Image merge %s -> %s failed!\n", "/cache/magisk.img", MAINIMG);
goto unblock;
}
if (merge_img("/data/magisk_merge.img", MAINIMG)) {
LOGE("Image merge %s -> %s failed!\n", "/data/magisk_merge.img", MAINIMG);
goto unblock;
}
// uninstaller
if (access(UNINSTALLER, F_OK) == 0) {
close(open(UNBLOCKFILE, O_RDONLY | O_CREAT));
setenv("BOOTMODE", "true", 1);
exec_command(0, NULL, bb_setenv, "sh", UNINSTALLER, NULL);
return;
}
// Trim, mount magisk.img, which will also travel through the modules
// After this, it will create the module list
if (prepare_img())
goto core_only; // Mounting fails, we can only do core only stuffs
// 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 core_only;
// Execute module scripts
LOGI("* Running module post-fs-data scripts\n");
exec_module_script("post-fs-data");
char *module;
struct node_entry *sys_root, *ven_root = NULL, *child;
// Create the system root entry
sys_root = xcalloc(sizeof(*sys_root), 1);
sys_root->name = strdup("system");
sys_root->status = IS_INTER;
int has_modules = 0;
LOGI("* Loading modules\n");
vec_for_each(&module_list, module) {
// Read props
snprintf(buf, PATH_MAX, "%s/%s/system.prop", MOUNTPOINT, module);
if (access(buf, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module);
read_prop_file(buf, 0);
}
// Check whether enable auto_mount
snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MOUNTPOINT, module);
if (access(buf, F_OK) == -1)
continue;
// Double check whether the system folder exists
snprintf(buf, PATH_MAX, "%s/%s/system", MOUNTPOINT, module);
if (access(buf, F_OK) == -1)
continue;
// Construct structure
has_modules = 1;
LOGI("%s: constructing magic mount structure\n", module);
// If /system/vendor exists in module, create a link outside
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, module);
if (access(buf, F_OK) == 0) {
snprintf(buf2, PATH_MAX, "%s/%s/vendor", MOUNTPOINT, module);
unlink(buf2);
symlink(buf, buf2);
}
construct_tree(module, sys_root);
}
if (has_modules) {
// Extract the vendor node out of system tree and swap with placeholder
vec_for_each(sys_root->children, child) {
if (strcmp(child->name, "vendor") == 0) {
ven_root = child;
child = xcalloc(sizeof(*child), 1);
child->type = seperate_vendor ? DT_LNK : DT_DIR;
child->parent = ven_root->parent;
child->name = strdup("vendor");
child->status = 0;
// Swap!
vec_entry(sys_root->children)[_] = child;
ven_root->parent = NULL;
break;
}
}
// Magic!!
magic_mount(sys_root);
if (ven_root) magic_mount(ven_root);
}
// Cleanup memory
destroy_subtree(sys_root);
if (ven_root) destroy_subtree(ven_root);
core_only:
// Systemless hosts
if (access(HOSTSFILE, F_OK) == 0) {
LOGI("* Enabling systemless hosts file support");
bind_mount(HOSTSFILE, "/system/etc/hosts");
}
// Enable magiskhide by default, only disable when set explicitly
char *hide_prop = getprop(MAGISKHIDE_PROP);
if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) {
pthread_t thread;
xpthread_create(&thread, NULL, start_magisk_hide, NULL);
pthread_detach(thread);
}
free(hide_prop);
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");
// Core only mode
if (access(DISABLEFILE, F_OK) == 0)
goto core_only;
LOGI("* Running module service scripts\n");
exec_module_script("service");
core_only:
// Install Magisk Manager if exists
if (access(MANAGERAPK, F_OK) == 0) {
while (1) {
sleep(5);
int apk_res = -1, pid;
pid = exec_command(1, &apk_res, pm_setenv,
"app_process",
"/system/bin", "com.android.commands.pm.Pm",
"install", "-r", MANAGERAPK, NULL);
if (pid != -1) {
waitpid(pid, NULL, 0);
fdgets(buf, PATH_MAX, apk_res);
close(apk_res);
// Keep trying until pm is started
if (strstr(buf, "Error:") == NULL)
break;
}
}
unlink(MANAGERAPK);
}
// All boot stage done, cleanup everything
free(buf);
free(buf2);
buf = buf2 = NULL;
vec_deep_destroy(&module_list);
#ifdef MAGISK_DEBUG
// Stop recording the boot logcat after every boot task is done
kill(debug_log_pid, SIGTERM);
waitpid(debug_log_pid, NULL, 0);
#endif
}

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

@@ -0,0 +1,204 @@
/* 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;
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 LS_HIDELIST:
case POST_FS:
case POST_FS_DATA:
case LATE_START:
if (credentials.uid != 0) {
write_int(client, ROOT_REQUIRED);
close(client);
return NULL;
}
default:
break;
}
switch (req) {
case LAUNCH_MAGISKHIDE:
launch_magiskhide(client);
break;
case STOP_MAGISKHIDE:
stop_magiskhide(client);
break;
case ADD_HIDELIST:
add_hide_list(client);
break;
case RM_HIDELIST:
rm_hide_list(client);
break;
case LS_HIDELIST:
ls_hide_list(client);
break;
case SUPERUSER:
su_daemon_receiver(client);
break;
case CHECK_VERSION:
write_string(client, MAGISK_VER_STR);
close(client);
break;
case CHECK_VERSION_CODE:
write_int(client, MAGISK_VER_CODE);
close(client);
break;
case POST_FS:
post_fs(client);
break;
case POST_FS_DATA:
post_fs_data(client);
break;
case LATE_START:
late_start(client);
break;
default:
break;
}
return NULL;
}
/* Setup the address and return socket fd */
static int setup_socket(struct sockaddr_un *sun) {
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_LOCAL;
memcpy(sun->sun_path, REQUESTOR_DAEMON_PATH, sizeof(REQUESTOR_DAEMON_PATH) - 1);
return fd;
}
static void *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);
int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
xdup2(fd, STDIN_FILENO);
xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO);
close(fd);
// 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;
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) "(" xstr(MAGISK_VER_CODE) ") 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);
xmkdir("/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 = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC);
pthread_t thread;
xpthread_create(&thread, NULL, request_handler, client);
// Detach the thread, we will never join it
pthread_detach(thread);
}
}
/* Connect the daemon, and return a socketfd */
int connect_daemon() {
struct sockaddr_un sun;
int fd = setup_socket(&sun);
if (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;
}

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

@@ -0,0 +1,45 @@
/* 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
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-s", "Magisk", "-v", "thread", NULL);
if (log_pid > 0)
waitpid(log_pid, NULL, 0);
// For some reason it went here, clear buffer and restart
exec_command_sync("logcat", "-c", NULL);
}
// Should never be here, but well...
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);
}

164
jni/daemon/magisk.c Normal file
View File

@@ -0,0 +1,164 @@
/* 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) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) multi-call binary\n"
"\n"
"Usage: %s [applet [arguments]...]\n"
" or: %s --install [SOURCE] DIR\n"
" if SOURCE not provided, will link itself\n"
" or: %s --list\n"
" or: %s --createimg IMG SIZE\n"
" create ext4 image, SIZE is interpreted in MB\n"
" or: %s --imgsize IMG\n"
" or: %s --resizeimg IMG SIZE\n"
" SIZE is interpreted in MB\n"
" or: %s --mountimg IMG PATH\n"
" mount IMG to PATH and prints the loop device\n"
" or: %s --umountimg PATH LOOP\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, 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("%d %d\n", used, total);
return 0;
} else if (strcmp(argv[1], "--resizeimg") == 0) {
if (argc < 4) usage();
int used, total, size;
sscanf(argv[3], "%d", &size);
if (get_img_size(argv[2], &used, &total)) {
fprintf(stderr, "Cannot check %s size\n", argv[2]);
return 1;
}
if (size <= used) {
fprintf(stderr, "Cannot resize smaller than %dM\n", used);
return 1;
}
return resize_img(argv[2], size);
} else if (strcmp(argv[1], "--mountimg") == 0) {
if (argc < 4) usage();
char *loop = mount_image(argv[2], argv[3]);
if (loop == NULL) {
fprintf(stderr, "Cannot mount image!\n");
return 1;
} else {
printf("%s\n", loop);
free(loop);
return 0;
}
} else if (strcmp(argv[1], "--umountimg") == 0) {
if (argc < 4) usage();
umount_image(argv[2], argv[3]);
return 0;
} else if (strcmp(argv[1], "--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;
}

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);
}

13
jni/external/Android.mk vendored Normal file
View File

@@ -0,0 +1,13 @@
LOCAL_PATH:= $(call my-dir)
# libsqlite.so (stub)
include $(CLEAR_VARS)
LOCAL_MODULE:= libsqlite
LOCAL_SRC_FILES := sqlite3_stub.c
include $(BUILD_SHARED_LIBRARY)
# libselinux.so (stub)
include $(CLEAR_VARS)
LOCAL_MODULE:= libselinux
LOCAL_SRC_FILES := selinux_stub.c
include $(BUILD_SHARED_LIBRARY)

1029
jni/external/selinux/av_permissions.h vendored Normal file

File diff suppressed because it is too large Load Diff

511
jni/external/selinux/avc.h vendored Normal file
View File

@@ -0,0 +1,511 @@
/*
* Access vector cache interface for object managers.
*
* Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
*/
#ifndef _SELINUX_AVC_H_
#define _SELINUX_AVC_H_
#include <stdint.h>
#include <errno.h>
#include <stdlib.h>
#include <selinux/selinux.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* SID format and operations
*/
struct security_id {
char * ctx;
unsigned int refcnt;
};
typedef struct security_id *security_id_t;
#define SECSID_WILD (security_id_t)NULL /* unspecified SID */
/**
* avc_sid_to_context - get copy of context corresponding to SID.
* @sid: input SID
* @ctx: pointer to context reference
*
* Return a copy of the security context corresponding to the input
* @sid in the memory referenced by @ctx. The caller is expected to
* free the context with freecon(). Return %0 on success, -%1 on
* failure, with @errno set to %ENOMEM if insufficient memory was
* available to make the copy, or %EINVAL if the input SID is invalid.
*/
int avc_sid_to_context(security_id_t sid, char ** ctx);
int avc_sid_to_context_raw(security_id_t sid, char ** ctx);
/**
* avc_context_to_sid - get SID for context.
* @ctx: input security context
* @sid: pointer to SID reference
*
* Look up security context @ctx in SID table, making
* a new entry if @ctx is not found. Increment the
* reference counter for the SID. Store a pointer
* to the SID structure into the memory referenced by @sid,
* returning %0 on success or -%1 on error with @errno set.
*/
int avc_context_to_sid(const char * ctx, security_id_t * sid);
int avc_context_to_sid_raw(const char * ctx, security_id_t * sid);
/**
* sidget - increment SID reference counter.
* @sid: SID reference
*
* Increment the reference counter for @sid, indicating that
* @sid is in use by an (additional) object. Return the
* new reference count, or zero if @sid is invalid (has zero
* reference count). Note that avc_context_to_sid() also
* increments reference counts.
*/
int sidget(security_id_t sid);
/**
* sidput - decrement SID reference counter.
* @sid: SID reference
*
* Decrement the reference counter for @sid, indicating that
* a reference to @sid is no longer in use. Return the
* new reference count. When the reference count reaches
* zero, the SID is invalid, and avc_context_to_sid() must
* be called to obtain a new SID for the security context.
*/
int sidput(security_id_t sid);
/**
* avc_get_initial_sid - get SID for an initial kernel security identifier
* @name: input name of initial kernel security identifier
* @sid: pointer to a SID reference
*
* Get the context for an initial kernel security identifier specified by
* @name using security_get_initial_context() and then call
* avc_context_to_sid() to get the corresponding SID.
*/
int avc_get_initial_sid(const char *name, security_id_t * sid);
/*
* AVC entry
*/
struct avc_entry;
struct avc_entry_ref {
struct avc_entry *ae;
};
/**
* avc_entry_ref_init - initialize an AVC entry reference.
* @aeref: pointer to avc entry reference structure
*
* Use this macro to initialize an avc entry reference structure
* before first use. These structures are passed to avc_has_perm(),
* which stores cache entry references in them. They can increase
* performance on repeated queries.
*/
#define avc_entry_ref_init(aeref) ((aeref)->ae = NULL)
/*
* User-provided callbacks for memory, auditing, and locking
*/
/* These structures are passed by reference to avc_init(). Passing
* a NULL reference will cause the AVC to use a default. The default
* memory callbacks are malloc() and free(). The default logging method
* is to print on stderr. If no thread callbacks are passed, a separate
* listening thread won't be started for kernel policy change messages.
* If no locking callbacks are passed, no locking will take place.
*/
struct avc_memory_callback {
/* malloc() equivalent. */
void *(*func_malloc) (size_t size);
/* free() equivalent. */
void (*func_free) (void *ptr);
/* Note that these functions should set errno on failure.
If not, some avc routines may return -1 without errno set. */
};
struct avc_log_callback {
/* log the printf-style format and arguments. */
void
#ifdef __GNUC__
__attribute__ ((format(printf, 1, 2)))
#endif
(*func_log) (const char *fmt, ...);
/* store a string representation of auditdata (corresponding
to the given security class) into msgbuf. */
void (*func_audit) (void *auditdata, security_class_t cls,
char *msgbuf, size_t msgbufsize);
};
struct avc_thread_callback {
/* create and start a thread, returning an opaque pointer to it;
the thread should run the given function. */
void *(*func_create_thread) (void (*run) (void));
/* cancel a given thread and free its resources. */
void (*func_stop_thread) (void *thread);
};
struct avc_lock_callback {
/* create a lock and return an opaque pointer to it. */
void *(*func_alloc_lock) (void);
/* obtain a given lock, blocking if necessary. */
void (*func_get_lock) (void *lock);
/* release a given lock. */
void (*func_release_lock) (void *lock);
/* destroy a given lock (free memory, etc.) */
void (*func_free_lock) (void *lock);
};
/*
* Available options
*/
/* no-op option, useful for unused slots in an array of options */
#define AVC_OPT_UNUSED 0
/* override kernel enforcing mode (boolean value) */
#define AVC_OPT_SETENFORCE 1
/*
* AVC operations
*/
/**
* avc_init - Initialize the AVC.
* @msgprefix: prefix for log messages
* @mem_callbacks: user-supplied memory callbacks
* @log_callbacks: user-supplied logging callbacks
* @thread_callbacks: user-supplied threading callbacks
* @lock_callbacks: user-supplied locking callbacks
*
* Initialize the access vector cache. Return %0 on
* success or -%1 with @errno set on failure.
* If @msgprefix is NULL, use "uavc". If any callback
* structure references are NULL, use default methods
* for those callbacks (see the definition of the callback
* structures above).
*/
int avc_init(const char *msgprefix,
const struct avc_memory_callback *mem_callbacks,
const struct avc_log_callback *log_callbacks,
const struct avc_thread_callback *thread_callbacks,
const struct avc_lock_callback *lock_callbacks);
/**
* avc_open - Initialize the AVC.
* @opts: array of selabel_opt structures specifying AVC options or NULL.
* @nopts: number of elements in opts array or zero for no options.
*
* This function is identical to avc_init(), except the message prefix
* is set to "avc" and any callbacks desired should be specified via
* selinux_set_callback(). Available options are listed above.
*/
int avc_open(struct selinux_opt *opts, unsigned nopts);
/**
* avc_cleanup - Remove unused SIDs and AVC entries.
*
* Search the SID table for SID structures with zero
* reference counts, and remove them along with all
* AVC entries that reference them. This can be used
* to return memory to the system.
*/
void avc_cleanup(void);
/**
* avc_reset - Flush the cache and reset statistics.
*
* Remove all entries from the cache and reset all access
* statistics (as returned by avc_cache_stats()) to zero.
* The SID mapping is not affected. Return %0 on success,
* -%1 with @errno set on error.
*/
int avc_reset(void);
/**
* avc_destroy - Free all AVC structures.
*
* Destroy all AVC structures and free all allocated
* memory. User-supplied locking, memory, and audit
* callbacks will be retained, but security-event
* callbacks will not. All SID's will be invalidated.
* User must call avc_init() if further use of AVC is desired.
*/
void avc_destroy(void);
/**
* avc_has_perm_noaudit - Check permissions but perform no auditing.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
* @aeref: AVC entry reference
* @avd: access vector decisions
*
* Check the AVC to determine whether the @requested permissions are granted
* for the SID pair (@ssid, @tsid), interpreting the permissions
* based on @tclass, and call the security server on a cache miss to obtain
* a new decision and add it to the cache. Update @aeref to refer to an AVC
* entry with the resulting decisions, and return a copy of the decisions
* in @avd. Return %0 if all @requested permissions are granted, -%1 with
* @errno set to %EACCES if any permissions are denied, or to another value
* upon other errors. This function is typically called by avc_has_perm(),
* but may also be called directly to separate permission checking from
* auditing, e.g. in cases where a lock must be held for the check but
* should be released for the auditing.
*/
int avc_has_perm_noaudit(security_id_t ssid,
security_id_t tsid,
security_class_t tclass,
access_vector_t requested,
struct avc_entry_ref *aeref, struct av_decision *avd);
/**
* avc_has_perm - Check permissions and perform any appropriate auditing.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
* @aeref: AVC entry reference
* @auditdata: auxiliary audit data
*
* Check the AVC to determine whether the @requested permissions are granted
* for the SID pair (@ssid, @tsid), interpreting the permissions
* based on @tclass, and call the security server on a cache miss to obtain
* a new decision and add it to the cache. Update @aeref to refer to an AVC
* entry with the resulting decisions. Audit the granting or denial of
* permissions in accordance with the policy. Return %0 if all @requested
* permissions are granted, -%1 with @errno set to %EACCES if any permissions
* are denied or to another value upon other errors.
*/
int avc_has_perm(security_id_t ssid, security_id_t tsid,
security_class_t tclass, access_vector_t requested,
struct avc_entry_ref *aeref, void *auditdata);
/**
* avc_audit - Audit the granting or denial of permissions.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions
* @avd: access vector decisions
* @result: result from avc_has_perm_noaudit
* @auditdata: auxiliary audit data
*
* Audit the granting or denial of permissions in accordance
* with the policy. This function is typically called by
* avc_has_perm() after a permission check, but can also be
* called directly by callers who use avc_has_perm_noaudit()
* in order to separate the permission check from the auditing.
* For example, this separation is useful when the permission check must
* be performed under a lock, to allow the lock to be released
* before calling the auditing code.
*/
void avc_audit(security_id_t ssid, security_id_t tsid,
security_class_t tclass, access_vector_t requested,
struct av_decision *avd, int result, void *auditdata);
/**
* avc_compute_create - Compute SID for labeling a new object.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @newsid: pointer to SID reference
*
* Call the security server to obtain a context for labeling a
* new object. Look up the context in the SID table, making
* a new entry if not found. Increment the reference counter
* for the SID. Store a pointer to the SID structure into the
* memory referenced by @newsid, returning %0 on success or -%1 on
* error with @errno set.
*/
int avc_compute_create(security_id_t ssid,
security_id_t tsid,
security_class_t tclass, security_id_t * newsid);
/**
* avc_compute_member - Compute SID for polyinstantation.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @newsid: pointer to SID reference
*
* Call the security server to obtain a context for labeling an
* object instance. Look up the context in the SID table, making
* a new entry if not found. Increment the reference counter
* for the SID. Store a pointer to the SID structure into the
* memory referenced by @newsid, returning %0 on success or -%1 on
* error with @errno set.
*/
int avc_compute_member(security_id_t ssid,
security_id_t tsid,
security_class_t tclass, security_id_t * newsid);
/*
* security event callback facility
*/
/* security events */
#define AVC_CALLBACK_GRANT 1
#define AVC_CALLBACK_TRY_REVOKE 2
#define AVC_CALLBACK_REVOKE 4
#define AVC_CALLBACK_RESET 8
#define AVC_CALLBACK_AUDITALLOW_ENABLE 16
#define AVC_CALLBACK_AUDITALLOW_DISABLE 32
#define AVC_CALLBACK_AUDITDENY_ENABLE 64
#define AVC_CALLBACK_AUDITDENY_DISABLE 128
/**
* avc_add_callback - Register a callback for security events.
* @callback: callback function
* @events: bitwise OR of desired security events
* @ssid: source security identifier or %SECSID_WILD
* @tsid: target security identifier or %SECSID_WILD
* @tclass: target security class
* @perms: permissions
*
* Register a callback function for events in the set @events
* related to the SID pair (@ssid, @tsid) and
* and the permissions @perms, interpreting
* @perms based on @tclass. Returns %0 on success or
* -%1 if insufficient memory exists to add the callback.
*/
int avc_add_callback(int (*callback)
(uint32_t event, security_id_t ssid,
security_id_t tsid, security_class_t tclass,
access_vector_t perms,
access_vector_t * out_retained),
uint32_t events, security_id_t ssid,
security_id_t tsid, security_class_t tclass,
access_vector_t perms);
/*
* AVC statistics
*/
/* If set, cache statistics are tracked. This may
* become a compile-time option in the future.
*/
#define AVC_CACHE_STATS 1
struct avc_cache_stats {
unsigned entry_lookups;
unsigned entry_hits;
unsigned entry_misses;
unsigned entry_discards;
unsigned cav_lookups;
unsigned cav_hits;
unsigned cav_probes;
unsigned cav_misses;
};
/**
* avc_cache_stats - get cache access statistics.
* @stats: reference to statistics structure
*
* Fill the supplied structure with information about AVC
* activity since the last call to avc_init() or
* avc_reset(). See the structure definition for
* details.
*/
void avc_cache_stats(struct avc_cache_stats *stats);
/**
* avc_av_stats - log av table statistics.
*
* Log a message with information about the size and
* distribution of the access vector table. The audit
* callback is used to print the message.
*/
void avc_av_stats(void);
/**
* avc_sid_stats - log SID table statistics.
*
* Log a message with information about the size and
* distribution of the SID table. The audit callback
* is used to print the message.
*/
void avc_sid_stats(void);
/**
* avc_netlink_open - Create a netlink socket and connect to the kernel.
*/
int avc_netlink_open(int blocking);
/**
* avc_netlink_loop - Wait for netlink messages from the kernel
*/
void avc_netlink_loop(void);
/**
* avc_netlink_close - Close the netlink socket
*/
void avc_netlink_close(void);
/**
* avc_netlink_acquire_fd - Acquire netlink socket fd.
*
* Allows the application to manage messages from the netlink socket in
* its own main loop.
*/
int avc_netlink_acquire_fd(void);
/**
* avc_netlink_release_fd - Release netlink socket fd.
*
* Returns ownership of the netlink socket to the library.
*/
void avc_netlink_release_fd(void);
/**
* avc_netlink_check_nb - Check netlink socket for new messages.
*
* Called by the application when using avc_netlink_acquire_fd() to
* process kernel netlink events.
*/
int avc_netlink_check_nb(void);
/**
* selinux_status_open - Open and map SELinux kernel status page
*
*/
int selinux_status_open(int fallback);
/**
* selinux_status_close - Unmap and close SELinux kernel status page
*
*/
void selinux_status_close(void);
/**
* selinux_status_updated - Inform us whether the kernel status has been updated
*
*/
int selinux_status_updated(void);
/**
* selinux_status_getenforce - Get the enforce flag value
*
*/
int selinux_status_getenforce(void);
/**
* selinux_status_policyload - Get the number of policy reloaded
*
*/
int selinux_status_policyload(void);
/**
* selinux_status_deny_unknown - Get the behavior for undefined classes/permissions
*
*/
int selinux_status_deny_unknown(void);
#ifdef __cplusplus
}
#endif
#endif /* _SELINUX_AVC_H_ */

50
jni/external/selinux/context.h vendored Normal file
View File

@@ -0,0 +1,50 @@
#ifndef _SELINUX_CONTEXT_H_
#define _SELINUX_CONTEXT_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Functions to deal with security contexts in user space.
*/
typedef struct {
void *ptr;
} context_s_t;
typedef context_s_t *context_t;
/* Return a new context initialized to a context string */
extern context_t context_new(const char *);
/*
* Return a pointer to the string value of the context_t
* Valid until the next call to context_str or context_free
* for the same context_t*
*/
extern char *context_str(context_t);
/* Free the storage used by a context */
extern void context_free(context_t);
/* Get a pointer to the string value of a context component */
extern const char *context_type_get(context_t);
extern const char *context_range_get(context_t);
extern const char *context_role_get(context_t);
extern const char *context_user_get(context_t);
/* Set a context component. Returns nonzero if unsuccessful */
extern int context_type_set(context_t, const char *);
extern int context_range_set(context_t, const char *);
extern int context_role_set(context_t, const char *);
extern int context_user_set(context_t, const char *);
#ifdef __cplusplus
}
#endif
#endif

118
jni/external/selinux/flask.h vendored Normal file
View File

@@ -0,0 +1,118 @@
/* This file is automatically generated. Do not edit. */
#ifndef _SELINUX_FLASK_H_
#define _SELINUX_FLASK_H_
#warning "Please remove any #include's of this header in your source code."
#warning "Instead, use string_to_security_class() to map the class name to a value."
/*
* Security object class definitions
*/
#define SECCLASS_SECURITY 1
#define SECCLASS_PROCESS 2
#define SECCLASS_SYSTEM 3
#define SECCLASS_CAPABILITY 4
#define SECCLASS_FILESYSTEM 5
#define SECCLASS_FILE 6
#define SECCLASS_DIR 7
#define SECCLASS_FD 8
#define SECCLASS_LNK_FILE 9
#define SECCLASS_CHR_FILE 10
#define SECCLASS_BLK_FILE 11
#define SECCLASS_SOCK_FILE 12
#define SECCLASS_FIFO_FILE 13
#define SECCLASS_SOCKET 14
#define SECCLASS_TCP_SOCKET 15
#define SECCLASS_UDP_SOCKET 16
#define SECCLASS_RAWIP_SOCKET 17
#define SECCLASS_NODE 18
#define SECCLASS_NETIF 19
#define SECCLASS_NETLINK_SOCKET 20
#define SECCLASS_PACKET_SOCKET 21
#define SECCLASS_KEY_SOCKET 22
#define SECCLASS_UNIX_STREAM_SOCKET 23
#define SECCLASS_UNIX_DGRAM_SOCKET 24
#define SECCLASS_SEM 25
#define SECCLASS_MSG 26
#define SECCLASS_MSGQ 27
#define SECCLASS_SHM 28
#define SECCLASS_IPC 29
#define SECCLASS_PASSWD 30
#define SECCLASS_X_DRAWABLE 31
#define SECCLASS_X_SCREEN 32
#define SECCLASS_X_GC 33
#define SECCLASS_X_FONT 34
#define SECCLASS_X_COLORMAP 35
#define SECCLASS_X_PROPERTY 36
#define SECCLASS_X_SELECTION 37
#define SECCLASS_X_CURSOR 38
#define SECCLASS_X_CLIENT 39
#define SECCLASS_X_DEVICE 40
#define SECCLASS_X_SERVER 41
#define SECCLASS_X_EXTENSION 42
#define SECCLASS_NETLINK_ROUTE_SOCKET 43
#define SECCLASS_NETLINK_FIREWALL_SOCKET 44
#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45
#define SECCLASS_NETLINK_NFLOG_SOCKET 46
#define SECCLASS_NETLINK_XFRM_SOCKET 47
#define SECCLASS_NETLINK_SELINUX_SOCKET 48
#define SECCLASS_NETLINK_AUDIT_SOCKET 49
#define SECCLASS_NETLINK_IP6FW_SOCKET 50
#define SECCLASS_NETLINK_DNRT_SOCKET 51
#define SECCLASS_DBUS 52
#define SECCLASS_NSCD 53
#define SECCLASS_ASSOCIATION 54
#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55
#define SECCLASS_APPLETALK_SOCKET 56
#define SECCLASS_PACKET 57
#define SECCLASS_KEY 58
#define SECCLASS_CONTEXT 59
#define SECCLASS_DCCP_SOCKET 60
#define SECCLASS_MEMPROTECT 61
#define SECCLASS_DB_DATABASE 62
#define SECCLASS_DB_TABLE 63
#define SECCLASS_DB_PROCEDURE 64
#define SECCLASS_DB_COLUMN 65
#define SECCLASS_DB_TUPLE 66
#define SECCLASS_DB_BLOB 67
#define SECCLASS_PEER 68
#define SECCLASS_CAPABILITY2 69
#define SECCLASS_X_RESOURCE 70
#define SECCLASS_X_EVENT 71
#define SECCLASS_X_SYNTHETIC_EVENT 72
#define SECCLASS_X_APPLICATION_DATA 73
/*
* Security identifier indices for initial entities
*/
#define SECINITSID_KERNEL 1
#define SECINITSID_SECURITY 2
#define SECINITSID_UNLABELED 3
#define SECINITSID_FS 4
#define SECINITSID_FILE 5
#define SECINITSID_FILE_LABELS 6
#define SECINITSID_INIT 7
#define SECINITSID_ANY_SOCKET 8
#define SECINITSID_PORT 9
#define SECINITSID_NETIF 10
#define SECINITSID_NETMSG 11
#define SECINITSID_NODE 12
#define SECINITSID_IGMP_PACKET 13
#define SECINITSID_ICMP_SOCKET 14
#define SECINITSID_TCP_SOCKET 15
#define SECINITSID_SYSCTL_MODPROBE 16
#define SECINITSID_SYSCTL 17
#define SECINITSID_SYSCTL_FS 18
#define SECINITSID_SYSCTL_KERNEL 19
#define SECINITSID_SYSCTL_NET 20
#define SECINITSID_SYSCTL_NET_UNIX 21
#define SECINITSID_SYSCTL_VM 22
#define SECINITSID_SYSCTL_DEV 23
#define SECINITSID_KMOD 24
#define SECINITSID_POLICY 25
#define SECINITSID_SCMP_PACKET 26
#define SECINITSID_DEVNULL 27
#define SECINITSID_NUM 27
#endif

82
jni/external/selinux/get_context_list.h vendored Normal file
View File

@@ -0,0 +1,82 @@
#ifndef _SELINUX_GET_SID_LIST_H_
#define _SELINUX_GET_SID_LIST_H_
#include <selinux/selinux.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SELINUX_DEFAULTUSER "user_u"
/* Get an ordered list of authorized security contexts for a user session
for 'user' spawned by 'fromcon' and set *conary to refer to the
NULL-terminated array of contexts. Every entry in the list will
be authorized by the policy, but the ordering is subject to user
customizable preferences. Returns number of entries in *conary.
If 'fromcon' is NULL, defaults to current context.
Caller must free via freeconary. */
extern int get_ordered_context_list(const char *user,
char * fromcon,
char *** list);
/* As above, but use the provided MLS level rather than the
default level for the user. */
int get_ordered_context_list_with_level(const char *user,
const char *level,
char * fromcon,
char *** list);
/* Get the default security context for a user session for 'user'
spawned by 'fromcon' and set *newcon to refer to it. The context
will be one of those authorized by the policy, but the selection
of a default is subject to user customizable preferences.
If 'fromcon' is NULL, defaults to current context.
Returns 0 on success or -1 otherwise.
Caller must free via freecon. */
extern int get_default_context(const char *user,
char * fromcon,
char ** newcon);
/* As above, but use the provided MLS level rather than the
default level for the user. */
int get_default_context_with_level(const char *user,
const char *level,
char * fromcon,
char ** newcon);
/* Same as get_default_context, but only return a context
that has the specified role. If no reachable context exists
for the user with that role, then return -1. */
int get_default_context_with_role(const char *user,
const char *role,
char * fromcon,
char ** newcon);
/* Same as get_default_context, but only return a context
that has the specified role and level. If no reachable context exists
for the user with that role, then return -1. */
int get_default_context_with_rolelevel(const char *user,
const char *role,
const char *level,
char * fromcon,
char ** newcon);
/* Given a list of authorized security contexts for the user,
query the user to select one and set *newcon to refer to it.
Caller must free via freecon.
Returns 0 on sucess or -1 otherwise. */
extern int query_user_context(char ** list,
char ** newcon);
/* Allow the user to manually enter a context as a fallback
if a list of authorized contexts could not be obtained.
Caller must free via freecon.
Returns 0 on success or -1 otherwise. */
extern int manual_user_enter_context(const char *user,
char ** newcon);
#ifdef __cplusplus
}
#endif
#endif

23
jni/external/selinux/get_default_type.h vendored Normal file
View File

@@ -0,0 +1,23 @@
/* get_default_type.h - contains header information and function prototypes
* for functions to get the default type for a role
*/
#ifndef _SELINUX_GET_DEFAULT_TYPE_H_
#define _SELINUX_GET_DEFAULT_TYPE_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Return path to default type file. */
const char *selinux_default_type_path(void);
/* Get the default type (domain) for 'role' and set 'type' to refer to it.
Caller must free via free().
Return 0 on success or -1 otherwise. */
int get_default_type(const char *role, char **type);
#ifdef __cplusplus
}
#endif
#endif /* ifndef _GET_DEFAULT_TYPE_H_ */

190
jni/external/selinux/label.h vendored Normal file
View File

@@ -0,0 +1,190 @@
/*
* Labeling interface for userspace object managers and others.
*
* Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
*/
#ifndef _SELABEL_H_
#define _SELABEL_H_
#include <stdbool.h>
#include <sys/types.h>
#include <selinux/selinux.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Opaque type used for all label handles.
*/
struct selabel_handle;
/*
* Available backends.
*/
/* file contexts */
#define SELABEL_CTX_FILE 0
/* media contexts */
#define SELABEL_CTX_MEDIA 1
/* x contexts */
#define SELABEL_CTX_X 2
/* db objects */
#define SELABEL_CTX_DB 3
/* Android property service contexts */
#define SELABEL_CTX_ANDROID_PROP 4
/* Android service contexts */
#define SELABEL_CTX_ANDROID_SERVICE 5
/*
* Available options
*/
/* no-op option, useful for unused slots in an array of options */
#define SELABEL_OPT_UNUSED 0
/* validate contexts before returning them (boolean value) */
#define SELABEL_OPT_VALIDATE 1
/* don't use local customizations to backend data (boolean value) */
#define SELABEL_OPT_BASEONLY 2
/* specify an alternate path to use when loading backend data */
#define SELABEL_OPT_PATH 3
/* select a subset of the search space as an optimization (file backend) */
#define SELABEL_OPT_SUBSET 4
/* require a hash calculation on spec files */
#define SELABEL_OPT_DIGEST 5
/* total number of options */
#define SELABEL_NOPT 6
/*
* Label operations
*/
/**
* selabel_open - Create a labeling handle.
* @backend: one of the constants specifying a supported labeling backend.
* @opts: array of selabel_opt structures specifying label options or NULL.
* @nopts: number of elements in opts array or zero for no options.
*
* Open a labeling backend for use. The available backend identifiers are
* listed above. Options may be provided via the opts parameter; available
* options are listed above. Not all options may be supported by every
* backend. Return value is the created handle on success or NULL with
* @errno set on failure.
*/
struct selabel_handle *selabel_open(unsigned int backend,
const struct selinux_opt *opts,
unsigned nopts);
/**
* selabel_close - Close a labeling handle.
* @handle: specifies handle to close
*
* Destroy the specified handle, closing files, freeing allocated memory,
* etc. The handle may not be further used after it has been closed.
*/
void selabel_close(struct selabel_handle *handle);
/**
* selabel_lookup - Perform labeling lookup operation.
* @handle: specifies backend instance to query
* @con: returns the appropriate context with which to label the object
* @key: string input to lookup operation
* @type: numeric input to the lookup operation
*
* Perform a labeling lookup operation. Return %0 on success, -%1 with
* @errno set on failure. The key and type arguments are the inputs to the
* lookup operation; appropriate values are dictated by the backend in use.
* The result is returned in the memory pointed to by @con and must be freed
* by the user with freecon().
*/
int selabel_lookup(struct selabel_handle *handle, char **con,
const char *key, int type);
int selabel_lookup_raw(struct selabel_handle *handle, char **con,
const char *key, int type);
bool selabel_partial_match(struct selabel_handle *handle, const char *key);
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type);
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type);
/**
* selabel_digest - Retrieve the SHA1 digest and the list of specfiles used to
* generate the digest. The SELABEL_OPT_DIGEST option must
* be set in selabel_open() to initiate the digest generation.
* @handle: specifies backend instance to query
* @digest: returns a pointer to the SHA1 digest.
* @digest_len: returns length of digest in bytes.
* @specfiles: a list of specfiles used in the SHA1 digest generation.
* The list is NULL terminated and will hold @num_specfiles entries.
* @num_specfiles: number of specfiles in the list.
*
* Return %0 on success, -%1 with @errno set on failure.
*/
int selabel_digest(struct selabel_handle *rec,
unsigned char **digest, size_t *digest_len,
char ***specfiles, size_t *num_specfiles);
enum selabel_cmp_result {
SELABEL_SUBSET,
SELABEL_EQUAL,
SELABEL_SUPERSET,
SELABEL_INCOMPARABLE
};
/**
* selabel_cmp - Compare two label configurations.
* @h1: handle for the first label configuration
* @h2: handle for the first label configuration
*
* Compare two label configurations.
* Return %SELABEL_SUBSET if @h1 is a subset of @h2, %SELABEL_EQUAL
* if @h1 is identical to @h2, %SELABEL_SUPERSET if @h1 is a superset
* of @h2, and %SELABEL_INCOMPARABLE if @h1 and @h2 are incomparable.
*/
enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
struct selabel_handle *h2);
/**
* selabel_stats - log labeling operation statistics.
* @handle: specifies backend instance to query
*
* Log a message with information about the number of queries performed,
* number of unused matching entries, or other operational statistics.
* Message is backend-specific, some backends may not output a message.
*/
void selabel_stats(struct selabel_handle *handle);
/*
* Type codes used by specific backends
*/
/* X backend */
#define SELABEL_X_PROP 1
#define SELABEL_X_EXT 2
#define SELABEL_X_CLIENT 3
#define SELABEL_X_EVENT 4
#define SELABEL_X_SELN 5
#define SELABEL_X_POLYPROP 6
#define SELABEL_X_POLYSELN 7
/* DB backend */
#define SELABEL_DB_DATABASE 1
#define SELABEL_DB_SCHEMA 2
#define SELABEL_DB_TABLE 3
#define SELABEL_DB_COLUMN 4
#define SELABEL_DB_SEQUENCE 5
#define SELABEL_DB_VIEW 6
#define SELABEL_DB_PROCEDURE 7
#define SELABEL_DB_BLOB 8
#define SELABEL_DB_TUPLE 9
#define SELABEL_DB_LANGUAGE 10
#define SELABEL_DB_EXCEPTION 11
#define SELABEL_DB_DATATYPE 12
#ifdef __cplusplus
}
#endif
#endif /* _SELABEL_H_ */

187
jni/external/selinux/restorecon.h vendored Normal file
View File

@@ -0,0 +1,187 @@
#ifndef _RESTORECON_H_
#define _RESTORECON_H_
#include <sys/types.h>
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* selinux_restorecon - Relabel files.
* @pathname: specifies file/directory to relabel.
* @restorecon_flags: specifies the actions to be performed when relabeling.
*
* selinux_restorecon(3) will automatically call
* selinux_restorecon_default_handle(3) and selinux_restorecon_set_sehandle(3)
* first time through to set the selabel_open(3) parameters to use the
* currently loaded policy file_contexts and request their computed digest.
*
* Should other selabel_open(3) parameters be required see
* selinux_restorecon_set_sehandle(3).
*/
extern int selinux_restorecon(const char *pathname,
unsigned int restorecon_flags);
/*
* restorecon_flags options
*/
/*
* Force the checking of labels even if the stored SHA1
* digest matches the specfiles SHA1 digest.
*/
#define SELINUX_RESTORECON_IGNORE_DIGEST 0x0001
/*
* Do not change file labels.
*/
#define SELINUX_RESTORECON_NOCHANGE 0x0002
/*
* If set set change file label to that in spec file.
* If not only change type component to that in spec file.
*/
#define SELINUX_RESTORECON_SET_SPECFILE_CTX 0x0004
/*
* Recursively descend directories.
*/
#define SELINUX_RESTORECON_RECURSE 0x0008
/*
* Log changes to selinux log. Note that if VERBOSE and
* PROGRESS are set, then PROGRESS will take precedence.
*/
#define SELINUX_RESTORECON_VERBOSE 0x0010
/*
* If SELINUX_RESTORECON_PROGRESS is true and
* SELINUX_RESTORECON_MASS_RELABEL is true, then output approx % complete,
* else output the number of files in 1k blocks processed to stdout.
*/
#define SELINUX_RESTORECON_PROGRESS 0x0020
/*
* Convert passed-in pathname to canonical pathname.
*/
#define SELINUX_RESTORECON_REALPATH 0x0040
/*
* Prevent descending into directories that have a different
* device number than the pathname from which the descent began.
*/
#define SELINUX_RESTORECON_XDEV 0x0080
/*
* Attempt to add an association between an inode and a specification.
* If there is already an association for the inode and it conflicts
* with the specification, then use the last matching specification.
*/
#define SELINUX_RESTORECON_ADD_ASSOC 0x0100
/*
* Abort on errors during the file tree walk.
*/
#define SELINUX_RESTORECON_ABORT_ON_ERROR 0x0200
/*
* Log any label changes to syslog.
*/
#define SELINUX_RESTORECON_SYSLOG_CHANGES 0x0400
/*
* Log what spec matched each file.
*/
#define SELINUX_RESTORECON_LOG_MATCHES 0x0800
/*
* Ignore files that do not exist.
*/
#define SELINUX_RESTORECON_IGNORE_NOENTRY 0x1000
/*
* Do not read /proc/mounts to obtain a list of non-seclabel
* mounts to be excluded from relabeling checks.
*/
#define SELINUX_RESTORECON_IGNORE_MOUNTS 0x2000
/*
* Set if there is a mass relabel required.
* See SELINUX_RESTORECON_PROGRESS flag for details.
*/
#define SELINUX_RESTORECON_MASS_RELABEL 0x4000
/**
* selinux_restorecon_set_sehandle - Set the global fc handle.
* @hndl: specifies handle to set as the global fc handle.
*
* Called by a process that has already called selabel_open(3) with it's
* required parameters, or if selinux_restorecon_default_handle(3) has been
* called to set the default selabel_open(3) parameters.
*/
// extern void selinux_restorecon_set_sehandle(struct selabel_handle *hndl);
/**
* selinux_restorecon_default_handle - Sets default selabel_open(3) parameters
* to use the currently loaded policy and
* file_contexts, also requests the digest.
*
* Return value is the created handle on success or NULL with @errno set on
* failure.
*/
extern struct selabel_handle *selinux_restorecon_default_handle(void);
/**
* selinux_restorecon_set_exclude_list - Add a list of directories that are
* to be excluded from relabeling.
* @exclude_list: containing a NULL terminated list of one or more
* directories not to be relabeled.
*/
extern void selinux_restorecon_set_exclude_list(const char **exclude_list);
/**
* selinux_restorecon_set_alt_rootpath - Use alternate rootpath.
* @alt_rootpath: containing the alternate rootpath to be used.
*
* Return %0 on success, -%1 with @errno set on failure.
*/
extern int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath);
/**
* selinux_restorecon_xattr - Read/remove RESTORECON_LAST xattr entries.
* @pathname: specifies directory path to check.
* @xattr_flags: specifies the actions to be performed.
* @xattr_list: a linked list of struct dir_xattr structures containing
* the directory, digest and result of the action on the
* RESTORECON_LAST entry.
*
* selinux_restorecon_xattr(3) will automatically call
* selinux_restorecon_default_handle(3) and selinux_restorecon_set_sehandle(3)
* first time through to set the selabel_open(3) parameters to use the
* currently loaded policy file_contexts and request their computed digest.
*
* Should other selabel_open(3) parameters be required see
* selinux_restorecon_set_sehandle(3), however note that a file_contexts
* computed digest is required for selinux_restorecon_xattr().
*/
enum digest_result {
MATCH = 0,
NOMATCH,
DELETED_MATCH,
DELETED_NOMATCH,
ERROR
};
struct dir_xattr {
char *directory;
char *digest; /* A hex encoded string that can be printed. */
enum digest_result result;
struct dir_xattr *next;
};
extern int selinux_restorecon_xattr(const char *pathname,
unsigned int xattr_flags,
struct dir_xattr ***xattr_list);
/*
* xattr_flags options
*/
/* Recursively descend directories. */
#define SELINUX_RESTORECON_XATTR_RECURSE 0x0001
/* Delete non-matching digests from each directory in pathname. */
#define SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS 0x0002
/* Delete all digests found in pathname. */
#define SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS 0x0004
/* Do not read /proc/mounts. */
#define SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS 0x0008
#ifdef __cplusplus
}
#endif
#endif

673
jni/external/selinux/selinux.h vendored Normal file
View File

@@ -0,0 +1,673 @@
#ifndef _SELINUX_H_
#define _SELINUX_H_
#include <sys/types.h>
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Return 1 if we are running on a SELinux kernel, or 0 if not or -1 if we get an error. */
extern int is_selinux_enabled(void);
/* Return 1 if we are running on a SELinux MLS kernel, or 0 otherwise. */
extern int is_selinux_mls_enabled(void);
/* No longer used; here for compatibility with legacy callers. */
typedef char *security_context_t;
/* Free the memory allocated for a context by any of the below get* calls. */
extern void freecon(char * con);
/* Free the memory allocated for a context array by security_compute_user. */
extern void freeconary(char ** con);
/* Wrappers for the /proc/pid/attr API. */
/* Get current context, and set *con to refer to it.
Caller must free via freecon. */
extern int getcon(char ** con);
extern int getcon_raw(char ** con);
/* Set the current security context to con.
Note that use of this function requires that the entire application
be trusted to maintain any desired separation between the old and new
security contexts, unlike exec-based transitions performed via setexeccon.
When possible, decompose your application and use setexeccon()+execve()
instead. Note that the application may lose access to its open descriptors
as a result of a setcon() unless policy allows it to use descriptors opened
by the old context. */
extern int setcon(const char * con);
extern int setcon_raw(const char * con);
/* Get context of process identified by pid, and
set *con to refer to it. Caller must free via freecon. */
extern int getpidcon(pid_t pid, char ** con);
extern int getpidcon_raw(pid_t pid, char ** con);
/* Get previous context (prior to last exec), and set *con to refer to it.
Caller must free via freecon. */
extern int getprevcon(char ** con);
extern int getprevcon_raw(char ** con);
/* Get exec context, and set *con to refer to it.
Sets *con to NULL if no exec context has been set, i.e. using default.
If non-NULL, caller must free via freecon. */
extern int getexeccon(char ** con);
extern int getexeccon_raw(char ** con);
/* Set exec security context for the next execve.
Call with NULL if you want to reset to the default. */
extern int setexeccon(const char * con);
extern int setexeccon_raw(const char * con);
/* Get fscreate context, and set *con to refer to it.
Sets *con to NULL if no fs create context has been set, i.e. using default.
If non-NULL, caller must free via freecon. */
extern int getfscreatecon(char ** con);
extern int getfscreatecon_raw(char ** con);
/* Set the fscreate security context for subsequent file creations.
Call with NULL if you want to reset to the default. */
extern int setfscreatecon(const char * context);
extern int setfscreatecon_raw(const char * context);
/* Get keycreate context, and set *con to refer to it.
Sets *con to NULL if no key create context has been set, i.e. using default.
If non-NULL, caller must free via freecon. */
extern int getkeycreatecon(char ** con);
extern int getkeycreatecon_raw(char ** con);
/* Set the keycreate security context for subsequent key creations.
Call with NULL if you want to reset to the default. */
extern int setkeycreatecon(const char * context);
extern int setkeycreatecon_raw(const char * context);
/* Get sockcreate context, and set *con to refer to it.
Sets *con to NULL if no socket create context has been set, i.e. using default.
If non-NULL, caller must free via freecon. */
extern int getsockcreatecon(char ** con);
extern int getsockcreatecon_raw(char ** con);
/* Set the sockcreate security context for subsequent socket creations.
Call with NULL if you want to reset to the default. */
extern int setsockcreatecon(const char * context);
extern int setsockcreatecon_raw(const char * context);
/* Wrappers for the xattr API. */
/* Get file context, and set *con to refer to it.
Caller must free via freecon. */
extern int getfilecon(const char *path, char ** con);
extern int getfilecon_raw(const char *path, char ** con);
extern int lgetfilecon(const char *path, char ** con);
extern int lgetfilecon_raw(const char *path, char ** con);
extern int fgetfilecon(int fd, char ** con);
extern int fgetfilecon_raw(int fd, char ** con);
/* Set file context */
extern int setfilecon(const char *path, const char * con);
extern int setfilecon_raw(const char *path, const char * con);
extern int lsetfilecon(const char *path, const char * con);
extern int lsetfilecon_raw(const char *path, const char * con);
extern int fsetfilecon(int fd, const char * con);
extern int fsetfilecon_raw(int fd, const char * con);
/* Wrappers for the socket API */
/* Get context of peer socket, and set *con to refer to it.
Caller must free via freecon. */
extern int getpeercon(int fd, char ** con);
extern int getpeercon_raw(int fd, char ** con);
/* Wrappers for the selinuxfs (policy) API. */
typedef unsigned int access_vector_t;
typedef unsigned short security_class_t;
struct av_decision {
access_vector_t allowed;
access_vector_t decided;
access_vector_t auditallow;
access_vector_t auditdeny;
unsigned int seqno;
unsigned int flags;
};
/* Definitions of av_decision.flags */
#define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001
/* Structure for passing options, used by AVC and label subsystems */
struct selinux_opt {
int type;
const char *value;
};
/* Callback facilities */
union selinux_callback {
/* log the printf-style format and arguments,
with the type code indicating the type of message */
int
#ifdef __GNUC__
__attribute__ ((format(printf, 2, 3)))
#endif
(*func_log) (int type, const char *fmt, ...);
/* store a string representation of auditdata (corresponding
to the given security class) into msgbuf. */
int (*func_audit) (void *auditdata, security_class_t cls,
char *msgbuf, size_t msgbufsize);
/* validate the supplied context, modifying if necessary */
int (*func_validate) (char **ctx);
/* netlink callback for setenforce message */
int (*func_setenforce) (int enforcing);
/* netlink callback for policyload message */
int (*func_policyload) (int seqno);
};
#define SELINUX_CB_LOG 0
#define SELINUX_CB_AUDIT 1
#define SELINUX_CB_VALIDATE 2
#define SELINUX_CB_SETENFORCE 3
#define SELINUX_CB_POLICYLOAD 4
extern union selinux_callback selinux_get_callback(int type);
extern void selinux_set_callback(int type, union selinux_callback cb);
/* Logging type codes, passed to the logging callback */
#define SELINUX_ERROR 0
#define SELINUX_WARNING 1
#define SELINUX_INFO 2
#define SELINUX_AVC 3
#define SELINUX_TRANS_DIR "/var/run/setrans"
/* Compute an access decision. */
extern int security_compute_av(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd);
extern int security_compute_av_raw(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd);
extern int security_compute_av_flags(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd);
extern int security_compute_av_flags_raw(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd);
/* Compute a labeling decision and set *newcon to refer to it.
Caller must free via freecon. */
extern int security_compute_create(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon);
extern int security_compute_create_raw(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon);
extern int security_compute_create_name(const char * scon,
const char * tcon,
security_class_t tclass,
const char *objname,
char ** newcon);
extern int security_compute_create_name_raw(const char * scon,
const char * tcon,
security_class_t tclass,
const char *objname,
char ** newcon);
/* Compute a relabeling decision and set *newcon to refer to it.
Caller must free via freecon. */
extern int security_compute_relabel(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon);
extern int security_compute_relabel_raw(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon);
/* Compute a polyinstantiation member decision and set *newcon to refer to it.
Caller must free via freecon. */
extern int security_compute_member(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon);
extern int security_compute_member_raw(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon);
/* Compute the set of reachable user contexts and set *con to refer to
the NULL-terminated array of contexts. Caller must free via freeconary. */
extern int security_compute_user(const char * scon,
const char *username,
char *** con);
extern int security_compute_user_raw(const char * scon,
const char *username,
char *** con);
/* Load a policy configuration. */
extern int security_load_policy(void *data, size_t len);
/* Get the context of an initial kernel security identifier by name.
Caller must free via freecon */
extern int security_get_initial_context(const char *name,
char ** con);
extern int security_get_initial_context_raw(const char *name,
char ** con);
/*
* Make a policy image and load it.
* This function provides a higher level interface for loading policy
* than security_load_policy, internally determining the right policy
* version, locating and opening the policy file, mapping it into memory,
* manipulating it as needed for current boolean settings and/or local
* definitions, and then calling security_load_policy to load it.
*
* 'preservebools' is a boolean flag indicating whether current
* policy boolean values should be preserved into the new policy (if 1)
* or reset to the saved policy settings (if 0). The former case is the
* default for policy reloads, while the latter case is an option for policy
* reloads but is primarily for the initial policy load.
*/
extern int selinux_mkload_policy(int preservebools);
/*
* Perform the initial policy load.
* This function determines the desired enforcing mode, sets the
* the *enforce argument accordingly for the caller to use, sets the
* SELinux kernel enforcing status to match it, and loads the policy.
* It also internally handles the initial selinuxfs mount required to
* perform these actions.
*
* The function returns 0 if everything including the policy load succeeds.
* In this case, init is expected to re-exec itself in order to transition
* to the proper security context.
* Otherwise, the function returns -1, and init must check *enforce to
* determine how to proceed. If enforcing (*enforce > 0), then init should
* halt the system. Otherwise, init may proceed normally without a re-exec.
*/
extern int selinux_init_load_policy(int *enforce);
/* Translate boolean strict to name value pair. */
typedef struct {
char *name;
int value;
} SELboolean;
/* save a list of booleans in a single transaction. */
extern int security_set_boolean_list(size_t boolcnt,
SELboolean * boollist, int permanent);
/* Load policy boolean settings.
Path may be NULL, in which case the booleans are loaded from
the active policy boolean configuration file. */
extern int security_load_booleans(char *path);
/* Check the validity of a security context. */
extern int security_check_context(const char * con);
extern int security_check_context_raw(const char * con);
/* Canonicalize a security context. */
extern int security_canonicalize_context(const char * con,
char ** canoncon);
extern int security_canonicalize_context_raw(const char * con,
char ** canoncon);
/* Get the enforce flag value. */
extern int security_getenforce(void);
/* Set the enforce flag value. */
extern int security_setenforce(int value);
/* Get the behavior for undefined classes/permissions */
extern int security_deny_unknown(void);
/* Disable SELinux at runtime (must be done prior to initial policy load). */
extern int security_disable(void);
/* Get the policy version number. */
extern int security_policyvers(void);
/* Get the boolean names */
extern int security_get_boolean_names(char ***names, int *len);
/* Get the pending value for the boolean */
extern int security_get_boolean_pending(const char *name);
/* Get the active value for the boolean */
extern int security_get_boolean_active(const char *name);
/* Set the pending value for the boolean */
extern int security_set_boolean(const char *name, int value);
/* Commit the pending values for the booleans */
extern int security_commit_booleans(void);
/* Userspace class mapping support */
struct security_class_mapping {
const char *name;
const char *perms[sizeof(access_vector_t) * 8 + 1];
};
/**
* selinux_set_mapping - Enable dynamic mapping between integer offsets and security class names
* @map: array of security_class_mapping structures
*
* The core avc_has_perm() API uses integers to represent security
* classes; previous to the introduction of this function, it was
* common for userspace object managers to be compiled using generated
* offsets for a particular policy. However, that strongly ties the build of the userspace components to a particular policy.
*
* By using this function to map between integer offsets and security
* class names, it's possible to replace a system policies that have
* at least the same set of security class names as used by the
* userspace object managers.
*
* To correctly use this function, you should override the generated
* security class defines from the system policy in a local header,
* starting at 1, and have one security_class_mapping structure entry
* per define.
*/
extern int selinux_set_mapping(struct security_class_mapping *map);
/* Common helpers */
/* Convert between mode and security class values */
extern security_class_t mode_to_security_class(mode_t mode);
/* Convert between security class values and string names */
extern security_class_t string_to_security_class(const char *name);
extern const char *security_class_to_string(security_class_t cls);
/* Convert between individual access vector permissions and string names */
extern const char *security_av_perm_to_string(security_class_t tclass,
access_vector_t perm);
extern access_vector_t string_to_av_perm(security_class_t tclass,
const char *name);
/* Returns an access vector in a string representation. User must free the
* returned string via free(). */
extern int security_av_string(security_class_t tclass,
access_vector_t av, char **result);
/* Display an access vector in a string representation. */
extern void print_access_vector(security_class_t tclass, access_vector_t av);
/* Set the function used by matchpathcon_init when displaying
errors about the file_contexts configuration. If not set,
then this defaults to fprintf(stderr, fmt, ...). */
extern void set_matchpathcon_printf(void (*f) (const char *fmt, ...));
/* Set the function used by matchpathcon_init when checking the
validity of a context in the file contexts configuration. If not set,
then this defaults to a test based on security_check_context().
The function is also responsible for reporting any such error, and
may include the 'path' and 'lineno' in such error messages. */
extern void set_matchpathcon_invalidcon(int (*f) (const char *path,
unsigned lineno,
char *context));
/* Same as above, but also allows canonicalization of the context,
by changing *context to refer to the canonical form. If not set,
and invalidcon is also not set, then this defaults to calling
security_canonicalize_context(). */
extern void set_matchpathcon_canoncon(int (*f) (const char *path,
unsigned lineno,
char **context));
/* Set flags controlling operation of matchpathcon_init or matchpathcon. */
#define MATCHPATHCON_BASEONLY 1 /* Only process the base file_contexts file. */
#define MATCHPATHCON_NOTRANS 2 /* Do not perform any context translation. */
#define MATCHPATHCON_VALIDATE 4 /* Validate/canonicalize contexts at init time. */
extern void set_matchpathcon_flags(unsigned int flags);
/* Load the file contexts configuration specified by 'path'
into memory for use by subsequent matchpathcon calls.
If 'path' is NULL, then load the active file contexts configuration,
i.e. the path returned by selinux_file_context_path().
Unless the MATCHPATHCON_BASEONLY flag has been set, this
function also checks for a 'path'.homedirs file and
a 'path'.local file and loads additional specifications
from them if present. */
extern int matchpathcon_init(const char *path);
/* Same as matchpathcon_init, but only load entries with
regexes that have stems that are prefixes of 'prefix'. */
extern int matchpathcon_init_prefix(const char *path, const char *prefix);
/* Free the memory allocated by matchpathcon_init. */
extern void matchpathcon_fini(void);
/* Resolve all of the symlinks and relative portions of a pathname, but NOT
* the final component (same a realpath() unless the final component is a
* symlink. Resolved path must be a path of size PATH_MAX + 1 */
extern int realpath_not_final(const char *name, char *resolved_path);
/* Match the specified pathname and mode against the file contexts
configuration and set *con to refer to the resulting context.
'mode' can be 0 to disable mode matching.
Caller must free via freecon.
If matchpathcon_init has not already been called, then this function
will call it upon its first invocation with a NULL path. */
extern int matchpathcon(const char *path,
mode_t mode, char ** con);
/* Same as above, but return a specification index for
later use in a matchpathcon_filespec_add() call - see below. */
extern int matchpathcon_index(const char *path,
mode_t mode, char ** con);
/* Maintain an association between an inode and a specification index,
and check whether a conflicting specification is already associated
with the same inode (e.g. due to multiple hard links). If so, then
use the latter of the two specifications based on their order in the
file contexts configuration. Return the used specification index. */
extern int matchpathcon_filespec_add(ino_t ino, int specind, const char *file);
/* Destroy any inode associations that have been added, e.g. to restart
for a new filesystem. */
extern void matchpathcon_filespec_destroy(void);
/* Display statistics on the hash table usage for the associations. */
extern void matchpathcon_filespec_eval(void);
/* Check to see whether any specifications had no matches and report them.
The 'str' is used as a prefix for any warning messages. */
extern void matchpathcon_checkmatches(char *str);
/* Match the specified media and against the media contexts
configuration and set *con to refer to the resulting context.
Caller must free con via freecon. */
extern int matchmediacon(const char *media, char ** con);
/*
selinux_getenforcemode reads the /etc/selinux/config file and determines
whether the machine should be started in enforcing (1), permissive (0) or
disabled (-1) mode.
*/
extern int selinux_getenforcemode(int *enforce);
/*
selinux_boolean_sub reads the /etc/selinux/TYPE/booleans.subs_dist file
looking for a record with boolean_name. If a record exists selinux_boolean_sub
returns the translated name otherwise it returns the original name.
The returned value needs to be freed. On failure NULL will be returned.
*/
extern char *selinux_boolean_sub(const char *boolean_name);
/*
selinux_getpolicytype reads the /etc/selinux/config file and determines
what the default policy for the machine is. Calling application must
free policytype.
*/
extern int selinux_getpolicytype(char **policytype);
/*
selinux_policy_root reads the /etc/selinux/config file and returns
the directory path under which the compiled policy file and context
configuration files exist.
*/
extern const char *selinux_policy_root(void);
/*
selinux_set_policy_root sets an alternate policy root directory path under
which the compiled policy file and context configuration files exist.
*/
extern int selinux_set_policy_root(const char *rootpath);
/* These functions return the paths to specific files under the
policy root directory. */
extern const char *selinux_current_policy_path(void);
extern const char *selinux_binary_policy_path(void);
extern const char *selinux_failsafe_context_path(void);
extern const char *selinux_removable_context_path(void);
extern const char *selinux_default_context_path(void);
extern const char *selinux_user_contexts_path(void);
extern const char *selinux_file_context_path(void);
extern const char *selinux_file_context_homedir_path(void);
extern const char *selinux_file_context_local_path(void);
extern const char *selinux_file_context_subs_path(void);
extern const char *selinux_file_context_subs_dist_path(void);
extern const char *selinux_homedir_context_path(void);
extern const char *selinux_media_context_path(void);
extern const char *selinux_virtual_domain_context_path(void);
extern const char *selinux_virtual_image_context_path(void);
extern const char *selinux_lxc_contexts_path(void);
extern const char *selinux_x_context_path(void);
extern const char *selinux_sepgsql_context_path(void);
extern const char *selinux_openrc_contexts_path(void);
extern const char *selinux_openssh_contexts_path(void);
extern const char *selinux_snapperd_contexts_path(void);
extern const char *selinux_systemd_contexts_path(void);
extern const char *selinux_contexts_path(void);
extern const char *selinux_securetty_types_path(void);
extern const char *selinux_booleans_subs_path(void);
extern const char *selinux_booleans_path(void);
extern const char *selinux_customizable_types_path(void);
extern const char *selinux_users_path(void);
extern const char *selinux_usersconf_path(void);
extern const char *selinux_translations_path(void);
extern const char *selinux_colors_path(void);
extern const char *selinux_netfilter_context_path(void);
extern const char *selinux_path(void);
/**
* selinux_check_access - Check permissions and perform appropriate auditing.
* @scon: source security context
* @tcon: target security context
* @tclass: target security class string
* @perm: requested permissions string, interpreted based on @tclass
* @auditdata: auxiliary audit data
*
* Check the AVC to determine whether the @perm permissions are granted
* for the SID pair (@scon, @tcon), interpreting the permissions
* based on @tclass.
* Return %0 if all @perm permissions are granted, -%1 with
* @errno set to %EACCES if any permissions are denied or to another
* value upon other errors.
* If auditing or logging is configured the appropriate callbacks will be called
* and passed the auditdata field
*/
extern int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata);
/* Check a permission in the passwd class.
Return 0 if granted or -1 otherwise. */
extern int selinux_check_passwd_access(access_vector_t requested);
extern int checkPasswdAccess(access_vector_t requested);
/* Check if the tty_context is defined as a securetty
Return 0 if secure, < 0 otherwise. */
extern int selinux_check_securetty_context(const char * tty_context);
/* Set the path to the selinuxfs mount point explicitly.
Normally, this is determined automatically during libselinux
initialization, but this is not always possible, e.g. for /sbin/init
which performs the initial mount of selinuxfs. */
void set_selinuxmnt(const char *mnt);
/* Check if selinuxfs exists as a kernel filesystem */
int selinuxfs_exists(void);
/* clear selinuxmnt variable and free allocated memory */
void fini_selinuxmnt(void);
/* Set an appropriate security context based on the filename of a helper
* program, falling back to a new context with the specified type. */
extern int setexecfilecon(const char *filename, const char *fallback_type);
#ifndef DISABLE_RPM
/* Execute a helper for rpm in an appropriate security context. */
extern int rpm_execcon(unsigned int verified,
const char *filename,
char *const argv[], char *const envp[]);
#endif
/* Returns whether a file context is customizable, and should not
be relabeled . */
extern int is_context_customizable(const char * scontext);
/* Perform context translation between the human-readable format
("translated") and the internal system format ("raw").
Caller must free the resulting context via freecon.
Returns -1 upon an error or 0 otherwise.
If passed NULL, sets the returned context to NULL and returns 0. */
extern int selinux_trans_to_raw_context(const char * trans,
char ** rawp);
extern int selinux_raw_to_trans_context(const char * raw,
char ** transp);
/* Perform context translation between security contexts
and display colors. Returns a space-separated list of ten
ten hex RGB triples prefixed by hash marks, e.g. "#ff0000".
Caller must free the resulting string via free.
Returns -1 upon an error or 0 otherwise. */
extern int selinux_raw_context_to_color(const char * raw,
char **color_str);
/* Get the SELinux username and level to use for a given Linux username.
These values may then be passed into the get_ordered_context_list*
and get_default_context* functions to obtain a context for the user.
Returns 0 on success or -1 otherwise.
Caller must free the returned strings via free. */
extern int getseuserbyname(const char *linuxuser, char **seuser, char **level);
/* Get the SELinux username and level to use for a given Linux username and service.
These values may then be passed into the get_ordered_context_list*
and get_default_context* functions to obtain a context for the user.
Returns 0 on success or -1 otherwise.
Caller must free the returned strings via free. */
extern int getseuser(const char *username, const char *service,
char **r_seuser, char **r_level);
/* Compare two file contexts, return 0 if equivalent. */
extern int selinux_file_context_cmp(const char * a,
const char * b);
/*
* Verify the context of the file 'path' against policy.
* Return 1 if match, 0 if not and -1 on error.
*/
extern int selinux_file_context_verify(const char *path, mode_t mode);
/* This function sets the file context on to the system defaults returns 0 on success */
extern int selinux_lsetfilecon_default(const char *path);
/*
* Force a reset of the loaded configuration
* WARNING: This is not thread safe. Be very sure that no other threads
* are calling into libselinux when this is called.
*/
extern void selinux_reset_config(void);
#ifdef __cplusplus
}
#endif
#endif

355
jni/external/selinux_stub.c vendored Normal file
View File

@@ -0,0 +1,355 @@
#include <stdbool.h>
#include "selinux/avc.h"
#include "selinux/context.h"
#include "selinux/get_context_list.h"
#include "selinux/get_default_type.h"
#include "selinux/restorecon.h"
#include "selinux/selinux.h"
int is_selinux_enabled(void) { return 0; }
int is_selinux_mls_enabled(void) { return 0; }
void freecon(char * con) { }
void freeconary(char ** con) { }
int getcon(char ** con) { return 0; }
int getcon_raw(char ** con) { return 0; }
int setcon(const char * con) { return 0; }
int setcon_raw(const char * con) { return 0; }
int getpidcon(pid_t pid, char ** con) { return 0; }
int getpidcon_raw(pid_t pid, char ** con) { return 0; }
int getprevcon(char ** con) { return 0; }
int getprevcon_raw(char ** con) { return 0; }
int getexeccon(char ** con) { return 0; }
int getexeccon_raw(char ** con) { return 0; }
int setexeccon(const char * con) { return 0; }
int setexeccon_raw(const char * con) { return 0; }
int getfscreatecon(char ** con) { return 0; }
int getfscreatecon_raw(char ** con) { return 0; }
int setfscreatecon(const char * context) { return 0; }
int setfscreatecon_raw(const char * context) { return 0; }
int getkeycreatecon(char ** con) { return 0; }
int getkeycreatecon_raw(char ** con) { return 0; }
int setkeycreatecon(const char * context) { return 0; }
int setkeycreatecon_raw(const char * context) { return 0; }
int getsockcreatecon(char ** con) { return 0; }
int getsockcreatecon_raw(char ** con) { return 0; }
int setsockcreatecon(const char * context) { return 0; }
int setsockcreatecon_raw(const char * context) { return 0; }
int getfilecon(const char *path, char ** con) { return 0; }
int getfilecon_raw(const char *path, char ** con) { return 0; }
int lgetfilecon(const char *path, char ** con) { return 0; }
int lgetfilecon_raw(const char *path, char ** con) { return 0; }
int fgetfilecon(int fd, char ** con) { return 0; }
int fgetfilecon_raw(int fd, char ** con) { return 0; }
int setfilecon(const char *path, const char * con) { return 0; }
int setfilecon_raw(const char *path, const char * con) { return 0; }
int lsetfilecon(const char *path, const char * con) { return 0; }
int lsetfilecon_raw(const char *path, const char * con) { return 0; }
int fsetfilecon(int fd, const char * con) { return 0; }
int fsetfilecon_raw(int fd, const char * con) { return 0; }
int getpeercon(int fd, char ** con) { return 0; }
int getpeercon_raw(int fd, char ** con) { return 0; }
void selinux_set_callback(int type, union selinux_callback cb) { }
int security_compute_av(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd) { return 0; }
int security_compute_av_raw(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd) { return 0; }
int security_compute_av_flags(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd) { return 0; }
int security_compute_av_flags_raw(const char * scon,
const char * tcon,
security_class_t tclass,
access_vector_t requested,
struct av_decision *avd) { return 0; }
int security_compute_create(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon) { return 0; }
int security_compute_create_raw(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon) { return 0; }
int security_compute_create_name(const char * scon,
const char * tcon,
security_class_t tclass,
const char *objname,
char ** newcon) { return 0; }
int security_compute_create_name_raw(const char * scon,
const char * tcon,
security_class_t tclass,
const char *objname,
char ** newcon) { return 0; }
int security_compute_relabel(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon) { return 0; }
int security_compute_relabel_raw(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon) { return 0; }
int security_compute_member(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon) { return 0; }
int security_compute_member_raw(const char * scon,
const char * tcon,
security_class_t tclass,
char ** newcon) { return 0; }
int security_compute_user(const char * scon,
const char *username,
char *** con) { return 0; }
int security_compute_user_raw(const char * scon,
const char *username,
char *** con) { return 0; }
int security_load_policy(void *data, size_t len) { return 0; }
int security_get_initial_context(const char *name,
char ** con) { return 0; }
int security_get_initial_context_raw(const char *name,
char ** con) { return 0; }
int selinux_mkload_policy(int preservebools) { return 0; }
int selinux_init_load_policy(int *enforce) { return 0; }
int security_set_boolean_list(size_t boolcnt,
SELboolean * boollist, int permanent) { return 0; }
int security_load_booleans(char *path) { return 0; }
int security_check_context(const char * con) { return 0; }
int security_check_context_raw(const char * con) { return 0; }
int security_canonicalize_context(const char * con,
char ** canoncon) { return 0; }
int security_canonicalize_context_raw(const char * con,
char ** canoncon) { return 0; }
int security_getenforce(void) { return 0; }
int security_setenforce(int value) { return 0; }
int security_deny_unknown(void) { return 0; }
int security_disable(void) { return 0; }
int security_policyvers(void) { return 0; }
int security_get_boolean_names(char ***names, int *len) { return 0; }
int security_get_boolean_pending(const char *name) { return 0; }
int security_get_boolean_active(const char *name) { return 0; }
int security_set_boolean(const char *name, int value) { return 0; }
int security_commit_booleans(void) { return 0; }
int selinux_set_mapping(struct security_class_mapping *map) { return 0; }
security_class_t mode_to_security_class(mode_t mode) { return 0; }
security_class_t string_to_security_class(const char *name) { return 0; }
const char *security_class_to_string(security_class_t cls) { return 0; }
const char *security_av_perm_to_string(security_class_t tclass,
access_vector_t perm) { return 0; }
access_vector_t string_to_av_perm(security_class_t tclass,
const char *name) { return 0; }
int security_av_string(security_class_t tclass,
access_vector_t av, char **result) { return 0; }
void print_access_vector(security_class_t tclass, access_vector_t av) { }
void set_matchpathcon_printf(void (*f) (const char *fmt, ...)) { }
void set_matchpathcon_invalidcon(int (*f) (const char *path,
unsigned lineno,
char *context)) { }
void set_matchpathcon_canoncon(int (*f) (const char *path,
unsigned lineno,
char **context)) { }
void set_matchpathcon_flags(unsigned int flags) { }
int matchpathcon_init(const char *path) { return 0; }
int matchpathcon_init_prefix(const char *path, const char *prefix) { return 0; }
void matchpathcon_fini(void) { }
int realpath_not_final(const char *name, char *resolved_path) { return 0; }
int matchpathcon(const char *path,
mode_t mode, char ** con) { return 0; }
int matchpathcon_index(const char *path,
mode_t mode, char ** con) { return 0; }
int matchpathcon_filespec_add(ino_t ino, int specind, const char *file) { return 0; }
void matchpathcon_filespec_destroy(void) { }
void matchpathcon_filespec_eval(void) { }
void matchpathcon_checkmatches(char *str) { }
int matchmediacon(const char *media, char ** con) { return 0; }
int selinux_getenforcemode(int *enforce) { return 0; }
char *selinux_boolean_sub(const char *boolean_name) { return 0; }
int selinux_getpolicytype(char **policytype) { return 0; }
const char *selinux_policy_root(void) { return 0; }
int selinux_set_policy_root(const char *rootpath) { return 0; }
const char *selinux_current_policy_path(void) { return 0; }
const char *selinux_binary_policy_path(void) { return 0; }
const char *selinux_failsafe_context_path(void) { return 0; }
const char *selinux_removable_context_path(void) { return 0; }
const char *selinux_default_context_path(void) { return 0; }
const char *selinux_user_contexts_path(void) { return 0; }
const char *selinux_file_context_path(void) { return 0; }
const char *selinux_file_context_homedir_path(void) { return 0; }
const char *selinux_file_context_local_path(void) { return 0; }
const char *selinux_file_context_subs_path(void) { return 0; }
const char *selinux_file_context_subs_dist_path(void) { return 0; }
const char *selinux_homedir_context_path(void) { return 0; }
const char *selinux_media_context_path(void) { return 0; }
const char *selinux_virtual_domain_context_path(void) { return 0; }
const char *selinux_virtual_image_context_path(void) { return 0; }
const char *selinux_lxc_contexts_path(void) { return 0; }
const char *selinux_x_context_path(void) { return 0; }
const char *selinux_sepgsql_context_path(void) { return 0; }
const char *selinux_openrc_contexts_path(void) { return 0; }
const char *selinux_openssh_contexts_path(void) { return 0; }
const char *selinux_snapperd_contexts_path(void) { return 0; }
const char *selinux_systemd_contexts_path(void) { return 0; }
const char *selinux_contexts_path(void) { return 0; }
const char *selinux_securetty_types_path(void) { return 0; }
const char *selinux_booleans_subs_path(void) { return 0; }
const char *selinux_booleans_path(void) { return 0; }
const char *selinux_customizable_types_path(void) { return 0; }
const char *selinux_users_path(void) { return 0; }
const char *selinux_usersconf_path(void) { return 0; }
const char *selinux_translations_path(void) { return 0; }
const char *selinux_colors_path(void) { return 0; }
const char *selinux_netfilter_context_path(void) { return 0; }
const char *selinux_path(void) { return 0; }
int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata) { return 0; }
int selinux_check_passwd_access(access_vector_t requested) { return 0; }
int checkPasswdAccess(access_vector_t requested) { return 0; }
int selinux_check_securetty_context(const char * tty_context) { return 0; }
void set_selinuxmnt(const char *mnt) { }
int selinuxfs_exists(void) { return 0; }
void fini_selinuxmnt(void) {}
int setexecfilecon(const char *filename, const char *fallback_type) { return 0; }
#ifndef DISABLE_RPM
int rpm_execcon(unsigned int verified,
const char *filename,
char *const argv[], char *const envp[]) { return 0; }
#endif
int is_context_customizable(const char * scontext) { return 0; }
int selinux_trans_to_raw_context(const char * trans,
char ** rawp) { return 0; }
int selinux_raw_to_trans_context(const char * raw,
char ** transp) { return 0; }
int selinux_raw_context_to_color(const char * raw,
char **color_str) { return 0; }
int getseuserbyname(const char *linuxuser, char **seuser, char **level) { return 0; }
int getseuser(const char *username, const char *service,
char **r_seuser, char **r_level) { return 0; }
int selinux_file_context_cmp(const char * a,
const char * b) { return 0; }
int selinux_file_context_verify(const char *path, mode_t mode) { return 0; }
int selinux_lsetfilecon_default(const char *path) { return 0; }
void selinux_reset_config(void) { }
int avc_sid_to_context(security_id_t sid, char ** ctx) { return 0; }
int avc_sid_to_context_raw(security_id_t sid, char ** ctx) { return 0; }
int avc_context_to_sid(const char * ctx, security_id_t * sid) { return 0; }
int avc_context_to_sid_raw(const char * ctx, security_id_t * sid) { return 0; }
int sidget(security_id_t sid) { return 0; }
int sidput(security_id_t sid) { return 0; }
int avc_get_initial_sid(const char *name, security_id_t * sid) { return 0; }
int avc_init(const char *msgprefix,
const struct avc_memory_callback *mem_callbacks,
const struct avc_log_callback *log_callbacks,
const struct avc_thread_callback *thread_callbacks,
const struct avc_lock_callback *lock_callbacks) { return 0; }
int avc_open(struct selinux_opt *opts, unsigned nopts) { return 0; }
void avc_cleanup(void) { }
int avc_reset(void) { return 0; }
void avc_destroy(void) { }
int avc_has_perm_noaudit(security_id_t ssid,
security_id_t tsid,
security_class_t tclass,
access_vector_t requested,
struct avc_entry_ref *aeref, struct av_decision *avd) { return 0; }
int avc_has_perm(security_id_t ssid, security_id_t tsid,
security_class_t tclass, access_vector_t requested,
struct avc_entry_ref *aeref, void *auditdata) { return 0; }
void avc_audit(security_id_t ssid, security_id_t tsid,
security_class_t tclass, access_vector_t requested,
struct av_decision *avd, int result, void *auditdata) { }
int avc_compute_create(security_id_t ssid,
security_id_t tsid,
security_class_t tclass, security_id_t * newsid) { return 0; }
int avc_compute_member(security_id_t ssid,
security_id_t tsid,
security_class_t tclass, security_id_t * newsid) { return 0; }
int avc_add_callback(int (*callback)
(uint32_t event, security_id_t ssid,
security_id_t tsid, security_class_t tclass,
access_vector_t perms,
access_vector_t * out_retained),
uint32_t events, security_id_t ssid,
security_id_t tsid, security_class_t tclass,
access_vector_t perms) { return 0; }
void avc_cache_stats(struct avc_cache_stats *stats) { }
void avc_av_stats(void) { }
void avc_sid_stats(void) { }
int avc_netlink_open(int blocking) { return 0; }
void avc_netlink_loop(void) { }
void avc_netlink_close(void) { }
int avc_netlink_acquire_fd(void) { return 0; }
void avc_netlink_release_fd(void) { }
int avc_netlink_check_nb(void) { return 0; }
int selinux_status_open(int fallback) { return 0; }
void selinux_status_close(void) { }
int selinux_status_updated(void) { return 0; }
int selinux_status_getenforce(void) { return 0; }
int selinux_status_policyload(void) { return 0; }
int selinux_status_deny_unknown(void) { return 0; }
context_t context_new(const char *s) { return 0; }
char *context_str(context_t c) { return 0; }
void context_free(context_t c) { }
const char *context_type_get(context_t c) { return 0; }
const char *context_range_get(context_t c) { return 0; }
const char *context_role_get(context_t c) { return 0; }
const char *context_user_get(context_t c) { return 0; }
int context_type_set(context_t c, const char *s) { return 0; }
int context_range_set(context_t c, const char *s) { return 0; }
int context_role_set(context_t c, const char *s) { return 0; }
int context_user_set(context_t c, const char *s) { return 0; }
int get_ordered_context_list(const char *user,
char * fromcon,
char *** list) { return 0; }
int get_ordered_context_list_with_level(const char *user,
const char *level,
char * fromcon,
char *** list) { return 0; }
int get_default_context(const char *user,
char * fromcon,
char ** newcon) { return 0; }
int get_default_context_with_level(const char *user,
const char *level,
char * fromcon,
char ** newcon) { return 0; }
int get_default_context_with_role(const char *user,
const char *role,
char * fromcon,
char ** newcon) { return 0; }
int get_default_context_with_rolelevel(const char *user,
const char *role,
const char *level,
char * fromcon,
char ** newcon) { return 0; }
int query_user_context(char ** list,
char ** newcon) { return 0; }
int manual_user_enter_context(const char *user,
char ** newcon) { return 0; }
const char *selinux_default_type_path(void) { return 0; }
int get_default_type(const char *role, char **type) { return 0; }
struct selabel_handle *selabel_open(unsigned int backend,
const struct selinux_opt *opts,
unsigned nopts) { return 0; }
void selabel_close(struct selabel_handle *handle) { }
int selabel_lookup(struct selabel_handle *handle, char **con,
const char *key, int type) { return 0; }
int selabel_lookup_raw(struct selabel_handle *handle, char **con,
const char *key, int type) { return 0; }
bool selabel_partial_match(struct selabel_handle *handle, const char *key) { return 0; }
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type) { return 0; }
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
const char *key, const char **aliases, int type) { return 0; }
int selabel_digest(struct selabel_handle *rec,
unsigned char **digest, size_t *digest_len,
char ***specfiles, size_t *num_specfiles) { return 0; }
void selabel_stats(struct selabel_handle *handle) { }
int selinux_restorecon(const char *pathname,
unsigned int restorecon_flags) { return 0; }
struct selabel_handle *selinux_restorecon_default_handle(void) { return 0; }
void selinux_restorecon_set_exclude_list(const char **exclude_list) { }
int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath) { return 0; }
int selinux_restorecon_xattr(const char *pathname,
unsigned int xattr_flags,
struct dir_xattr ***xattr_list) { return 0; }

10491
jni/external/sqlite3.h vendored Normal file

File diff suppressed because it is too large Load Diff

676
jni/external/sqlite3_stub.c vendored Normal file
View File

@@ -0,0 +1,676 @@
#include "sqlite3.h"
SQLITE_API const char *sqlite3_libversion(void) { return 0; }
SQLITE_API const char *sqlite3_sourceid(void) { return 0; }
SQLITE_API int sqlite3_libversion_number(void) { return 0; }
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_API int sqlite3_compileoption_used(const char *zOptName) { return 0; }
SQLITE_API const char *sqlite3_compileoption_get(int N) { return 0; }
#endif
SQLITE_API int sqlite3_threadsafe(void) { return 0; }
SQLITE_API int sqlite3_close(sqlite3 *db) { return 0; }
SQLITE_API int sqlite3_close_v2(sqlite3 *db) { return 0; }
SQLITE_API int sqlite3_exec(
sqlite3 *db,
const char *sql,
int (*callback)(void*,int,char**,char**),
void *v,
char **errmsg
) { return 0; }
SQLITE_API int sqlite3_initialize(void) { return 0; }
SQLITE_API int sqlite3_shutdown(void) { return 0; }
SQLITE_API int sqlite3_os_init(void) { return 0; }
SQLITE_API int sqlite3_os_end(void) { return 0; }
SQLITE_API int sqlite3_config(int i, ...) { return 0; }
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...) { return 0; }
SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff) { return 0; }
SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3 *db) { return 0; }
SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db,sqlite3_int64 i) { }
SQLITE_API int sqlite3_changes(sqlite3 *db) { return 0; }
SQLITE_API int sqlite3_total_changes(sqlite3 *db) { return 0; }
SQLITE_API void sqlite3_interrupt(sqlite3 *db) { }
SQLITE_API int sqlite3_complete(const char *sql) { return 0; }
SQLITE_API int sqlite3_complete16(const void *sql) { return 0; }
SQLITE_API int sqlite3_busy_handler(sqlite3 *db, int(*f) (void *v,int i), void* v) { return 0; }
SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms) { return 0; }
SQLITE_API int sqlite3_get_table(
sqlite3 *db,
const char *zSql,
char ***pazResult,
int *pnRow,
int *pnColumn,
char **pzErrmsg
) { return 0; }
SQLITE_API void sqlite3_free_table(char **result) { }
SQLITE_API char *sqlite3_mprintf(const char* s,...) { return 0; }
SQLITE_API char *sqlite3_vmprintf(const char* s, va_list v) { return 0; }
SQLITE_API char *sqlite3_snprintf(int i, char* s, const char* st, ...) { return 0; }
SQLITE_API char *sqlite3_vsnprintf(int i, char* s, const char* st, va_list v) { return 0; }
SQLITE_API void *sqlite3_malloc(int i) { return 0; }
SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 i) { return 0; }
SQLITE_API void *sqlite3_realloc(void* v, int i) { return 0; }
SQLITE_API void *sqlite3_realloc64(void* v, sqlite3_uint64 i) { return 0; }
SQLITE_API void sqlite3_free(void* v) { }
SQLITE_API sqlite3_uint64 sqlite3_msize(void* v) { return 0; }
SQLITE_API sqlite3_int64 sqlite3_memory_used(void) { return 0; }
SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag) { return 0; }
SQLITE_API void sqlite3_randomness(int N, void *P) { }
SQLITE_API int sqlite3_set_authorizer(
sqlite3 *db,
int (*xAuth)(void *v,int i,const char*,const char*,const char*,const char*),
void *pUserData
) { return 0; }
SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3 *db,
void(*xTrace)(void *v,const char*), void* v) { return 0; }
SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3 *db,
void(*xProfile)(void *v,const char*,sqlite3_uint64), void* v) { return 0; }
SQLITE_API int sqlite3_trace_v2(
sqlite3 *db,
unsigned uMask,
int(*xCallback)(unsigned,void *v,void *vv,void*),
void *pCtx
) { return 0; }
SQLITE_API void sqlite3_progress_handler(sqlite3 *db, int i, int(*f)(void*), void* v) { }
SQLITE_API int sqlite3_open(
const char *filename,
sqlite3 **ppDb
) { return 0; }
SQLITE_API int sqlite3_open16(
const void *filename,
sqlite3 **ppDb
) { return 0; }
SQLITE_API int sqlite3_open_v2(
const char *filename,
sqlite3 **ppDb,
int flags,
const char *zVfs
) { return 0; }
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam) { return 0; }
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault) { return 0; }
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char* s, const char* st, sqlite3_int64 i) { return 0; }
SQLITE_API int sqlite3_errcode(sqlite3 *db) { return 0; }
SQLITE_API int sqlite3_extended_errcode(sqlite3 *db) { return 0; }
SQLITE_API const char *sqlite3_errmsg(sqlite3 *db) { return 0; }
SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db) { return 0; }
SQLITE_API const char *sqlite3_errstr(int i) { return 0; }
SQLITE_API int sqlite3_limit(sqlite3 *db, int id, int newVal) { return 0; }
SQLITE_API int sqlite3_prepare(
sqlite3 *db,
const char *zSql,
int nByte,
sqlite3_stmt **ppStmt,
const char **pzTail
) { return 0; }
SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db,
const char *zSql,
int nByte,
sqlite3_stmt **ppStmt,
const char **pzTail
) { return 0; }
SQLITE_API int sqlite3_prepare16(
sqlite3 *db,
const void *zSql,
int nByte,
sqlite3_stmt **ppStmt,
const void **pzTail
) { return 0; }
SQLITE_API int sqlite3_prepare16_v2(
sqlite3 *db,
const void *zSql,
int nByte,
sqlite3_stmt **ppStmt,
const void **pzTail
) { return 0; }
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt) { return 0; }
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt) { return 0; }
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt) { return 0; }
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt* s) { return 0; }
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt* s, int i, const void*v, int n, void(*f)(void*)) { return 0; }
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt* s, int i, const void *v, sqlite3_uint64 ii,
void(*f)(void*)) { return 0; }
SQLITE_API int sqlite3_bind_double(sqlite3_stmt* s, int i, double d) { return 0; }
SQLITE_API int sqlite3_bind_int(sqlite3_stmt* s, int i, int ii) { return 0; }
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt* s, int i, sqlite3_int64 ii) { return 0; }
SQLITE_API int sqlite3_bind_null(sqlite3_stmt* s, int i) { return 0; }
SQLITE_API int sqlite3_bind_text(sqlite3_stmt* s,int i,const char* str, int ii, void(*f)(void*)) { return 0; }
SQLITE_API int sqlite3_bind_text16(sqlite3_stmt* s, int i, const void *v, int ii, void(*f)(void*)) { return 0; }
SQLITE_API int sqlite3_bind_text64(sqlite3_stmt* s, int i, const char* str, sqlite3_uint64 ii,
void(*f)(void*), unsigned char encoding) { return 0; }
SQLITE_API int sqlite3_bind_value(sqlite3_stmt* s, int i, const sqlite3_value* v) { return 0; }
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt* s, int i, int n) { return 0; }
SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt* s, int i, sqlite3_uint64 ii) { return 0; }
SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt* s) { return 0; }
SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt* s, int i) { return 0; }
SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt* s, const char *zName) { return 0; }
SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt* s) { return 0; }
SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt) { return 0; }
SQLITE_API const char *sqlite3_column_name(sqlite3_stmt* s, int N) { return 0; }
SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt* s, int N) { return 0; }
SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt* s,int i) { return 0; }
SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt* s,int i){ return 0; }
SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt* s,int i) { return 0; }
SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt* s,int i) { return 0; }
SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt* s,int i) { return 0; }
SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt* s,int i) { return 0; }
SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt* s,int i) { return 0; }
SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt* s,int i) { return 0; }
SQLITE_API int sqlite3_step(sqlite3_stmt* s) { return 0; }
SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt) { return 0; }
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API int sqlite3_column_bytes(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API double sqlite3_column_double(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API int sqlite3_column_int(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API int sqlite3_column_type(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt* s, int iCol) { return 0; }
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt) { return 0; }
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt) { return 0; }
SQLITE_API int sqlite3_create_function(
sqlite3 *db,
const char *zFunctionName,
int nArg,
int eTextRep,
void *pApp,
void (*xFunc)(sqlite3_context* c,int i,sqlite3_value**),
void (*xStep)(sqlite3_context* c,int i,sqlite3_value**),
void (*xFinal)(sqlite3_context* c)
) { return 0; }
SQLITE_API int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
int eTextRep,
void *pApp,
void (*xFunc)(sqlite3_context* c,int i,sqlite3_value**),
void (*xStep)(sqlite3_context* c,int i,sqlite3_value**),
void (*xFinal)(sqlite3_context* c)
) { return 0; }
SQLITE_API int sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunctionName,
int nArg,
int eTextRep,
void *pApp,
void (*xFunc)(sqlite3_context* c,int i,sqlite3_value**),
void (*xStep)(sqlite3_context* c,int i,sqlite3_value**),
void (*xFinal)(sqlite3_context* c),
void(*xDestroy)(void*)
) { return 0; }
#ifndef SQLITE_OMIT_DEPRECATED
SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context* c) { return 0; }
SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt* s) { return 0; }
SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt* s, sqlite3_stmt* ss) { return 0; }
SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void) { return 0; }
SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void) { }
SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*f)(void *v,sqlite3_int64,int),
void *v,sqlite3_int64 i) { return 0; }
#endif
SQLITE_API const void *sqlite3_value_blob(sqlite3_value* v) { return 0; }
SQLITE_API int sqlite3_value_bytes(sqlite3_value* v) { return 0; }
SQLITE_API int sqlite3_value_bytes16(sqlite3_value* v) { return 0; }
SQLITE_API double sqlite3_value_double(sqlite3_value* v) { return 0; }
SQLITE_API int sqlite3_value_int(sqlite3_value* v) { return 0; }
SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value* v) { return 0; }
SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value* v) { return 0; }
SQLITE_API const void *sqlite3_value_text16(sqlite3_value* v) { return 0; }
SQLITE_API const void *sqlite3_value_text16le(sqlite3_value* v) { return 0; }
SQLITE_API const void *sqlite3_value_text16be(sqlite3_value* v) { return 0; }
SQLITE_API int sqlite3_value_type(sqlite3_value* v) { return 0; }
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value* v) { return 0; }
SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value* v) { return 0; }
SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value* v) { return 0; }
SQLITE_API void sqlite3_value_free(sqlite3_value* v) { }
SQLITE_API void *sqlite3_aggregate_context(sqlite3_context* c, int nBytes) { return 0; }
SQLITE_API void *sqlite3_user_data(sqlite3_context* c) { return 0; }
SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context* c) { return 0; }
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context* c, int N) { return 0; }
SQLITE_API void sqlite3_set_auxdata(sqlite3_context* c, int N, void *v, void (*f)(void*)) { }
SQLITE_API void sqlite3_result_blob(sqlite3_context* c, const void *v, int i, void(*f)(void*)) { }
SQLITE_API void sqlite3_result_blob64(sqlite3_context* c,const void *v,
sqlite3_uint64 i,void(*f)(void*)) { }
SQLITE_API void sqlite3_result_double(sqlite3_context* c, double d) { }
SQLITE_API void sqlite3_result_error(sqlite3_context* c, const char* s, int i) { }
SQLITE_API void sqlite3_result_error16(sqlite3_context* c, const void *v, int i) { }
SQLITE_API void sqlite3_result_error_toobig(sqlite3_context* c) { }
SQLITE_API void sqlite3_result_error_nomem(sqlite3_context* c) { }
SQLITE_API void sqlite3_result_error_code(sqlite3_context* c, int i) { }
SQLITE_API void sqlite3_result_int(sqlite3_context* c, int i) { }
SQLITE_API void sqlite3_result_int64(sqlite3_context* c, sqlite3_int64 i) { }
SQLITE_API void sqlite3_result_null(sqlite3_context* c) { }
SQLITE_API void sqlite3_result_text(sqlite3_context* c, const char* s, int i, void(*f)(void*)) { }
SQLITE_API void sqlite3_result_text64(sqlite3_context* c, const char* s, sqlite3_uint64 i,
void(*f)(void*), unsigned char encoding) { }
SQLITE_API void sqlite3_result_text16(sqlite3_context* c, const void *v, int i, void(*f)(void*)) { }
SQLITE_API void sqlite3_result_text16le(sqlite3_context* c, const void *v, int i,void(*f)(void*)) { }
SQLITE_API void sqlite3_result_text16be(sqlite3_context* c, const void *v, int i,void(*f)(void*)) { }
SQLITE_API void sqlite3_result_value(sqlite3_context* c, sqlite3_value* v) { }
SQLITE_API void sqlite3_result_zeroblob(sqlite3_context* c, int n) { }
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context* c, sqlite3_uint64 n) { return 0; }
SQLITE_API void sqlite3_result_subtype(sqlite3_context* c,unsigned int i) { }
SQLITE_API int sqlite3_create_collation(
sqlite3 *db,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void *,int,const void *,int,const void*)
) { return 0; }
SQLITE_API int sqlite3_create_collation_v2(
sqlite3 *db,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void *,int,const void*,int,const void*),
void(*xDestroy)(void*)
) { return 0; }
SQLITE_API int sqlite3_create_collation16(
sqlite3 *db,
const void *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void *,int,const void *,int,const void*)
) { return 0; }
SQLITE_API int sqlite3_collation_needed(
sqlite3 *db,
void *v,
void(*f)(void *v,sqlite3 *db,int eTextRep,const char*)
) { return 0; }
SQLITE_API int sqlite3_collation_needed16(
sqlite3 *db,
void *v,
void(*f)(void *v,sqlite3 *db,int eTextRep,const void*)
) { return 0; }
#ifdef SQLITE_HAS_CODEC
SQLITE_API int sqlite3_key(
sqlite3 *db,
const void *pKey, int nKey
) { return 0; }
SQLITE_API int sqlite3_key_v2(
sqlite3 *db,
const char *zDbName,
const void *pKey, int nKey
) { return 0; }
SQLITE_API int sqlite3_rekey(
sqlite3 *db,
const void *pKey, int nKey
) { return 0; }
SQLITE_API int sqlite3_rekey_v2(
sqlite3 *db,
const char *zDbName,
const void *pKey, int nKey
) { return 0; }
SQLITE_API void sqlite3_activate_see(
const char *zPassPhrase
) { return 0; }
#endif
#ifdef SQLITE_ENABLE_CEROD
SQLITE_API void sqlite3_activate_cerod(
const char *zPassPhrase
) { return 0; }
#endif
SQLITE_API int sqlite3_sleep(int i) { return 0; }
SQLITE_API int sqlite3_get_autocommit(sqlite3 *db) { return 0; }
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *s) { return 0; }
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName) { return 0; }
SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName) { return 0; }
SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt) { return 0; }
SQLITE_API void *sqlite3_commit_hook(sqlite3 *db, int(*f)(void*), void *v) { return 0; }
SQLITE_API void *sqlite3_rollback_hook(sqlite3 *db, void(*f)(void *), void *v) { return 0; }
SQLITE_API void *sqlite3_update_hook(
sqlite3 *db,
void(*f)(void *,int ,char const *,char const *,sqlite3_int64),
void *v
) { return 0; }
SQLITE_API int sqlite3_enable_shared_cache(int i) { return 0; }
SQLITE_API int sqlite3_release_memory(int i) { return 0; }
SQLITE_API int sqlite3_db_release_memory(sqlite3 *db) { return 0; }
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N) { return 0; }
SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N) { }
SQLITE_API int sqlite3_table_column_metadata(
sqlite3 *db,
const char *zDbName,
const char *zTableName,
const char *zColumnName,
char const **pzDataType,
char const **pzCollSeq,
int *pNotNull,
int *pPrimaryKey,
int *pAutoinc
) { return 0; }
SQLITE_API int sqlite3_load_extension(
sqlite3 *db,
const char *zFile,
const char *zProc,
char **pzErrMsg
) { return 0; }
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff) { return 0; }
SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)) { return 0; }
SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)) { return 0; }
SQLITE_API void sqlite3_reset_auto_extension(void) { }
SQLITE_API int sqlite3_create_module(
sqlite3 *db,
const char *zName,
const sqlite3_module *p,
void *pClientData
) { return 0; }
SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db,
const char *zName,
const sqlite3_module *p,
void *pClientData,
void(*xDestroy)(void*)
) { return 0; }
SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zSQL) { return 0; }
SQLITE_API int sqlite3_overload_function(sqlite3 *db, const char *zFuncName, int nArg) { return 0; }
SQLITE_API int sqlite3_blob_open(
sqlite3 *db,
const char *zDb,
const char *zTable,
const char *zColumn,
sqlite3_int64 iRow,
int flags,
sqlite3_blob **ppBlob
) { return 0; }
SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *b, sqlite3_int64 i) { return 0; }
SQLITE_API int sqlite3_blob_close(sqlite3_blob *b) { return 0; }
SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *b) { return 0; }
SQLITE_API int sqlite3_blob_read(sqlite3_blob *b, void *Z, int N, int iOffset) { return 0; }
SQLITE_API int sqlite3_blob_write(sqlite3_blob *b, const void *z, int n, int iOffset) { return 0; }
SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName) { return 0; }
SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *v, int makeDflt) { return 0; }
SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *v) { return 0; }
SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int i) { return 0; }
SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *m) { }
SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *m) { }
SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *m) { return 0; }
SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *m) { }
#ifndef NDEBUG
SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *m) { return 0; }
SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *m) { return 0; }
#endif
SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3* db) { return 0; }
SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void* v) { return 0; }
SQLITE_API int sqlite3_test_control(int op, ...) { return 0; }
SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag) { return 0; }
SQLITE_API int sqlite3_status64(
int op,
sqlite3_int64 *pCurrent,
sqlite3_int64 *pHighwater,
int resetFlag
) { return 0; }
SQLITE_API int sqlite3_db_status(sqlite3 *db, int op, int *pCur, int *pHiwtr, int resetFlg) { return 0; }
SQLITE_API int sqlite3_stmt_status(sqlite3_stmt* s, int op,int resetFlg) { return 0; }
SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3 *pDest,
const char *zDestName,
sqlite3 *pSource,
const char *zSourceName
) { return 0; }
SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage) { return 0; }
SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p) { return 0; }
SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p) { return 0; }
SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p) { return 0; }
SQLITE_API int sqlite3_unlock_notify(
sqlite3 *pBlocked,
void (*xNotify)(void **apArg, int nArg),
void *pNotifyArg
) { return 0; }
SQLITE_API int sqlite3_stricmp(const char *s, const char *ss) { return 0; }
SQLITE_API int sqlite3_strnicmp(const char *s, const char *ss, int i) { return 0; }
SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr) { return 0; }
SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc) { return 0; }
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...) { }
SQLITE_API void *sqlite3_wal_hook(
sqlite3 *db,
int(*f)(void *,sqlite3 *db,const char*,int i),
void *v
) { return 0; }
SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N) { return 0; }
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb) { return 0; }
SQLITE_API int sqlite3_wal_checkpoint_v2(
sqlite3 *db,
const char *zDb,
int eMode,
int *pnLog,
int *pnCkpt
) { return 0; }
#define SQLITE_CHECKPOINT_PASSIVE 0
#define SQLITE_CHECKPOINT_FULL 1
#define SQLITE_CHECKPOINT_RESTART 2
#define SQLITE_CHECKPOINT_TRUNCATE 3
SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...) { return 0; }
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db) { return 0; }
#define SQLITE_ROLLBACK 1
#define SQLITE_FAIL 3
#define SQLITE_REPLACE 5
#define SQLITE_SCANSTAT_NLOOP 0
#define SQLITE_SCANSTAT_NVISIT 1
#define SQLITE_SCANSTAT_EST 2
#define SQLITE_SCANSTAT_NAME 3
#define SQLITE_SCANSTAT_EXPLAIN 4
#define SQLITE_SCANSTAT_SELECTID 5
SQLITE_API int sqlite3_stmt_scanstatus(
sqlite3_stmt *pStmt,
int idx,
int iScanStatusOp,
void *pOut
) { return 0; }
SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *s) { }
SQLITE_API int sqlite3_db_cacheflush(sqlite3* db) { return 0; }
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
SQLITE_API void *sqlite3_preupdate_hook(
sqlite3 *db,
void(*xPreUpdate)(
void *pCtx,
sqlite3 *db,
int op,
char const *zDb,
char const *zName,
sqlite3_int64 iKey1,
sqlite3_int64 iKey2
),
void*
) { return 0; }
SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int i, sqlite3_value **) { return 0; }
SQLITE_API int sqlite3_preupdate_count(sqlite3 *) { return 0; }
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *) { return 0; }
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int i, sqlite3_value **) { return 0; }
#endif
SQLITE_API int sqlite3_system_errno(sqlite3 *db) { return 0; }
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot **ppSnapshot
) { return 0; }
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot *pSnapshot
) { return 0; }
SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot* s) { }
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
sqlite3_snapshot *p1,
sqlite3_snapshot *p2
) { return 0; }
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb) { return 0; }
SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry*, int i, sqlite3_rtree_dbl*,int*),
void *pContext
) { return 0; }
SQLITE_API int sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
void *pContext,
void (*xDestructor)(void*)
) { return 0; }
typedef struct sqlite3_session sqlite3_session;
typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
SQLITE_API int sqlite3session_create(
sqlite3 *db,
const char *zDb,
sqlite3_session **ppSession
) { return 0; }
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession) { }
SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable) { return 0; }
SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect) { return 0; }
SQLITE_API int sqlite3session_attach(
sqlite3_session *pSession,
const char *zTab
) { return 0; }
SQLITE_API void sqlite3session_table_filter(
sqlite3_session *pSession,
int(*xFilter)(
void *pCtx,
const char *zTab
),
void *pCtx
) { }
SQLITE_API int sqlite3session_changeset(
sqlite3_session *pSession,
int *pnChangeset,
void **ppChangeset
) { return 0; }
SQLITE_API int sqlite3session_diff(
sqlite3_session *pSession,
const char *zFromDb,
const char *zTbl,
char **pzErrMsg
) { return 0; }
SQLITE_API int sqlite3session_patchset(
sqlite3_session *pSession,
int *pnPatchset,
void **ppPatchset
) { return 0; }
SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession) { return 0; }
SQLITE_API int sqlite3changeset_start(
sqlite3_changeset_iter **pp,
int nChangeset,
void *pChangeset
) { return 0; }
SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter) { return 0; }
SQLITE_API int sqlite3changeset_op(
sqlite3_changeset_iter *pIter,
const char **pzTab,
int *pnCol,
int *pOp,
int *pbIndirect
) { return 0; }
SQLITE_API int sqlite3changeset_pk(
sqlite3_changeset_iter *pIter,
unsigned char **pabPK,
int *pnCol
) { return 0; }
SQLITE_API int sqlite3changeset_old(
sqlite3_changeset_iter *pIter,
int iVal,
sqlite3_value **ppValue
) { return 0; }
SQLITE_API int sqlite3changeset_new(
sqlite3_changeset_iter *pIter,
int iVal,
sqlite3_value **ppValue
) { return 0; }
SQLITE_API int sqlite3changeset_conflict(
sqlite3_changeset_iter *pIter,
int iVal,
sqlite3_value **ppValue
) { return 0; }
SQLITE_API int sqlite3changeset_fk_conflicts(
sqlite3_changeset_iter *pIter,
int *pnOut
) { return 0; }
SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter) { return 0; }
SQLITE_API int sqlite3changeset_invert(
int nIn, const void *pIn,
int *pnOut, void **ppOut
) { return 0; }
SQLITE_API int sqlite3changeset_concat(
int nA,
void *pA,
int nB,
void *pB,
int *pnOut,
void **ppOut
) { return 0; }
typedef struct sqlite3_changegroup sqlite3_changegroup;
int sqlite3changegroup_new(sqlite3_changegroup **pp) { return 0; }
int sqlite3changegroup_add(sqlite3_changegroup *c, int nData, void *pData) { return 0; }
int sqlite3changegroup_output(
sqlite3_changegroup *c,
int *pnData,
void **ppData
) { return 0; }
void sqlite3changegroup_delete(sqlite3_changegroup *c) { }
SQLITE_API int sqlite3changeset_apply(
sqlite3 *db,
int nChangeset,
void *pChangeset,
int(*xFilter)(
void *pCtx,
const char *zTab
),
int(*xConflict)(
void *pCtx,
int eConflict,
sqlite3_changeset_iter *p
),
void *pCtx
) { return 0; }
SQLITE_API int sqlite3changeset_apply_strm(
sqlite3 *db,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int(*xFilter)(
void *pCtx,
const char *zTab
),
int(*xConflict)(
void *pCtx,
int eConflict,
sqlite3_changeset_iter *p
),
void *pCtx
) { return 0; }
SQLITE_API int sqlite3changeset_concat_strm(
int (*xInputA)(void *pIn, void *pData, int *pnData),
void *pInA,
int (*xInputB)(void *pIn, void *pData, int *pnData),
void *pInB,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
) { return 0; }
SQLITE_API int sqlite3changeset_invert_strm(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
) { return 0; }
SQLITE_API int sqlite3changeset_start_strm(
sqlite3_changeset_iter **pp,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
) { return 0; }
SQLITE_API int sqlite3session_changeset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
) { return 0; }
SQLITE_API int sqlite3session_patchset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
) { return 0; }
int sqlite3changegroup_add_strm(sqlite3_changegroup *c,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
) { return 0; }
int sqlite3changegroup_output_strm(sqlite3_changegroup *c,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
) { return 0; }

81
jni/include/daemon.h Normal file
View File

@@ -0,0 +1,81 @@
/* 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,
LS_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);
void ls_hide_list(int client);
/*************
* Superuser *
*************/
void su_daemon_receiver(int client);
#endif

43
jni/include/list.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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);
struct list_head *list_pop(struct list_head *pos);
struct list_head *list_pop_end(struct list_head *head);
#define list_entry(pos, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (pos); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define list_for_each(ptr, head, type, member) \
ptr = list_entry((head)->next, type, member); \
for (struct list_head *__ = (head)->next; __ != (head); __ = __->next, ptr = list_entry(__, type, member))
#define list_for_each_r(ptr, head, type, member) \
ptr = list_entry((head)->prev, type, member); \
for (struct list_head *__ = (head)->prev; __ != (head); __ = __->prev, ptr = list_entry(__, type, member))
#define list_destory(head, type, member, func) ({ \
struct list_head *node = head->next; \
while(node != head) { \
node = node->next; \
if (func) func(list_entry(node->prev, line_list, pos)); \
free(list_entry(node->prev, line_list, pos)); \
} \
head->next = head; \
head->prev = head; \
})
#endif

91
jni/include/magisk.h Normal file
View File

@@ -0,0 +1,91 @@
/* 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 str(a) #a
#define xstr(a) str(a)
#define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK"
#define REQUESTOR_DAEMON_PATH "\0MAGISK"
#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 BBPATH MAGISKTMP "/bin"
#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 MAGISK_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 *[]);
// Multi-call entrypoints
int magiskhide_main(int argc, char *argv[]);
int magiskpolicy_main(int argc, char *argv[]);
int su_client_main(int argc, char *argv[]);
#ifdef __cplusplus
extern "C" {
#endif
int resetprop_main(int argc, char *argv[]);
#ifdef __cplusplus
}
#endif
#endif

View File

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

23
jni/include/resetprop.h Normal file
View File

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

109
jni/include/utils.h Normal file
View File

@@ -0,0 +1,109 @@
/* 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 xpipe2(int pipefd[2], int flags);
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 xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
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);
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 exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, ...);
int exec_command_sync(char *const argv0, ...);
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);
void fclone_attr(const int sourcefd, const int targetfd);
void clone_attr(const char *source, const char *target);
void get_client_cred(int fd, struct ucred *cred);
int switch_mnt_ns(int pid);
// img.c
#define round_size(a) ((((a) / 32) + 2) * 32)
#define SOURCE_TMP "/dev/source"
#define TARGET_TMP "/dev/target"
int create_img(const char *img, int size);
int get_img_size(const char *img, int *used, int *total);
int resize_img(const char *img, int size);
char *mount_image(const char *img, const char *target);
void umount_image(const char *target, const char *device);
int merge_img(const char *source, const char *target);
void trim_img(const char *img);
#endif

35
jni/include/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

View File

@@ -1,19 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := magiskboot
LOCAL_STATIC_LIBRARIES := libz liblzma liblz4 libbz2
LOCAL_C_INCLUDES := \
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
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

@@ -0,0 +1,97 @@
#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 cleanup() {
fprintf(stderr, "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);
}
}

310
jni/magiskboot/bootimg.c Normal file
View File

@@ -0,0 +1,310 @@
#include "bootimg.h"
#include "magiskboot.h"
static unsigned char *kernel, *ramdisk, *second, *dtb, *extra;
static boot_img_hdr hdr;
static int mtk_kernel = 0, mtk_ramdisk = 0;
static file_t ramdisk_type;
static void dump(unsigned char *buf, size_t size, const char *filename) {
int fd = open_new(filename);
xwrite(fd, buf, size);
close(fd);
}
static size_t restore(const char *filename, int fd) {
int ifd = xopen(filename, O_RDONLY);
size_t size = lseek(ifd, 0, SEEK_END);
lseek(ifd, 0, SEEK_SET);
xsendfile(fd, ifd, NULL, size);
close(ifd);
return size;
}
static void restore_buf(int fd, const void *buf, size_t size) {
xwrite(fd, buf, size);
}
static void print_info() {
fprintf(stderr, "KERNEL [%d] @ 0x%08x\n", hdr.kernel_size, hdr.kernel_addr);
fprintf(stderr, "RAMDISK [%d] @ 0x%08x\n", hdr.ramdisk_size, hdr.ramdisk_addr);
fprintf(stderr, "SECOND [%d] @ 0x%08x\n", hdr.second_size, hdr.second_addr);
fprintf(stderr, "DTB [%d] @ 0x%08x\n", hdr.dt_size, hdr.tags_addr);
fprintf(stderr, "PAGESIZE [%d]\n", hdr.page_size);
if (hdr.os_version != 0) {
int a,b,c,y,m = 0;
int os_version, os_patch_level;
os_version = hdr.os_version >> 11;
os_patch_level = hdr.os_version & 0x7ff;
a = (os_version >> 14) & 0x7f;
b = (os_version >> 7) & 0x7f;
c = os_version & 0x7f;
fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c);
y = (os_patch_level >> 4) + 2000;
m = os_patch_level & 0xf;
fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m);
}
fprintf(stderr, "NAME [%s]\n", hdr.name);
fprintf(stderr, "CMDLINE [%s]\n", hdr.cmdline);
switch (ramdisk_type) {
case GZIP:
fprintf(stderr, "COMPRESSION [%s]\n", "gzip");
break;
case XZ:
fprintf(stderr, "COMPRESSION [%s]\n", "xz");
break;
case LZMA:
fprintf(stderr, "COMPRESSION [%s]\n", "lzma");
break;
case BZIP2:
fprintf(stderr, "COMPRESSION [%s]\n", "bzip2");
break;
case LZ4:
fprintf(stderr, "COMPRESSION [%s]\n", "lz4");
break;
case LZ4_LEGACY:
fprintf(stderr, "COMPRESSION [%s]\n", "lz4_legacy");
break;
default:
fprintf(stderr, "Unknown ramdisk format!\n");
}
fprintf(stderr, "\n");
}
int parse_img(unsigned char *orig, size_t size) {
unsigned char *base, *end;
size_t pos = 0;
int ret = 0;
for(base = orig, end = orig + size; base < end; base += 256, size -= 256) {
switch (check_type(base)) {
case CHROMEOS:
// The caller should know it's chromeos, as it needs additional signing
ret = 2;
continue;
case ELF32:
exit(3);
case ELF64:
exit(4);
case AOSP:
// Read the header
memcpy(&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 ramdisk compression type
ramdisk_type = check_type(ramdisk);
// Check MTK
if (check_type(kernel) == MTK) {
fprintf(stderr, "MTK header found in kernel\n");
mtk_kernel = 1;
}
if (ramdisk_type == MTK) {
fprintf(stderr, "MTK header found in ramdisk\n");
mtk_ramdisk = 1;
ramdisk_type = check_type(ramdisk + 512);
}
// Print info
print_info();
return ret;
default:
continue;
}
}
LOGE(1, "No boot image magic found!\n");
}
void unpack(const char* image) {
size_t size;
unsigned char *orig;
mmap_ro(image, &orig, &size);
// Parse image
fprintf(stderr, "Parsing boot image: [%s]\n\n", image);
int ret = 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);
exit(ret);
}
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
fprintf(stderr, "Parsing boot image: [%s]\n\n", orig_image);
parse_img(orig, size);
fprintf(stderr, "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);
}

View File

@@ -16,17 +16,16 @@
#define LZ4_LEGACY_BLOCKSIZE 0x800000
static void write_file(const int fd, const void *buf, const size_t size, const char *filename) {
if (write(fd, buf, size) != size)
error(1, "Error in writing %s", 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);
fprintf(stderr, "Decompressing to [%s]\n\n", filename);
break;
default:
printf("Compressing to [%s]\n\n", filename);
fprintf(stderr, "Compressing to [%s]\n\n", filename);
break;
}
}
@@ -52,11 +51,11 @@ void gzip(int mode, const char* filename, const unsigned char* buf, size_t size)
ret = deflateInit2(&strm, 9, Z_DEFLATED, windowBits | ZLIB_GZIP, memLevel, Z_DEFAULT_STRATEGY);
break;
default:
error(1, "Unsupported gzip mode!");
LOGE(1, "Unsupported gzip mode!\n");
}
if (ret != Z_OK)
error(1, "Unable to init zlib stream");
LOGE(1, "Unable to init zlib stream\n");
do {
strm.next_in = buf + pos;
@@ -81,7 +80,7 @@ void gzip(int mode, const char* filename, const unsigned char* buf, size_t size)
break;
}
if (ret == Z_STREAM_ERROR)
error(1, "Error when running gzip");
LOGE(1, "Error when running gzip\n");
have = CHUNK - strm.avail_out;
write_file(fd, out, have, filename);
@@ -126,18 +125,18 @@ void lzma(int mode, const char* filename, const unsigned char* buf, size_t size)
ret = lzma_auto_decoder(&strm, UINT64_MAX, 0);
break;
case 1:
ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC64);
ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC32);
break;
case 2:
ret = lzma_alone_encoder(&strm, &opt);
break;
default:
error(1, "Unsupported lzma mode!");
LOGE(1, "Unsupported lzma mode!\n");
}
if (ret != LZMA_OK)
error(1, "Unable to init lzma stream");
LOGE(1, "Unable to init lzma stream\n");
do {
strm.next_in = buf + pos;
@@ -159,7 +158,7 @@ void lzma(int mode, const char* filename, const unsigned char* buf, size_t size)
} while (strm.avail_out == 0 && ret == LZMA_OK);
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
error(1, "LZMA error %d!", ret);
LOGE(1, "LZMA error %d!\n", ret);
} while (pos < size);
@@ -189,11 +188,11 @@ void lz4(int mode, const char* filename, const unsigned char* buf, size_t size)
ret = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
break;
default:
error(1, "Unsupported lz4 mode!");
LOGE(1, "Unsupported lz4 mode!\n");
}
if (LZ4F_isError(ret))
error(1, "Context creation error: %s\n", LZ4F_getErrorName(ret));
LOGE(1, "Context creation error: %s\n", LZ4F_getErrorName(ret));
// Allocate out buffer
switch(mode) {
@@ -202,7 +201,7 @@ void lz4(int mode, const char* filename, const unsigned char* buf, size_t size)
read = CHUNK;
ret = LZ4F_getFrameInfo(dctx, &info, buf, &read);
if (LZ4F_isError(ret))
error(1, "LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(ret));
LOGE(1, "LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(ret));
switch (info.blockSizeID) {
case LZ4F_default:
case LZ4F_max64KB: outCapacity = 1 << 16; break;
@@ -210,7 +209,7 @@ void lz4(int mode, const char* filename, const unsigned char* buf, size_t size)
case LZ4F_max1MB: outCapacity = 1 << 20; break;
case LZ4F_max4MB: outCapacity = 1 << 22; break;
default:
error(1, "Impossible unless more block sizes are allowed\n");
LOGE(1, "Impossible unless more block sizes are allowed\n");
}
pos += read;
break;
@@ -219,15 +218,13 @@ void lz4(int mode, const char* filename, const unsigned char* buf, size_t size)
break;
}
out = malloc(outCapacity);
if (!out)
error(1, "LZ4 malloc error!");
out = xmalloc(outCapacity);
// Write header
if (mode == 1) {
have = ret = LZ4F_compressBegin(cctx, out, size, NULL);
if (LZ4F_isError(ret))
error(1, "Failed to start compression: error %s\n", LZ4F_getErrorName(ret));
LOGE(1, "Failed to start compression: error %s\n", LZ4F_getErrorName(ret));
write_file(fd, out, have, filename);
}
@@ -250,7 +247,7 @@ void lz4(int mode, const char* filename, const unsigned char* buf, size_t size)
break;
}
if (LZ4F_isError(ret))
error(1, "LZ4 coding error: %s\n", LZ4F_getErrorName(ret));
LOGE(1, "LZ4 coding error: %s\n", LZ4F_getErrorName(ret));
write_file(fd, out, have, filename);
// Update status
@@ -267,7 +264,7 @@ void lz4(int mode, const char* filename, const unsigned char* buf, size_t size)
case 1:
have = ret = LZ4F_compressEnd(cctx, out, outCapacity, NULL);
if (LZ4F_isError(ret))
error(1, "Failed to end compression: error %s\n", LZ4F_getErrorName(ret));
LOGE(1, "Failed to end compression: error %s\n", LZ4F_getErrorName(ret));
write_file(fd, out, have, filename);
@@ -300,11 +297,11 @@ void bzip2(int mode, const char* filename, const unsigned char* buf, size_t size
ret = BZ2_bzCompressInit(&strm, 9, 0, 0);
break;
default:
error(1, "Unsupported bzip2 mode!");
LOGE(1, "Unsupported bzip2 mode!\n");
}
if (ret != BZ_OK)
error(1, "Unable to init bzlib stream");
LOGE(1, "Unable to init bzlib stream\n");
do {
strm.next_in = (char *) buf + pos;
@@ -361,22 +358,19 @@ void lz4_legacy(int mode, const char* filename, const unsigned char* buf, size_t
switch(mode) {
case 0:
out = malloc(LZ4_LEGACY_BLOCKSIZE);
out = xmalloc(LZ4_LEGACY_BLOCKSIZE);
// Skip magic
pos += 4;
break;
case 1:
out = malloc(LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE));
out = xmalloc(LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE));
// Write magic
write_file(fd, "\x02\x21\x4c\x18", 4, filename);
break;
default:
error(1, "Unsupported lz4_legacy mode!");
LOGE(1, "Unsupported lz4_legacy mode!\n");
}
if (!out)
error(1, "lz4_legacy malloc error");
do {
switch(mode) {
case 0:
@@ -386,10 +380,10 @@ void lz4_legacy(int mode, const char* filename, const unsigned char* buf, size_t
block_size += ((unsigned)buf[pos + 3])<<24;
pos += 4;
if (block_size > LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE))
error(1, "lz4_legacy block size too large!");
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)
error(1, "Cannot decode lz4_legacy block");
LOGE(1, "Cannot decode lz4_legacy block\n");
pos += block_size;
break;
case 1:
@@ -399,7 +393,7 @@ void lz4_legacy(int mode, const char* filename, const unsigned char* buf, size_t
insize = LZ4_LEGACY_BLOCKSIZE;
have = LZ4_compress_default((const char*) (buf + pos), out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE));
if (have == 0)
error(1, "lz4_legacy compression error");
LOGE(1, "lz4_legacy compression error\n");
pos += insize;
block_size_le[0] = (unsigned char)have;
block_size_le[1] = (unsigned char)(have >> 8);
@@ -496,7 +490,7 @@ void decomp_file(char *from, const char *to) {
char *ext;
ext = strrchr(from, '.');
if (ext == NULL)
error(1, "Bad filename extention");
LOGE(1, "Bad filename extention\n");
// File type and extension should match
switch (type) {
@@ -522,7 +516,7 @@ void decomp_file(char *from, const char *to) {
ok = 0;
break;
default:
error(1, "Provided file \'%s\' is not a supported archive format", from);
LOGE(1, "Provided file \'%s\' is not a supported archive format\n", from);
}
if (ok) {
// If all match, strip out the suffix
@@ -536,7 +530,7 @@ void decomp_file(char *from, const char *to) {
unlink(from);
}
} else {
error(1, "Bad filename extention \'%s\'", ext);
LOGE(1, "Bad filename extention \'%s\'\n", ext);
}
munmap(file, size);
}
@@ -556,7 +550,11 @@ void comp_file(const char *method, const char *from, const char *to) {
} else if (strcmp(method, "bzip2") == 0) {
type = BZIP2;
} else {
error(1, "Only support following methods: " SUP_LIST);
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;

View File

@@ -1,5 +1,7 @@
#include "magiskboot.h"
#include "cpio.h"
#include "vector.h"
#include "list.h"
static uint32_t x8u(char *hex) {
uint32_t val, inpos = 8, outpos;
@@ -12,7 +14,7 @@ static uint32_t x8u(char *hex) {
// Because scanf gratuitously treats %*X differently than printf does.
sprintf(pattern, "%%%dx%%n", inpos);
sscanf(hex, pattern, &val, &outpos);
if (inpos != outpos) error(1, "bad cpio header");
if (inpos != outpos) LOGE(1, "bad cpio header\n");
return val;
}
@@ -25,13 +27,13 @@ static void cpio_free(cpio_file *f) {
}
}
static void cpio_vec_insert(vector *v, cpio_file *n) {
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)[_i] = t;
vec_entry(v)[_] = t;
t = f;
continue;
}
@@ -39,11 +41,11 @@ static void cpio_vec_insert(vector *v, cpio_file *n) {
if (strcmp(f->filename, n->filename) == 0) {
// Replace, then all is done
cpio_free(f);
vec_entry(v)[_i] = n;
vec_entry(v)[_] = n;
return;
} else if (strcmp(f->filename, n->filename) > 0) {
// Insert, then start shifting
vec_entry(v)[_i] = n;
vec_entry(v)[_] = n;
t = f;
shift = 1;
}
@@ -59,15 +61,13 @@ static int cpio_compare(const void *a, const void *b) {
}
// Parse cpio file to a vector of cpio_file
static void parse_cpio(const char *filename, vector *v) {
printf("Loading cpio: [%s]\n\n", filename);
int fd = open(filename, O_RDONLY);
if (fd < 0)
error(1, "Cannot open %s", filename);
static void parse_cpio(const char *filename, struct vector *v) {
fprintf(stderr, "Loading cpio: [%s]\n\n", filename);
int fd = xopen(filename, O_RDONLY);
cpio_newc_header header;
cpio_file *f;
while(read(fd, &header, 110) == 110) {
f = calloc(sizeof(*f), 1);
f = xcalloc(sizeof(*f), 1);
// f->ino = x8u(header.ino);
f->mode = x8u(header.mode);
f->uid = x8u(header.uid);
@@ -82,7 +82,7 @@ static void parse_cpio(const char *filename, vector *v) {
f->namesize = x8u(header.namesize);
// f->check = x8u(header.check);
f->filename = malloc(f->namesize);
read(fd, f->filename, 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);
@@ -94,7 +94,7 @@ static void parse_cpio(const char *filename, vector *v) {
}
if (f->filesize) {
f->data = malloc(f->filesize);
read(fd, f->data, f->filesize);
xxread(fd, f->data, f->filesize);
file_align(fd, 4, 0);
}
vec_push_back(v, f);
@@ -104,8 +104,8 @@ static void parse_cpio(const char *filename, vector *v) {
vec_sort(v, cpio_compare);
}
static void dump_cpio(const char *filename, vector *v) {
printf("\nDump cpio: [%s]\n\n", filename);
static void dump_cpio(const char *filename, struct vector *v) {
fprintf(stderr, "\nDump cpio: [%s]\n\n", filename);
int fd = open_new(filename);
unsigned inode = 300000;
char header[111];
@@ -127,23 +127,23 @@ static void dump_cpio(const char *filename, vector *v) {
f->namesize,
0 // f->check
);
write(fd, header, 110);
write(fd, f->filename, f->namesize);
xwrite(fd, header, 110);
xwrite(fd, f->filename, f->namesize);
file_align(fd, 4, 1);
if (f->filesize) {
write(fd, f->data, 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);
write(fd, header, 110);
write(fd, "TRAILER!!!\0", 11);
xwrite(fd, header, 110);
xwrite(fd, "TRAILER!!!\0", 11);
file_align(fd, 4, 1);
close(fd);
}
static void cpio_vec_destroy(vector *v) {
static void cpio_vec_destroy(struct vector *v) {
// Free each cpio_file
cpio_file *f;
vec_for_each(v, f) {
@@ -152,13 +152,13 @@ static void cpio_vec_destroy(vector *v) {
vec_destroy(v);
}
static void cpio_rm(int recursive, const char *entry, vector *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);
fprintf(stderr, "Remove [%s]\n", entry);
f->remove = 1;
}
if (!recursive) return;
@@ -166,48 +166,48 @@ static void cpio_rm(int recursive, const char *entry, vector *v) {
}
}
static void cpio_mkdir(mode_t mode, const char *entry, vector *v) {
cpio_file *f = calloc(sizeof(*f), 1);
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 = malloc(f->namesize);
f->filename = xmalloc(f->namesize);
memcpy(f->filename, entry, f->namesize);
cpio_vec_insert(v, f);
printf("Create directory [%s] (%04o)\n",entry, mode);
fprintf(stderr, "Create directory [%s] (%04o)\n",entry, mode);
}
static void cpio_add(mode_t mode, const char *entry, const char *filename, vector *v) {
int fd = open(filename, O_RDONLY);
if (fd < 0)
error(1, "Cannot open %s", filename);
cpio_file *f = calloc(sizeof(*f), 1);
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 = malloc(f->namesize);
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);
read(fd, f->data, f->filesize);
xxread(fd, f->data, f->filesize);
close(fd);
cpio_vec_insert(v, f);
printf("Add entry [%s] (%04o)\n", entry, mode);
fprintf(stderr, "Add entry [%s] (%04o)\n", entry, mode);
}
static void cpio_test(vector *v) {
static void cpio_test(struct vector *v) {
#define MAGISK_PATCH 0x1
#define SUPERSU_PATCH 0x2
#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) {
if (strcmp(f->filename, "sbin/launch_daemonsu.sh") == 0) {
ret |= SUPERSU_PATCH;
} else if (strcmp(f->filename, "init.magisk.rc") == 0) {
ret |= MAGISK_PATCH;
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 & SUPERSU_PATCH) ? SUPERSU_PATCH : (ret & MAGISK_PATCH));
exit((ret & OTHER_PATCH) ? OTHER_PATCH : (ret & MAGISK_PATCH));
}
static int check_verity_pattern(const char *s) {
@@ -221,76 +221,137 @@ static int check_verity_pattern(const char *s) {
return pos;
}
static void cpio_dmverity(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 struct list_head *block_to_list(char *data) {
struct list_head *head = xmalloc(sizeof(*head));
line_list *line;
init_list_head(head);
char *tok;
tok = strsep(&data, "\n");
while (tok) {
line = xcalloc(sizeof(*line), 1);
line->line = tok;
list_insert_end(head, &line->pos);
tok = strsep(&data, "\n");
}
return head;
}
static void cpio_forceencrypt(vector *v) {
static char *list_to_block(struct list_head *head, uint32_t filesize) {
line_list *line;
char *data = xmalloc(filesize);
uint32_t off = 0;
list_for_each(line, head, line_list, pos) {
strcpy(data + off, line->line);
off += strlen(line->line);
data[off++] = '\n';
}
return data;
}
static void free_newline(line_list *line) {
if (line->isNew)
free(line->line);
}
static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
struct list_head *head;
line_list *line;
cpio_file *f;
int skip, injected = 0;
size_t read, write;
#define ENCRYPT_LIST_SIZE 2
const char *ENCRYPT_LIST[ENCRYPT_LIST_SIZE] = { "forceencrypt", "forcefdeorfbe" };
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 ; i < ENCRYPT_LIST_SIZE; ++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;
if (strcmp(f->filename, "init.rc") == 0) {
head = block_to_list(f->data);
list_for_each(line, head, line_list, pos) {
if (strstr(line->line, "import")) {
if (strstr(line->line, "init.magisk.rc"))
injected = 1;
if (injected)
continue;
// Inject magisk script as import
fprintf(stderr, "Inject new line [import /init.magisk.rc] in [init.rc]\n");
line = xcalloc(sizeof(*line), 1);
line->line = strdup("import /init.magisk.rc");
line->isNew = 1;
f->filesize += 23;
list_insert(__->prev, &line->pos);
injected = 1;
} else if (strstr(line->line, "selinux.reload_policy")) {
// Remove this line
fprintf(stderr, "Remove line [%s] in [init.rc]\n", line->line);
f->filesize -= strlen(line->line) + 1;
__ = list_pop(&line->pos);
free(line);
}
}
char *temp = list_to_block(head, f->filesize);
free(f->data);
f->data = temp;
list_destory(head, list_head, pos, free_newline);
free(head);
} else {
if (!keepverity) {
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) {
fprintf(stderr, "Remove pattern [%.*s] in [%s]\n", skip, f->data + read, f->filename);
read += skip;
}
f->data[write] = f->data[read];
}
f->filesize = write;
} else if (strcmp(f->filename, "verity_key") == 0) {
fprintf(stderr, "Remove [verity_key]\n");
f->remove = 1;
}
}
if (!keepforceencrypt) {
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
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);
fprintf(stderr, "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;
}
f->data[write] = f->data[read];
}
f->filesize = write;
}
}
}
static void cpio_extract(const char *entry, const char *filename, vector *v) {
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);
fprintf(stderr, "Extracting [%s] to [%s]\n\n", entry, filename);
int fd = open_new(filename);
write(fd, f->data, f->filesize);
xwrite(fd, f->data, f->filesize);
fchmod(fd, f->mode);
fchown(fd, f->uid, f->gid);
close(fd);
exit(0);
}
}
error(1, "Cannot find the file entry [%s]", entry);
LOGE(1, "Cannot find the file entry [%s]\n", entry);
}
static void cpio_backup(const char *orig, vector *v) {
vector o_body, *o = &o_body, bak;
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 chk1[21], chk2[21], buf[PATH_MAX];
char buf[PATH_MAX];
int res, doBak;
dir = calloc(sizeof(*dir), 1);
rem = calloc(sizeof(*rem), 1);
dir = xcalloc(sizeof(*dir), 1);
rem = xcalloc(sizeof(*rem), 1);
vec_init(o);
vec_init(&bak);
// First push back the directory and the rmlist
@@ -329,28 +390,29 @@ static void cpio_backup(const char *orig, vector *v) {
// Something is missing in new ramdisk, backup!
++i;
doBak = 1;
printf("Entry [%s] is missing\n", m->filename);
fprintf(stderr, "Backup missing entry: ");
} else if (res == 0) {
++i; ++j;
if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0)
continue;
// Not the same!
doBak = 1;
printf("Entry [%s] missmatch\n", m->filename);
fprintf(stderr, "Backup mismatch entry: ");
} else {
// Someting new in ramdisk, record in rem
++j;
if (n->remove) continue;
rem->data = realloc(rem->data, rem->filesize + n->namesize);
rem->data = xrealloc(rem->data, rem->filesize + n->namesize);
memcpy(rem->data + rem->filesize, n->filename, n->namesize);
rem->filesize += n->namesize;
printf("Entry [%s] is new\n", n->filename);
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", n->filename);
}
if (doBak) {
m->namesize += 8;
m->filename = realloc(m->filename, m->namesize);
strcpy(buf, m->filename);
sprintf(m->filename, ".backup/%s", buf);
fprintf(stderr, "[%s] -> [%s]\n", buf, m->filename);
vec_push_back(&bak, m);
// NULL the original entry, so it won't be freed
vec_entry(o)[i - 1] = NULL;
@@ -376,7 +438,7 @@ static void cpio_backup(const char *orig, vector *v) {
cpio_vec_destroy(o);
}
static int cpio_restore(vector *v) {
static int cpio_restore(struct vector *v) {
cpio_file *f, *n;
int ret = 1;
vec_for_each(v, f) {
@@ -389,15 +451,15 @@ static int cpio_restore(vector *v) {
cpio_rm(0, f->data + pos, v);
continue;
}
n = calloc(sizeof(*n), 1);
n = xcalloc(sizeof(*n), 1);
memcpy(n, f, sizeof(*f));
n->namesize -= 8;
n->filename = malloc(n->namesize);
n->filename = xmalloc(n->namesize);
memcpy(n->filename, f->filename + 8, n->namesize);
n->data = malloc(n->filesize);
n->data = xmalloc(n->filesize);
memcpy(n->data, f->data, n->filesize);
n->remove = 0;
printf("Restoring [%s] -> [%s]\n", f->filename, n->filename);
fprintf(stderr, "Restoring [%s] -> [%s]\n", f->filename, n->filename);
cpio_vec_insert(v, n);
}
}
@@ -408,6 +470,24 @@ static int cpio_restore(vector *v) {
return ret;
}
static void cpio_stocksha1(struct vector *v) {
cpio_file *f;
char sha1[41];
vec_for_each(v, f) {
if (strcmp(f->filename, "init.magisk.rc") == 0) {
for (char *pos = f->data; pos < f->data + f->filesize; pos = strchr(pos + 1, '\n') + 1) {
if (memcmp(pos, "# STOCKSHA1=", 12) == 0) {
pos += 12;
memcpy(sha1, pos, 40);
sha1[40] = '\0';
printf("%s\n", sha1);
return;
}
}
}
}
}
int cpio_commands(const char *command, int argc, char *argv[]) {
int recursive = 0, ret = 0;
command_t cmd;
@@ -416,12 +496,10 @@ int cpio_commands(const char *command, int argc, char *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 (strcmp(command, "stocksha1") == 0) {
cmd = STOCKSHA1;
} else if (argc == 1 && strcmp(command, "backup") == 0) {
cmd = BACKUP;
} else if (argc > 0 && strcmp(command, "rm") == 0) {
@@ -431,6 +509,8 @@ int cpio_commands(const char *command, int argc, char *argv[]) {
++argv;
--argc;
}
} else if (argc == 2 && strcmp(command, "patch") == 0) {
cmd = PATCH;
} else if (argc == 2 && strcmp(command, "extract") == 0) {
cmd = EXTRACT;
} else if (argc == 2 && strcmp(command, "mkdir") == 0) {
@@ -439,41 +519,39 @@ int cpio_commands(const char *command, int argc, char *argv[]) {
cmd = ADD;
} else {
cmd = NONE;
return 1;
}
vector v;
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;
case TEST:
cpio_test(&v);
break;
case RESTORE:
ret = cpio_restore(&v);
break;
case STOCKSHA1:
cpio_stocksha1(&v);
return 0;
case BACKUP:
cpio_backup(argv[0], &v);
case RM:
cpio_rm(recursive, argv[0], &v);
break;
case PATCH:
cpio_patch(&v, strcmp(argv[0], "true") == 0, strcmp(argv[1], "true") == 0);
break;
case EXTRACT:
cpio_extract(argv[0], argv[1], &v);
break;
case MKDIR:
cpio_mkdir(strtoul(argv[0], NULL, 8), argv[1], &v);
break;
case ADD:
cpio_add(strtoul(argv[0], NULL, 8), argv[1], argv[2], &v);
break;
case NONE:
return 1;
}
dump_cpio(incpio, &v);
cpio_vec_destroy(&v);

View File

@@ -3,6 +3,8 @@
#include <stdint.h>
#include "list.h"
typedef struct cpio_file {
// uint32_t ino;
uint32_t mode;
@@ -22,6 +24,12 @@ typedef struct cpio_file {
int remove;
} cpio_file;
typedef struct line_list {
char *line;
int isNew;
struct list_head pos;
} line_list;
typedef struct cpio_newc_header {
char magic[6];
char ino[8];

View File

@@ -1,151 +0,0 @@
#ifndef _ELF_H_
#define _ELF_H_
#include <stdint.h>
/*
** ELF structure
**
** +-----------------+
** | ELF magic | | 4 bytes
** +------------ +
** | ELF class | | 1 byte
** +------------ +
** | ELF header |
** +-----------------+
** ~
** +-----------------+
** | program header | kernel info
** +-----------------+
** | program header | ramdisk info
** +-----------------+
** | program header | dtb info
** +-----------------+
** | program header | (possible) cmdline info
** +-----------------+
** ~
** +-----------------+
** | section header | cmdline info
** +-----------------+
** ~
** +-----------------+
** | |
** | Data |
** | |
** +-----------------+
*/
typedef uint32_t elf32_addr;
typedef uint16_t elf32_half;
typedef uint32_t elf32_off;
typedef uint32_t elf32_word;
typedef uint64_t elf64_addr;
typedef uint16_t elf64_half;
typedef uint64_t elf64_off;
typedef uint32_t elf64_word;
typedef uint64_t elf64_xword;
#define ELF_MAGIC "\x7f""ELF"
#define ELF_MAGIC_SIZE 4
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_OSABI 7
#define EI_PAD 8
#define ELFCLASSNONE 0
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFCLASSNUM 3
#define ET_EXEC 2
#define EM_ARM 40
#define EI_NIDENT 16
typedef struct elf32_ehdr {
unsigned char e_ident[EI_NIDENT];
elf32_half e_type;
elf32_half e_machine;
elf32_word e_version;
elf32_addr e_entry; /* Entry point */
elf32_off e_phoff;
elf32_off e_shoff;
elf32_word e_flags;
elf32_half e_ehsize;
elf32_half e_phentsize;
elf32_half e_phnum;
elf32_half e_shentsize;
elf32_half e_shnum;
elf32_half e_shstrndx;
} elf32_ehdr;
typedef struct elf64_ehdr {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
elf64_half e_type;
elf64_half e_machine;
elf64_word e_version;
elf64_addr e_entry; /* Entry point virtual address */
elf64_off e_phoff; /* Program header table file offset */
elf64_off e_shoff; /* Section header table file offset */
elf64_word e_flags;
elf64_half e_ehsize;
elf64_half e_phentsize;
elf64_half e_phnum;
elf64_half e_shentsize;
elf64_half e_shnum;
elf64_half e_shstrndx;
} elf64_ehdr;
typedef struct elf32_phdr {
elf32_word p_type;
elf32_off p_offset;
elf32_addr p_vaddr;
elf32_addr p_paddr;
elf32_word p_filesz;
elf32_word p_memsz;
elf32_word p_flags;
elf32_word p_align;
} elf32_phdr;
typedef struct elf64_phdr {
elf64_word p_type;
elf64_word p_flags;
elf64_off p_offset; /* Segment file offset */
elf64_addr p_vaddr; /* Segment virtual address */
elf64_addr p_paddr; /* Segment physical address */
elf64_xword p_filesz; /* Segment size in file */
elf64_xword p_memsz; /* Segment size in memory */
elf64_xword p_align; /* Segment alignment, file & memory */
} elf64_phdr;
typedef struct elf32_shdr {
elf32_word s_name;
elf32_word s_type;
elf32_word s_flags;
elf32_addr s_addr;
elf32_off s_offset;
elf32_word s_size;
elf32_word s_link;
elf32_word s_info;
elf32_word s_addralign;
elf32_word s_entsize;
} elf32_shdr;
typedef struct elf64_shdr {
elf64_word s_name; /* Section name, index in string tbl */
elf64_word s_type; /* Type of section */
elf64_xword s_flags; /* Miscellaneous section attributes */
elf64_addr s_addr; /* Section virtual addr at execution */
elf64_off s_offset; /* Section file offset */
elf64_xword s_size; /* Size of section in bytes */
elf64_word s_link; /* Index of another section */
elf64_word s_info; /* Additional section information */
elf64_xword s_addralign; /* Section alignment */
elf64_xword s_entsize; /* Entry size if section holds table */
} elf64_shdr;
#endif

View File

@@ -14,13 +14,13 @@ void hexpatch(const char *image, const char *from, const char *to) {
size_t filesize;
unsigned char *file, *pattern, *patch;
mmap_rw(image, &file, &filesize);
pattern = malloc(patternsize);
patch = malloc(patchsize);
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);
fprintf(stderr, "Pattern %s found!\nPatching to %s\n", from, to);
memset(file + i, 0, patternsize);
memcpy(file + i, patch, patchsize);
i += patternsize - 1;

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

View File

@@ -8,28 +8,34 @@
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.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 CHROMEOS_MAGIC_SIZE 8
#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 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,
ELF,
ELF32,
ELF64,
GZIP,
LZOP,
XZ,
@@ -37,8 +43,7 @@ typedef enum {
BZIP2,
LZ4,
LZ4_LEGACY,
MTK,
QCDT,
MTK
} file_t;
typedef enum {
@@ -48,52 +53,21 @@ typedef enum {
ADD,
EXTRACT,
TEST,
DMVERITY,
FORCEENCRYPT,
PATCH,
BACKUP,
RESTORE
RESTORE,
STOCKSHA1
} command_t;
#define SUP_LIST "gzip, xz, lzma, bzip2, lz4, lz4_legacy"
#define SUP_NUM 6
// Cannot declare in header, but place a copy here for convenience
// char *SUP_EXT_LIST[SUP_NUM] = { "gz", "xz", "lzma", "bz2", "lz4", "lz4" };
// file_t SUP_TYPE_LIST[SUP_NUM] = { GZIP, XZ, LZMA, BZIP2, LZ4, LZ4_LEGACY };
extern char *SUP_EXT_LIST[SUP_NUM];
extern file_t SUP_TYPE_LIST[SUP_NUM];
// Vector
typedef struct vector {
size_t size;
size_t cap;
void **data;
} vector;
void vec_init(vector *v);
void vec_push_back(vector *v, void *p);
void vec_sort(vector *v, int (*compar)(const void *, const void *));
void vec_destroy(vector *v);
#define vec_size(v) (v)->size
#define vec_cap(v) (v)->cap
#define vec_entry(v) (v)->data
// vec_for_each(vector *v, void *e)
#define vec_for_each(v, e) \
e = (v)->data[0]; \
for (size_t _i = 0; _i < (v)->size; ++_i, e = (v)->data[_i])
// Global variables
extern unsigned char *kernel, *ramdisk, *second, *dtb, *extra;
extern boot_img_hdr hdr;
extern file_t boot_type, ramdisk_type, dtb_type;
extern int mtk_kernel, mtk_ramdisk;
extern char *SUP_LIST[];
extern char *SUP_EXT_LIST[];
extern file_t SUP_TYPE_LIST[];
// 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 error(int rc, const char *msg, ...);
void parse_img(unsigned char *orig, size_t size);
int parse_img(unsigned char *orig, size_t size);
int cpio_commands(const char *command, int argc, char *argv[]);
void cleanup();
@@ -116,6 +90,5 @@ 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

View File

@@ -5,65 +5,61 @@
*********************/
static void usage(char *arg0) {
fprintf(stderr, "%s --unpack <bootimg>\n", arg0);
fprintf(stderr, " Unpack <bootimg> to kernel, ramdisk.cpio, (second), (dtb) into the\n current directory\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s --repack <origbootimg> [outbootimg]\n", arg0);
fprintf(stderr, " Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory\n");
fprintf(stderr, " to [outbootimg], or new-boot.img if not specified.\n");
fprintf(stderr, " It will compress ramdisk.cpio with the same method used in <origbootimg>\n");
fprintf(stderr, " if exists, or attempt to find ramdisk.cpio.[ext], and repack\n");
fprintf(stderr, " directly with the compressed ramdisk file\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s --hexpatch <file> <hexpattern1> <hexpattern2>\n", arg0);
fprintf(stderr, " Search <hexpattern1> in <file>, and replace with <hexpattern2>\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s --cpio-<cmd> <incpio> [flags...] [params...]\n", arg0);
fprintf(stderr, " Do cpio related cmds to <incpio> (modifications are done directly)\n Supported commands:\n");
fprintf(stderr, " --cpio-rm <incpio> [-r] <entry>\n Remove entry from cpio, flag -r to remove recursively\n");
fprintf(stderr, " --cpio-mkdir <incpio> <mode> <entry>\n Create directory as an <entry>\n");
fprintf(stderr, " --cpio-add <incpio> <mode> <entry> <infile>\n Add <infile> as an <entry>; replaces <entry> if already exists\n");
fprintf(stderr, " --cpio-extract <incpio> <entry> <outfile>\n Extract <entry> to <outfile>\n");
fprintf(stderr, " --cpio-test <incpio>\n Return value: 0/not patched 1/Magisk 2/SuperSU\n");
fprintf(stderr, " --cpio-patch-dmverity <incpio>\n Remove dm-verity\n");
fprintf(stderr, " --cpio-patch-forceencrypt <incpio>\n Change forceencrypt flag to encryptable\n");
fprintf(stderr, " --cpio-backup <incpio> <origcpio>\n Create ramdisk backups into <incpio> from <origcpio>\n");
fprintf(stderr, " --cpio-restore <incpio>\n Restore ramdisk from ramdisk backup within <incpio>\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s --compress[=method] <infile> [outfile]\n", arg0);
fprintf(stderr, " Compress <infile> with [method] (default: gzip), optionally to [outfile]\n Supported methods: " SUP_LIST "\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s --decompress <infile> [outfile]\n", arg0);
fprintf(stderr, " Detect method and decompress <infile>, optionally to [outfile]\n Supported methods: " SUP_LIST "\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s --sha1 <file>\n", arg0);
fprintf(stderr, " Print the SHA1 checksum for <file>\n");
fprintf(stderr, "\n");
fprintf(stderr, "%s --cleanup\n", arg0);
fprintf(stderr, " Cleanup the current working directory\n");
fprintf(stderr, "\n");
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 and params:\n"
" -rm [-r] <entry>\n Remove entry from <incpio>, flag -r to remove recursively\n"
" -mkdir <mode> <entry>\n Create directory as an <entry>\n"
" -add <mode> <entry> <infile>\n Add <infile> as an <entry>; replaces <entry> if already exists\n"
" -extract <entry> <outfile>\n Extract <entry> to <outfile>\n"
" -test \n Return value: 0/not patched 1/Magisk 2/Other (e.g. phh, SuperSU)\n"
" -patch <KEEPVERITY> <KEEPFORCEENCRYPT>\n Patch cpio for Magisk. KEEP**** are true/false values\n"
" -backup <origcpio>\n Create ramdisk backups into <incpio> from <origcpio>\n"
" -restore\n Restore ramdisk from ramdisk backup within <incpio>\n"
" -stocksha1\n Get stock boot SHA1 recorded 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);
}
void error(int rc, const char *msg, ...) {
va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
fprintf(stderr,"\n\n");
va_end(ap);
exit(rc);
}
int main(int argc, char *argv[]) {
printf("MagiskBoot (by topjohnwu) - Boot Image Modification Tool\n\n");
fprintf(stderr, "MagiskBoot v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Boot Image Modification Tool\n\n");
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
cleanup();

View File

@@ -1,253 +0,0 @@
#include "bootimg.h"
#include "elf.h"
#include "magiskboot.h"
unsigned char *kernel, *ramdisk, *second, *dtb, *extra;
boot_img_hdr hdr;
int mtk_kernel = 0, mtk_ramdisk = 0;
file_t boot_type, ramdisk_type, dtb_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);
}
// Check dtb if ELF boot
if (boot_type == ELF && hdr.dt_size) {
dtb_type = check_type(dtb);
}
// Print info
print_info();
}
static void elf_header_check(void *elf, int is64) {
size_t e_size, mach, ver, p_size, p_num, s_size, s_num;
size_t r_e_size, r_p_size, r_s_size;
if (is64) {
e_size = ((elf64_ehdr *) elf)->e_ehsize;
mach = ((elf64_ehdr *) elf)->e_machine;
ver = ((elf64_ehdr *) elf)->e_version;
p_size = ((elf64_ehdr *) elf)->e_phentsize;
p_num = ((elf64_ehdr *) elf)->e_phnum;
s_size = ((elf64_ehdr *) elf)->e_shentsize;
s_num = ((elf64_ehdr *) elf)->e_shnum;
r_e_size = sizeof(elf64_ehdr);
r_p_size = sizeof(elf64_phdr);
r_s_size = sizeof(elf64_shdr);
} else {
e_size = ((elf32_ehdr *) elf)->e_ehsize;
mach = ((elf32_ehdr *) elf)->e_machine;
ver = ((elf32_ehdr *) elf)->e_version;
p_size = ((elf32_ehdr *) elf)->e_phentsize;
p_num = ((elf32_ehdr *) elf)->e_phnum;
s_size = ((elf32_ehdr *) elf)->e_shentsize;
s_num = ((elf32_ehdr *) elf)->e_shnum;
r_e_size = sizeof(elf32_ehdr);
r_p_size = sizeof(elf32_phdr);
r_s_size = sizeof(elf32_shdr);
}
if (e_size != r_e_size)
error(1, "Header size not %d", r_e_size);
if (mach != EM_ARM)
error(1, "ELF machine is not ARM");
if (ver != 1)
error(1, "Unknown ELF version");
if (p_size != r_p_size)
error(1, "Program header size not %d", r_p_size);
if (p_num < 2 || p_num > 4)
error(1, "Unexpected number of elements: %d", p_num);
if (s_num && s_size != r_s_size)
error(1, "Section header size not %d", r_s_size);
if (s_num > 1)
error(1, "More than one section header");
}
static void elf_set(int i, unsigned char *base, size_t size, size_t offset, size_t addr) {
if (size <= 4096) {
// Possible cmdline
memset(hdr.cmdline, 0, BOOT_ARGS_SIZE);
strncpy((char *) hdr.cmdline, (char *) (base + offset), BOOT_ARGS_SIZE);
hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0';
return;
}
switch(i) {
case 0:
// kernel
kernel = base + offset;
hdr.kernel_size = size;
hdr.kernel_addr = addr;
break;
case 1:
// ramdisk
ramdisk = base + offset;
hdr.ramdisk_size = size;
hdr.ramdisk_addr = addr;
break;
case 2:
// dtb
dtb = base + offset;
hdr.dt_size = size;
hdr.tags_addr = addr;
break;
}
}
static void parse_elf(unsigned char *base) {
// Reset boot image header
memset(&hdr, 0, sizeof(hdr));
// Hardcode header magic and pagesize
memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
hdr.page_size = 4096;
switch(base[EI_CLASS]) {
case ELFCLASS32: {
elf32_ehdr *elf32;
elf32_phdr *ph32;
elf32_shdr *sh32;
printf("IMAGE [ELF32]\n");
elf32 = (elf32_ehdr *) base;
elf_header_check(elf32, 0);
ph32 = (elf32_phdr *) (base + elf32->e_phoff);
sh32 = (elf32_shdr *) (base + elf32->e_shoff);
for (int i = 0; i < elf32->e_phnum; ++i) {
elf_set(i, base, ph32[i].p_filesz, ph32[i].p_offset, ph32[i].p_paddr);
}
if (elf32->e_shnum) {
// cmdline
memset(hdr.cmdline, 0, BOOT_ARGS_SIZE);
strncpy((char *) hdr.cmdline, (char *) (base + sh32->s_offset + 8), BOOT_ARGS_SIZE);
hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0';
}
break;
}
case ELFCLASS64: {
elf64_ehdr *elf64;
elf64_phdr *ph64;
elf64_shdr *sh64;
printf("IMAGE [ELF64]\n");
elf64 = (elf64_ehdr *) base;
elf_header_check(elf64, 1);
ph64 = (elf64_phdr *) (base + elf64->e_phoff);
sh64 = (elf64_shdr *) (base + elf64->e_shoff);
for (int i = 0; i < elf64->e_phnum; ++i) {
elf_set(i, base, ph64[i].p_filesz, ph64[i].p_offset, ph64[i].p_paddr);
}
if (elf64->e_shnum) {
// cmdline
memset(hdr.cmdline, 0, BOOT_ARGS_SIZE);
strncpy((char *) hdr.cmdline, (char *) (base + sh64->s_offset + 8), BOOT_ARGS_SIZE);
hdr.cmdline[strcspn((char*) hdr.cmdline, "\n")] = '\0';
}
break;
}
default:
error(1, "ELF format error!");
}
check_headers();
}
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:
boot_type = CHROMEOS;
continue;
case AOSP:
// Don't override CHROMEOS
if (boot_type != CHROMEOS)
boot_type = AOSP;
parse_aosp(base, size);
return;
case ELF:
boot_type = ELF;
parse_elf(base);
return;
default:
continue;
}
}
error(1, "No boot image magic found!");
}

View File

@@ -1,146 +0,0 @@
#include "magiskboot.h"
static size_t restore(const char *filename, int fd) {
int ifd = open(filename, O_RDONLY);
if (ifd < 0)
error(1, "Cannot open %s\n", filename);
size_t size = lseek(ifd, 0, SEEK_END);
lseek(ifd, 0, SEEK_SET);
if (sendfile(fd, ifd, NULL, size) != size) {
error(1, "Cannot write %s\n", filename);
}
close(ifd);
return size;
}
static void restore_buf(int fd, const void *buf, size_t size) {
if (write(fd, buf, size) != size) {
error(1, "Cannot dump from input file\n");
}
}
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; i < SUP_NUM; ++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))
error(1, "Unsupported ramdisk format!");
munmap(cpio, cpio_size);
}
int found = 0;
for (int i = 0; i < SUP_NUM; ++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)
error(1, "No ramdisk exists!");
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);
if (lseek(fd, 0, SEEK_END) > size) {
error(2, "Boot partition too small!");
}
close(fd);
}

View File

@@ -1,64 +0,0 @@
#include "magiskboot.h"
static void dump(unsigned char *buf, size_t size, const char *filename) {
int fd = open_new(filename);
if (write(fd, buf, size) != size)
error(1, "Cannot dump %s", filename);
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);
if (boot_type == CHROMEOS) {
// The caller should know it's chromeos, as it needs additional signing
dump(orig, 0, "chromeos");
}
char name[PATH_MAX];
// 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");
error(1, "Unsupported ramdisk format! Dumped to %s", RAMDISK_FILE ".unsupport");
}
if (hdr.second_size) {
// Dump second
dump(second, hdr.second_size, SECOND_FILE);
}
if (hdr.dt_size) {
if (boot_type == ELF && (dtb_type != QCDT && dtb_type != ELF)) {
printf("Non QC dtb found in ELF kernel, recreate kernel\n");
gzip(1, KERNEL_FILE, kernel, hdr.kernel_size);
int kfp = open(KERNEL_FILE, O_WRONLY | O_APPEND);
write(kfp, dtb, hdr.dt_size);
close(kfp);
} else {
// Dump dtb
dump(dtb, hdr.dt_size, DTB_FILE);
}
}
munmap(orig, size);
}

View File

@@ -1,182 +0,0 @@
#include "magiskboot.h"
#include "elf.h"
char *SUP_EXT_LIST[SUP_NUM] = { "gz", "xz", "lzma", "bz2", "lz4", "lz4" };
file_t SUP_TYPE_LIST[SUP_NUM] = { GZIP, XZ, LZMA, BZIP2, LZ4, LZ4_LEGACY };
void mmap_ro(const char *filename, unsigned char **buf, size_t *size) {
int fd = open(filename, O_RDONLY);
if (fd < 0)
error(1, "Cannot open %s", filename);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0);
close(fd);
}
void mmap_rw(const char *filename, unsigned char **buf, size_t *size) {
int fd = open(filename, O_RDWR);
if (fd < 0)
error(1, "Cannot open %s", filename);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = mmap(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, CHROMEOS_MAGIC_SIZE) == 0) {
return CHROMEOS;
} else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
return AOSP;
} else if (memcmp(buf, ELF_MAGIC, ELF_MAGIC_SIZE) == 0) {
return ELF;
} 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 if (memcmp(buf, "QCDT", 4) == 0) {
return QCDT;
} 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) {
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0)
error(1, "Unable to create %s", filename);
return fd;
}
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);
unlink(NEW_BOOT);
for (int i = 0; i < SUP_NUM; ++i) {
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
unlink(name);
}
}
void vec_init(vector *v) {
vec_size(v) = 0;
vec_cap(v) = 1;
vec_entry(v) = malloc(sizeof(void*));
}
void vec_push_back(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_sort(vector *v, int (*compar)(const void *, const void *)) {
qsort(vec_entry(v), vec_size(v), sizeof(void*), compar);
}
void vec_destroy(vector *v) {
// Will not free each entry!
// Manually free each entry, then call this function
vec_size(v) = 0;
vec_cap(v) = 0;
free(v->data);
}

View File

@@ -1,6 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := magiskhide
LOCAL_SRC_FILES := main.c hide.c list_monitor.c proc_monitor.c util.c
include $(BUILD_EXECUTABLE)

View File

@@ -1,78 +0,0 @@
#include "magiskhide.h"
int hideMagisk() {
close(pipefd[1]);
int pid, fd;
char cache_block[256];
cache_block[0] = '\0';
while(1) {
read(pipefd[0], &pid, sizeof(pid));
// Termination called
if(pid == -1) break;
manage_selinux();
snprintf(buffer, sizeof(buffer), "/proc/%d/ns/mnt", pid);
if((fd = open(buffer, O_RDONLY)) == -1) continue; // Maybe process died..
if(setns(fd, 0) == -1) {
fprintf(logfile, "MagiskHide: Unable to change namespace for pid=%d\n", pid);
continue;
}
close(fd);
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
FILE *mount_fp = fopen(buffer, "r");
if (mount_fp == NULL) {
fprintf(logfile, "MagiskHide: Error opening mount list!\n");
continue;
}
int mount_size;
char **mount_list = file_to_str_arr(mount_fp, &mount_size);
// Find the cache block name if not found yet
if (strlen(cache_block) == 0) {
for(i = 0; i < mount_size; ++i) {
if (strstr(mount_list[i], " /cache ")) {
sscanf(mount_list[i], "%256s", cache_block);
break;
}
}
}
// First unmount the dummy skeletons, cache mounts, and /sbin links
for(i = mount_size - 1; i >= 0; --i) {
if (strstr(mount_list[i], "tmpfs /system") || strstr(mount_list[i], "tmpfs /vendor")
|| strstr(mount_list[i], "tmpfs /sbin")
|| (strstr(mount_list[i], cache_block) && strstr(mount_list[i], "/system/")) ) {
sscanf(mount_list[i], "%*s %512s", buffer);
lazy_unmount(buffer);
}
free(mount_list[i]);
}
free(mount_list);
// Re-read mount infos
fseek(mount_fp, 0, SEEK_SET);
mount_list = file_to_str_arr(mount_fp, &mount_size);
fclose(mount_fp);
// Unmount loop mounts
for(i = mount_size - 1; i >= 0; --i) {
if (strstr(mount_list[i], "/dev/block/loop") && !strstr(mount_list[i], DUMMYPATH)) {
sscanf(mount_list[i], "%*s %512s", buffer);
lazy_unmount(buffer);
}
free(mount_list[i]);
}
free(mount_list);
// Send resume signal
kill(pid, SIGCONT);
}
// Should never go here
return 1;
}

254
jni/magiskhide/hide_utils.c Normal file
View File

@@ -0,0 +1,254 @@
/* hide_utils.c - Some utility functions for MagiskHide
*/
#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"
#include "daemon.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", "ro.build.type", "ro.build.tags", "ro.build.selinux", NULL };
static char *prop_value[] =
{ "green", "1", "enforcing", "0", "0", "0", "1", "user", "release-keys", "0", NULL };
static int mocked = 0;
void manage_selinux() {
if (mocked) 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);
mocked = 1;
}
}
void hide_sensitive_props() {
LOGI("hide_utils: 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);
}
}
}
static void rm_magisk_prop(const char *name) {
if (strstr(name, "magisk")) {
deleteprop(name, 0);
}
}
void clean_magisk_props() {
LOGD("hide_utils: Cleaning magisk props\n");
getprop_all(rm_magisk_prop);
}
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_utils: 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))) {
if (strcmp(entry->d_name, "..") == 0)
continue;
snprintf(from, sizeof(from), "/sbin_orig/%s", entry->d_name);
if (entry->d_type == DT_LNK)
xreadlink(from, from, sizeof(from));
snprintf(to, sizeof(to), "/dev/sbin_bind/%s", entry->d_name);
symlink(from, to);
lsetfilecon(to, "u:object_r:rootfs:s0");
}
closedir(dir);
xmount("/dev/sbin_bind", "/sbin", NULL, MS_BIND, NULL);
}
}
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);
vector_to_file(HIDELIST, hide_list); // Do not complain if file not found
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);
vector_to_file(HIDELIST, hide_list); // Do not complain if file not found
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);
}
void ls_hide_list(int client) {
err_handler = do_nothing;
if (!hideEnabled) {
write_int(client, HIDE_NOT_ENABLED);
return;
}
write_int(client, DAEMON_SUCCESS);
write_int(client, vec_size(hide_list));
char *s;
vec_for_each(hide_list, s) {
write_string(client, s);
}
close(client);
}

View File

@@ -1,56 +0,0 @@
#include "magiskhide.h"
void *monitor_list(void *path) {
char* listpath = (char*) path;
signal(SIGQUIT, quit_pthread);
int inotifyFd = -1;
char str[512];
while(1) {
if (inotifyFd == -1 || read(inotifyFd, str, sizeof(str)) == -1) {
close(inotifyFd);
inotifyFd = inotify_init();
if (inotifyFd == -1) {
fprintf(logfile, "MagiskHide: Unable to watch %s\n", listpath);
exit(1);
}
if (inotify_add_watch(inotifyFd, listpath, IN_CLOSE_WRITE) == -1) {
fprintf(logfile, "MagiskHide: Unable to watch %s\n", listpath);
exit(1);
}
}
update_list(listpath);
}
return NULL;
}
void update_list(const char *listpath) {
FILE *hide_fp = fopen(listpath, "r");
if (hide_fp == NULL) {
fprintf(logfile, "MagiskHide: Error opening hide list\n");
exit(1);
}
pthread_mutex_lock(&mutex);
if (hide_list) {
// Free memory
for(i = 0; i < list_size; ++i)
free(hide_list[i]);
free(hide_list);
}
hide_list = file_to_str_arr(hide_fp, &list_size);
pthread_mutex_unlock(&mutex);
fclose(hide_fp);
if (list_size) fprintf(logfile, "MagiskHide: Update process/package list:\n");
for(i = 0; i < list_size; i++)
fprintf(logfile, "MagiskHide: [%s]\n", hide_list[i]);
}
void quit_pthread(int sig) {
// Free memory
for(i = 0; i < list_size; ++i)
free(hide_list[i]);
free(hide_list);
pthread_exit(NULL);
}

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

@@ -0,0 +1,168 @@
/* 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"
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) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Hide Magisk!\n\n"
"Usage: %s [--options [arguments...] ]\n\n"
"Options:\n"
" --enable Start magiskhide\n"
" --disable Stop magiskhide\n"
" --add PROCESS Add PROCESS to the hide list\n"
" --rm PROCESS Remove PROCESS from the hide 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) {
if (client > 0) {
write_int(client, HIDE_IS_ENABLED);
close(client);
}
return;
}
hideEnabled = 1;
LOGI("* Starting MagiskHide\n");
deleteprop(MAGISKHIDE_PROP, 1);
hide_sensitive_props();
// 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"));
if (client > 0) {
write_int(client, DAEMON_SUCCESS);
close(client);
}
// Get thread reference
proc_monitor_thread = pthread_self();
// Start monitoring
proc_monitor();
return;
error:
hideEnabled = 0;
if (client > 0) {
write_int(client, DAEMON_ERROR);
close(client);
}
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");
// Remove without actually removing persist props
deleteprop(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) {
req = LS_HIDELIST;
}
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);
switch (code) {
case DAEMON_ERROR:
fprintf(stderr, "Error occured in daemon...\n");
return code;
case DAEMON_SUCCESS:
break;
case ROOT_REQUIRED:
fprintf(stderr, "Root is required for this operation\n");
return code;
case HIDE_NOT_ENABLED:
fprintf(stderr, "Magisk hide is not enabled yet\n");
return code;
case HIDE_IS_ENABLED:
fprintf(stderr, "Magisk hide is already enabled\n");
return code;
case HIDE_ITEM_EXIST:
fprintf(stderr, "Process [%s] already exists in hide list\n", argv[2]);
return code;
case HIDE_ITEM_NOT_EXIST:
fprintf(stderr, "Process [%s] does not exist in hide list\n", argv[2]);
return code;
}
if (req == LS_HIDELIST) {
int argc = read_int(fd);
for (int i = 0; i < argc; ++i) {
char *s = read_string(fd);
printf("%s\n", s);
free(s);
}
}
close(fd);
return 0;
}

View File

@@ -1,53 +1,28 @@
#ifndef MAGISK_HIDE_H
#define MAGISK_HIDE_H
#define _GNU_SOURCE
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mount.h>
#include <sys/inotify.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
// Kill process
void kill_proc(int pid);
#define LOGFILE "/cache/magisk.log"
#define HIDELIST "/magisk/.core/magiskhide/hidelist"
#define DUMMYPATH "/dev/magisk/dummy"
#define ENFORCE_FILE "/sys/fs/selinux/enforce"
#define POLICY_FILE "/sys/fs/selinux/policy"
#define SEPOLICY_INJECT "/data/magisk/magiskpolicy"
// Process monitor
void proc_monitor();
// Main thread
void monitor_proc();
// Forked process for namespace setting
int hideMagisk();
// List monitor thread
void update_list(const char *listpath);
void quit_pthread(int sig);
void *monitor_list(void *path);
// Util functions
char **file_to_str_arr(FILE *fp, int *size);
void read_namespace(const int pid, char* target, const size_t size);
void lazy_unmount(const char* mountpoint);
void run_as_daemon();
// Utility functions
void manage_selinux();
void hide_sensitive_props();
void relink_sbin();
void clean_magisk_props();
// Global variable sharing through process/threads
extern FILE *logfile;
extern int i, list_size, pipefd[2];
extern char **hide_list, buffer[512];
extern pthread_t list_monitor;
extern pthread_mutex_t mutex;
// List managements
int add_list(char *proc);
int rm_list(char *proc);
int init_list();
int destroy_list();
extern int hideEnabled;
extern struct vector *hide_list;
extern pthread_mutex_t hide_lock, file_lock;
#endif

View File

@@ -1,65 +0,0 @@
#include "magiskhide.h"
FILE *logfile;
int i, list_size, pipefd[2];
char **hide_list = NULL, buffer[512];
pthread_t list_monitor;
pthread_mutex_t mutex;
static void terminate(int sig) {
// Close the config list monitor
pthread_kill(list_monitor, SIGQUIT);
pthread_mutex_destroy(&mutex);
// Terminate our children
i = -1;
write(pipefd[1], &i, sizeof(i));
exit(0);
}
int main(int argc, char *argv[]) {
if (argc > 1) {
if (strcmp(argv[1], "--daemon") == 0)
run_as_daemon();
else {
fprintf(stderr, "%s (with no options)\n\tRun magiskhide and output to stdout\n", argv[0]);
fprintf(stderr, "%s --daemon\n\tRun magiskhide as daemon, output to magisk.log\n", argv[0]);
return 1;
}
} else
logfile = stdout;
// Handle all killing signals
signal(SIGINT, terminate);
signal(SIGTERM, terminate);
// Fork a child to handle namespace switches and unmounts
pipe(pipefd);
switch(fork()) {
case -1:
exit(-1);
case 0:
return hideMagisk();
default:
break;
}
close(pipefd[0]);
// Start a thread to constantly check the hide list
pthread_mutex_init(&mutex, NULL);
pthread_create(&list_monitor, NULL, monitor_list, HIDELIST);
// Set main process to the top priority
setpriority(PRIO_PROCESS, 0, -20);
monitor_proc();
terminate(0);
fprintf(logfile, "MagiskHide: Cannot monitor am_proc_start, abort...\n");
fclose(logfile);
return 1;
}

View File

@@ -1,106 +1,273 @@
/* proc_monitor.c - Monitor am_proc_start events and unmount
*
* We monitor the logcat am_proc_start events. When a target starts up,
* we pause it ASAP, and fork a new process to join its mount namespace
* and do all the unmounting/mocking
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include "magisk.h"
#include "utils.h"
#include "magiskhide.h"
void monitor_proc() {
int pid, badns, i, zygote_num = 0;
char init_ns[32], zygote_ns[2][32];
static int zygote_num;
static char init_ns[32], zygote_ns[2][32], cache_block[256];
static int log_pid, log_fd, target_pid;
static char *buffer;
// Get the mount namespace of init
read_namespace(1, init_ns, 32);
printf("%s\n", init_ns);
// Get the mount namespace of zygote
FILE *p = popen("ps | grep zygote | grep -v grep", "r");
while(fgets(buffer, sizeof(buffer), p)) {
if (zygote_num == 2) break;
sscanf(buffer, "%d", &pid);
do {
usleep(500);
read_namespace(pid, zygote_ns[zygote_num], 32);
} while (strcmp(zygote_ns[zygote_num], init_ns) == 0);
++zygote_num;
// 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 > 0) {
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
close(log_fd);
}
pclose(p);
// Resume process if possible
if (target_pid > 0)
kill(target_pid, SIGCONT);
pthread_mutex_destroy(&hide_lock);
pthread_mutex_destroy(&file_lock);
LOGD("proc_monitor: terminating...\n");
pthread_exit(NULL);
}
for (i = 0; i < zygote_num; ++i)
fprintf(logfile, "Zygote(%d) ns=%s ", i, zygote_ns[i]);
fprintf(logfile, "\n");
static void proc_monitor_err() {
LOGD("proc_monitor: error occured, stopping magiskhide services\n");
quit_pthread(SIGUSR1);
}
// get a sample line from am_proc_start
p = popen("logcat -b events -v raw -s am_proc_start -t 1", "r");
static int read_namespace(const int pid, char* target, const size_t size) {
char path[32];
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
if (access(path, R_OK) == -1)
return 1;
xreadlink(path, target, size);
return 0;
}
/**
* Format of am_proc_start is (as of Android 5.1 and 6.0)
* UserID, pid, unix uid, processName, hostingType, hostingName
* but sometimes can have 7 fields, with processName as 5th field
*/
fgets(buffer, sizeof(buffer), p);
int commas = 0;
char *s = buffer;
for (i = 0;s[i] != '\0';i++) {
if (s[i] == ',')
commas++;
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;
}
}
int numFields = commas + 1;
static void lazy_unmount(const char* mountpoint) {
if (umount2(mountpoint, MNT_DETACH) != -1)
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
else
LOGD("hide_daemon: Unmount Failed (%s)\n", mountpoint);
}
pclose(p);
static void hide_daemon_err() {
LOGD("hide_daemon: error occured, stopping magiskhide services\n");
_exit(-1);
}
// Monitor am_proc_start
p = popen("logcat -b events -c; logcat -b events -v raw -s am_proc_start", "r");
static void hide_daemon(int pid) {
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
// When an error occurs, report its failure to main process
err_handler = hide_daemon_err;
while(!feof(p)) {
fgets(buffer, sizeof(buffer), p);
char *line;
struct vector mount_list;
char *pos = buffer;
while(1) {
pos = strchr(pos, ',');
if(pos == NULL)
break;
pos[0] = ' ';
}
manage_selinux();
relink_sbin();
clean_magisk_props();
char processName[256];
int ret;
if (switch_mnt_ns(pid))
return;
if (numFields == 7) {
ret = sscanf(buffer, "[%*d %d %*d %*d %256s", &pid, processName);
} else {
ret = sscanf(buffer, "[%*d %d %*d %256s", &pid, processName);
}
snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid);
vec_init(&mount_list);
file_to_vector(buffer, &mount_list);
if(ret != 2)
continue;
pthread_mutex_lock(&mutex);
for (i = 0; i < list_size; ++i) {
if(strcmp(processName, hide_list[i]) == 0) {
while(1) {
badns = 0;
read_namespace(pid, buffer, 32);
for (i = 0; i < zygote_num; ++i) {
if (strcmp(buffer, zygote_ns[i]) == 0) {
usleep(500);
badns = 1;
break;
}
}
if (!badns) break;
}
// Send pause signal ASAP
if (kill(pid, SIGSTOP) == -1) continue;
fprintf(logfile, "MagiskHide: %s(PID=%d ns=%s)\n", processName, pid, buffer);
// Unmount start
write(pipefd[1], &pid, sizeof(pid));
// Find the cache block name if not found yet
if (cache_block[0] == '\0') {
vec_for_each(&mount_list, line) {
if (strstr(line, " /cache ")) {
sscanf(line, "%256s", cache_block);
break;
}
}
pthread_mutex_unlock(&mutex);
}
// Close the logcat monitor
pclose(p);
// First unmount dummy skeletons, /sbin links, cache mounts, and mirrors
vec_for_each(&mount_list, line) {
if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin")
|| (strstr(line, cache_block) && (strstr(line, " /system") || strstr(line, " /vendor")))
|| strstr(line, MIRRDIR)) {
sscanf(line, "%*s %4096s", buffer);
lazy_unmount(buffer);
}
free(line);
}
vec_destroy(&mount_list);
// Re-read mount infos
snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid);
vec_init(&mount_list);
file_to_vector(buffer, &mount_list);
// Unmount any loop mounts and dummy mounts
vec_for_each(&mount_list, line) {
if (strstr(line, "/dev/block/loop") || strstr(line, DUMMDIR)) {
sscanf(line, "%*s %4096s", buffer);
lazy_unmount(buffer);
}
free(line);
}
// Free uo memory
vec_destroy(&mount_list);
}
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;
log_pid = target_pid = -1;
buffer = xmalloc(PATH_MAX);
cache_block[0] = '\0';
// Get the mount namespace of init
if (read_namespace(1, init_ns, 32)) {
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
proc_monitor_err();
}
LOGI("proc_monitor: init ns=%s\n", init_ns);
// Get the mount namespace of zygote
zygote_num = 0;
while(!zygote_num) {
// Check zygote every 2 secs
sleep(2);
ps_filter_proc_name("zygote", store_zygote_ns);
}
ps_filter_proc_name("zygote64", store_zygote_ns);
switch(zygote_num) {
case 1:
LOGI("proc_monitor: zygote ns=%s\n", zygote_ns[0]);
break;
case 2:
LOGI("proc_monitor: zygote ns=%s zygote64 ns=%s\n", zygote_ns[0], zygote_ns[1]);
break;
}
while (1) {
// Clear previous logcat buffer
exec_command_sync("logcat", "-b", "events", "-c", NULL);
// Monitor am_proc_start
log_fd = -1;
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-b", "events", "-v", "raw", "-s", "am_proc_start", NULL);
if (log_pid < 0) continue;
if (kill(log_pid, 0)) continue;
while(fdgets(buffer, PATH_MAX, log_fd)) {
int pid, 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) {
target_pid = pid;
while(1) {
ret = 1;
for (int i = 0; i < zygote_num; ++i) {
read_namespace(target_pid, buffer, 32);
if (strcmp(buffer, zygote_ns[i]) == 0) {
usleep(50);
ret = 0;
break;
}
}
if (ret) break;
}
// Send pause signal ASAP
if (kill(target_pid, SIGSTOP) == -1) continue;
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, target_pid, buffer);
/*
* The setns system call do not support multithread processes
* We have to fork a new process, setns, then do the unmounts
*/
int hide_pid = fork();
switch(hide_pid) {
case -1:
PLOGE("fork");
return;
case 0:
hide_daemon(target_pid);
_exit(0);
default:
break;
}
// Wait till the unmount process is done
waitpid(hide_pid, &ret, 0);
if (WEXITSTATUS(ret))
quit_pthread(SIGUSR1);
// All done, send resume signal
kill(target_pid, SIGCONT);
target_pid = -1;
break;
}
}
pthread_mutex_unlock(&hide_lock);
}
// For some reason it went here, restart logging
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
close(log_fd);
}
}

View File

@@ -1,103 +0,0 @@
#include "magiskhide.h"
char **file_to_str_arr(FILE *fp, int *size) {
int allocated = 16;
char *line = NULL, **array;
size_t len = 0;
ssize_t read;
array = (char **) malloc(sizeof(char*) * allocated);
*size = 0;
while ((read = getline(&line, &len, fp)) != -1) {
if (*size >= allocated) {
// Double our allocation and re-allocate
allocated *= 2;
array = (char **) realloc(array, sizeof(char*) * allocated);
}
// Remove end newline
if (line[read - 1] == '\n') {
line[read - 1] = '\0';
}
array[*size] = line;
line = NULL;
++(*size);
}
return array;
}
void read_namespace(const int pid, char* target, const size_t size) {
char path[32];
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
ssize_t len = readlink(path, target, size);
target[len] = '\0';
}
void lazy_unmount(const char* mountpoint) {
if (umount2(mountpoint, MNT_DETACH) != -1)
fprintf(logfile, "MagiskHide: Unmounted (%s)\n", mountpoint);
else
fprintf(logfile, "MagiskHide: Unmount Failed (%s)\n", mountpoint);
}
void run_as_daemon() {
switch(fork()) {
case -1:
exit(-1);
case 0:
if (setsid() < 0)
exit(-1);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
logfile = fopen(LOGFILE, "a+");
setbuf(logfile, NULL);
break;
default:
exit(0);
}
}
void manage_selinux() {
char *argv[] = { SEPOLICY_INJECT, "--live", "permissive *", NULL };
char val[1];
int fd, ret;
fd = open(ENFORCE_FILE, O_RDWR);
if (fd < 0)
return;
if (read(fd, val, 1) < 1)
return;
lseek(fd, 0, SEEK_SET);
// Permissive
if (val[0] == '0') {
fprintf(logfile, "MagiskHide: Permissive detected\n");
if (write(fd, "1", 1) < 1)
return;
lseek(fd, 0, SEEK_SET);
if (read(fd, val, 1) < 1)
return;
lseek(fd, 0, SEEK_SET);
close(fd);
if (val[0] == '0') {
fprintf(logfile, "MagiskHide: Unable to set to enforce, hide the state\n");
chmod(ENFORCE_FILE, 0640);
chmod(POLICY_FILE, 0440);
return;
}
fprintf(logfile, "MagiskHide: Calling magiskpolicy for pseudo enforce mode\n");
switch(fork()) {
case -1:
return;
case 0:
execvp(argv[0], argv);
default:
return;
}
}
}

View File

@@ -4,5 +4,5 @@ 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
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

@@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) 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
this service 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 make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. 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.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the 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 a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE 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.
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
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision 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, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This 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.

View File

@@ -29,74 +29,47 @@
#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
#else
#include <sys/system_properties.h>
#endif
typedef struct prop_msg prop_msg;
#define PROP_AREA_MAGIC 0x504f5250
#define PROP_AREA_VERSION 0xfc6ed0ab
#define PROP_AREA_VERSION_COMPAT 0x45434f76
#define PROP_SERVICE_NAME "property_service"
#define PROP_FILENAME_MAX 1024
#define PROP_FILENAME "/dev/__properties__"
#define PA_SIZE (128 * 1024)
#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
#define SERIAL_DIRTY(serial) ((serial) & 1)
// #include <sys/system_properties.h>
#include "system_properties.h"
__BEGIN_DECLS
struct prop_msg
{
unsigned cmd;
char name[PROP_NAME_MAX];
char value[PROP_VALUE_MAX];
};
#define PROP_SERVICE_NAME "property_service"
#define PROP_FILENAME "/dev/__properties__"
#define PROP_MSG_SETPROP 1
#define PROP_MSG_SETPROP2 0x00020001
/*
** Rules:
**
** - there is only one writer, but many readers
** - prop_area.count will never decrease in value
** - once allocated, a prop_info's name will not change
** - once allocated, a prop_info's offset will not change
** - reading a value requires the following steps
** 1. serial = pi->serial
** 2. if SERIAL_DIRTY(serial), wait*, then goto 1
** 3. memcpy(local, pi->value, SERIAL_VALUE_LEN(serial) + 1)
** 4. if pi->serial != serial, goto 2
**
** - writing a value requires the following steps
** 1. pi->serial = pi->serial | 1
** 2. memcpy(pi->value, local_value, value_len)
** 3. pi->serial = (value_len << 24) | ((pi->serial + 1) & 0xffffff)
*/
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_VENDOR_BUILD "/vendor/build.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
#define PROP_PATH_FACTORY "/factory/factory.prop"
#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_filename(const char *filename);
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_init();
int __system_property_area_init2();
/* Read the global serial number of the system properties
**
@@ -120,7 +93,7 @@ int __system_property_area_init();
**
** Returns the serial number on success, -1 on error.
*/
unsigned int __system_property_area_serial();
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
@@ -130,9 +103,12 @@ unsigned int __system_property_area_serial();
**
** Returns 0 on success, -1 if the property area is full.
*/
int __system_property_add(const char *name, unsigned int namelen,
const char *value, unsigned int valuelen);
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
@@ -143,28 +119,14 @@ int __system_property_del(const char *name);
**
** Returns 0 on success, -1 if the parameters are incorrect.
*/
int __system_property_update(prop_info *pi, const char *value, unsigned int len);
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_find.
**
** Returns the serial number on success, -1 on error.
*/
unsigned int __system_property_serial(const prop_info *pi);
/* Wait for any system property to be updated. Caller must pass
** in 0 the first time, and the previous return value on each
** successive call. */
unsigned int __system_property_wait_any(unsigned int serial);
/* Compatibility functions to support using an old init with a new libc,
** mostly for the OTA updater binary. These can be deleted once OTAs from
** a pre-K release no longer needed to be supported. */
// const prop_info *__system_property_find_compat(const char *name);
// int __system_property_read_compat(const prop_info *pi, char *name, char *value);
// int __system_property_foreach_compat(
// void (*propfn)(const prop_info *pi, void *cookie),
// void *cookie);
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
@@ -172,9 +134,11 @@ unsigned int __system_property_wait_any(unsigned int serial);
*
* Returns 0 on success, -1 otherwise.
*/
int __system_properties_init();
int __system_properties_init2();
/* Deprecated: use __system_property_wait instead. */
uint32_t __system_property_wait_any2(uint32_t old_serial);
__END_DECLS
#endif
#endif

View File

@@ -17,6 +17,8 @@
#ifndef _BIONIC_MACROS_H_
#define _BIONIC_MACROS_H_
#include <stdint.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
@@ -46,4 +48,22 @@
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
static constexpr uintptr_t align_down(uintptr_t p, size_t align) {
return p & ~(align - 1);
}
static constexpr uintptr_t align_up(uintptr_t p, size_t align) {
return (p + align - 1) & ~(align - 1);
}
template <typename T>
static inline T* align_down(T* p, size_t align) {
return reinterpret_cast<T*>(align_down(reinterpret_cast<uintptr_t>(p), align));
}
template <typename T>
static inline T* align_up(T* p, size_t align) {
return reinterpret_cast<T*>(align_up(reinterpret_cast<uintptr_t>(p), align));
}
#endif // _BIONIC_MACROS_H_

View File

@@ -1,659 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
#include "libc_logging.h" // Relative path so we can #include this .cpp file for testing.
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include "_system_properties.h"
static pthread_mutex_t g_abort_msg_lock = PTHREAD_MUTEX_INITIALIZER;
__LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
enum AndroidEventLogType {
EVENT_TYPE_INT = 0,
EVENT_TYPE_LONG = 1,
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
EVENT_TYPE_FLOAT = 4,
};
struct BufferOutputStream {
public:
BufferOutputStream(char* buffer, size_t size) : total(0) {
buffer_ = buffer;
end_ = buffer + size - 1;
pos_ = buffer_;
pos_[0] = '\0';
}
~BufferOutputStream() {
}
void Send(const char* data, int len) {
if (len < 0) {
len = strlen(data);
}
total += len;
while (len > 0) {
int avail = end_ - pos_;
if (avail == 0) {
return;
}
if (avail > len) {
avail = len;
}
memcpy(pos_, data, avail);
pos_ += avail;
pos_[0] = '\0';
len -= avail;
}
}
size_t total;
private:
char* buffer_;
char* pos_;
char* end_;
};
struct FdOutputStream {
public:
FdOutputStream(int fd) : total(0), fd_(fd) {
}
void Send(const char* data, int len) {
if (len < 0) {
len = strlen(data);
}
total += len;
while (len > 0) {
int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
if (rc == -1) {
return;
}
data += rc;
len -= rc;
}
}
size_t total;
private:
int fd_;
};
/*** formatted output implementation
***/
/* Parse a decimal string from 'format + *ppos',
* return the value, and writes the new position past
* the decimal string in '*ppos' on exit.
*
* NOTE: Does *not* handle a sign prefix.
*/
static unsigned parse_decimal(const char *format, int *ppos) {
const char* p = format + *ppos;
unsigned result = 0;
for (;;) {
int ch = *p;
unsigned d = static_cast<unsigned>(ch - '0');
if (d >= 10U) {
break;
}
result = result*10 + d;
p++;
}
*ppos = p - format;
return result;
}
// Writes number 'value' in base 'base' into buffer 'buf' of size 'buf_size' bytes.
// Assumes that buf_size > 0.
static void format_unsigned(char* buf, size_t buf_size, uint64_t value, int base, bool caps) {
char* p = buf;
char* end = buf + buf_size - 1;
// Generate digit string in reverse order.
while (value) {
unsigned d = value % base;
value /= base;
if (p != end) {
char ch;
if (d < 10) {
ch = '0' + d;
} else {
ch = (caps ? 'A' : 'a') + (d - 10);
}
*p++ = ch;
}
}
// Special case for 0.
if (p == buf) {
if (p != end) {
*p++ = '0';
}
}
*p = '\0';
// Reverse digit string in-place.
size_t length = p - buf;
for (size_t i = 0, j = length - 1; i < j; ++i, --j) {
char ch = buf[i];
buf[i] = buf[j];
buf[j] = ch;
}
}
static void format_integer(char* buf, size_t buf_size, uint64_t value, char conversion) {
// Decode the conversion specifier.
int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
int base = 10;
if (conversion == 'x' || conversion == 'X') {
base = 16;
} else if (conversion == 'o') {
base = 8;
}
bool caps = (conversion == 'X');
if (is_signed && static_cast<int64_t>(value) < 0) {
buf[0] = '-';
buf += 1;
buf_size -= 1;
value = static_cast<uint64_t>(-static_cast<int64_t>(value));
}
format_unsigned(buf, buf_size, value, base, caps);
}
template <typename Out>
static void SendRepeat(Out& o, char ch, int count) {
char pad[8];
memset(pad, ch, sizeof(pad));
const int pad_size = static_cast<int>(sizeof(pad));
while (count > 0) {
int avail = count;
if (avail > pad_size) {
avail = pad_size;
}
o.Send(pad, avail);
count -= avail;
}
}
/* Perform formatted output to an output target 'o' */
template <typename Out>
static void out_vformat(Out& o, const char* format, va_list args) {
int nn = 0;
for (;;) {
int mm;
int padZero = 0;
int padLeft = 0;
char sign = '\0';
int width = -1;
int prec = -1;
size_t bytelen = sizeof(int);
int slen;
char buffer[32]; /* temporary buffer used to format numbers */
char c;
/* first, find all characters that are not 0 or '%' */
/* then send them to the output directly */
mm = nn;
do {
c = format[mm];
if (c == '\0' || c == '%')
break;
mm++;
} while (1);
if (mm > nn) {
o.Send(format+nn, mm-nn);
nn = mm;
}
/* is this it ? then exit */
if (c == '\0')
break;
/* nope, we are at a '%' modifier */
nn++; // skip it
/* parse flags */
for (;;) {
c = format[nn++];
if (c == '\0') { /* single trailing '%' ? */
c = '%';
o.Send(&c, 1);
return;
}
else if (c == '0') {
padZero = 1;
continue;
}
else if (c == '-') {
padLeft = 1;
continue;
}
else if (c == ' ' || c == '+') {
sign = c;
continue;
}
break;
}
/* parse field width */
if ((c >= '0' && c <= '9')) {
nn --;
width = static_cast<int>(parse_decimal(format, &nn));
c = format[nn++];
}
/* parse precision */
if (c == '.') {
prec = static_cast<int>(parse_decimal(format, &nn));
c = format[nn++];
}
/* length modifier */
switch (c) {
case 'h':
bytelen = sizeof(short);
if (format[nn] == 'h') {
bytelen = sizeof(char);
nn += 1;
}
c = format[nn++];
break;
case 'l':
bytelen = sizeof(long);
if (format[nn] == 'l') {
bytelen = sizeof(long long);
nn += 1;
}
c = format[nn++];
break;
case 'z':
bytelen = sizeof(size_t);
c = format[nn++];
break;
case 't':
bytelen = sizeof(ptrdiff_t);
c = format[nn++];
break;
default:
;
}
/* conversion specifier */
const char* str = buffer;
if (c == 's') {
/* string */
str = va_arg(args, const char*);
if (str == NULL) {
str = "(null)";
}
} else if (c == 'c') {
/* character */
/* NOTE: char is promoted to int when passed through the stack */
buffer[0] = static_cast<char>(va_arg(args, int));
buffer[1] = '\0';
} else if (c == 'p') {
uint64_t value = reinterpret_cast<uintptr_t>(va_arg(args, void*));
buffer[0] = '0';
buffer[1] = 'x';
format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
} else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
/* integers - first read value from stack */
uint64_t value;
int is_signed = (c == 'd' || c == 'i' || c == 'o');
/* NOTE: int8_t and int16_t are promoted to int when passed
* through the stack
*/
switch (bytelen) {
case 1: value = static_cast<uint8_t>(va_arg(args, int)); break;
case 2: value = static_cast<uint16_t>(va_arg(args, int)); break;
case 4: value = va_arg(args, uint32_t); break;
case 8: value = va_arg(args, uint64_t); break;
default: return; /* should not happen */
}
/* sign extension, if needed */
if (is_signed) {
int shift = 64 - 8*bytelen;
value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
}
/* format the number properly into our buffer */
format_integer(buffer, sizeof(buffer), value, c);
} else if (c == '%') {
buffer[0] = '%';
buffer[1] = '\0';
} else {
__assert(__FILE__, __LINE__, "conversion specifier unsupported");
}
/* if we are here, 'str' points to the content that must be
* outputted. handle padding and alignment now */
slen = strlen(str);
if (sign != '\0' || prec != -1) {
__assert(__FILE__, __LINE__, "sign/precision unsupported");
}
if (slen < width && !padLeft) {
char padChar = padZero ? '0' : ' ';
SendRepeat(o, padChar, width - slen);
}
o.Send(str, slen);
if (slen < width && padLeft) {
char padChar = padZero ? '0' : ' ';
SendRepeat(o, padChar, width - slen);
}
}
}
int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
BufferOutputStream os(buffer, buffer_size);
va_list args;
va_start(args, format);
out_vformat(os, format, args);
va_end(args);
return os.total;
}
int __libc_format_fd(int fd, const char* format, ...) {
FdOutputStream os(fd);
va_list args;
va_start(args, format);
out_vformat(os, format, args);
va_end(args);
return os.total;
}
static int __libc_write_stderr(const char* tag, const char* msg) {
int fd = TEMP_FAILURE_RETRY(open("/dev/stderr", O_CLOEXEC | O_WRONLY | O_APPEND));
if (fd == -1) {
return -1;
}
iovec vec[4];
vec[0].iov_base = const_cast<char*>(tag);
vec[0].iov_len = strlen(tag);
vec[1].iov_base = const_cast<char*>(": ");
vec[1].iov_len = 2;
vec[2].iov_base = const_cast<char*>(msg);
vec[2].iov_len = strlen(msg);
vec[3].iov_base = const_cast<char*>("\n");
vec[3].iov_len = 1;
int result = TEMP_FAILURE_RETRY(writev(fd, vec, 4));
close(fd);
return result;
}
static int __libc_open_log_socket() {
// ToDo: Ideally we want this to fail if the gid of the current
// process is AID_LOGD, but will have to wait until we have
// registered this in private/android_filesystem_config.h. We have
// found that all logd crashes thus far have had no problem stuffing
// the UNIX domain socket and moving on so not critical *today*.
int log_fd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (log_fd < 0) {
return -1;
}
if (fcntl(log_fd, F_SETFL, O_NONBLOCK) == -1) {
close(log_fd);
return -1;
}
union {
struct sockaddr addr;
struct sockaddr_un addrUn;
} u;
memset(&u, 0, sizeof(u));
u.addrUn.sun_family = AF_UNIX;
strlcpy(u.addrUn.sun_path, "/dev/socket/logdw", sizeof(u.addrUn.sun_path));
if (TEMP_FAILURE_RETRY(connect(log_fd, &u.addr, sizeof(u.addrUn))) != 0) {
close(log_fd);
return -1;
}
return log_fd;
}
struct cache {
const prop_info* pinfo;
uint32_t serial;
char c;
};
static void refresh_cache(struct cache *cache, const char *key)
{
if (!cache->pinfo) {
cache->pinfo = __system_property_find(key);
if (!cache->pinfo) {
return;
}
}
uint32_t serial = __system_property_serial(cache->pinfo);
if (serial == cache->serial) {
return;
}
cache->serial = serial;
char buf[PROP_VALUE_MAX];
__system_property_read(cache->pinfo, 0, buf);
cache->c = buf[0];
}
// Timestamp state generally remains constant, since a change is
// rare, we can accept a trylock failure gracefully.
static pthread_mutex_t lock_clockid = PTHREAD_MUTEX_INITIALIZER;
static clockid_t __android_log_clockid()
{
static struct cache r_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
static struct cache p_time_cache = { NULL, static_cast<uint32_t>(-1), 0 };
char c;
if (pthread_mutex_trylock(&lock_clockid)) {
// We are willing to accept some race in this context
if (!(c = p_time_cache.c)) {
c = r_time_cache.c;
}
} else {
static uint32_t serial;
uint32_t current_serial = __system_property_area_serial();
if (current_serial != serial) {
refresh_cache(&r_time_cache, "ro.logd.timestamp");
refresh_cache(&p_time_cache, "persist.logd.timestamp");
serial = current_serial;
}
if (!(c = p_time_cache.c)) {
c = r_time_cache.c;
}
pthread_mutex_unlock(&lock_clockid);
}
return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
}
struct log_time { // Wire format
uint32_t tv_sec;
uint32_t tv_nsec;
};
int __libc_write_log(int priority, const char* tag, const char* msg) {
int main_log_fd = __libc_open_log_socket();
if (main_log_fd == -1) {
// Try stderr instead.
return __libc_write_stderr(tag, msg);
}
iovec vec[6];
char log_id = (priority == ANDROID_LOG_FATAL) ? LOG_ID_CRASH : LOG_ID_MAIN;
vec[0].iov_base = &log_id;
vec[0].iov_len = sizeof(log_id);
uint16_t tid = gettid();
vec[1].iov_base = &tid;
vec[1].iov_len = sizeof(tid);
timespec ts;
clock_gettime(__android_log_clockid(), &ts);
log_time realtime_ts;
realtime_ts.tv_sec = ts.tv_sec;
realtime_ts.tv_nsec = ts.tv_nsec;
vec[2].iov_base = &realtime_ts;
vec[2].iov_len = sizeof(realtime_ts);
vec[3].iov_base = &priority;
vec[3].iov_len = 1;
vec[4].iov_base = const_cast<char*>(tag);
vec[4].iov_len = strlen(tag) + 1;
vec[5].iov_base = const_cast<char*>(msg);
vec[5].iov_len = strlen(msg) + 1;
int result = TEMP_FAILURE_RETRY(writev(main_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
close(main_log_fd);
return result;
}
int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
char buffer[1024];
BufferOutputStream os(buffer, sizeof(buffer));
out_vformat(os, format, args);
return __libc_write_log(priority, tag, buffer);
}
int __libc_format_log(int priority, const char* tag, const char* format, ...) {
va_list args;
va_start(args, format);
int result = __libc_format_log_va_list(priority, tag, format, args);
va_end(args);
return result;
}
static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
iovec vec[6];
char log_id = LOG_ID_EVENTS;
vec[0].iov_base = &log_id;
vec[0].iov_len = sizeof(log_id);
uint16_t tid = gettid();
vec[1].iov_base = &tid;
vec[1].iov_len = sizeof(tid);
timespec ts;
clock_gettime(__android_log_clockid(), &ts);
log_time realtime_ts;
realtime_ts.tv_sec = ts.tv_sec;
realtime_ts.tv_nsec = ts.tv_nsec;
vec[2].iov_base = &realtime_ts;
vec[2].iov_len = sizeof(realtime_ts);
vec[3].iov_base = &tag;
vec[3].iov_len = sizeof(tag);
vec[4].iov_base = &type;
vec[4].iov_len = sizeof(type);
vec[5].iov_base = const_cast<void*>(payload);
vec[5].iov_len = len;
int event_log_fd = __libc_open_log_socket();
if (event_log_fd == -1) {
return -1;
}
int result = TEMP_FAILURE_RETRY(writev(event_log_fd, vec, sizeof(vec) / sizeof(vec[0])));
close(event_log_fd);
return result;
}
void __libc_android_log_event_int(int32_t tag, int value) {
__libc_android_log_event(tag, EVENT_TYPE_INT, &value, sizeof(value));
}
void __libc_android_log_event_uid(int32_t tag) {
__libc_android_log_event_int(tag, getuid());
}
void __fortify_chk_fail(const char* msg, uint32_t tag) {
if (tag != 0) {
__libc_android_log_event_uid(tag);
}
__libc_fatal("FORTIFY: %s", msg);
}
void __libc_fatal_no_abort(const char* format, ...) {
va_list args;
va_start(args, format);
__libc_fatal(format, args);
va_end(args);
}
void __libc_fatal(const char* format, ...) {
va_list args;
va_start(args, format);
__libc_fatal(format, args);
va_end(args);
abort();
}

View File

@@ -1,115 +0,0 @@
/*
* Copyright (C) 2010 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 _LIBC_LOGGING_H
#define _LIBC_LOGGING_H
#include <sys/cdefs.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
__BEGIN_DECLS
enum {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
};
enum {
LOG_ID_MIN = 0,
LOG_ID_MAIN = 0,
LOG_ID_RADIO = 1,
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3,
LOG_ID_CRASH = 4,
LOG_ID_MAX
};
struct abort_msg_t {
size_t size;
char msg[0];
};
//
// Formats a message to the log (priority 'fatal'), then aborts.
//
__LIBC_HIDDEN__ __noreturn void __libc_fatal(const char* format, ...) __printflike(1, 2);
//
// Formats a message to the log (priority 'fatal'), but doesn't abort.
// Used by the malloc implementation to ensure that debuggerd dumps memory
// around the bad address.
//
__LIBC_HIDDEN__ void __libc_fatal_no_abort(const char* format, ...)
__printflike(1, 2);
//
// Formatting routines for the C library's internal debugging.
// Unlike the usual alternatives, these don't allocate, and they don't drag in all of stdio.
//
__LIBC_HIDDEN__ int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...)
__printflike(3, 4);
__LIBC_HIDDEN__ int __libc_format_fd(int fd, const char* format, ...)
__printflike(2, 3);
__LIBC_HIDDEN__ int __libc_format_log(int priority, const char* tag, const char* format, ...)
__printflike(3, 4);
__LIBC_HIDDEN__ int __libc_format_log_va_list(int priority, const char* tag, const char* format,
va_list ap);
__LIBC_HIDDEN__ int __libc_write_log(int priority, const char* tag, const char* msg);
//
// Event logging.
//
__LIBC_HIDDEN__ void __libc_android_log_event_int(int32_t tag, int value);
__LIBC_HIDDEN__ void __libc_android_log_event_uid(int32_t tag);
__LIBC_HIDDEN__ __noreturn void __fortify_chk_fail(const char* msg, uint32_t event_tag);
__END_DECLS
#endif

View File

@@ -1,48 +1,17 @@
/*
/* resetprop.cpp - Manipulate any system props
*
* resetprop.cpp
*
* Copyright 2016 nkk71 <nkk71x@gmail.com>
* Copyright 2016 topjohnwu <topjohnwu#gmail.com>
* Copyright 2016 topjohnwu <topjohnwu@gmail.com>
*
* Info:
*
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include "_system_properties.h"
#include <sys/system_properties.h>
/* 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_init()
* 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(); });
@@ -57,23 +26,23 @@
*
* 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.
@@ -81,25 +50,41 @@
*
*/
int verbose = 0, del = 0, file = 0, trigger = 1;
#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 "system_properties.h"
#include "magisk.h"
#include "resetprop.h"
#define PRINT_D(...) { LOGD(__VA_ARGS__); if (verbose) printf(__VA_ARGS__); }
#define PRINT_E(...) { LOGE(__VA_ARGS__); fprintf(stderr, __VA_ARGS__); }
#define PERSISTENT_PROPERTY_DIR "/data/property"
static int verbose = 0;
static bool is_legal_property_name(const char *name, size_t namelen) {
static bool is_legal_property_name(const char* name, size_t namelen)
{
size_t i;
if (namelen >= PROP_NAME_MAX) return false;
if (namelen < 1) return false;
if (name[0] == '.') return false;
if (name[namelen - 1] == '.') return false;
/* Only allow alphanumeric, plus '.', '-', or '_' */
/* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
/* Don't allow ".." to appear in a property name */
for (i = 0; i < namelen; i++) {
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] == '_' || name[i] == '-' || 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;
@@ -109,54 +94,126 @@ static bool is_legal_property_name(const char* name, size_t namelen)
return true;
}
int x_property_set(const char *name, const char *value)
{
int ret;
char value_read[PROP_VALUE_MAX];
static int usage(char* arg0) {
fprintf(stderr,
"resetprop v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu & nkk71) - System Props Modification Tool\n\n"
"Usage: %s [options] [args...]\n"
"\n"
"Options:\n"
" -v show verbose output\n"
" -n only modify property in memory\n"
"\n"
"%s NAME VALUE set property entry NAME with VALUE\n"
"%s --file FILE load props from FILE\n"
"%s --delete NAME remove prop entry NAME\n"
"\n"
size_t namelen = strlen(name);
size_t valuelen = strlen(value);
, arg0, arg0, arg0, arg0);
return 1;
}
if (trigger) {
printf("Set with property_service: '%s'='%s'\n", name, value);
} else {
printf("Modify data structure: '%s'='%s'\n", name, value);
static int init_resetprop() {
if (__system_properties_init2()) {
PRINT_E("resetprop: Initialize error\n");
return -1;
}
__system_property_get(name, value_read);
if(strlen(value_read)) {
printf("Existing property: '%s'='%s'\n", name, value_read);
if (trigger) {
if (!strncmp(name, "ro.", 3)) __system_property_del(name); // Only delete ro props
ret = __system_property_set(name, value);
} else {
ret = __system_property_update((prop_info*) __system_property_find(name), value, valuelen);
}
} else {
if (trigger) {
ret = __system_property_set(name, value);
} else {
ret = __system_property_add(name, namelen, value, valuelen);
}
}
if (ret != 0) {
fprintf(stderr, "Failed to set '%s'='%s'\n", name, value);
return ret;
}
__system_property_get(name, value_read);
printf("Recheck property: '%s'='%s'\n", name, value_read);
return 0;
}
int read_prop_file(const char* filename) {
printf("Attempting to read props from \'%s\'\n", filename);
int prop_exist(const char *name) {
if (init_resetprop()) return 0;
return __system_property_find2(name) != NULL;
}
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) {
if (init_resetprop()) return NULL;
const prop_info *pi = __system_property_find2(name);
if (pi == NULL) {
PRINT_D("resetprop: prop [%s] does not exist\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);
}
static void (*cb)(const char *);
static void run_actual_cb(void* cookie, const char *name, const char *value, uint32_t serial) {
cb(name);
}
static void prop_foreach_cb(const prop_info* pi, void* cookie) {
__system_property_read_callback2(pi, run_actual_cb, NULL);
}
void getprop_all(void (*cbk)(const char *name)) {
if (init_resetprop()) return;
cb = cbk;
__system_property_foreach2(prop_foreach_cb, NULL);
}
int setprop(const char *name, const char *value) {
return setprop2(name, value, 1);
}
int setprop2(const char *name, const char *value, const int trigger) {
if (init_resetprop()) return -1;
int ret;
prop_info *pi = (prop_info*) __system_property_find2(name);
if (pi != NULL) {
if (trigger) {
if (!strncmp(name, "ro.", 3)) deleteprop(name, trigger);
ret = __system_property_set2(name, value);
} else {
ret = __system_property_update2(pi, 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, const int trigger) {
if (init_resetprop()) return -1;
PRINT_D("resetprop: deleteprop [%s]\n", name);
if (__system_property_del(name)) {
PRINT_D("resetprop: delete prop: [%s] error\n", name);
return -1;
}
if (trigger && strstr(name, "persist.")) {
char buffer[PATH_MAX];
snprintf(buffer, sizeof(buffer), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
unlink(buffer);
}
return 0;
}
int read_prop_file(const char* filename, const int trigger) {
if (init_resetprop()) return -1;
PRINT_D("resetprop: Load prop file [%s]\n", filename);
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open \'%s\'\n", filename);
PRINT_E("Cannot open [%s]\n", filename);
return 1;
}
char *line = NULL, *pch;
@@ -185,30 +242,18 @@ int read_prop_file(const char* filename) {
if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
// Separate the string
*pch = '\0';
x_property_set(line + i, pch + 1);
setprop2(line + i, pch + 1, trigger);
}
free(line);
fclose(fp);
return 0;
}
int usage(char* name) {
fprintf(stderr, "usage: %s [-v] [-n] [--file propfile] [--delete name] [ name value ] \n", name);
fprintf(stderr, " -v :\n");
fprintf(stderr, " verbose output (Default: Disabled)\n");
fprintf(stderr, " -n :\n");
fprintf(stderr, " no event triggers when changing props (Default: Will trigger events)\n");
fprintf(stderr, " --file propfile :\n");
fprintf(stderr, " Read props from prop files (e.g. build.prop)\n");
fprintf(stderr, " --delete name :\n");
fprintf(stderr, " Remove a prop entry\n\n");
return 1;
}
int resetprop_main(int argc, char *argv[]) {
int main(int argc, char *argv[])
{
int exp_arg = 2, stdout_bak, null;
int del = 0, file = 0, trigger = 1;
int exp_arg = 2;
char *name, *value, *filename;
if (argc < 3) {
@@ -235,13 +280,13 @@ int main(int argc, char *argv[])
break;
} else {
if(!is_legal_property_name(argv[i], strlen(argv[i]))) {
fprintf(stderr, "Illegal property name \'%s\'\n", 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) {
fprintf(stderr, "Value too long \'%s\'\n", argv[i + 1]);
PRINT_E("Value too long: [%s]\n", argv[i + 1]);
return 1;
}
value = argv[i + 1];
@@ -251,30 +296,13 @@ int main(int argc, char *argv[])
}
}
if (!verbose) {
fflush(stdout);
stdout_bak = dup(1);
null = open("/dev/null", O_WRONLY);
dup2(null, 1);
}
printf("resetprop by nkk71 & topjohnwu\n");
printf("Initializing...\n");
if (__system_properties_init()) {
fprintf(stderr, "Error during init\n");
return 1;
}
if (file) {
if (read_prop_file(filename)) return 1;
return read_prop_file(filename, trigger);
} else if (del) {
printf("Attempting to delete '%s'\n", name);
if (__system_property_del(name)) return 1;
return deleteprop(name, trigger);
} else {
if(x_property_set(name, value)) return 1;
return setprop2(name, value, trigger);
}
printf("Done!\n\n");
return 0;
return 0;
}

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_callback 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_callback() 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_callback instead. */
int __system_property_read2(const prop_info* pi, char* name, char* value);
/* Deprecated. Use __system_property_read_callback instead. */
int __system_property_get2(const char* name, char* value);
/* Deprecated. Use __system_property_foreach instead. */
const prop_info* __system_property_find_nth2(unsigned n);
__END_DECLS
#endif

2
jni/su

Submodule jni/su updated: 356b2c0f5f...c66632227b

212
jni/utils/img.c Normal file
View File

@@ -0,0 +1,212 @@
/* img.c - All image related functions
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <linux/loop.h>
#include "magisk.h"
#include "utils.h"
static int e2fsck(const char *img) {
// Check and repair ext4 image
char buffer[128];
int pid, fd = -1;
pid = exec_command(1, &fd, NULL, "e2fsck", "-yf", img, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd))
LOGD("magisk_img: %s", buffer);
waitpid(pid, NULL, 0);
close(fd);
return 0;
}
static char *loopsetup(const char *img) {
char device[20];
struct loop_info64 info;
int i, lfd, ffd;
memset(&info, 0, sizeof(info));
// First get an empty loop device
for (i = 0; i <= 7; ++i) {
sprintf(device, "/dev/block/loop%d", i);
lfd = xopen(device, O_RDWR);
if (ioctl(lfd, LOOP_GET_STATUS64, &info) == -1)
break;
close(lfd);
}
if (i == 8) return NULL;
ffd = xopen(img, O_RDWR);
if (ioctl(lfd, LOOP_SET_FD, ffd) == -1)
return NULL;
strcpy((char *) info.lo_file_name, img);
ioctl(lfd, LOOP_SET_STATUS64, &info);
close(lfd);
close(ffd);
return strdup(device);
}
int create_img(const char *img, int size) {
unlink(img);
LOGI("Create %s with size %dM\n", img, size);
// Create a temp file with the file contexts
char file_contexts[] = "/magisk(/.*)? u:object_r:system_file:s0\n";
// If not root, attempt to create in current diretory
char *filename = getuid() == UID_ROOT ? "/dev/file_contexts_image" : "file_contexts_image";
int ret, fd = xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
xwrite(fd, file_contexts, sizeof(file_contexts));
close(fd);
char buffer[16];
snprintf(buffer, sizeof(buffer), "%dM", size);
ret = exec_command_sync("make_ext4fs", "-l", buffer, "-a", "/magisk", "-S", filename, img, NULL);
if (ret < 0)
return 1;
unlink(filename);
return ret;
}
int get_img_size(const char *img, int *used, int *total) {
if (access(img, R_OK) == -1)
return 1;
char buffer[PATH_MAX];
int pid, fd = -1, status = 1;
pid = exec_command(1, &fd, NULL, "e2fsck", "-n", img, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd)) {
if (strstr(buffer, img)) {
char *tok = strtok(buffer, ",");
while(tok != NULL) {
if (strstr(tok, "blocks")) {
status = 0;
break;
}
tok = strtok(NULL, ",");
}
if (status) continue;
sscanf(tok, "%d/%d", used, total);
*used = *used / 256 + 1;
*total /= 256;
break;
}
}
close(fd);
waitpid(pid, NULL, 0);
return 0;
}
int resize_img(const char *img, int size) {
LOGI("Resize %s to %dM\n", img, size);
if (e2fsck(img))
return 1;
char buffer[128];
int pid, status, fd = -1;
snprintf(buffer, sizeof(buffer), "%dM", size);
pid = exec_command(1, &fd, NULL, "resize2fs", img, buffer, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd))
LOGD("magisk_img: %s", buffer);
close(fd);
waitpid(pid, &status, 0);
return WEXITSTATUS(status);
}
char *mount_image(const char *img, const char *target) {
if (access(img, F_OK) == -1)
return NULL;
if (access(target, F_OK) == -1) {
if (xmkdir(target, 0755) == -1) {
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
xmkdir(target, 0755);
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
}
}
if (e2fsck(img))
return NULL;
char *device = loopsetup(img);
if (device)
xmount(device, target, "ext4", 0, NULL);
return device;
}
void umount_image(const char *target, const char *device) {
xumount(target);
int fd = xopen(device, O_RDWR);
ioctl(fd, LOOP_CLR_FD);
close(fd);
}
int merge_img(const char *source, const char *target) {
if (access(source, F_OK) == -1)
return 0;
if (access(target, F_OK) == -1) {
rename(source, target);
return 0;
}
char buffer[PATH_MAX];
// resize target to worst case
int s_used, s_total, t_used, t_total, n_total;
get_img_size(source, &s_used, &s_total);
get_img_size(target, &t_used, &t_total);
n_total = round_size(s_used + t_used);
if (n_total != t_total)
resize_img(target, n_total);
xmkdir(SOURCE_TMP, 0755);
xmkdir(TARGET_TMP, 0755);
char *s_loop, *t_loop;
s_loop = mount_image(source, SOURCE_TMP);
if (s_loop == NULL) return 1;
t_loop = mount_image(target, TARGET_TMP);
if (t_loop == NULL) return 1;
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(SOURCE_TMP)))
return 1;
while ((entry = xreaddir(dir))) {
if (entry->d_type == DT_DIR) {
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0 ||
strcmp(entry->d_name, ".core") == 0 ||
strcmp(entry->d_name, "lost+found") == 0)
continue;
// Cleanup old module if exists
snprintf(buffer, sizeof(buffer), "%s/%s", TARGET_TMP, entry->d_name);
if (access(buffer, F_OK) == 0) {
LOGI("Upgrade module: %s\n", entry->d_name);
exec_command_sync(BBPATH "/rm", "-rf", buffer, NULL);
} else {
LOGI("New module: %s\n", entry->d_name);
}
}
}
closedir(dir);
cp_afc(SOURCE_TMP, TARGET_TMP);
// Unmount all loop devices
umount_image(SOURCE_TMP, s_loop);
umount_image(TARGET_TMP, t_loop);
rmdir(SOURCE_TMP);
rmdir(TARGET_TMP);
free(s_loop);
free(t_loop);
unlink(source);
return 0;
}
void trim_img(const char *img) {
int used, total, new_size;
get_img_size(img, &used, &total);
new_size = round_size(used);
if (new_size != total)
resize_img(img, new_size);
}

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

@@ -0,0 +1,42 @@
/* 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);
}
struct list_head *list_pop(struct list_head *pos) {
struct list_head *ret;
ret = pos->prev;
// Maintain the list
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
// Remove references
pos->next = pos;
pos->prev = pos;
// Return the previous node in the list
return ret;
}
struct list_head *list_pop_end(struct list_head *head) {
return list_pop(head->prev);
}

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

@@ -0,0 +1,433 @@
/* 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 <stdarg.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 = xfopen(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 */
static int is_num(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 (is_num(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
*cb -> A callback function which runs after fork
*/
static int v_exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, va_list argv) {
int pipefd[2], writeEnd = -1;
if (fd) {
if (*fd < 0) {
if (xpipe2(pipefd, O_CLOEXEC) == -1)
return -1;
writeEnd = pipefd[1];
} else {
writeEnd = *fd;
}
}
// Collect va_list into vector
struct vector args;
vec_init(&args);
vec_push_back(&args, strdup(argv0));
for (void *arg = va_arg(argv, void*); arg; arg = va_arg(argv, void*))
vec_push_back(&args, strdup(arg));
vec_push_back(&args, NULL);
// Setup environment
char *const *envp;
struct vector env;
vec_init(&env);
if (setupenv) {
setupenv(&env);
envp = (char **) vec_entry(&env);
} else {
extern char **environ;
envp = environ;
}
int pid = fork();
if (pid != 0) {
if (fd && *fd < 0) {
// Give the read end and close write end
*fd = pipefd[0];
close(pipefd[1]);
}
vec_deep_destroy(&args);
vec_deep_destroy(&env);
return pid;
}
// Don't return to the daemon if anything goes wrong
err_handler = exit_proc;
if (fd) {
xdup2(writeEnd, STDOUT_FILENO);
if (err) xdup2(writeEnd, STDERR_FILENO);
}
execvpe(argv0, (char **) vec_entry(&args), envp);
PLOGE("execvpe");
return -1;
}
int exec_command_sync(char *const argv0, ...) {
va_list argv;
va_start(argv, argv0);
int pid, status;
pid = v_exec_command(0, NULL, NULL, argv0, argv);
va_end(argv);
if (pid < 0)
return pid;
waitpid(pid, &status, 0);
return WEXITSTATUS(status);
}
int exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, ...) {
va_list argv;
va_start(argv, argv0);
int pid = v_exec_command(err, fd, setupenv, argv0, argv);
va_end(argv);
return pid;
}
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 MAGISK_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);
}
int cp_afc(const char *source, const char *target) {
struct stat buf;
xlstat(source, &buf);
if (S_ISDIR(buf.st_mode)) {
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);
cp_afc(s_path, t_path);
}
free(s_path);
free(t_path);
closedir(dir);
} else{
unlink(target);
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);
fclone_attr(sfd, tfd);
close(sfd);
close(tfd);
} else if (S_ISLNK(buf.st_mode)) {
char buffer[PATH_MAX];
xreadlink(source, buffer, sizeof(buffer));
xsymlink(buffer, target);
clone_attr(source, target);
} else {
return 1;
}
}
return 0;
}
void clone_attr(const char *source, const char *target) {
struct stat buf;
lstat(target, &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 fclone_attr(const int sourcefd, const int targetfd) {
struct stat buf;
fstat(sourcefd, &buf);
fchmod(targetfd, buf.st_mode & 0777);
fchown(targetfd, buf.st_uid, buf.st_gid);
char *con;
fgetfilecon(sourcefd, &con);
fsetfilecon(targetfd, 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 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;
}

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;
}

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 xpipe2(int pipefd[2], int flags) {
int ret = pipe2(pipefd, flags);
if (ret == -1) {
PLOGE("pipe2");
}
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 xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
int fd = accept4(sockfd, addr, addrlen, flags);
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 && errno != EEXIST) {
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;
}

97
scripts/addon.d.sh Normal file
View File

@@ -0,0 +1,97 @@
#!/sbin/sh
##########################################################################################
#
# Magisk Survival Script for ROMs with addon.d support
# by topjohnwu
#
# Inspired by 99-flashafterupdate.sh of osm0sis @ xda-developers
#
##########################################################################################
. /tmp/backuptool.functions
main() {
# Magisk binaries
MAGISKBIN=/data/magisk
# This script always run in recovery
BOOTMODE=false
if [ ! -d $MAGISKBIN ]; then
echo "! Cannot find Magisk binaries!"
exit 1
fi
# Wait for post addon.d processes to finish
sleep 5
mount -o ro /system 2>/dev/null
mount -o ro /vendor 2>/dev/null
mount /data 2>/dev/null
# Load utility functions
. $MAGISKBIN/util_functions.sh
[ -f /system/build.prop ] || abort "! /system could not be mounted!"
ui_print "************************"
ui_print "* Magisk v$MAGISK_VER addon.d"
ui_print "************************"
api_level_arch_detect
# Check if system root is installed and remove
remove_system_su
recovery_actions
find_boot_image
[ -z $BOOTIMAGE ] && abort "! Unable to detect boot image"
ui_print "- Found Boot Image: $BOOTIMAGE"
SOURCEDMODE=true
cd $MAGISKBIN
# Source the boot patcher
. $MAGISKBIN/boot_patch.sh "$BOOTIMAGE"
[ -f stock_boot* ] && rm -f /data/stock_boot* 2>/dev/null
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 >/dev/null 2>&1
fi
rm -f new-boot.img
cd /
recovery_cleanup
ui_print "- Done"
exit 0
}
case "$1" in
backup)
# Stub
;;
restore)
# Stub
;;
pre-backup)
# Stub
;;
post-backup)
# Stub
;;
pre-restore)
# Stub
;;
post-restore)
# Get the FD for ui_print
OUTFD=`ps | grep -v grep | grep -oE "update(.*)" | cut -d" " -f3`
# Run the main function in a parallel subshell
(main) &
;;
esac

243
scripts/boot_patch.sh Normal file
View File

@@ -0,0 +1,243 @@
#!/system/bin/sh
##########################################################################################
#
# Magisk Boot Image Patcher
# by topjohnwu
#
# This script should be placed in a directory with 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 the ramdisk for Magisk support
# init.magisk.rc script A new line will be added to init.rc to import this script.
# All magisk entrypoints are defined here
# chromeos folder This folder should store all the utilities and keys to sign
# (optional) a chromeos device, used in the tablet Pixel C
#
# 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
#
##########################################################################################
##########################################################################################
# Functions
##########################################################################################
# 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"
}
# Call abort if exists, or else show error message and exit
# Essential when wrapped in flashable zip
abort_wrap() {
type abort >/dev/null 2>&1
if [ $? -ne 0 ]; then
ui_print_wrap "$1"
exit 1
else
abort "$1"
fi
}
# Pure bash dirname implementation
dirname_wrap() {
case "$1" in
*/*)
dir=${1%/*}
[ -z $dir ] && echo "/" || echo $dir
;;
*)
echo "."
;;
esac
}
# Pure bash basename implementation
basename_wrap() {
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() {
./magiskboot --cpio-add ramdisk.cpio $1 $2 $3
}
# --cpio-extract <incpio> <entry> <outfile>
cpio_extract() {
./magiskboot --cpio-extract ramdisk.cpio $1 $2
}
# --cpio-mkdir <incpio> <mode> <entry>
cpio_mkdir() {
./magiskboot --cpio-mkdir ramdisk.cpio $1 $2
}
##########################################################################################
# Initialization
##########################################################################################
[ -z $1 ] && abort_wrap "This script requires a boot image as a parameter"
cwd=`pwd`
cd "`dirname_wrap $1`"
BOOTIMAGE="`pwd`/`basename_wrap $1`"
cd $cwd
[ -e "$BOOTIMAGE" ] || abort_wrap "$BOOTIMAGE does not exist!"
# Presets
[ -z $KEEPVERITY ] && KEEPVERITY=false
[ -z $KEEPFORCEENCRYPT ] && KEEPFORCEENCRYPT=false
# Detect whether running as root
id | grep "uid=0" >/dev/null 2>&1 && ROOT=true || ROOT=false
# Switch to the location of the script file
[ -z $SOURCEDMODE ] && cd "`dirname_wrap "${BASH_SOURCE:-$0}"`"
chmod -R 755 .
##########################################################################################
# Unpack
##########################################################################################
migrate_boot_backup
CHROMEOS=false
ui_print_wrap "- Unpacking boot image"
./magiskboot --unpack "$BOOTIMAGE"
case $? in
1 )
abort_wrap "! Unable to unpack boot image"
;;
2 )
CHROMEOS=true
;;
3 )
ui_print_wrap "! Sony ELF32 format detected"
abort_wrap "! Please use BootBridge from @AdrianDC to flash Magisk"
;;
4 )
ui_print_wrap "! Sony ELF64 format detected"
abort_wrap "! Stock kernel cannot be patched, please use a custom kernel"
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"
./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=`./magiskboot --sha1 "$BOOTIMAGE" 2>/dev/null`
STOCKDUMP=stock_boot_${SHA1}.img
dd if="$BOOTIMAGE" of=$STOCKDUMP
./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
[ -z $SHA1 ] && SHA1=`./magiskboot --cpio-stocksha1 ramdisk.cpio 2>/dev/null`
OK=false
./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"
./magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
./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!"
abort_wrap "! Please restore stock boot image"
;;
esac
##########################################################################################
# Ramdisk patches
##########################################################################################
ui_print_wrap "- Patching ramdisk"
# Add magisk entrypoint
./magiskboot --cpio-patch ramdisk.cpio $KEEPVERITY $KEEPFORCEENCRYPT
# sepolicy patches
cpio_extract sepolicy sepolicy
./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
mv init.magisk.rc.bak init.magisk.rc 2>/dev/null
cpio_add 755 sbin/magisk magisk
# Create ramdisk backups
./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig
rm -f ramdisk.cpio.orig
##########################################################################################
# Repack and flash
##########################################################################################
# Hexpatches
# Remove Samsung RKP in stock kernel
./magiskboot --hexpatch kernel \
49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
ui_print_wrap "- Repacking boot image"
./magiskboot --repack "$BOOTIMAGE" || abort_wrap "! Unable to repack boot image!"
# Sign chromeos boot
$CHROMEOS && sign_chromeos
./magiskboot --cleanup

View File

@@ -1,57 +0,0 @@
#!/system/bin/sh
RAMDISK=$1
TMPDIR=/dev/tmp
MAGISKBIN=/data/magisk
[ ! -e $MAGISKBIN ] && MAGISKBIN=/cache/data_bin
[ ! -e $MAGISKBIN ] && exit 1
SYSTEMLIB=/system/lib
[ -d /system/lib64 ] && SYSTEMLIB=/system/lib64
mkdir -p $TMPDIR 2>/dev/null
cd $TMPDIR
cpio_add() {
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-add $RAMDISK $RAMDISK $1 $2 $3
}
cpio_extract() {
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-extract $RAMDISK $1 $2
}
cpio_mkdir() {
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-mkdir $RAMDISK $RAMDISK $1 $2
}
# Recursive
cpio_rm() {
if [ "$1" = "-r" ]; then
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-ls $RAMDISK | grep "^$2/" | while read i ; do
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-rm $RAMDISK $RAMDISK $i
done
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-rmdir $RAMDISK $RAMDISK $2
else
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-rm $RAMDISK $RAMDISK $1
fi
}
# Cleanup SuperSU backups
cpio_rm -r .subackup
# 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
# sepolicy patches
cpio_extract sepolicy sepolicy
LD_LIBRARY_PATH=$SYSTEMLIB $MAGISKBIN/magiskpolicy --load sepolicy --save sepolicy --minimal
cpio_add 644 sepolicy sepolicy
# Add new items
cpio_mkdir 755 magisk
cpio_add 750 init.magisk.rc $MAGISKBIN/init.magisk.rc
cpio_add 750 sbin/magic_mask.sh $MAGISKBIN/magic_mask.sh

View File

@@ -1,257 +1,80 @@
#!/sbin/sh
#MAGISK
##########################################################################################
#
# Magisk Boot Image Patcher
# Magisk Flash Script
# by topjohnwu
#
# This zip will patch your boot image with Magisk support
#
# This script will detect, construct the environment for Magisk
# It will then call boot_patch.sh to patch the boot image
#
##########################################################################################
MAGISK=true
##########################################################################################
# Preparation
##########################################################################################
# Detect whether in boot mode
ps | grep zygote | grep -v grep >/dev/null && BOOTMODE=true || BOOTMODE=false
$BOOTMODE || ps -A 2>/dev/null | grep zygote | grep -v grep >/dev/null && BOOTMODE=true
# This path should work in any cases
TMPDIR=/dev/tmp
INSTALLER=$TMPDIR/magisk
INSTALLER=$TMPDIR/install
COMMONDIR=$INSTALLER/common
BOOTTMP=$TMPDIR/boottmp
COREDIR=/magisk/.core
CHROMEDIR=$INSTALLER/chromeos
COREDIR=/magisk/.core
# 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
if [ ! -d "$COMMONDIR" ]; then
echo "! Unable to extract zip file!"
exit 1
fi
mkdir -p $INSTALLER
cd $INSTALLER
unzip -o "$ZIP"
# Load utility fuctions
. $COMMONDIR/util_functions.sh
##########################################################################################
# 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
}
# --cpio-add <incpio> <mode> <entry> <infile>
cpio_add() {
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-add ramdisk.cpio $1 $2 $3
}
# --cpio-extract <incpio> <entry> <outfile>
cpio_extract() {
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-extract ramdisk.cpio $1 $2
}
# --cpio-mkdir <incpio> <mode> <entry>
cpio_mkdir() {
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-mkdir ramdisk.cpio $1 $2
}
get_outfd
##########################################################################################
# Detection
##########################################################################################
ui_print "*****************************"
ui_print "MAGISK_VERSION_STUB"
ui_print "*****************************"
ui_print "************************"
ui_print "* Magisk v$MAGISK_VER Installer"
ui_print "************************"
if [ ! -d "$COMMONDIR" ]; then
ui_print "! Failed: Unable to extract zip file!"
exit 1
fi
ui_print "- Mounting /system(ro), /cache, /data"
ui_print "- Mounting /system, /vendor, /cache, /data"
mount -o ro /system 2>/dev/null
mount -o ro /vendor 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
[ -f /system/build.prop ] || abort "! /system could not be mounted!"
# read override variables
getvar KEEPVERITY
getvar KEEPFORCEENCRYPT
getvar BOOTIMAGE
[ -z $KEEPVERITY ] && KEEPVERITY=false
[ -z $KEEPFORCEENCRYPT ] && KEEPFORCEENCRYPT=false
# Detect version and architecture
api_level_arch_detect
[ $API -lt 21 ] && abort "! Magisk is only for Lollipop 5.0+ (SDK 21+)"
# 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
SYSTEMLIB=/system/lib
$IS64BIT && SYSTEMLIB=/system/lib64
find_boot_image
if [ -z $BOOTIMAGE ]; then
ui_print "! Unable to detect boot image"
exit 1
fi
##########################################################################################
# Environment
##########################################################################################
@@ -260,268 +83,57 @@ ui_print "- Constructing environment"
is_mounted /data && MAGISKBIN=/data/magisk || MAGISKBIN=/cache/data_bin
if $BOOTMODE; then
# Cleanup binary mirrors
umount -l /dev/magisk/mirror/bin 2>/dev/null
rm -rf /dev/magisk/mirror/bin 2>/dev/null
fi
# Copy required files
rm -rf $MAGISKBIN 2>/dev/null
mkdir -p $MAGISKBIN
cp -af $BINDIR/busybox $BINDIR/magiskboot $BINDIR/magiskpolicy $COMMONDIR/magisk.apk \
$COMMONDIR/init.magisk.rc $COMMONDIR/custom_ramdisk_patch.sh $COMMONDIR/magic_mask.sh $MAGISKBIN
# Legacy support
ln -sf /data/magisk/magiskpolicy $MAGISKBIN/sepolicy-inject
cp -af $BINDIR/. $COMMONDIR/. $CHROMEDIR $TMPDIR/bin/busybox $MAGISKBIN
chmod -R 755 $MAGISKBIN
chcon -h u:object_r:system_file:s0 $MAGISKBIN $MAGISKBIN/*
# Temporary busybox for installation
rm -rf $TMPDIR/busybox 2>/dev/null
mkdir -p $TMPDIR/busybox
$BINDIR/busybox --install -s $TMPDIR/busybox
rm -f $TMPDIR/busybox/su $TMPDIR/busybox/sh $TMPDIR/busybox/reboot
PATH=$TMPDIR/busybox:$PATH
##########################################################################################
# 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"
# addon.d
if [ -d /system/addon.d ]; then
ui_print "- Adding addon.d survival script"
mount -o rw,remount /system
cp -af $INSTALLER/addon.d/99-magisk.sh /system/addon.d/99-magisk.sh
chmod 755 /system/addon.d/99-magisk.sh
fi
if [ -f $IMG ]; then
ui_print "- $IMG detected!"
else
ui_print "- Creating $IMG"
make_ext4fs -l 64M -a /magisk -S $COMMONDIR/file_contexts_image $IMG
fi
mount_image $IMG /magisk
if (! is_mounted /magisk); then
ui_print "! Magisk image mount failed..."
exit 1
fi
MAGISKLOOP=$LOOPDEVICE
# Core folders and scripts
mkdir -p $COREDIR/bin $COREDIR/props $COREDIR/magiskhide $COREDIR/post-fs-data.d $COREDIR/service.d 2>/dev/null
cp -af $COMMONDIR/magiskhide/. $COREDIR/magiskhide
cp -af $BINDIR/resetprop $BINDIR/magiskhide $BINDIR/su $BINDIR/magiskpolicy $COREDIR/bin
# Legacy support
ln -sf $COREDIR/bin/resetprop $MAGISKBIN/resetprop
chmod -R 755 $COREDIR/bin $COREDIR/magiskhide $COREDIR/post-fs-data.d $COREDIR/service.d
chown -R 0.0 $COREDIR/bin $COREDIR/magiskhide $COREDIR/post-fs-data.d $COREDIR/service.d
$BOOTMODE && boot_actions || recovery_actions
##########################################################################################
# Unpack boot
# Boot patching
##########################################################################################
find_boot_image
[ -z $BOOTIMAGE ] && abort "! Unable to detect boot image"
ui_print "- Found Boot Image: $BOOTIMAGE"
rm -rf $BOOTTMP 2>/dev/null
mkdir -p $BOOTTMP
cd $BOOTTMP
SOURCEDMODE=true
cd $MAGISKBIN
ui_print "- Unpacking boot image"
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --unpack $BOOTIMAGE
if [ $? -ne 0 ]; then
ui_print "! Unable to unpack boot image"
exit 1
fi
# Source the boot patcher
. $COMMONDIR/boot_patch.sh "$BOOTIMAGE"
##########################################################################################
# Ramdisk restores
##########################################################################################
# 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
# Test patch status and do restore, after this section, ramdisk.cpio.orig is guaranteed to exist
SUPERSU=false
ui_print "- Checking patch status"
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-test ramdisk.cpio
case $? in
0 ) # Stock boot
ui_print "- Backing up stock boot image"
rm -f /data/stock_boot*
SHA1=`LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --sha1 $BOOTIMAGE | tail -n 1`
is_mounted /data && STOCKDUMP=/data/stock_boot_${SHA1}.img || STOCKDUMP=/cache/stock_boot_${SHA1}.img
dd if=$BOOTIMAGE of=$STOCKDUMP
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --compress $STOCKDUMP
cp -af ramdisk.cpio ramdisk.cpio.orig
;;
1 ) # Magisk patched
# Find SHA1 of stock boot image
if [ -z $SHA1 ]; then
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-extract ramdisk.cpio init.magisk.rc init.magisk.rc
SHA1=`grep_prop "# STOCKSHA1" init.magisk.rc`
[ ! -z $SHA1 ] && STOCKDUMP=/data/stock_boot_${SHA1}.img
rm -f init.magisk.rc
fi
ui_print "- Restoring ramdisk backup"
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-restore ramdisk.cpio
if [ $? -ne 0 ]; then
# Restore failed, try to find original
ui_print "! Cannot restore from ramdisk backup"
ui_print "- Finding stock boot image backup"
if [ -f ${STOCKDUMP}.gz ]; then
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --decompress ${STOCKDUMP}.gz stock_boot.img
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --unpack stock_boot.img
rm -f stock_boot.img
else
ui_print "! Cannot find stock boot image backup"
ui_print "! Will still try to complete installation"
fi
fi
cp -af ramdisk.cpio ramdisk.cpio.orig
;;
2 ) # SuperSU patched
SUPERSU=true
ui_print "- SuperSU patched boot detected!"
ui_print "- Adding ramdisk patch script for SuperSU"
cp -af $COMMONDIR/custom_ramdisk_patch.sh /data/custom_ramdisk_patch.sh
ui_print "- We are using SuperSU's own tools, mounting su.img"
is_mounted /data && SUIMG=/data/su.img || SUIMG=/cache/su.img
mount_image $SUIMG /su
SUPERSULOOP=$LOOPDEVICE
if (is_mounted /su); then
ui_print "- Restoring ramdisk backup with sukernel"
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-restore ramdisk.cpio ramdisk.cpio.orig
if [ $? -ne 0 ]; then
ui_print "! Cannot restore from ramdisk"
ui_print "- Finding stock boot image backup with sukernel"
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --restore ramdisk.cpio stock_boot.img
if [ $? -eq 0 ]; then
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --unpack stock_boot.img
cp -af ramdisk.cpio ramdisk.cpio.orig
rm stock_boot.img
else
ui_print "! Cannot find stock boot image backup"
exit 1
fi
fi
else
ui_print "! SuperSU image mount failed..."
ui_print "! Magisk scripts are placed correctly"
ui_print "! Flash SuperSU immediately to finish installation"
exit 1
fi
;;
esac
##########################################################################################
# Boot image patches
##########################################################################################
# All ramdisk patch commands are stored in a separate script
ui_print "- Patching ramdisk"
if $SUPERSU; then
# Use sukernel to patch ramdisk, so we can use its own tools to backup
sh $COMMONDIR/custom_ramdisk_patch.sh $BOOTTMP/ramdisk.cpio
# Create ramdisk backups
LD_LIBRARY_PATH=$SYSTEMLIB /su/bin/sukernel --cpio-backup ramdisk.cpio.orig ramdisk.cpio ramdisk.cpio
else
# The common patches
$KEEPVERITY || LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-patch-dmverity ramdisk.cpio
$KEEPFORCEENCRYPT || LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/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
# sepolicy patches
cpio_extract sepolicy sepolicy
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskpolicy --load sepolicy --save sepolicy --minimal
cpio_add 644 sepolicy sepolicy
# Add new items
cpio_mkdir 755 magisk
[ ! -z $SHA1 ] && echo "# STOCKSHA1=$SHA1" >> $COMMONDIR/init.magisk.rc
cpio_add 750 init.magisk.rc $COMMONDIR/init.magisk.rc
cpio_add 750 sbin/magic_mask.sh $COMMONDIR/magic_mask.sh
# Create ramdisk backups
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig
fi
rm -f ramdisk.cpio.orig
##########################################################################################
# Repack and flash
##########################################################################################
# Hexpatches
# Remove Samsung RKP in stock kernel
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --hexpatch kernel \
49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
ui_print "- Repacking boot image"
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --repack $BOOTIMAGE
case $? in
1 )
ui_print "! Unable to repack boot image!"
exit 1
;;
2 )
ui_print "! Boot partition space insufficient"
ui_print "! Remove ramdisk backups and try again"
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --cpio-rm ramdisk.cpio -r .backup
LD_LIBRARY_PATH=$SYSTEMLIB $BINDIR/magiskboot --repack $BOOTIMAGE
if [ $? -eq 2 ]; then
ui_print "! Boot partition size still too small..."
ui_print "! Unable to install Magisk"
exit 1
fi
;;
esac
# Sign chromeos boot
if [ -f chromeos ]; then
cp -af $CHROMEDIR/. $MAGISKBIN/chromeos
echo > config
echo > bootloader
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 config --arch arm --bootloader bootloader --flags 0x1
rm -f new-boot.img
mv new-boot.img.signed new-boot.img
fi
[ -f stock_boot* ] && rm -f /data/stock_boot* 2>/dev/null
ui_print "- Flashing new boot image"
[ ! -L $BOOTIMAGE ] && dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null
dd if=new-boot.img of=$BOOTIMAGE bs=4096
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 >/dev/null 2>&1
fi
rm -f new-boot.img
cd /
if ! $BOOTMODE; then
ui_print "- Unmounting partitions"
umount /magisk
losetup -d $MAGISKLOOP
rmdir /magisk
if $SUPERSU; then
umount /su
losetup -d $SUPERSULOOP
rmdir /su
fi
umount /system
fi
# Cleanups
$BOOTMODE || recovery_cleanup
rm -rf $TMPDIR
ui_print "- Done"
exit 0

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