mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-10-31 10:40:52 +01:00 
			
		
		
		
	Compare commits
	
		
			21 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | cdc5d983f3 | ||
|   | 96688e4dac | ||
|   | 28a945fee9 | ||
|   | c7e777255a | ||
|   | 2dd4cf040e | ||
|   | d1b9eca5eb | ||
|   | 594a67fe28 | ||
|   | cddeaffada | ||
|   | 2a8898e7c3 | ||
|   | ce3f3b09b4 | ||
|   | fe4b3df7e9 | ||
|   | 25bdbcf526 | ||
|   | df7eaa5598 | ||
|   | bb7099376b | ||
|   | 0327fd9710 | ||
|   | e645c6e465 | ||
|   | 78a3d36ccc | ||
|   | 3942858ccd | ||
|   | 03c8d716cc | ||
|   | 60181c4fcb | ||
|   | c215447405 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -2,6 +2,7 @@ obj/ | ||||
| libs/ | ||||
| *.zip | ||||
| *.jks | ||||
| *.apk | ||||
|  | ||||
| # Copied binaries | ||||
| # Built binaries | ||||
| ziptools/zipadjust | ||||
|   | ||||
							
								
								
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -11,7 +11,7 @@ | ||||
| 	path = jni/magiskpolicy | ||||
| 	url = https://github.com/topjohnwu/magiskpolicy.git | ||||
| [submodule "MagiskManager"] | ||||
| 	path = MagiskManager | ||||
| 	path = java | ||||
| 	url = https://github.com/topjohnwu/MagiskManager.git | ||||
| [submodule "jni/busybox"] | ||||
| 	path = jni/external/busybox | ||||
|   | ||||
 Submodule MagiskManager deleted from 773c24b7fc
									
								
							| @@ -45,7 +45,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| ## Credits | ||||
|  | ||||
| **MagiskManager** (`MagiskManager`) | ||||
| **MagiskManager** (`java`) | ||||
|  | ||||
| * Copyright 2016-2017, John Wu (@topjohnwu) | ||||
| * All contributors and translators | ||||
|   | ||||
							
								
								
									
										85
									
								
								build.py
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								build.py
									
									
									
									
									
								
							| @@ -51,6 +51,10 @@ def zip_with_msg(zipfile, source, target): | ||||
