root-rw.m 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //
  2. // root-rw.m
  3. // Meridian
  4. //
  5. // Created by Ben Sparkes on 16/12/2017.
  6. // Copyright © 2017 Ben Sparkes. All rights reserved.
  7. //
  8. #include "root-rw.h"
  9. #include "kernel.h"
  10. #include "patchfinder64.h"
  11. #include "helpers.h"
  12. #include "ViewController.h"
  13. #include "offsetfinder.h"
  14. #include <stdio.h>
  15. #include <unistd.h>
  16. #include <sys/utsname.h>
  17. #include <sys/types.h>
  18. #include <sys/sysctl.h>
  19. #define MOUNT_MNT_FLAG 0x70
  20. #define VNODE_V_UN 0xd8
  21. #define VNODE_V_UN_OTHER 0xd0
  22. const unsigned OFF_LWVM__PARTITIONS = 0x1a0;
  23. const unsigned OFF_LWVMPART__ISWP = 0x28;
  24. const unsigned OFF_PROC__TASK = 0x18;
  25. const unsigned OFF_IPC_PORT__IP_KOBJECT = 0x68;
  26. const unsigned OFF_IPC_SPACE__IS_TABLE = 0x20;
  27. const unsigned SIZ_IPC_ENTRY_T = 0x18;
  28. const unsigned OFF_TASK__ITK_SPACE = 0x300;
  29. #define rkbuffer(w, p, s) kread(w, p, s);
  30. #define wkbuffer(w, p, s) kwrite(w, p, s);
  31. typedef mach_port_t io_service_t;
  32. typedef mach_port_t io_connect_t;
  33. extern const mach_port_t kIOMasterPortDefault;
  34. CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;
  35. io_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
  36. kern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t *connect);
  37. bool fix_root_iswriteprotected() {
  38. io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("LightweightVolumeManager"));
  39. if (!MACH_PORT_VALID(service)) {
  40. return false;
  41. }
  42. uint64_t inkernel = find_port_address(service);
  43. uint64_t lwvm_kaddr = rk64(inkernel + OFF_IPC_PORT__IP_KOBJECT);
  44. uint64_t rootp_kaddr = rk64(lwvm_kaddr + OFF_LWVM__PARTITIONS);
  45. uint64_t varp_kaddr = rk64(lwvm_kaddr + OFF_LWVM__PARTITIONS + sizeof(void*));
  46. uint64_t rootp_iswp_addr = rootp_kaddr + OFF_LWVMPART__ISWP;
  47. uint64_t varp_iswp_addr = varp_kaddr + OFF_LWVMPART__ISWP;
  48. // Check we found the right values
  49. uint64_t varp_iswp = rk64(varp_iswp_addr);
  50. if (varp_iswp != 0) {
  51. NSLog(@"rk64(varp_iswp_addr) != 0! val: %llx", varp_iswp);
  52. return false;
  53. }
  54. uint64_t rootp_iswp = rk64(rootp_iswp_addr);
  55. if (rootp_iswp != 1) {
  56. NSLog(@"rk64(rootp_iswp_addr) != 1! val: %llx", rootp_iswp);
  57. return false;
  58. }
  59. wk64(rootp_iswp_addr, 0);
  60. return true;
  61. }
  62. #define BOOTARGS_PATCH "rd=mdx"
  63. bool fake_rootedramdisk(void) {
  64. unsigned cmdline_offset;
  65. uint64_t pestate_bootargs = find_boot_args(&cmdline_offset);
  66. if (pestate_bootargs == 0) {
  67. return false;
  68. }
  69. uint64_t struct_boot_args = rk64(pestate_bootargs);
  70. uint64_t boot_args_cmdline = struct_boot_args + cmdline_offset;
  71. // max size is 256 on arm
  72. char buf_bootargs[256];
  73. rkbuffer(boot_args_cmdline, buf_bootargs, sizeof(buf_bootargs));
  74. strcat(buf_bootargs, BOOTARGS_PATCH);
  75. wkbuffer(boot_args_cmdline, buf_bootargs, sizeof(buf_bootargs));
  76. bzero(buf_bootargs, sizeof(buf_bootargs));
  77. size_t size = sizeof(buf_bootargs);
  78. int err = sysctlbyname("kern.bootargs", buf_bootargs, &size, NULL, 0);
  79. if (err) {
  80. NSLog(@"sysctlbyname(kern.bootargs) failed");
  81. return false;
  82. }
  83. if (strstr(buf_bootargs, BOOTARGS_PATCH) == NULL) {
  84. NSLog(@"kern.bootargs doesn't contain '%s' after patch!", BOOTARGS_PATCH);
  85. NSLog(@"kern.bootargs: '%s'", buf_bootargs);
  86. return false;
  87. }
  88. return true;
  89. }
  90. // props to xerub for the original '/' r/w remount code
  91. int remount_root(uint64_t kslide, uint64_t root_vnode) {
  92. uint64_t _rootnode = root_vnode + kslide;
  93. NSLog(@"_rootnode = %llx", _rootnode);
  94. uint64_t rootfs_vnode = rk64(_rootnode);
  95. NSLog(@"roofs_vnode = %llx", rootfs_vnode);
  96. uint64_t off = VNODE_V_UN;
  97. struct utsname uts;
  98. uname(&uts);
  99. if (strstr(uts.version, "16.0.0")) {
  100. off = VNODE_V_UN_OTHER;
  101. }
  102. // read the original flags
  103. uint64_t v_mount = rk64(rootfs_vnode + off);
  104. uint32_t v_flag = rk32(v_mount + MOUNT_MNT_FLAG);
  105. v_flag = v_flag & ~MNT_NOSUID;
  106. v_flag = v_flag & ~MNT_RDONLY;
  107. // unset rootfs flag
  108. wk32(v_mount + MOUNT_MNT_FLAG, v_flag & ~MNT_ROOTFS);
  109. // remount
  110. char *nmz = strdup("/dev/disk0s1s1");
  111. kern_return_t rv = mount("hfs", "/", MNT_UPDATE, (void *)&nmz);
  112. NSLog(@"remounting: %d", rv);
  113. // set original flags back
  114. v_mount = rk64(rootfs_vnode + off);
  115. wk32(v_mount + MOUNT_MNT_FLAG, v_flag);
  116. return rv;
  117. }
  118. int mount_root(uint64_t kslide, uint64_t root_vnode, int pre130) {
  119. if (pre130 == 1) {
  120. // further patches are requried on <10.3
  121. NSLog(@"pre-10.3 detected: patching lwvm...");
  122. if (!fix_root_iswriteprotected()) {
  123. NSLog(@"fix_root_iswriteprotected failed!");
  124. return -61;
  125. }
  126. if (!fake_rootedramdisk()) {
  127. NSLog(@"fake_rootedramdisk failed!");
  128. return -62;
  129. }
  130. }
  131. return remount_root(kslide, root_vnode);
  132. }