main.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. #define _GNU_SOURCE 1
  4. #ifndef __GNUC__
  5. #define __GNUC__ 1
  6. #endif
  7. #include <stdint.h>
  8. #include <stddef.h>
  9. #include <linux/unistd.h>
  10. #include <sys/socket.h>
  11. #include <linux/in.h>
  12. #include <linux/in6.h>
  13. #include <linux/fs.h>
  14. #include <asm/fcntl.h>
  15. #include <asm/mman.h>
  16. #include <asm/errno.h>
  17. #include <elf/elf.h>
  18. #include <sysdeps/generic/ldsodefs.h>
  19. #include "pal_security.h"
  20. #include "internal.h"
  21. #include "graphene.h"
  22. #define PRESET_PAGESIZE (4096UL)
  23. unsigned long pagesize = PRESET_PAGESIZE;
  24. unsigned long pageshift = PRESET_PAGESIZE - 1;
  25. unsigned long pagemask = ~(PRESET_PAGESIZE - 1);
  26. # define POOL_SIZE 4096 * 64
  27. static char mem_pool[POOL_SIZE];
  28. static char *bump = mem_pool;
  29. static char *mem_pool_end = &mem_pool[POOL_SIZE];
  30. void * malloc (size_t size)
  31. {
  32. void * addr = (void *) bump;
  33. bump += size;
  34. if (bump >= mem_pool_end) {
  35. printf("Pal reference monitor out of internal memory!\n");
  36. INLINE_SYSCALL(exit_group, 1, -1);
  37. return NULL;
  38. }
  39. return addr;
  40. }
  41. void free (void * mem)
  42. {
  43. /* no freeing */
  44. }
  45. #if __WORDSIZE == 2
  46. # define FILEBUF_SIZE 512
  47. #else
  48. # define FILEBUF_SIZE 832
  49. #endif
  50. static void do_bootstrap (void * args, int * pargc, const char *** pargv,
  51. const char *** penvp, ElfW(auxv_t) ** pauxv,
  52. void ** baseaddr, const char ** program_name)
  53. {
  54. const char ** all_args = (const char **) args;
  55. int argc = (uintptr_t) all_args[0];
  56. const char ** argv = &all_args[1];
  57. const char ** envp = argv + argc + 1;
  58. void * base = NULL;
  59. /* fetch environment information from aux vectors */
  60. void ** auxv = (void **) envp + 1;
  61. for (; *(auxv - 1); auxv++);
  62. ElfW(auxv_t) *av;
  63. for (av = (ElfW(auxv_t) *) auxv ; av->a_type != AT_NULL ; av++)
  64. switch (av->a_type) {
  65. case AT_PAGESZ:
  66. pagesize = av->a_un.a_val;
  67. pageshift = pagesize - 1;
  68. pagemask = ~pageshift;
  69. break;
  70. case AT_BASE:
  71. base = (void *) av->a_un.a_val;
  72. break;
  73. }
  74. if (!base) {
  75. asm ("leaq start(%%rip), %0\r\n"
  76. "subq 1f(%%rip), %0\r\n"
  77. ".section\t.data.rel.ro\r\n"
  78. "1:\t.quad start\r\n"
  79. ".previous\r\n"
  80. : "=r" (base) : : "cc");
  81. }
  82. *program_name = *argv;
  83. argv++;
  84. argc--;
  85. *pargc = argc;
  86. *pargv = argv;
  87. *penvp = envp;
  88. *pauxv = (ElfW(auxv_t) *) auxv;
  89. *baseaddr = base;
  90. }
  91. int open_manifest (const char ** argv)
  92. {
  93. const char * manifest_name = *argv;
  94. int ret, fd;
  95. fd = INLINE_SYSCALL(open, 3, manifest_name, O_RDONLY, 0);
  96. if (IS_ERR(fd))
  97. return -ERRNO(fd);
  98. /* check if the first argument is an executable. If its not,
  99. * it must be a manifest */
  100. char filebuf[4], elfmagic[4] = "\177ELF";
  101. ret = INLINE_SYSCALL(read, 3, fd, filebuf, sizeof(filebuf));
  102. if (IS_ERR(ret))
  103. return -ERRNO(ret);
  104. if (memcmp(filebuf, elfmagic, sizeof(filebuf)))
  105. return fd;
  106. INLINE_SYSCALL(close, 1, fd);
  107. /* find a manifest file with the same name as executable */
  108. int len = strlen(*argv);
  109. manifest_name = __alloca(len + static_strlen(".manifest") + 1);
  110. memcpy((void *) manifest_name, &argv, len);
  111. memcpy((void *) manifest_name + len, ".manifest",
  112. static_strlen(".manifest"));
  113. fd = INLINE_SYSCALL(open, 3, manifest_name, O_RDONLY, 0);
  114. if (!IS_ERR(fd))
  115. return fd;
  116. /* find "manifest" file */
  117. fd = INLINE_SYSCALL(open, 3, "manifest", O_RDONLY, 0);
  118. if (!IS_ERR(fd))
  119. return fd;
  120. return -ENOENT;
  121. }
  122. int load_manifest (int fd, struct config_store * config)
  123. {
  124. int nbytes = INLINE_SYSCALL(lseek, 3, fd, 0, SEEK_END);
  125. if (IS_ERR(nbytes))
  126. return -ERRNO(nbytes);
  127. void * config_raw = (void *)
  128. INLINE_SYSCALL(mmap, 6, NULL, nbytes,
  129. PROT_READ|PROT_WRITE, MAP_PRIVATE,
  130. fd, 0);
  131. if (IS_ERR_P(config_raw))
  132. return -ERRNO_P(config_raw);
  133. config->raw_data = config_raw;
  134. config->raw_size = nbytes;
  135. config->malloc = malloc;
  136. config->free = NULL;
  137. const char * errstring = NULL;
  138. int ret = read_config(config, NULL, &errstring);
  139. if (ret < 0) {
  140. printf("can't read manifest: %s\n", errstring);
  141. return ret;
  142. }
  143. return 0;
  144. }
  145. static int do_relocate (ElfW(Dyn) * dyn, ElfW(Addr) addr)
  146. {
  147. ElfW(Dyn) * dt_rela = NULL;
  148. ElfW(Dyn) * dt_relacount = NULL;
  149. for ( ; dyn->d_tag != DT_NULL ; dyn++)
  150. switch (dyn->d_tag) {
  151. case DT_RELA: dt_rela = dyn; break;
  152. case DT_RELACOUNT: dt_relacount = dyn; break;
  153. }
  154. if (!dt_rela || !dt_relacount)
  155. return -EINVAL;
  156. ElfW(Rela) * r = (void *) (addr + dt_rela->d_un.d_ptr);
  157. ElfW(Rela) * end = r + dt_relacount->d_un.d_val;
  158. for ( ; r < end ; r++)
  159. *(ElfW(Addr) *) (addr + r->r_offset) = addr + r->r_addend;
  160. return 0;
  161. }
  162. static void *
  163. find_symbol (const ElfW(Dyn) * dyn, ElfW(Addr) addr, const char * name)
  164. {
  165. const ElfW(Dyn) * dt_symtab = NULL;
  166. const ElfW(Dyn) * dt_strtab = NULL;
  167. const ElfW(Dyn) * dt_rela = NULL;
  168. const ElfW(Dyn) * dt_relasz = NULL;
  169. const ElfW(Dyn) * dt_relacount = NULL;
  170. for ( ; dyn->d_tag != DT_NULL ; dyn++)
  171. switch (dyn->d_tag) {
  172. case DT_SYMTAB: dt_symtab = dyn; break;
  173. case DT_STRTAB: dt_strtab = dyn; break;
  174. case DT_RELA: dt_rela = dyn; break;
  175. case DT_RELASZ: dt_relasz = dyn; break;
  176. case DT_RELACOUNT: dt_relacount = dyn; break;
  177. }
  178. if (!dt_symtab || !dt_strtab || !dt_rela || !dt_relasz || !dt_relacount)
  179. return NULL;
  180. ElfW(Sym) * symtab = (void *) (addr + dt_symtab->d_un.d_ptr);
  181. const char * strtab = (void *) (addr + dt_strtab->d_un.d_ptr);
  182. ElfW(Rela) * r = (void *) (addr + dt_rela->d_un.d_ptr);
  183. ElfW(Rela) * rel = r + dt_relacount->d_un.d_val;
  184. ElfW(Rela) * end = r + dt_relasz->d_un.d_val / sizeof(ElfW(Rela));
  185. int len = strlen(name);
  186. for (r = rel ; r < end ; r++) {
  187. ElfW(Sym) * sym = &symtab[ELFW(R_SYM) (r->r_info)];
  188. if (!sym->st_name)
  189. continue;
  190. if (!memcmp(strtab + sym->st_name, name, len + 1))
  191. return (void *) addr + sym->st_value;
  192. }
  193. return NULL;
  194. }
  195. static int load_static (const char * filename, void ** load_addr,
  196. void ** entry, ElfW(Dyn) ** dyn,
  197. unsigned long * phoff, int * phnum)
  198. {
  199. int ret = 0;
  200. int fd = INLINE_SYSCALL(open, 2, filename, O_RDONLY|O_CLOEXEC);
  201. if (IS_ERR(fd))
  202. return -ERRNO(fd);
  203. char filebuf[FILEBUF_SIZE];
  204. ret = INLINE_SYSCALL(read, 3, fd, filebuf, FILEBUF_SIZE);
  205. if (IS_ERR(ret)) {
  206. ret = -ERRNO(ret);
  207. goto out;
  208. }
  209. const ElfW(Ehdr) * header = (void *) filebuf;
  210. const ElfW(Phdr) * phdr = (void *) filebuf + header->e_phoff;
  211. const ElfW(Phdr) * ph;
  212. ElfW(Addr) base = 0;
  213. *phoff = header->e_phoff;
  214. *phnum = header->e_phnum;
  215. struct loadcmd {
  216. ElfW(Addr) mapstart, mapend, dataend, allocend;
  217. off_t mapoff;
  218. int prot;
  219. } loadcmds[16], *c;
  220. int nloadcmds = 0;
  221. for (ph = phdr ; ph < &phdr[header->e_phnum] ; ph++)
  222. switch (ph->p_type) {
  223. case PT_DYNAMIC:
  224. *dyn = (void *) ph->p_vaddr;
  225. break;
  226. case PT_LOAD:
  227. if (nloadcmds == 16) {
  228. ret = -EINVAL;
  229. goto out;
  230. }
  231. c = &loadcmds[nloadcmds++];
  232. c->mapstart = ph->p_vaddr & pagemask;
  233. c->mapend = (ph->p_vaddr + ph->p_filesz + pageshift) & pagemask;
  234. c->dataend = ph->p_vaddr + ph->p_filesz;
  235. c->allocend = ph->p_vaddr + ph->p_memsz;
  236. c->mapoff = ph->p_offset & pagemask;
  237. c->prot = (ph->p_flags & PF_R ? PROT_READ : 0) |
  238. (ph->p_flags & PF_W ? PROT_WRITE : 0) |
  239. (ph->p_flags & PF_X ? PROT_EXEC : 0);
  240. break;
  241. }
  242. c = loadcmds;
  243. int maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
  244. base = INLINE_SYSCALL(mmap, 6, NULL, maplength, c->prot,
  245. MAP_PRIVATE | MAP_FILE, fd, c->mapoff);
  246. if (IS_ERR(base)) {
  247. ret = -ERRNO_P(base);
  248. goto out;
  249. }
  250. goto postmap;
  251. for ( ; c < &loadcmds[nloadcmds] ; c++) {
  252. ElfW(Addr) addr = INLINE_SYSCALL(mmap, 6, base + c->mapstart,
  253. c->mapend - c->mapstart,
  254. c->prot,
  255. MAP_PRIVATE|MAP_FILE|MAP_FIXED,
  256. fd, c->mapoff);
  257. if (IS_ERR_P(addr)) {
  258. ret = -ERRNO_P(addr);
  259. goto out;
  260. }
  261. postmap:
  262. if (c == loadcmds)
  263. INLINE_SYSCALL(munmap, 2, base + c->mapend, maplength - c->mapend);
  264. if (c->allocend <= c->dataend)
  265. continue;
  266. ElfW(Addr) zero, zeroend, zeropage;
  267. zero = base + c->dataend;
  268. zeroend = (base + c->allocend + pageshift) & pagemask;
  269. zeropage = (zero + pageshift) & pagemask;
  270. if (zeroend < zeropage)
  271. zeropage = zeroend;
  272. if (zeropage > zero)
  273. memset((void *) zero, 0, zeropage - zero);
  274. if (zeroend <= zeropage)
  275. continue;
  276. addr = INLINE_SYSCALL(mmap, 6, zeropage, zeroend - zeropage, c->prot,
  277. MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0);
  278. if (IS_ERR_P(addr)) {
  279. ret = -ERRNO_P(addr);
  280. goto out;
  281. }
  282. }
  283. *dyn = (void *) (base + (ElfW(Addr)) *dyn);
  284. *load_addr = (void *) base;
  285. *entry = (void *) base + header->e_entry;
  286. out:
  287. INLINE_SYSCALL(close, 1, fd);
  288. return ret;
  289. }
  290. static int find_code_range (void * load_addr, void ** start, void ** end)
  291. {
  292. const ElfW(Ehdr) * header = load_addr;
  293. const ElfW(Phdr) * phdr = load_addr + header->e_phoff, * ph;
  294. for (ph = phdr ; ph < &phdr[header->e_phnum] ; ph++)
  295. if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X)) {
  296. *start = load_addr + ph->p_vaddr;
  297. *end = load_addr + ph->p_vaddr + ph->p_filesz;
  298. return 0;
  299. }
  300. return -ENOENT;
  301. }
  302. void __attribute__((noinline)) ___dl_debug_state (void) {}
  303. extern __typeof(___dl_debug_state) _dl_debug_state
  304. __attribute ((alias ("___dl_debug_state")));
  305. struct link_map {
  306. ElfW(Addr) l_addr;
  307. const char * l_name;
  308. const ElfW(Dyn) * l_ld;
  309. struct link_map * l_next, * l_prev;
  310. };
  311. static struct link_map init_link_map;
  312. struct r_debug ___r_debug =
  313. { 1, NULL, (ElfW(Addr)) &___dl_debug_state, RT_CONSISTENT, 0 };
  314. extern __typeof(___r_debug) _r_debug
  315. __attribute ((alias ("___r_debug")));
  316. int ioctl_set_graphene (struct config_store * sandbox_config, int npolices,
  317. const struct graphene_user_policy * policies);
  318. int set_sandbox (struct config_store * sandbox_config,
  319. struct pal_sec * pal_sec_addr, void * pal_addr)
  320. {
  321. struct graphene_user_policy policies[] = {
  322. { .type = GRAPHENE_LIB_NAME, .value = PAL_LOADER, },
  323. { .type = GRAPHENE_LIB_ADDR, .value = pal_addr, },
  324. { .type = GRAPHENE_UNIX_PREFIX, .value = &pal_sec_addr->pipe_prefix_id, },
  325. { .type = GRAPHENE_MCAST_PORT, .value = &pal_sec_addr->mcast_port, },
  326. { .type = GRAPHENE_FS_PATH | GRAPHENE_FS_READ,
  327. .value = "/proc/meminfo", },
  328. };
  329. return ioctl_set_graphene(sandbox_config,
  330. sizeof(policies) / sizeof(policies[0]),
  331. policies);
  332. }
  333. int install_initial_syscall_filter (void);
  334. int install_syscall_filter (void * code_start, void * code_end);
  335. void start(void);
  336. asm (".global start\r\n"
  337. " .type start,@function\r\n"
  338. ".global main\r\n"
  339. " .type do_main,@function\r\n");
  340. /* At the begining of entry point, rsp starts at argc, then argvs,
  341. envps and auxvs. Here we store rsp to rdi, so it will not be
  342. messed up by function calls */
  343. asm ("start:\r\n"
  344. " movq %rsp, %rdi\r\n"
  345. " call do_main\r\n");
  346. void do_main (void * args)
  347. {
  348. const char * program_name;
  349. int argc;
  350. const char ** argv, ** envp;
  351. ElfW(auxv_t) * auxv;
  352. void * baseaddr;
  353. unsigned long pid = INLINE_SYSCALL(getpid, 0);
  354. int ret = 0;
  355. do_bootstrap(args, &argc, &argv, &envp, &auxv, &baseaddr, &program_name);
  356. /* VERY IMPORTANT: This is the filter that gets applied to the startup code
  357. * before applying the real filter in the function install_syscall_filter.
  358. * If you face any issues, you may have to enable certain syscalls here to
  359. * successfully make changes to startup code. */
  360. ret = install_initial_syscall_filter();
  361. if (ret < 0) {
  362. printf("Unable to install initial system call filter\n");
  363. goto exit;
  364. }
  365. /* occupy PAL_INIT_FD */
  366. INLINE_SYSCALL(dup2, 2, 0, PROC_INIT_FD);
  367. ElfW(Dyn) * dyn = (ElfW(Dyn) *) (baseaddr + (ElfW(Addr)) &_DYNAMIC);
  368. do_relocate(dyn, (ElfW(Addr)) baseaddr);
  369. init_link_map.l_addr = (ElfW(Addr)) baseaddr;
  370. init_link_map.l_ld = dyn;
  371. init_link_map.l_name = program_name;
  372. ___r_debug.r_map = &init_link_map;
  373. ___r_debug.r_ldbase = (ElfW(Addr)) baseaddr;
  374. int manifest;
  375. if (!argc || (manifest = open_manifest(argv)) < 0) {
  376. printf("USAGE: %s [executable|manifest] args ...\n", program_name);
  377. goto exit;
  378. }
  379. struct config_store sandbox_config;
  380. ret = load_manifest(manifest, &sandbox_config);
  381. if (ret < 0)
  382. goto exit;
  383. void * pal_addr = NULL;
  384. void * pal_entry = NULL;
  385. ElfW(Dyn) * pal_dyn = NULL;
  386. unsigned long pal_phoff = 0;
  387. int pal_phnum = 0;
  388. ret = load_static(PAL_LOADER, &pal_addr, &pal_entry, &pal_dyn,
  389. &pal_phoff, &pal_phnum);
  390. if (ret < 0) {
  391. printf("Unable to load PAL loader\n");
  392. goto exit;
  393. }
  394. int rand_gen = INLINE_SYSCALL(open, 3, RANDGEN_DEVICE, O_RDONLY, 0);
  395. if (IS_ERR(rand_gen)) {
  396. printf("Unable to open random generator device\n");
  397. goto exit;
  398. }
  399. struct pal_sec * pal_sec_addr =
  400. find_symbol(pal_dyn, (ElfW(Addr)) pal_addr, "pal_sec");
  401. if (!pal_sec_addr) {
  402. printf("Unable to find 'pal_sec' in PAL loader\n");
  403. goto exit;
  404. }
  405. unsigned short mcast_port = 0;
  406. ret = INLINE_SYSCALL(read, 3, rand_gen, &mcast_port, sizeof(mcast_port));
  407. if (IS_ERR(ret)) {
  408. ret = -ERRNO(ret);
  409. goto exit;
  410. }
  411. pal_sec_addr->process_id = pid;
  412. pal_sec_addr->random_device = rand_gen;
  413. pal_sec_addr->pipe_prefix_id = 0;
  414. pal_sec_addr->mcast_port = mcast_port % (65536 - 1024) + 1024;
  415. pal_sec_addr->_dl_debug_state = &___dl_debug_state;
  416. pal_sec_addr->_r_debug = &___r_debug;
  417. ret = set_sandbox(&sandbox_config, pal_sec_addr, pal_addr);
  418. if (ret < 0) {
  419. printf("Unable to load sandbox policies\n");
  420. goto exit;
  421. }
  422. /* free PAL_INIT_FD */
  423. INLINE_SYSCALL(close, 1, PROC_INIT_FD);
  424. void * code_start = NULL;
  425. void * code_end = NULL;
  426. ret = find_code_range(pal_addr, &code_start, &code_end);
  427. if (ret < 0) {
  428. printf("Unable to find a code segment\n");
  429. goto exit;
  430. }
  431. ret = install_syscall_filter(code_start, code_end);
  432. if (ret < 0) {
  433. printf("Unable to install system call filter\n");
  434. goto exit;
  435. }
  436. /* after installing syscall, you can't execute any system call */
  437. const char ** new_envp, ** new_argv;
  438. ElfW(auxv_t) * new_auxv;
  439. int envc = 1, auxc = 1;
  440. for (const char ** e = envp ; *e ; e++, envc++);
  441. for (ElfW(auxv_t) * av = auxv ; av->a_type != AT_NULL ; av++, auxc++);
  442. /* skip 1024 bytes as a red zone */
  443. void * stack = __alloca(sizeof(unsigned long) +
  444. sizeof(char *) * (argc + 2) +
  445. sizeof(char *) * envc +
  446. sizeof(ElfW(auxv_t)) * auxc);
  447. *(unsigned long *) stack = argc + 1;
  448. new_argv = stack + sizeof(unsigned long *);
  449. new_envp = (void *) &new_argv[argc + 2];
  450. new_auxv = (void *) &new_envp[envc + 1];
  451. new_argv[0] = PAL_LOADER;
  452. memcpy(&new_argv[1], argv, sizeof(char *) * (argc + 1));
  453. memcpy(new_envp, envp, sizeof(char *) * envc);
  454. memcpy(new_auxv, auxv, sizeof(ElfW(auxv_t)) * auxc);
  455. for (ElfW(auxv_t) * av = new_auxv ; av->a_type != AT_NULL ; av++)
  456. switch (av->a_type) {
  457. case AT_ENTRY:
  458. av->a_un.a_val = (unsigned long) pal_entry;
  459. break;
  460. case AT_BASE:
  461. av->a_un.a_val = (unsigned long) pal_addr;
  462. break;
  463. case AT_PHDR:
  464. av->a_un.a_val = (unsigned long) pal_addr + pal_phoff;
  465. break;
  466. case AT_PHNUM:
  467. av->a_un.a_val = pal_phnum;
  468. break;
  469. }
  470. asm volatile ("xorq %%rsp, %%rsp\r\n"
  471. "movq %0, %%rsp\r\n"
  472. "jmpq *%1\r\n"
  473. :: "r"(stack), "r"(pal_entry) : "memory");
  474. exit:
  475. INLINE_SYSCALL(exit_group, 1, ret);
  476. }
  477. /* This does not return */
  478. void __abort(void) {
  479. INLINE_SYSCALL(exit_group, 1, -1);
  480. }
  481. void warn (const char *format, ...)
  482. {
  483. va_list args;
  484. va_start (args, format);
  485. printf(format, args);
  486. va_end (args);
  487. }