sandbox.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #include "kmem.h"
  2. #include "kern_utils.h"
  3. #include "sandbox.h"
  4. #include "patchfinder64.h"
  5. #include "kexecute.h"
  6. typedef uint64_t extension_hdr_t;
  7. typedef uint64_t extension_t;
  8. struct extension_hdr {
  9. /* 0x00 */ extension_hdr_t next;
  10. /* 0x08 */ uint64_t desc;
  11. /* 0x10 */ extension_t ext_lst;
  12. /* 0x18 */
  13. };
  14. struct extension {
  15. /* 0x00 */ extension_t next;
  16. /* 0x08 */ uint64_t desc; // always 0xffffffffffffffff
  17. /* 0x10 */ uint64_t ext_lst; // zero, since it's extension and not a header
  18. /* 0x18 */ uint8_t something[32]; // zeroed from what I've seen
  19. /* 0x38 */ uint32_t type; // see ext_type enum
  20. /* 0x3c */ uint32_t subtype; // either 0 or 4 (or whatever unhex gave?..)
  21. /* 0x40 */ uint64_t data; // a c string, meaning depends on type and hdr which had this extension
  22. /* 0x48 */ uint64_t data_len; // strlen(data)
  23. /* 0x50 */ uint64_t unk0; // always 0
  24. /* 0x58 */ uint64_t unk1; // always 0xdeadbeefdeadbeef
  25. /* 0x60 */
  26. };
  27. uint64_t _smalloc(uint64_t size) {
  28. return kexecute(find_smalloc(), size, 0, 0, 0, 0, 0, 0);
  29. }
  30. uint64_t smalloc(uint64_t size) {
  31. uint64_t ret = _smalloc(size);
  32. if (ret != 0) {
  33. // IOAlloc's of small size go to zalloc
  34. ret = zm_fix_addr(ret);
  35. }
  36. return ret;
  37. }
  38. uint64_t sstrdup(const char* s) {
  39. size_t slen = strlen(s) + 1;
  40. uint64_t ks = smalloc(slen);
  41. if (ks) {
  42. kwrite(ks, s, slen);
  43. }
  44. return ks;
  45. }
  46. // Notice: path should *not* end with '/' !
  47. uint64_t extension_create_file(const char* path, uint64_t nextptr) {
  48. size_t slen = strlen(path);
  49. if (path[slen - 1] == '/') {
  50. fprintf(stderr, "No traling slash in path pls\n");
  51. return 0;
  52. }
  53. uint64_t ext_p = smalloc(sizeof(struct extension));
  54. uint64_t ks = sstrdup(path);
  55. if (ext_p && ks) {
  56. struct extension ext;
  57. bzero(&ext, sizeof(ext));
  58. ext.next = nextptr;
  59. ext.desc = 0xffffffffffffffff;
  60. // ext.type = 0;
  61. // ext.subtype = 0;
  62. ext.data = ks;
  63. ext.data_len = slen;
  64. kwrite(ext_p, &ext, sizeof(ext));
  65. } else {
  66. // XXX oh no a leak
  67. }
  68. return ext_p;
  69. }
  70. // get 64 higher bits of 64bit int multiplication
  71. // https://stackoverflow.com/a/28904636
  72. // ofc in asm it's done with 1 instruction huh
  73. // XXX there has to be a cleaner way utilizing hardware support
  74. uint64_t mulhi(uint64_t a, uint64_t b) {
  75. uint64_t a_lo = (uint32_t)a;
  76. uint64_t a_hi = a >> 32;
  77. uint64_t b_lo = (uint32_t)b;
  78. uint64_t b_hi = b >> 32;
  79. uint64_t a_x_b_hi = a_hi * b_hi;
  80. uint64_t a_x_b_mid = a_hi * b_lo;
  81. uint64_t b_x_a_mid = b_hi * a_lo;
  82. uint64_t a_x_b_lo = a_lo * b_lo;
  83. uint64_t carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +
  84. (uint64_t)(uint32_t)b_x_a_mid +
  85. (a_x_b_lo >> 32) ) >> 32;
  86. uint64_t multhi = a_x_b_hi +
  87. (a_x_b_mid >> 32) + (b_x_a_mid >> 32) +
  88. carry_bit;
  89. return multhi;
  90. }
  91. int hashing_magic(const char *desc) {
  92. // inlined into exception_add
  93. uint64_t hashed = 0x1505;
  94. // if desc == NULL, then returned value would be 8
  95. // APPL optimizes it for some reason
  96. // but meh, desc should never be NULL or you get
  97. // null dereference in exception_add
  98. // if (desc == NULL) return 8;
  99. if (desc != NULL) {
  100. for (const char* dp = desc; *dp != '\0'; ++dp) {
  101. hashed += hashed << 5;
  102. hashed += (int64_t) *dp;
  103. }
  104. }
  105. uint64_t magic = 0xe38e38e38e38e38f;
  106. uint64_t hi = mulhi(hashed, magic);
  107. hi >>= 3;
  108. hi = (hi<<3) + hi;
  109. hashed -= hi;
  110. return hashed;
  111. }
  112. static const char *ent_key = "com.apple.security.exception.files.absolute-path.read-only";
  113. uint64_t make_ext_hdr(const char* key, uint64_t ext_lst) {
  114. struct extension_hdr hdr;
  115. uint64_t khdr = smalloc(sizeof(hdr));
  116. if (khdr) {
  117. // we add headers to end
  118. hdr.next = 0;
  119. hdr.desc = sstrdup(key);
  120. if (hdr.desc == 0) {
  121. // XXX leak
  122. return 0;
  123. }
  124. hdr.ext_lst = ext_lst;
  125. kwrite(khdr, &hdr, sizeof(hdr));
  126. }
  127. return khdr;
  128. }
  129. void extension_add(uint64_t ext, uint64_t sb, const char* desc) {
  130. // XXX patchfinder + kexecute would be way better
  131. int slot = hashing_magic(ent_key);
  132. uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
  133. uint64_t insert_at = rk64(insert_at_p);
  134. while (insert_at != 0) {
  135. uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
  136. if (kstrcmp(kdsc, desc) == 0) {
  137. break;
  138. }
  139. insert_at_p = insert_at;
  140. insert_at = rk64(insert_at);
  141. }
  142. if (insert_at == 0) {
  143. insert_at = make_ext_hdr(ent_key, ext);
  144. wk64(insert_at_p, insert_at);
  145. } else {
  146. // XXX no duplicate check
  147. uint64_t ext_lst_p = insert_at + offsetof(struct extension_hdr, ext_lst);
  148. uint64_t ext_lst = rk64(ext_lst_p);
  149. while (ext_lst != 0) {
  150. fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
  151. ext_lst_p = ext_lst + offsetof(struct extension, next);
  152. ext_lst = rk64(ext_lst_p);
  153. }
  154. fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
  155. wk64(ext_lst_p, ext);
  156. }
  157. }
  158. // 1 if yes
  159. int has_file_extension(uint64_t sb, const char* path) {
  160. const char* desc = ent_key;
  161. int found = 0;
  162. int slot = hashing_magic(ent_key);
  163. uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
  164. uint64_t insert_at = rk64(insert_at_p);
  165. while (insert_at != 0) {
  166. uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
  167. if (kstrcmp(kdsc, desc) == 0) {
  168. break;
  169. }
  170. insert_at_p = insert_at;
  171. insert_at = rk64(insert_at);
  172. }
  173. if (insert_at != 0) {
  174. uint64_t ext_lst = rk64(insert_at + offsetof(struct extension_hdr, ext_lst));
  175. uint64_t plen = strlen(path);
  176. char *exist = malloc(plen + 1);
  177. exist[plen] = '\0';
  178. while (ext_lst != 0) {
  179. // XXX no type/subtype check
  180. uint64_t data_len = rk64(ext_lst + offsetof(struct extension, data_len));
  181. if (data_len == plen) {
  182. uint64_t data = rk64(ext_lst + offsetof(struct extension, data));
  183. kread(data, exist, plen);
  184. if (strcmp(path, exist) == 0) {
  185. found = 1;
  186. break;
  187. }
  188. }
  189. ext_lst = rk64(ext_lst);
  190. }
  191. free(exist);
  192. }
  193. return found;
  194. }