| 	print('zip: {} -> {}'.format(source, target)) | ||||
| 	zipfile.write(source, target) | ||||
|  | ||||
| def cp(source, target): | ||||
| 	print('cp: {} -> {}'.format(source, target)) | ||||
| 	shutil.copyfile(source, target) | ||||
|  | ||||
| def build_all(args): | ||||
| 	build_binary(args) | ||||
| 	build_apk(args) | ||||
| @@ -75,26 +79,23 @@ def build_apk(args): | ||||
|  | ||||
| 	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) | ||||
| 		target = os.path.join('java', 'app', 'src', 'main', 'assets', key) | ||||
| 		cp(source, target) | ||||
|  | ||||
| 	for script in ['magisk_uninstaller.sh', 'util_functions.sh']: | ||||
| 		source = os.path.join('scripts', script) | ||||
| 		target = os.path.join('MagiskManager', 'app', 'src', 'main', 'assets', script) | ||||
| 		print('cp: {} -> {}'.format(source, target)) | ||||
| 		shutil.copyfile(source, target) | ||||
| 		target = os.path.join('java', 'app', 'src', 'main', 'assets', script) | ||||
| 		cp(source, target) | ||||
|  | ||||
| 	os.chdir('MagiskManager') | ||||
| 	os.chdir('java') | ||||
|  | ||||
| 	# Build unhide app and place in assets | ||||
| 	proc = subprocess.run('{} unhide::assembleRelease'.format(os.path.join('.', 'gradlew')), shell=True) | ||||
| 	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) | ||||
| 	cp(source, target) | ||||
|  | ||||
| 	print('') | ||||
|  | ||||
| @@ -102,7 +103,7 @@ def build_apk(args): | ||||
| 		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) | ||||
| 		proc = subprocess.run('{} app:assembleRelease'.format(os.path.join('.', 'gradlew')), shell=True) | ||||
| 		if proc.returncode != 0: | ||||
| 			error('Build Magisk Manager failed!') | ||||
|  | ||||
| @@ -141,16 +142,26 @@ def build_apk(args): | ||||
| 		silentremove(unsigned) | ||||
| 		silentremove(aligned) | ||||
| 	else: | ||||
| 		proc = subprocess.run('{} app::assembleDebug'.format(os.path.join('.', 'gradlew')), shell=True) | ||||
| 		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): | ||||
| def build_snet(args): | ||||
| 	os.chdir('java') | ||||
| 	proc = subprocess.run('{} snet:assembleRelease'.format(os.path.join('.', 'gradlew')), shell=True) | ||||
| 	if proc.returncode != 0: | ||||
| 		error('Build snet extention failed!') | ||||
| 	source = os.path.join('snet', 'build', 'outputs', 'apk', 'release', 'snet-release-unsigned.apk') | ||||
| 	target = os.path.join('..', 'snet.apk') | ||||
| 	print('') | ||||
| 	cp(source, target) | ||||
| 	os.chdir('..') | ||||
|  | ||||
| 	zipsigner = os.path.join('ziptools', 'zipsigner', 'build', 'libs', 'zipsigner.jar') | ||||
| def sign_adjust_zip(unsigned, output): | ||||
| 	jarsigner = os.path.join('java', 'jarsigner', 'build', 'libs', 'jarsigner-fat.jar') | ||||
|  | ||||
| 	if os.name != 'nt' and not os.path.exists(os.path.join('ziptools', 'zipadjust')): | ||||
| 		header('* Building zipadjust') | ||||
| @@ -158,13 +169,13 @@ def sign_adjust_zip(unsigned, output): | ||||
| 		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 not os.path.exists(jarsigner): | ||||
| 		header('* Building jarsigner-fat.jar') | ||||
| 		os.chdir('java') | ||||
| 		proc = subprocess.run('{} jarsigner:shadowJar'.format(os.path.join('.', 'gradlew')), shell=True) | ||||
| 		if proc.returncode != 0: | ||||
| 			error('Build zipsigner.jar failed!') | ||||
| 		os.chdir(os.path.join('..', '..')) | ||||
| 			error('Build jarsigner-fat.jar failed!') | ||||
| 		os.chdir('..') | ||||
|  | ||||
| 	header('* Signing / Adjusting Zip') | ||||
|  | ||||
| @@ -172,7 +183,7 @@ def sign_adjust_zip(unsigned, output): | ||||
| 	privateKey = os.path.join('ziptools', 'private.key.pk8') | ||||
|  | ||||
| 	# Unsigned->signed | ||||
| 	proc = subprocess.run(['java', '-jar', zipsigner, | ||||
| 	proc = subprocess.run(['java', '-jar', jarsigner, | ||||
| 		publicKey, privateKey, unsigned, 'tmp_signed.zip']) | ||||
| 	if proc.returncode != 0: | ||||
| 		error('First sign flashable zip failed!') | ||||
| @@ -183,7 +194,7 @@ def sign_adjust_zip(unsigned, output): | ||||
| 		error('Adjust flashable zip failed!') | ||||
|  | ||||
| 	# Adjusted -> output | ||||
| 	proc = subprocess.run(['java', '-jar', zipsigner, | ||||
| 	proc = subprocess.run(['java', '-jar', jarsigner, | ||||
| 		"-m", publicKey, privateKey, 'tmp_adjusted.zip', output]) | ||||
| 	if proc.returncode != 0: | ||||
| 		error('Second sign flashable zip failed!') | ||||
| @@ -199,15 +210,15 @@ def gen_update_binary(): | ||||
| 	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())) | ||||
| 		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())) | ||||
| 		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('\'\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: | ||||
| @@ -243,7 +254,7 @@ def zip_main(args): | ||||
| 		zip_with_msg(zipf, source, target) | ||||
|  | ||||
| 		# APK | ||||
| 		source = os.path.join('MagiskManager', 'app', 'build', 'outputs', 'apk', | ||||
| 		source = os.path.join('java', '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) | ||||
| @@ -328,20 +339,21 @@ def zip_uninstaller(args): | ||||
|  | ||||
| def cleanup(args): | ||||
| 	if len(args.target) == 0: | ||||
| 		args.target = ['binary', 'apk', 'zip'] | ||||
| 		args.target = ['binary', 'java', 'zip'] | ||||
|  | ||||
| 	if 'binary' in args.target: | ||||
| 		header('* Cleaning Magisk binaries') | ||||
| 		header('* Cleaning 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') | ||||
| 	if 'java' in args.target: | ||||
| 		header('* Cleaning java') | ||||
| 		os.chdir('java') | ||||
| 		subprocess.run('{} clean'.format(os.path.join('.', 'gradlew')), shell=True) | ||||
| 		os.chdir('..') | ||||
| 		silentremove('snet.apk') | ||||
|  | ||||
| 	if 'zip' in args.target: | ||||
| 		header('* Cleaning created zip files') | ||||
| 		header('* Cleaning zip files') | ||||
| 		for f in os.listdir('.'): | ||||
| 			if '.zip' in f: | ||||
| 				print('rm {}'.format(f)) | ||||
| @@ -364,6 +376,9 @@ 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) | ||||
|  | ||||
| snet_parser = subparsers.add_parser('snet', help='build snet extention for Magisk Manager') | ||||
| snet_parser.set_defaults(func=build_snet) | ||||
|  | ||||
| zip_parser = subparsers.add_parser('zip', help='zip and sign Magisk into a flashable zip') | ||||
| zip_parser.add_argument('versionString') | ||||
| zip_parser.add_argument('versionCode', type=int) | ||||
| @@ -372,7 +387,7 @@ 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 = subparsers.add_parser('clean', help='clean [target...] targets: binary java zip') | ||||
| clean_parser.add_argument('target', nargs='*') | ||||
| clean_parser.set_defaults(func=cleanup) | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								java
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								java
									
									
									
									
									
										Submodule
									
								
							 Submodule java added at 13bf1b27b4
									
								
							| @@ -40,6 +40,7 @@ LOCAL_SRC_FILES := \ | ||||
| 	utils/xwrap.c \ | ||||
| 	utils/list.c \ | ||||
| 	utils/img.c \ | ||||
| 	utils/file.c \ | ||||
| 	magiskhide/magiskhide.c \ | ||||
| 	magiskhide/proc_monitor.c \ | ||||
| 	magiskhide/hide_utils.c \ | ||||
| @@ -97,10 +98,12 @@ LOCAL_C_INCLUDES := jni/include $(LIBSEPOL) | ||||
| LOCAL_SRC_FILES := \ | ||||
| 	magiskinit.c \ | ||||
| 	magiskboot/boot_utils.c \ | ||||
| 	utils/file.c \ | ||||
| 	utils/xwrap.c \ | ||||
| 	magiskpolicy/rules.c \ | ||||
| 	magiskpolicy/sepolicy.c \ | ||||
| 	magiskpolicy/api.c | ||||
| LOCAL_CFLAGS := -DNO_SELINUX | ||||
| LOCAL_LDFLAGS := -static | ||||
| include $(BUILD_EXECUTABLE) | ||||
| endif | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -21,13 +21,12 @@ | ||||
| #include "utils.h" | ||||
| #include "daemon.h" | ||||
| #include "magiskpolicy.h" | ||||
| #include "resetprop.h" | ||||
|  | ||||
| pthread_t sepol_patch; | ||||
| int is_restart = 0; | ||||
|  | ||||
| static void *request_handler(void *args) { | ||||
| 	// Setup the default error handler for threads | ||||
| 	err_handler = exit_thread; | ||||
|  | ||||
| 	int client = *((int *) args); | ||||
| 	free(args); | ||||
| 	client_request req = read_int(client); | ||||
| @@ -114,25 +113,22 @@ static void *large_sepol_patch(void *args) { | ||||
| 	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"); | ||||
| 	} | ||||
| static void *start_magisk_hide(void *args) { | ||||
| 	launch_magiskhide(-1); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| 	switch (fork()) { | ||||
| 	case -1: | ||||
| 		PLOGE("fork"); | ||||
| 	case 0: | ||||
| 		break; | ||||
| 	default: | ||||
| 		return; | ||||
| void auto_start_magiskhide() { | ||||
| 	char *hide_prop = getprop2(MAGISKHIDE_PROP, 1); | ||||
| 	if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) { | ||||
| 		pthread_t thread; | ||||
| 		xpthread_create(&thread, NULL, start_magisk_hide, NULL); | ||||
| 		pthread_detach(thread); | ||||
| 	} | ||||
| 	free(hide_prop); | ||||
| } | ||||
|  | ||||
| 	// First close the client, it's useless for us | ||||
| 	close(client); | ||||
| 	xsetsid(); | ||||
| void start_daemon() { | ||||
| 	setcon("u:r:su:s0"); | ||||
| 	umask(0); | ||||
| 	int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC); | ||||
| @@ -146,32 +142,36 @@ void start_daemon(int client) { | ||||
| 	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)); | ||||
| 	if (xbind(fd, (struct sockaddr*) &sun, sizeof(sun)) == -1) | ||||
| 		exit(1); | ||||
| 	xlisten(fd, 10); | ||||
|  | ||||
| 	if ((is_restart = access(UNBLOCKFILE, F_OK) == 0)) { | ||||
| 		// Restart stuffs if the daemon is restarted | ||||
| 		exec_command_sync("logcat", "-b", "all", "-c", NULL); | ||||
| 		auto_start_magiskhide(); | ||||
| 		start_debug_log(); | ||||
| 	} | ||||
|  | ||||
| 	// Start the log monitor | ||||
| 	monitor_logs(); | ||||
|  | ||||
| 	// Continue the larger patch in another thread, we will join later | ||||
| 	xpthread_create(&sepol_patch, NULL, large_sepol_patch, NULL); | ||||
|  | ||||
| 	LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n"); | ||||
|  | ||||
| 	// 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); | ||||
| 	xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL); | ||||
| 	// Notifiy init the daemon is started | ||||
| 	close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT)); | ||||
|  | ||||
| 	// Loop forever to listen for requests | ||||
| 	while(1) { | ||||
| @@ -188,12 +188,21 @@ void start_daemon(int client) { | ||||
| 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); | ||||
| 	if (xconnect(fd, (struct sockaddr*) &sun, sizeof(sun))) { | ||||
| 		// If we cannot access the daemon, we start a daemon in the child process if possible | ||||
|  | ||||
| 		if (getuid() != UID_ROOT || getgid() != UID_ROOT) { | ||||
| 			fprintf(stderr, "No daemon is currently running!\n"); | ||||
| 			exit(1); | ||||
| 		} | ||||
|  | ||||
| 		if (xfork() == 0) { | ||||
| 			LOGD("client: connect fail, try launching new daemon process\n"); | ||||
| 			close(fd); | ||||
| 			xsetsid(); | ||||
| 			start_daemon(); | ||||
| 		} | ||||
|  | ||||
| 		do { | ||||
| 			// Wait for 10ms | ||||
| 			usleep(10); | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| /* 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 | ||||
|  * | ||||
|  * A universal logcat monitor for many usages. Add listeners to the list, | ||||
|  * and the pointer of the new log line will be sent through pipes to trigger | ||||
|  * asynchronous events without polling | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| @@ -13,33 +13,146 @@ | ||||
|  | ||||
| #include "magisk.h" | ||||
| #include "utils.h" | ||||
| #include "daemon.h" | ||||
|  | ||||
| int logcat_events[] = { -1, -1, -1 }; | ||||
| extern int is_restart; | ||||
|  | ||||
| #ifdef MAGISK_DEBUG | ||||
| static int debug_log_pid, debug_log_fd; | ||||
| #endif | ||||
|  | ||||
| static void *logger_thread(void *args) { | ||||
| 	// Setup error handler | ||||
| 	err_handler = exit_thread; | ||||
| 	int log_fd = -1, log_pid; | ||||
| 	char line[4096]; | ||||
|  | ||||
| 	rename(LOGFILE, LASTLOG); | ||||
| 	int log_fd, log_pid; | ||||
|  | ||||
| 	log_fd = xopen(LOGFILE, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644); | ||||
| 	LOGD("log_monitor: logger start"); | ||||
|  | ||||
| 	while (1) { | ||||
| 		// Start logcat | ||||
| 		log_pid = exec_command(0, &log_fd, NULL, "logcat", "-v", "thread", "Magisk:I", "*:S", 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); | ||||
| 		log_pid = exec_command(0, &log_fd, NULL, "logcat", "-b", "all" , "-v", "threadtime", "-s", "am_proc_start", "Magisk", NULL); | ||||
| 		while (fdgets(line, sizeof(line), log_fd)) { | ||||
| 			for (int i = 0; i < (sizeof(logcat_events) / sizeof(int)); ++i) { | ||||
| 				if (logcat_events[i] > 0) { | ||||
| 					char *s = strdup(line); | ||||
| 					xwrite(logcat_events[i], &s, sizeof(s)); | ||||
| 				} | ||||
| 			} | ||||
| 			if (kill(log_pid, 0)) | ||||
| 				break; | ||||
| 		} | ||||
| 		// Clear buffer if restart required | ||||
| 		exec_command_sync("logcat", "-b", "all", "-c", NULL); | ||||
| 	} | ||||
|  | ||||
| 	// Should never be here, but well... | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* Start a new thread to monitor logcat and dump to logfile */ | ||||
| static void *magisk_log_thread(void *args) { | ||||
| 	int have_data = 0; | ||||
|  | ||||
| 	// Temp buffer for logs before we have data access | ||||
| 	struct vector logs; | ||||
| 	vec_init(&logs); | ||||
|  | ||||
| 	FILE *log; | ||||
| 	int pipefd[2]; | ||||
| 	if (xpipe2(pipefd, O_CLOEXEC) == -1) | ||||
| 		return NULL; | ||||
|  | ||||
| 	// Register our listener | ||||
| 	logcat_events[LOG_EVENT] = pipefd[1]; | ||||
|  | ||||
| 	LOGD("log_monitor: magisk log dumper start"); | ||||
|  | ||||
| 	for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) { | ||||
| 		char *ss; | ||||
| 		if ((ss = strstr(line, " Magisk")) && (ss[-1] != 'D') && (ss[-1] != 'V')) { | ||||
| 			if (!have_data) { | ||||
| 				if ((have_data = check_data())) { | ||||
| 					// Dump buffered logs to file | ||||
| 					if (!is_restart) | ||||
| 						rename(LOGFILE, LASTLOG); | ||||
| 					log = xfopen(LOGFILE, "a"); | ||||
| 					setbuf(log, NULL); | ||||
| 					char *tmp; | ||||
| 					vec_for_each(&logs, tmp) { | ||||
| 						fprintf(log, "%s", tmp); | ||||
| 						free(tmp); | ||||
| 					} | ||||
| 					vec_destroy(&logs); | ||||
| 				} else { | ||||
| 					vec_push_back(&logs, strdup(line)); | ||||
| 				} | ||||
| 			} | ||||
| 			if (have_data) | ||||
| 				fprintf(log, "%s", line); | ||||
| 		} | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static void *debug_magisk_log_thread(void *args) { | ||||
| 	FILE *log = xfopen(DEBUG_LOG, "a"); | ||||
| 	setbuf(log, NULL); | ||||
| 	int pipefd[2]; | ||||
| 	if (xpipe2(pipefd, O_CLOEXEC) == -1) | ||||
| 		return NULL; | ||||
|  | ||||
| 	LOGD("log_monitor: debug log dumper start"); | ||||
|  | ||||
| 	// Register our listener | ||||
| 	logcat_events[DEBUG_EVENT] = pipefd[1]; | ||||
|  | ||||
| 	for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) { | ||||
| 		char *ss; | ||||
| 		if ((ss = strstr(line, "Magisk"))) | ||||
| 			fprintf(log, "%s", line); | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* Start new threads to monitor logcat and dump to logfile */ | ||||
| void monitor_logs() { | ||||
| 	pthread_t thread; | ||||
|  | ||||
| 	// Start log file dumper before monitor | ||||
| 	xpthread_create(&thread, NULL, magisk_log_thread, NULL); | ||||
| 	pthread_detach(thread); | ||||
|  | ||||
| 	// Start logcat monitor | ||||
| 	xpthread_create(&thread, NULL, logger_thread, NULL); | ||||
| 	pthread_detach(thread); | ||||
|  | ||||
| } | ||||
|  | ||||
| void start_debug_full_log() { | ||||
| #ifdef MAGISK_DEBUG | ||||
| 	// Log everything initially | ||||
| 	debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644); | ||||
| 	debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", "-v", "threadtime", NULL); | ||||
| 	close(debug_log_fd); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void stop_debug_full_log() { | ||||
| #ifdef MAGISK_DEBUG | ||||
| 	// Stop recording the boot logcat after every boot task is done | ||||
| 	kill(debug_log_pid, SIGTERM); | ||||
| 	waitpid(debug_log_pid, NULL, 0); | ||||
| 	pthread_t thread; | ||||
| 	// Start debug thread | ||||
| 	xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL); | ||||
| 	pthread_detach(thread); | ||||
| 	start_debug_log(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void start_debug_log() { | ||||
| #ifdef MAGISK_DEBUG | ||||
| 	pthread_t thread; | ||||
| 	// Start debug thread | ||||
| 	xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL); | ||||
| 	pthread_detach(thread); | ||||
| #endif | ||||
| } | ||||
|   | ||||
| @@ -32,10 +32,6 @@ int create_links(const char *bin, const char *path) { | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| // 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" | ||||
| @@ -54,11 +50,12 @@ static void usage() { | ||||
| 		"   --resizeimg IMG SIZE      resize ext4 image. SIZE is interpreted in MB\n" | ||||
| 		"   --mountimg IMG PATH       mount IMG to PATH and prints the loop device\n" | ||||
| 		"   --umountimg PATH LOOP     unmount PATH and delete LOOP device\n" | ||||
| 		"   --[boot stage]            start boot stage service\n" | ||||
| 		"   --[init service]          start init service\n" | ||||
| 		"   --unlock-blocks           set BLKROSET flag to OFF for all block devices\n" | ||||
| 		"   --restorecon              fix selinux context on Magisk files and folders\n" | ||||
| 		"\n" | ||||
| 		"Supported boot stages:\n" | ||||
| 		"   post-fs, post-fs-data, service\n" | ||||
| 		"Supported init services:\n" | ||||
| 		"   daemon post-fs, post-fs-data, service\n" | ||||
| 		"\n" | ||||
| 		"Supported applets:\n" | ||||
| 	, argv0, argv0); | ||||
| @@ -71,8 +68,6 @@ static void usage() { | ||||
|  | ||||
| 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]; | ||||
| @@ -146,6 +141,12 @@ int main(int argc, char *argv[]) { | ||||
| 		} else if (strcmp(argv[1], "--unlock-blocks") == 0) { | ||||
| 			unlock_blocks(); | ||||
| 			return 0; | ||||
| 		} else if (strcmp(argv[1], "--restorecon") == 0) { | ||||
| 			fix_filecon(); | ||||
| 			return 0; | ||||
| 		} else if (strcmp(argv[1], "--daemon") == 0) { | ||||
| 			// Start daemon, this process won't return | ||||
| 			start_daemon(); | ||||
| 		} else if (strcmp(argv[1], "--post-fs") == 0) { | ||||
| 			int fd = connect_daemon(); | ||||
| 			write_int(fd, POST_FS); | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include <pthread.h> | ||||
|  | ||||
| extern pthread_t sepol_patch; | ||||
| extern int is_restart; | ||||
|  | ||||
| // Commands require connecting to daemon | ||||
| typedef enum { | ||||
| @@ -38,8 +39,9 @@ typedef enum { | ||||
|  | ||||
| // daemon.c | ||||
|  | ||||
| void start_daemon(int client); | ||||
| void start_daemon(); | ||||
| int connect_daemon(); | ||||
| void auto_start_magiskhide(); | ||||
|  | ||||
| // socket_trans.c | ||||
|  | ||||
| @@ -50,10 +52,6 @@ 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 * | ||||
|  ***************/ | ||||
| @@ -61,6 +59,7 @@ void monitor_logs(); | ||||
| void post_fs(int client); | ||||
| void post_fs_data(int client); | ||||
| void late_start(int client); | ||||
| void fix_filecon(); | ||||
|  | ||||
| /************** | ||||
|  * MagiskHide * | ||||
|   | ||||
| @@ -15,14 +15,6 @@ | ||||
|  | ||||
| #define LOG_TAG    "Magisk" | ||||
|  | ||||
| // 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() {} | ||||
|  | ||||
| #ifdef MAGISK_DEBUG | ||||
| #define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) | ||||
| #else | ||||
| @@ -32,7 +24,19 @@ static inline void do_nothing() {} | ||||
| #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(); } | ||||
| #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)) | ||||
|  | ||||
| enum { | ||||
| 	HIDE_EVENT, | ||||
| 	LOG_EVENT, | ||||
| 	DEBUG_EVENT | ||||
| }; | ||||
| extern int logcat_events[]; | ||||
|  | ||||
| void monitor_logs(); | ||||
| void start_debug_full_log(); | ||||
| void stop_debug_full_log(); | ||||
| void start_debug_log(); | ||||
|  | ||||
| #else // IS_DAEMON | ||||
|  | ||||
|   | ||||
| @@ -12,9 +12,11 @@ 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); | ||||
| char *getprop2(const char *name, int persist); | ||||
| int deleteprop(const char *name); | ||||
| int deleteprop2(const char *name, const int persist); | ||||
| int read_prop_file(const char* filename, const int trigger); | ||||
| void getprop_all(void (*cbk)(const char *name)); | ||||
| void getprop_all(void (*callback)(const char*, const char*)); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|   | ||||
| @@ -6,8 +6,6 @@ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <dirent.h> | ||||
| #include <pthread.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| @@ -18,8 +16,6 @@ | ||||
| #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); | ||||
| @@ -28,12 +24,14 @@ FILE *xfdopen(int fd, const char *mode); | ||||
| #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); | ||||
| int xopenat(int dirfd, const char *pathname, int flags); | ||||
| 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); | ||||
| DIR *xfdopendir(int fd); | ||||
| struct dirent *xreaddir(DIR *dirp); | ||||
| pid_t xsetsid(); | ||||
| int xsocket(int domain, int type, int protocol); | ||||
| @@ -53,22 +51,26 @@ 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); | ||||
| ssize_t xreadlinkat(int dirfd, 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); | ||||
| int xmkdir_p(const char *pathname, mode_t mode); | ||||
| int xmkdirat(int dirfd, const char *pathname, mode_t mode); | ||||
| void *xmmap(void *addr, size_t length, int prot, int flags, | ||||
| 	int fd, off_t offset); | ||||
| ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count); | ||||
| int xmkdir_p(const char *pathname, mode_t mode); | ||||
| pid_t xfork(); | ||||
|  | ||||
| // misc.c | ||||
|  | ||||
| extern int quit_signals[]; | ||||
|  | ||||
| unsigned get_shell_uid(); | ||||
| unsigned get_system_uid(); | ||||
| unsigned get_radio_uid(); | ||||
| @@ -82,14 +84,38 @@ 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); | ||||
| int fork_dont_care(); | ||||
|  | ||||
| // file.c | ||||
|  | ||||
| extern char **excl_list; | ||||
|  | ||||
| struct file_attr { | ||||
| 	struct stat st; | ||||
| 	char con[128]; | ||||
| }; | ||||
|  | ||||
| int fd_getpath(int fd, char *path, size_t size); | ||||
| int mkdir_p(const char *pathname, mode_t mode); | ||||
| void rm_rf(const char *path); | ||||
| void frm_rf(int dirfd); | ||||
| void mv_f(const char *source, const char *destination); | ||||
| void mv_dir(int src, int dest); | ||||
| void cp_afc(const char *source, const char *destination); | ||||
| void clone_dir(int src, int dest); | ||||
| int getattr(const char *path, struct file_attr *a); | ||||
| int getattrat(int dirfd, const char *pathname, struct file_attr *a); | ||||
| int fgetattr(int fd, struct file_attr *a); | ||||
| int setattr(const char *path, struct file_attr *a); | ||||
| int setattrat(int dirfd, const char *pathname, struct file_attr *a); | ||||
| int fsetattr(int fd, struct file_attr *a); | ||||
| void fclone_attr(const int sourcefd, const int targetfd); | ||||
| void clone_attr(const char *source, const char *target); | ||||
| void restorecon(int dirfd, int force); | ||||
|  | ||||
| // img.c | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ void mmap_ro(const char *filename, void **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); | ||||
| 	*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0) : NULL; | ||||
| 	close(fd); | ||||
| } | ||||
|  | ||||
| @@ -16,7 +16,7 @@ void mmap_rw(const char *filename, void **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); | ||||
| 	*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) : NULL; | ||||
| 	close(fd); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,7 @@ static void print_hdr(const boot_img_hdr *hdr) { | ||||
| 	fprintf(stderr, "KERNEL [%d] @ 0x%08x\n", hdr->kernel_size, hdr->kernel_addr); | ||||
| 	fprintf(stderr, "RAMDISK [%d] @ 0x%08x\n", hdr->ramdisk_size, hdr->ramdisk_addr); | ||||
| 	fprintf(stderr, "SECOND [%d] @ 0x%08x\n", hdr->second_size, hdr->second_addr); | ||||
| 	fprintf(stderr, "DTB [%d] @ 0x%08x\n", hdr->dt_size, hdr->tags_addr); | ||||
| 	fprintf(stderr, "EXTRA [%d] @ 0x%08x\n", hdr->extra_size, hdr->tags_addr); | ||||
| 	fprintf(stderr, "PAGESIZE [%d]\n", hdr->page_size); | ||||
| 	if (hdr->os_version != 0) { | ||||
| 		int a,b,c,y,m = 0; | ||||
| @@ -88,26 +88,24 @@ int parse_img(void *orig, size_t size, boot_img *boot) { | ||||
| 				mem_align(&pos, boot->hdr.page_size); | ||||
| 			} | ||||
|  | ||||
| 			if (boot->hdr.dt_size) { | ||||
| 				boot->dtb = base + pos; | ||||
| 				pos += boot->hdr.dt_size; | ||||
| 			if (boot->hdr.extra_size) { | ||||
| 				boot->extra = base + pos; | ||||
| 				pos += boot->hdr.extra_size; | ||||
| 				mem_align(&pos, boot->hdr.page_size); | ||||
| 			} | ||||
|  | ||||
| 			if (pos < size) { | ||||
| 				boot->extra = base + pos; | ||||
| 				boot->tail = base + pos; | ||||
| 				boot->tail_size = end - base - pos; | ||||
| 			} | ||||
|  | ||||
| 			// Search for dtb in kernel if not found | ||||
| 			if (boot->hdr.dt_size == 0) { | ||||
| 				for (int i = 0; i < boot->hdr.kernel_size; ++i) { | ||||
| 					if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) { | ||||
| 						boot->flags |= APPEND_DTB; | ||||
| 						boot->dtb = boot->kernel + i; | ||||
| 						boot->hdr.dt_size = boot->hdr.kernel_size - i; | ||||
| 						boot->hdr.kernel_size = i; | ||||
| 						fprintf(stderr, "APPEND_DTB [%d]\n", boot->hdr.dt_size); | ||||
| 					} | ||||
| 			// Search for dtb in kernel | ||||
| 			for (int i = 0; i < boot->hdr.kernel_size; ++i) { | ||||
| 				if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) { | ||||
| 					boot->dtb = boot->kernel + i; | ||||
| 					boot->dt_size = boot->hdr.kernel_size - i; | ||||
| 					boot->hdr.kernel_size = i; | ||||
| 					fprintf(stderr, "DTB [%d]\n", boot->dt_size); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| @@ -146,6 +144,7 @@ int parse_img(void *orig, size_t size, boot_img *boot) { | ||||
| 		} | ||||
| 	} | ||||
| 	LOGE("No boot image magic found!\n"); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| void unpack(const char* image) { | ||||
| @@ -160,22 +159,27 @@ void unpack(const char* image) { | ||||
| 	int ret = parse_img(orig, size, &boot); | ||||
|  | ||||
| 	// Dump kernel | ||||
| 	if (boot.kernel_type == UNKNOWN) { | ||||
| 		dump(boot.kernel, boot.hdr.kernel_size, KERNEL_FILE); | ||||
| 	} else { | ||||
| 	if (COMPRESSED(boot.kernel_type)) { | ||||
| 		fd = open_new(KERNEL_FILE); | ||||
| 		decomp(boot.kernel_type, fd, boot.kernel, boot.hdr.kernel_size); | ||||
| 		close(fd); | ||||
| 	} else { | ||||
| 		dump(boot.kernel, boot.hdr.kernel_size, KERNEL_FILE); | ||||
| 	} | ||||
|  | ||||
| 	if (boot.dt_size) { | ||||
| 		// Dump dtb | ||||
| 		dump(boot.dtb, boot.dt_size, DTB_FILE); | ||||
| 	} | ||||
|  | ||||
| 	// Dump ramdisk | ||||
| 	if (boot.ramdisk_type == UNKNOWN) { | ||||
| 		dump(boot.ramdisk, boot.hdr.ramdisk_size, RAMDISK_FILE ".raw"); | ||||
| 		LOGE("Unknown ramdisk format! Dumped to %s\n", RAMDISK_FILE ".raw"); | ||||
| 	} else { | ||||
| 	if (COMPRESSED(boot.ramdisk_type)) { | ||||
| 		fd = open_new(RAMDISK_FILE); | ||||
| 		decomp(boot.ramdisk_type, fd, boot.ramdisk, boot.hdr.ramdisk_size); | ||||
| 		close(fd); | ||||
| 	} else { | ||||
| 		dump(boot.ramdisk, boot.hdr.ramdisk_size, RAMDISK_FILE ".raw"); | ||||
| 		LOGE("Unknown ramdisk format! Dumped to %s\n", RAMDISK_FILE ".raw"); | ||||
| 	} | ||||
|  | ||||
| 	if (boot.hdr.second_size) { | ||||
| @@ -183,9 +187,9 @@ void unpack(const char* image) { | ||||
| 		dump(boot.second, boot.hdr.second_size, SECOND_FILE); | ||||
| 	} | ||||
|  | ||||
| 	if (boot.hdr.dt_size) { | ||||
| 		// Dump dtb | ||||
| 		dump(boot.dtb, boot.hdr.dt_size, DTB_FILE); | ||||
| 	if (boot.hdr.extra_size) { | ||||
| 		// Dump extra | ||||
| 		dump(boot.extra, boot.hdr.extra_size, EXTRA_FILE); | ||||
| 	} | ||||
|  | ||||
| 	munmap(orig, size); | ||||
| @@ -220,18 +224,18 @@ void repack(const char* orig_image, const char* out_image) { | ||||
| 		mtk_kernel_off = lseek(fd, 0, SEEK_CUR); | ||||
| 		write_zero(fd, 512); | ||||
| 	} | ||||
| 	if (boot.kernel_type == UNKNOWN) { | ||||
| 		boot.hdr.kernel_size = restore(KERNEL_FILE, fd); | ||||
| 	} else { | ||||
| 	if (COMPRESSED(boot.kernel_type)) { | ||||
| 		size_t raw_size; | ||||
| 		void *kernel_raw; | ||||
| 		mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size); | ||||
| 		boot.hdr.kernel_size = comp(boot.kernel_type, fd, kernel_raw, raw_size); | ||||
| 		munmap(kernel_raw, raw_size); | ||||
| 	} else { | ||||
| 		boot.hdr.kernel_size = restore(KERNEL_FILE, fd); | ||||
| 	} | ||||
| 	if (boot.flags & APPEND_DTB) { | ||||
| 	// Restore dtb | ||||
| 	if (boot.dt_size && access(DTB_FILE, R_OK) == 0) { | ||||
| 		boot.hdr.kernel_size += restore(DTB_FILE, fd); | ||||
| 		boot.hdr.dt_size = 0; | ||||
| 	} | ||||
| 	file_align(fd, boot.hdr.page_size, 1); | ||||
|  | ||||
| @@ -270,18 +274,17 @@ void repack(const char* orig_image, const char* out_image) { | ||||
| 		file_align(fd, boot.hdr.page_size, 1); | ||||
| 	} | ||||
|  | ||||
| 	// Restore dtb | ||||
| 	if (boot.hdr.dt_size && access(DTB_FILE, R_OK) == 0) { | ||||
| 		printf("Here\n"); | ||||
| 		boot.hdr.dt_size = restore(DTB_FILE, fd); | ||||
| 	// Restore extra | ||||
| 	if (boot.hdr.extra_size && access(EXTRA_FILE, R_OK) == 0) { | ||||
| 		boot.hdr.extra_size = restore(EXTRA_FILE, fd); | ||||
| 		file_align(fd, boot.hdr.page_size, 1); | ||||
| 	} | ||||
|  | ||||
| 	// Check extra info, currently only for LG Bump and Samsung SEANDROIDENFORCE | ||||
| 	if (boot.extra) { | ||||
| 		if (memcmp(boot.extra, "SEANDROIDENFORCE", 16) == 0 || | ||||
| 			memcmp(boot.extra, LG_BUMP_MAGIC, 16) == 0 ) { | ||||
| 			restore_buf(fd, boot.extra, 16); | ||||
| 	// Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE | ||||
| 	if (boot.tail_size >= 16) { | ||||
| 		if (memcmp(boot.tail, "SEANDROIDENFORCE", 16) == 0 || | ||||
| 			memcmp(boot.tail, LG_BUMP_MAGIC, 16) == 0 ) { | ||||
| 			restore_buf(fd, boot.tail, 16); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -44,7 +44,7 @@ struct boot_img_hdr | ||||
|  | ||||
|     uint32_t tags_addr;    /* physical addr for kernel tags */ | ||||
|     uint32_t page_size;    /* flash page size we assume */ | ||||
|     uint32_t dt_size;      /* device tree in bytes */ | ||||
|     uint32_t extra_size;   /* extra blob size in bytes */ | ||||
|  | ||||
|     /* operating system version and security patch level; for | ||||
|      * version "A.B.C" and patch level "Y-M-D": | ||||
| @@ -74,13 +74,13 @@ struct boot_img_hdr | ||||
| ** +-----------------+ | ||||
| ** | second stage    | o pages | ||||
| ** +-----------------+ | ||||
| ** | device tree     | p pages | ||||
| ** | extra blobs     | p pages | ||||
| ** +-----------------+ | ||||
| ** | ||||
| ** n = (kernel_size + page_size - 1) / page_size | ||||
| ** m = (ramdisk_size + page_size - 1) / page_size | ||||
| ** o = (second_size + page_size - 1) / page_size | ||||
| ** p = (dt_size + page_size - 1) / page_size | ||||
| ** p = (extra_size + page_size - 1) / page_size | ||||
| ** | ||||
| ** 0. all entities are page_size aligned in flash | ||||
| ** 1. kernel and ramdisk are required (size != 0) | ||||
| @@ -103,16 +103,18 @@ typedef struct mtk_hdr { | ||||
| // Flags | ||||
| #define MTK_KERNEL    0x1 | ||||
| #define MTK_RAMDISK   0x2 | ||||
| #define APPEND_DTB    0x4 | ||||
|  | ||||
| typedef struct boot_img { | ||||
|     boot_img_hdr hdr; | ||||
|     void *kernel; | ||||
|     void *dtb; | ||||
|     uint32_t dt_size; | ||||
|     void *ramdisk; | ||||
|     void *second; | ||||
|     void *dtb; | ||||
|     void *extra; | ||||
|     int flags; | ||||
|     void *tail; | ||||
|     uint32_t tail_size; | ||||
|     uint32_t flags; | ||||
|     file_t kernel_type, ramdisk_type; | ||||
|     mtk_hdr mtk_kernel_hdr, mtk_ramdisk_hdr; | ||||
| } boot_img; | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include <lzma.h> | ||||
| #include <lz4.h> | ||||
| #include <lz4frame.h> | ||||
| #include <lz4hc.h> | ||||
| #include <bzlib.h> | ||||
|  | ||||
| #include "magiskboot.h" | ||||
| @@ -37,8 +38,6 @@ size_t gzip(int mode, int fd, const void *buf, size_t size) { | ||||
| 		case 1: | ||||
| 			ret = deflateInit2(&strm, 9, Z_DEFLATED, windowBits | ZLIB_GZIP, memLevel, Z_DEFAULT_STRATEGY); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOGE("Unsupported gzip mode!\n"); | ||||
| 	} | ||||
|  | ||||
| 	if (ret != Z_OK) | ||||
| @@ -98,7 +97,7 @@ size_t lzma(int mode, int fd, const void *buf, size_t size) { | ||||
| 	unsigned char out[BUFSIZ]; | ||||
|  | ||||
| 	// Initialize preset | ||||
| 	lzma_lzma_preset(&opt, LZMA_PRESET_DEFAULT); | ||||
| 	lzma_lzma_preset(&opt, 9); | ||||
| 	lzma_filter filters[] = { | ||||
| 		{ .id = LZMA_FILTER_LZMA2, .options = &opt }, | ||||
| 		{ .id = LZMA_VLI_UNKNOWN, .options = NULL }, | ||||
| @@ -114,8 +113,6 @@ size_t lzma(int mode, int fd, const void *buf, size_t size) { | ||||
| 		case 2: | ||||
| 			ret = lzma_alone_encoder(&strm, &opt); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOGE("Unsupported lzma mode!\n"); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| @@ -168,8 +165,6 @@ size_t lz4(int mode, int fd, const void *buf, size_t size) { | ||||
| 		case 1: | ||||
| 			ret = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOGE("Unsupported lz4 mode!\n"); | ||||
| 	} | ||||
|  | ||||
| 	if (LZ4F_isError(ret)) | ||||
| @@ -283,8 +278,6 @@ size_t bzip2(int mode, int fd, const void* buf, size_t size) { | ||||
| 		case 1: | ||||
| 			ret = BZ2_bzCompressInit(&strm, 9, 0, 0); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOGE("Unsupported bzip2 mode!\n"); | ||||
| 	} | ||||
|  | ||||
| 	if (ret != BZ_OK) | ||||
| @@ -333,11 +326,10 @@ size_t bzip2(int mode, int fd, const void* buf, size_t size) { | ||||
|  | ||||
| // Mode: 0 = decode; 1 = encode | ||||
| size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) { | ||||
| 	size_t pos = 0, total = 0; | ||||
| 	size_t pos = 0; | ||||
| 	int have; | ||||
| 	char *out; | ||||
| 	unsigned block_size, insize; | ||||
| 	unsigned char block_size_le[4]; | ||||
| 	unsigned block_size, insize, total = 0; | ||||
|  | ||||
| 	switch(mode) { | ||||
| 		case 0: | ||||
| @@ -350,22 +342,17 @@ size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) { | ||||
| 			// Write magic | ||||
| 			total += xwrite(fd, "\x02\x21\x4c\x18", 4); | ||||
| 			break; | ||||
| 		default: | ||||
| 			LOGE("Unsupported lz4_legacy mode!\n"); | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
| 		const char *buff = buf; | ||||
| 		switch(mode) { | ||||
| 			case 0: | ||||
| 				block_size = buff[pos]; | ||||
| 				block_size += (buff[pos + 1]<<8); | ||||
| 				block_size += (buff[pos + 2]<<16); | ||||
| 				block_size += ((unsigned)buff[pos + 3])<<24; | ||||
| 				// Read block size | ||||
| 				block_size = *(unsigned *)(buf + pos); | ||||
| 				pos += 4; | ||||
| 				if (block_size > LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE)) | ||||
| 					LOGE("lz4_legacy block size too large!\n"); | ||||
| 				have = LZ4_decompress_safe((const char*) (buf + pos), out, block_size, LZ4_LEGACY_BLOCKSIZE); | ||||
| 					goto done; | ||||
| 				have = LZ4_decompress_safe(buf + pos, out, block_size, LZ4_LEGACY_BLOCKSIZE); | ||||
| 				if (have < 0) | ||||
| 					LOGE("Cannot decode lz4_legacy block\n"); | ||||
| 				pos += block_size; | ||||
| @@ -375,21 +362,24 @@ size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) { | ||||
| 					insize = size - pos; | ||||
| 				else | ||||
| 					insize = LZ4_LEGACY_BLOCKSIZE; | ||||
| 				have = LZ4_compress_default((const char*) (buf + pos), out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE)); | ||||
| 				have = LZ4_compress_HC(buf + pos, out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE), 9); | ||||
| 				if (have == 0) | ||||
| 					LOGE("lz4_legacy compression error\n"); | ||||
| 				pos += insize; | ||||
| 				block_size_le[0] = have & 0xff; | ||||
| 				block_size_le[1] = (have >> 8) & 0xff; | ||||
| 				block_size_le[2] = (have >> 16) & 0xff; | ||||
| 				block_size_le[3] = (have >> 24) & 0xff; | ||||
| 				total += xwrite(fd, block_size_le, 4); | ||||
| 				// Write block size | ||||
| 				total += xwrite(fd, &have, sizeof(have)); | ||||
| 				break; | ||||
| 		} | ||||
| 		// Write main data | ||||
| 		total += xwrite(fd, out, have); | ||||
| 	} while(pos < size); | ||||
|  | ||||
| done: | ||||
| 	if (mode == 1) { | ||||
| 		// Append original size to output | ||||
| 		unsigned uncomp = size; | ||||
| 		xwrite(fd, &uncomp, sizeof(uncomp)); | ||||
| 	} | ||||
| 	free(out); | ||||
| 	return total; | ||||
| } | ||||
|   | ||||
| @@ -5,16 +5,14 @@ | ||||
| #include "magiskboot.h" | ||||
| #include "utils.h" | ||||
|  | ||||
| /* Left here for debugging */ | ||||
|  | ||||
| // static void print_subnode(const void *fdt, int parent, int depth) { | ||||
| // 	int node; | ||||
| // 	fdt_for_each_subnode(node, fdt, parent) { | ||||
| // 		for (int i = 0; i < depth; ++i) printf("  "); | ||||
| // 		printf("%d: %s\n", node, fdt_get_name(fdt, node, NULL)); | ||||
| // 		print_subnode(fdt, node, depth + 1); | ||||
| // 	} | ||||
| // } | ||||
| static void print_subnode(const void *fdt, int parent, int depth) { | ||||
| 	int node; | ||||
| 	fdt_for_each_subnode(node, fdt, parent) { | ||||
| 		for (int i = 0; i < depth; ++i) printf("  "); | ||||
| 		printf("%d: %s\n", node, fdt_get_name(fdt, node, NULL)); | ||||
| 		print_subnode(fdt, node, depth + 1); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int find_fstab(const void *fdt, int parent) { | ||||
| 	int node, fstab; | ||||
| @@ -28,6 +26,25 @@ static int find_fstab(const void *fdt, int parent) { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| void dtb_print(const char *file) { | ||||
| 	size_t size ; | ||||
| 	void *dtb, *fdt; | ||||
| 	fprintf(stderr, "Loading dtbs from [%s]\n", file); | ||||
| 	mmap_ro(file, &dtb, &size); | ||||
| 	// Loop through all the dtbs | ||||
| 	int dtb_num = 0; | ||||
| 	for (int i = 0; i < size; ++i) { | ||||
| 		if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) { | ||||
| 			fdt = dtb + i; | ||||
| 			fprintf(stderr, "\nPrinting dtb.%04d\n\n", dtb_num++); | ||||
| 			print_subnode(fdt, 0, 0); | ||||
| 		} | ||||
| 	} | ||||
| 	fprintf(stderr, "\n"); | ||||
| 	munmap(dtb, size); | ||||
| 	exit(0); | ||||
| } | ||||
|  | ||||
| void dtb_patch(const char *file) { | ||||
| 	size_t size ; | ||||
| 	void *dtb, *fdt; | ||||
|   | ||||
| @@ -24,7 +24,7 @@ void hexpatch(const char *image, const char *from, const char *to) { | ||||
| 	patch = xmalloc(patchsize); | ||||
| 	hex2byte(from, pattern); | ||||
| 	hex2byte(to, patch); | ||||
| 	for (size_t i = 0; i < filesize - patternsize; ++i) { | ||||
| 	for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) { | ||||
| 		if (memcmp(file + i, pattern, patternsize) == 0) { | ||||
| 			fprintf(stderr, "Pattern %s found!\nPatching to %s\n", from, to); | ||||
| 			memset(file + i, 0, patternsize); | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #define KERNEL_FILE     "kernel" | ||||
| #define RAMDISK_FILE    "ramdisk.cpio" | ||||
| #define SECOND_FILE     "second" | ||||
| #define EXTRA_FILE      "extra" | ||||
| #define DTB_FILE        "dtb" | ||||
| #define NEW_BOOT        "new-boot.img" | ||||
|  | ||||
| @@ -22,6 +23,7 @@ int parse_img(void *orig, size_t size, boot_img *boot); | ||||
| int cpio_commands(const char *command, int argc, char *argv[]); | ||||
| void comp_file(const char *method, const char *from, const char *to); | ||||
| void decomp_file(char *from, const char *to); | ||||
| void dtb_print(const char *file); | ||||
| void dtb_patch(const char *file); | ||||
|  | ||||
| // Compressions | ||||
|   | ||||
| @@ -54,6 +54,9 @@ static void usage(char *arg0) { | ||||
| 		"    -stocksha1\n" | ||||
| 		"      Get stock boot SHA1 recorded within <incpio>\n" | ||||
| 		"\n" | ||||
| 		" --dtb-print <dtb>\n" | ||||
| 		"  Print all nodes in <dtb>, for debugging\n" | ||||
| 		"\n" | ||||
| 		" --dtb-patch <dtb>\n" | ||||
| 		"  Search for fstab in <dtb> and remove verity checks\n" | ||||
| 		"\n" | ||||
| @@ -94,6 +97,7 @@ int main(int argc, char *argv[]) { | ||||
| 		unlink(RAMDISK_FILE ".raw"); | ||||
| 		unlink(SECOND_FILE); | ||||
| 		unlink(DTB_FILE); | ||||
| 		unlink(EXTRA_FILE); | ||||
| 		for (int i = 0; SUP_EXT_LIST[i]; ++i) { | ||||
| 			sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]); | ||||
| 			unlink(name); | ||||
| @@ -113,6 +117,8 @@ int main(int argc, char *argv[]) { | ||||
| 		repack(argv[2], argc > 3 ? argv[3] : NEW_BOOT); | ||||
| 	} else if (argc > 2 && strcmp(argv[1], "--decompress") == 0) { | ||||
| 		decomp_file(argv[2], argc > 3 ? argv[3] : NULL); | ||||
| 	} else if (argc > 2 && strcmp(argv[1], "--dtb-print") == 0) { | ||||
| 		dtb_print(argv[2]); | ||||
| 	} else if (argc > 2 && strcmp(argv[1], "--dtb-patch") == 0) { | ||||
| 		dtb_patch(argv[2]); | ||||
| 	} else if (argc > 2 && strncmp(argv[1], "--compress", 10) == 0) { | ||||
|   | ||||
| @@ -18,6 +18,8 @@ typedef enum { | ||||
|     DTB | ||||
| } file_t; | ||||
|  | ||||
| #define COMPRESSED(type)  (type >= GZIP && type <= LZ4_LEGACY) | ||||
|  | ||||
| #define CHROMEOS_MAGIC  "CHROMEOS" | ||||
| #define ELF32_MAGIC     "\x7f""ELF\x01" | ||||
| #define ELF64_MAGIC     "\x7f""ELF\x02" | ||||
|   | ||||
| @@ -58,9 +58,9 @@ void hide_sensitive_props() { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void rm_magisk_prop(const char *name) { | ||||
| static void rm_magisk_prop(const char *name, const char *value) { | ||||
| 	if (strstr(name, "magisk")) { | ||||
| 		deleteprop(name, 0); | ||||
| 		deleteprop2(name, 0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -69,42 +69,6 @@ void clean_magisk_props() { | ||||
| 	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); | ||||
| @@ -223,7 +187,6 @@ int destroy_list() { | ||||
| } | ||||
|  | ||||
| void add_hide_list(int client) { | ||||
| 	err_handler = do_nothing; | ||||
| 	char *proc = read_string(client); | ||||
| 	// ack | ||||
| 	write_int(client, add_list(proc)); | ||||
| @@ -231,7 +194,6 @@ void add_hide_list(int client) { | ||||
| } | ||||
|  | ||||
| void rm_hide_list(int client) { | ||||
| 	err_handler = do_nothing; | ||||
| 	char *proc = read_string(client); | ||||
| 	// ack | ||||
| 	write_int(client, rm_list(proc)); | ||||
| @@ -239,7 +201,6 @@ void rm_hide_list(int client) { | ||||
| } | ||||
|  | ||||
| void ls_hide_list(int client) { | ||||
| 	err_handler = do_nothing; | ||||
| 	if (!hideEnabled) { | ||||
| 		write_int(client, HIDE_NOT_ENABLED); | ||||
| 		return; | ||||
|   | ||||
| @@ -41,9 +41,6 @@ static void usage(char *arg0) { | ||||
| } | ||||
|  | ||||
| void launch_magiskhide(int client) { | ||||
| 	// We manually handle crashes | ||||
| 	err_handler = do_nothing; | ||||
|  | ||||
| 	if (hideEnabled) { | ||||
| 		if (client > 0) { | ||||
| 			write_int(client, HIDE_IS_ENABLED); | ||||
| @@ -55,7 +52,7 @@ void launch_magiskhide(int client) { | ||||
| 	hideEnabled = 1; | ||||
| 	LOGI("* Starting MagiskHide\n"); | ||||
|  | ||||
| 	deleteprop(MAGISKHIDE_PROP, 1); | ||||
| 	deleteprop2(MAGISKHIDE_PROP, 1); | ||||
|  | ||||
| 	hide_sensitive_props(); | ||||
|  | ||||
| @@ -102,7 +99,7 @@ void stop_magiskhide(int client) { | ||||
| 	hideEnabled = 0; | ||||
| 	setprop(MAGISKHIDE_PROP, "0"); | ||||
| 	// Remove without actually removing persist props | ||||
| 	deleteprop(MAGISKHIDE_PROP, 0); | ||||
| 	deleteprop2(MAGISKHIDE_PROP, 0); | ||||
| 	pthread_kill(proc_monitor_thread, SIGUSR1); | ||||
|  | ||||
| 	write_int(client, DAEMON_SUCCESS); | ||||
| @@ -124,6 +121,8 @@ int magiskhide_main(int argc, char *argv[]) { | ||||
| 		req = RM_HIDELIST; | ||||
| 	} else if (strcmp(argv[1], "--ls") == 0) { | ||||
| 		req = LS_HIDELIST; | ||||
| 	} else { | ||||
| 		usage(argv[0]); | ||||
| 	} | ||||
| 	int fd = connect_daemon(); | ||||
| 	write_int(fd, req); | ||||
|   | ||||
| @@ -12,7 +12,6 @@ void proc_monitor(); | ||||
| // Utility functions | ||||
| void manage_selinux(); | ||||
| void hide_sensitive_props(); | ||||
| void relink_sbin(); | ||||
| void clean_magisk_props(); | ||||
|  | ||||
| // List managements | ||||
|   | ||||
| @@ -19,38 +19,25 @@ | ||||
| #include "utils.h" | ||||
| #include "magiskhide.h" | ||||
|  | ||||
| static int zygote_num; | ||||
| static char init_ns[32], zygote_ns[2][32], cache_block[256]; | ||||
| static int log_pid, log_fd, target_pid, has_cache = 1; | ||||
| static char *buffer; | ||||
| static int zygote_num, has_cache = 1, pipefd[2] = { -1, -1 }; | ||||
|  | ||||
| // 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); | ||||
| 	} | ||||
| 	// Resume process if possible | ||||
| 	if (target_pid > 0) | ||||
| 		kill(target_pid, SIGCONT); | ||||
| 	// Unregister listener | ||||
| 	logcat_events[HIDE_EVENT] = -1; | ||||
| 	close(pipefd[0]); | ||||
| 	close(pipefd[1]); | ||||
| 	pipefd[0] = pipefd[1] = -1; | ||||
| 	pthread_mutex_destroy(&hide_lock); | ||||
| 	pthread_mutex_destroy(&file_lock); | ||||
| 	LOGD("proc_monitor: terminating...\n"); | ||||
| 	pthread_exit(NULL); | ||||
| } | ||||
|  | ||||
| static void proc_monitor_err() { | ||||
| 	LOGD("proc_monitor: error occured, stopping magiskhide services\n"); | ||||
| 	quit_pthread(SIGUSR1); | ||||
| } | ||||
|  | ||||
| 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); | ||||
| @@ -76,27 +63,19 @@ static void lazy_unmount(const char* mountpoint) { | ||||
| 		LOGD("hide_daemon: Unmount Failed (%s)\n", mountpoint); | ||||
| } | ||||
|  | ||||
| static void hide_daemon_err() { | ||||
| 	LOGD("hide_daemon: error occured, stopping magiskhide services\n"); | ||||
| 	_exit(-1); | ||||
| } | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	char *line; | ||||
| 	char *line, buffer[PATH_MAX]; | ||||
| 	struct vector mount_list; | ||||
|  | ||||
| 	manage_selinux(); | ||||
| 	relink_sbin(); | ||||
| 	clean_magisk_props(); | ||||
|  | ||||
| 	if (switch_mnt_ns(pid)) | ||||
| 		return; | ||||
| 		goto exit; | ||||
|  | ||||
| 	snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid); | ||||
| 	snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid); | ||||
| 	vec_init(&mount_list); | ||||
| 	file_to_vector(buffer, &mount_list); | ||||
|  | ||||
| @@ -133,7 +112,7 @@ static void hide_daemon(int pid) { | ||||
| 	vec_destroy(&mount_list); | ||||
|  | ||||
| 	// Re-read mount infos | ||||
| 	snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid); | ||||
| 	snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid); | ||||
| 	vec_init(&mount_list); | ||||
| 	file_to_vector(buffer, &mount_list); | ||||
|  | ||||
| @@ -146,8 +125,12 @@ static void hide_daemon(int pid) { | ||||
| 		free(line); | ||||
| 	} | ||||
|  | ||||
| 	// Free uo memory | ||||
| exit: | ||||
| 	// Send resume signal | ||||
| 	kill(pid, SIGCONT); | ||||
| 	// Free up memory | ||||
| 	vec_destroy(&mount_list); | ||||
| 	_exit(0); | ||||
| } | ||||
|  | ||||
| void proc_monitor() { | ||||
| @@ -157,17 +140,12 @@ void proc_monitor() { | ||||
| 	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(); | ||||
| 		quit_pthread(SIGUSR1); | ||||
| 	} | ||||
| 	LOGI("proc_monitor: init ns=%s\n", init_ns); | ||||
|  | ||||
| @@ -189,20 +167,15 @@ void proc_monitor() { | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	while (1) { | ||||
| 		// Clear previous logcat buffer | ||||
| 		exec_command_sync("logcat", "-b", "events", "-c", NULL); | ||||
| 	// Register our listener to logcat monitor | ||||
| 	xpipe2(pipefd, O_CLOEXEC); | ||||
| 	logcat_events[HIDE_EVENT] = pipefd[1]; | ||||
|  | ||||
| 		// 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)) { | ||||
| 	for (char *log, *line; xxread(pipefd[0], &log, sizeof(log)) > 0; free(log)) { | ||||
| 		char *ss; | ||||
| 		if ((ss = strstr(log, "am_proc_start")) && (ss = strchr(ss, '['))) { | ||||
| 			int pid, ret, comma = 0; | ||||
| 			char *pos = buffer, *line, processName[256]; | ||||
| 			char *pos = ss, processName[256], ns[32]; | ||||
|  | ||||
| 			while(1) { | ||||
| 				pos = strchr(pos, ','); | ||||
| @@ -213,9 +186,9 @@ void proc_monitor() { | ||||
| 			} | ||||
|  | ||||
| 			if (comma == 6) | ||||
| 				ret = sscanf(buffer, "[%*d %d %*d %*d %256s", &pid, processName); | ||||
| 				ret = sscanf(ss, "[%*d %d %*d %*d %256s", &pid, processName); | ||||
| 			else | ||||
| 				ret = sscanf(buffer, "[%*d %d %*d %256s", &pid, processName); | ||||
| 				ret = sscanf(ss, "[%*d %d %*d %256s", &pid, processName); | ||||
|  | ||||
| 			if(ret != 2) | ||||
| 				continue; | ||||
| @@ -226,12 +199,11 @@ void proc_monitor() { | ||||
| 			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) { | ||||
| 							read_namespace(pid, ns, sizeof(ns)); | ||||
| 							if (strcmp(ns, zygote_ns[i]) == 0) { | ||||
| 								usleep(50); | ||||
| 								ret = 0; | ||||
| 								break; | ||||
| @@ -241,43 +213,21 @@ void proc_monitor() { | ||||
| 					} | ||||
|  | ||||
| 					// Send pause signal ASAP | ||||
| 					if (kill(target_pid, SIGSTOP) == -1) continue; | ||||
| 					if (kill(pid, SIGSTOP) == -1) continue; | ||||
|  | ||||
| 					LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, target_pid, buffer); | ||||
| 					LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, pid, ns); | ||||
|  | ||||
| 					/* | ||||
| 					 * The setns system call do not support multithread processes | ||||
| 					 * We have to fork a new process, setns, then do the unmounts | ||||
| 					 */ | ||||
| 					int hide_pid = fork(); | ||||
| 					switch(hide_pid) { | ||||
| 					case -1: | ||||
| 						PLOGE("fork"); | ||||
| 						return; | ||||
| 					case 0: | ||||
| 						hide_daemon(target_pid); | ||||
| 						_exit(0); | ||||
| 					default: | ||||
| 						break; | ||||
| 					} | ||||
| 					if (fork_dont_care() == 0) | ||||
| 						hide_daemon(pid); | ||||
|  | ||||
| 					// 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); | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										137
									
								
								jni/magiskinit.c
									
									
									
									
									
								
							
							
						
						
									
										137
									
								
								jni/magiskinit.c
									
									
									
									
									
								
							| @@ -25,6 +25,7 @@ | ||||
|  | ||||
| #include <cil/cil.h> | ||||
|  | ||||
| #include "utils.h" | ||||
| #include "magiskpolicy.h" | ||||
|  | ||||
| struct cmdline { | ||||
| @@ -46,114 +47,6 @@ extern void mmap_ro(const char *filename, void **buf, size_t *size); | ||||
| extern void mmap_rw(const char *filename, void **buf, size_t *size); | ||||
| extern void *patch_init_rc(char *data, uint32_t *size); | ||||
|  | ||||
| static void clone_dir(int src, int dest) { | ||||
| 	struct dirent *entry; | ||||
| 	DIR *dir; | ||||
| 	int srcfd, destfd, newsrc, newdest; | ||||
| 	struct stat st; | ||||
| 	char buf[PATH_MAX]; | ||||
| 	ssize_t size; | ||||
|  | ||||
| 	dir = fdopendir(src); | ||||
| 	while ((entry = readdir(dir))) { | ||||
| 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||||
| 			continue; | ||||
| 		fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW); | ||||
| 		switch (entry->d_type) { | ||||
| 		case DT_DIR: | ||||
| 			mkdirat(dest, entry->d_name, st.st_mode & 0777); | ||||
| 			fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); | ||||
| 			// Don't clone recursive if it's /system | ||||
| 			if (strcmp(entry->d_name, "system") == 0) | ||||
| 				continue; | ||||
| 			newsrc = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); | ||||
| 			newdest = openat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); | ||||
| 			clone_dir(newsrc, newdest); | ||||
| 			close(newsrc); | ||||
| 			close(newdest); | ||||
| 			break; | ||||
| 		case DT_REG: | ||||
| 			destfd = openat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, st.st_mode & 0777); | ||||
| 			srcfd = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); | ||||
| 			sendfile(destfd, srcfd, 0, st.st_size); | ||||
| 			fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); | ||||
| 			close(destfd); | ||||
| 			close(srcfd); | ||||
| 			break; | ||||
| 		case DT_LNK: | ||||
| 			size = readlinkat(src, entry->d_name, buf, sizeof(buf)); | ||||
| 			buf[size] = '\0'; | ||||
| 			symlinkat(buf, dest, entry->d_name); | ||||
| 			fchownat(dest, entry->d_name, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void mv_dir(int src, int dest) { | ||||
| 	struct dirent *entry; | ||||
| 	DIR *dir; | ||||
| 	int newsrc, newdest; | ||||
| 	struct stat st; | ||||
| 	char buf[PATH_MAX]; | ||||
| 	ssize_t size; | ||||
|  | ||||
| 	dir = fdopendir(src); | ||||
| 	while ((entry = readdir(dir))) { | ||||
| 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||||
| 			continue; | ||||
| 		fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW); | ||||
| 		switch (entry->d_type) { | ||||
| 		case DT_DIR: | ||||
| 			mkdirat(dest, entry->d_name, st.st_mode & 0777); | ||||
| 			fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); | ||||
| 			newsrc = openat(src, entry->d_name, O_RDONLY | O_CLOEXEC); | ||||
| 			newdest = openat(dest, entry->d_name, O_RDONLY | O_CLOEXEC); | ||||
| 			mv_dir(newsrc, newdest); | ||||
| 			close(newsrc); | ||||
| 			close(newdest); | ||||
| 			break; | ||||
| 		case DT_REG: | ||||
| 			renameat(src, entry->d_name, dest, entry->d_name); | ||||
| 			fchmodat(dest, entry->d_name, st.st_mode & 0777, 0); | ||||
| 			fchownat(dest, entry->d_name, st.st_uid, st.st_gid, 0); | ||||
| 			break; | ||||
| 		case DT_LNK: | ||||
| 			size = readlinkat(src, entry->d_name, buf, sizeof(buf)); | ||||
| 			buf[size] = '\0'; | ||||
| 			symlinkat(buf, dest, entry->d_name); | ||||
| 			fchownat(dest, entry->d_name, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW); | ||||
| 			break; | ||||
| 		} | ||||
| 		unlinkat(src, entry->d_name, AT_REMOVEDIR); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void rm_rf(int path) { | ||||
| 	struct dirent *entry; | ||||
| 	int newfd; | ||||
| 	DIR *dir = fdopendir(path); | ||||
|  | ||||
| 	while ((entry = readdir(dir))) { | ||||
| 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||||
| 			continue; | ||||
| 		switch (entry->d_type) { | ||||
| 		case DT_DIR: | ||||
| 			// Preserve overlay | ||||
| 			if (strcmp(entry->d_name, "overlay") == 0) | ||||
| 				continue; | ||||
| 			newfd = openat(path, entry->d_name, O_RDONLY | O_CLOEXEC); | ||||
| 			rm_rf(newfd); | ||||
| 			close(newfd); | ||||
| 			unlinkat(path, entry->d_name, AT_REMOVEDIR); | ||||
| 			break; | ||||
| 		default: | ||||
| 			unlinkat(path, entry->d_name, 0); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void parse_cmdline(struct cmdline *cmd) { | ||||
| 	char *tok; | ||||
| 	char buffer[4096]; | ||||
| @@ -197,8 +90,6 @@ static void parse_device(struct device *dev, char *uevent) { | ||||
|  | ||||
| static int setup_block(struct device *dev, const char *partname) { | ||||
| 	char buffer[1024], path[128]; | ||||
| 	mkdir("/sys", 0755); | ||||
| 	mount("sysfs", "/sys", "sysfs", 0, NULL); | ||||
| 	struct dirent *entry; | ||||
| 	DIR *dir = opendir("/sys/dev/block"); | ||||
| 	if (dir == NULL) | ||||
| @@ -266,7 +157,8 @@ static void patch_sepolicy() { | ||||
| 	if (sepolicy == NULL && access("/vendor/etc/selinux/precompiled_sepolicy", R_OK) == 0) { | ||||
| 		void *sys_sha = NULL, *ven_sha = NULL; | ||||
| 		size_t sys_size = 0, ven_size = 0; | ||||
| 		dir = opendir("/vendor/etc/selinux"); | ||||
| 		if ((dir = opendir("/vendor/etc/selinux")) == NULL) | ||||
| 			goto check_done; | ||||
| 		while ((entry = readdir(dir))) { | ||||
| 			if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||||
| 				continue; | ||||
| @@ -277,7 +169,8 @@ static void patch_sepolicy() { | ||||
| 			} | ||||
| 		} | ||||
| 		closedir(dir); | ||||
| 		dir = opendir("/system/etc/selinux"); | ||||
| 		if ((dir = opendir("/system/etc/selinux")) == NULL) | ||||
| 			goto check_done; | ||||
| 		while ((entry = readdir(dir))) { | ||||
| 			if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||||
| 				continue; | ||||
| @@ -294,6 +187,8 @@ static void patch_sepolicy() { | ||||
| 		munmap(ven_sha, ven_size); | ||||
| 	} | ||||
|  | ||||
| check_done: | ||||
|  | ||||
| 	if (sepolicy) { | ||||
| 		load_policydb(sepolicy); | ||||
| 	} else { | ||||
| @@ -362,7 +257,13 @@ int main(int argc, char *argv[]) { | ||||
| 		// Normal boot mode | ||||
| 		// Clear rootfs | ||||
| 		int root = open("/", O_RDONLY | O_CLOEXEC); | ||||
| 		rm_rf(root); | ||||
|  | ||||
| 		// Exclude overlay folder | ||||
| 		excl_list = (char *[]) { "overlay", NULL }; | ||||
| 		frm_rf(root); | ||||
|  | ||||
| 		mkdir("/sys", 0755); | ||||
| 		mount("sysfs", "/sys", "sysfs", 0, NULL); | ||||
|  | ||||
| 		char partname[32]; | ||||
| 		snprintf(partname, sizeof(partname), "system%s", cmd.slot); | ||||
| @@ -373,7 +274,11 @@ int main(int argc, char *argv[]) { | ||||
| 		mkdir("/system_root", 0755); | ||||
| 		mount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL); | ||||
| 		int system_root = open("/system_root", O_RDONLY | O_CLOEXEC); | ||||
|  | ||||
| 		// Exclude system folder | ||||
| 		excl_list = (char *[]) { "system", NULL }; | ||||
| 		clone_dir(system_root, root); | ||||
| 		mkdir("/system", 0755); | ||||
| 		mount("/system_root/system", "/system", NULL, MS_BIND, NULL); | ||||
|  | ||||
| 		int overlay = open("/overlay", O_RDONLY | O_CLOEXEC); | ||||
| @@ -381,8 +286,10 @@ int main(int argc, char *argv[]) { | ||||
| 			mv_dir(overlay, root); | ||||
|  | ||||
| 		snprintf(partname, sizeof(partname), "vendor%s", cmd.slot); | ||||
| 		setup_block(&dev, partname); | ||||
| 		mount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL); | ||||
|  | ||||
| 		// We need to mount independent vendor partition | ||||
| 		if (setup_block(&dev, partname) == 0) | ||||
| 			mount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL); | ||||
|  | ||||
| 		patch_ramdisk(); | ||||
| 		patch_sepolicy(); | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								jni/su
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								jni/su
									
									
									
									
									
								
							 Submodule jni/su updated: c912c192e0...6de95e0d9b
									
								
							
							
								
								
									
										333
									
								
								jni/utils/file.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								jni/utils/file.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user