db_main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  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. /* Copyright (C) 2014 OSCAR lab, Stony Brook University
  4. This file is part of Graphene Library OS.
  5. Graphene Library OS is free software: you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. Graphene Library OS is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * db_main.c
  17. *
  18. * This file contains the main function of the PAL loader, which loads and
  19. * processes environment, arguments and manifest.
  20. */
  21. #include "pal_defs.h"
  22. #include "pal_linux_defs.h"
  23. #include "pal.h"
  24. #include "pal_internal.h"
  25. #include "pal_linux.h"
  26. #include "pal_debug.h"
  27. #include "pal_error.h"
  28. #include "pal_security.h"
  29. #include "api.h"
  30. #include <asm/mman.h>
  31. #include <asm/ioctls.h>
  32. #include <fcntl.h>
  33. #include <asm-errno.h>
  34. #include <elf/elf.h>
  35. #include <sysdeps/generic/ldsodefs.h>
  36. #include <sys/types.h>
  37. /* At the begining of entry point, rsp starts at argc, then argvs,
  38. envps and auxvs. Here we store rsp to rdi, so it will not be
  39. messed up by function calls */
  40. asm (".global pal_start \n"
  41. " .type pal_start,@function \n"
  42. "pal_start: \n"
  43. " movq %rsp, %rdi \n"
  44. " call pal_linux_main \n");
  45. #define RTLD_BOOTSTRAP
  46. /* pal_start is the entry point of libpal.so, which calls pal_main */
  47. #define _ENTRY pal_start
  48. asm (".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\r\n"
  49. ".byte 1\r\n"
  50. ".asciz \"" XSTRINGIFY(GDB_SCRIPT) "\"\r\n"
  51. ".popsection\r\n");
  52. struct pal_linux_config pal_linux_config;
  53. static size_t pagesz = PRESET_PAGESIZE;
  54. static uid_t uid;
  55. static gid_t gid;
  56. #if USE_VDSO_GETTIME == 1
  57. static ElfW(Addr) sysinfo_ehdr;
  58. #endif
  59. static void pal_init_bootstrap (void * args, int * pargc,
  60. const char *** pargv,
  61. const char *** penvp)
  62. {
  63. /*
  64. * fetch arguments and environment variables, the previous stack
  65. * pointer is in rdi (arg). The stack structure starting at rdi
  66. * will look like:
  67. * auxv[m - 1] = AT_NULL
  68. * ...
  69. * auxv[0]
  70. * envp[n - 1] = NULL
  71. * ...
  72. * envp[0]
  73. * argv[argc] = NULL
  74. * argv[argc - 1]
  75. * ...
  76. * argv[0]
  77. * argc
  78. * ---------------------------------------
  79. * user stack
  80. */
  81. const char ** all_args = (const char **) args;
  82. int argc = (uintptr_t) all_args[0];
  83. const char ** argv = &all_args[1];
  84. const char ** envp = argv + argc + 1;
  85. /* fetch environment information from aux vectors */
  86. void ** auxv = (void **) envp + 1;
  87. for (; *(auxv - 1); auxv++);
  88. ElfW(auxv_t) *av;
  89. for (av = (ElfW(auxv_t) *)auxv ; av->a_type != AT_NULL ; av++)
  90. switch (av->a_type) {
  91. case AT_PAGESZ:
  92. pagesz = av->a_un.a_val;
  93. break;
  94. case AT_UID:
  95. case AT_EUID:
  96. uid ^= av->a_un.a_val;
  97. break;
  98. case AT_GID:
  99. case AT_EGID:
  100. gid ^= av->a_un.a_val;
  101. break;
  102. #if USE_VDSO_GETTIME == 1
  103. case AT_SYSINFO_EHDR:
  104. sysinfo_ehdr = av->a_un.a_val;
  105. break;
  106. #endif
  107. }
  108. argv++;
  109. argc--;
  110. *pargc = argc;
  111. *pargv = argv;
  112. *penvp = envp;
  113. }
  114. unsigned long _DkGetPagesize (void)
  115. {
  116. return pagesz;
  117. }
  118. unsigned long _DkGetAllocationAlignment (void)
  119. {
  120. return pagesz;
  121. }
  122. static PAL_HANDLE try_open_runnable (const char * name, bool try_path,
  123. const char ** uri)
  124. {
  125. PAL_HANDLE handle = NULL;
  126. /* Try to open the manifest file specified by the first argument */
  127. if (_DkStreamOpen(&handle, name, PAL_ACCESS_RDONLY, 0, 0, 0) == 0) {
  128. if (uri)
  129. *uri = name;
  130. return handle;
  131. }
  132. if (!try_path)
  133. return NULL;
  134. /* might be a real path, let's try open it */
  135. int fd = INLINE_SYSCALL(open, 3, name, O_RDONLY|O_CLOEXEC, 0);
  136. if (IS_ERR(fd))
  137. return NULL;
  138. int len = strlen(name);
  139. handle = malloc(HANDLE_SIZE(file) + len + 1);
  140. SET_HANDLE_TYPE(handle, file);
  141. handle->__in.flags |= RFD(0)|WFD(0)|WRITEABLE(0);
  142. handle->file.fd = fd;
  143. char * path = (void *) handle + HANDLE_SIZE(file);
  144. memcpy(path, name, len + 1);
  145. handle->file.realpath = path;
  146. if (uri) {
  147. char * new_uri = malloc(len + 6);
  148. memcpy(new_uri, "file:", 5);
  149. memcpy(new_uri + 5, name, len + 1);
  150. *uri = new_uri;
  151. }
  152. return handle;
  153. }
  154. int read_shebang (const char ** argv)
  155. {
  156. /* must be a shebang */
  157. int fd = INLINE_SYSCALL(open, 3, *argv, O_RDONLY|O_CLOEXEC, 0);
  158. if (IS_ERR(fd)) {
  159. bad_shebang:
  160. INLINE_SYSCALL(close, 1, fd);
  161. return -PAL_ERROR_INVAL;
  162. }
  163. /* the maximun length for shebang path is 80 chars */
  164. char buffer[80];
  165. int bytes = INLINE_SYSCALL(read, 3, fd, buffer, 80);
  166. if (IS_ERR(bytes))
  167. goto bad_shebang;
  168. /* the format of shebang should be '#!/absoulte/path/of/pal' */
  169. if (buffer[0] != '#' || buffer[1] != '!')
  170. goto bad_shebang;
  171. char * p = &buffer[2];
  172. while (*p && *p != ' ' && *p != '\r' && *p != '\n')
  173. p++;
  174. int len = strlen(*argv);
  175. PAL_HANDLE manifest = malloc(HANDLE_SIZE(file) + len + 1);
  176. SET_HANDLE_TYPE(manifest, file);
  177. manifest->__in.flags |= RFD(0)|WFD(0)|WRITEABLE(0);
  178. manifest->file.fd = fd;
  179. char * path = (void *) manifest + HANDLE_SIZE(file);
  180. memcpy(path, *argv, len + 1);
  181. manifest->file.realpath = path;
  182. char * uri = malloc(len + 6);
  183. memcpy(uri, "file:", 5);
  184. memcpy(uri + 5, *argv, len + 1);
  185. pal_config.manifest = uri;
  186. pal_config.manifest_handle = manifest;
  187. return 0;
  188. }
  189. #include "elf-x86_64.h"
  190. #include "dynamic_link.h"
  191. extern void setup_pal_map (const char * realname, ElfW(Dyn) ** dyn,
  192. ElfW(Addr) addr);
  193. void pal_linux_main (void * args)
  194. {
  195. int argc;
  196. const char ** argv, ** envp;
  197. /* parse argc, argv, envp and auxv */
  198. pal_init_bootstrap(args, &argc, &argv, &envp);
  199. ElfW(Addr) pal_addr = elf_machine_load_address();
  200. ElfW(Dyn) * pal_dyn[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM +
  201. DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
  202. memset(pal_dyn, 0, sizeof(pal_dyn));
  203. elf_get_dynamic_info((void *) pal_addr + elf_machine_dynamic(), pal_dyn,
  204. pal_addr);
  205. ELF_DYNAMIC_RELOCATE(pal_dyn, pal_addr);
  206. allocsize = PRESET_PAGESIZE;
  207. allocshift = PRESET_PAGESIZE - 1;
  208. allocmask = ~(PRESET_PAGESIZE - 1);
  209. init_slab_mgr();
  210. setup_pal_map(XSTRINGIFY(SRCDIR) "/pal", pal_dyn, pal_addr);
  211. /* jump to main function */
  212. pal_main(argc, argv, envp);
  213. }
  214. int create_domain_dir (void)
  215. {
  216. int ret = 0;
  217. const char * path;
  218. ret = INLINE_SYSCALL(mkdir, 2, (path = GRAPHENE_PIPEDIR), 0777);
  219. if (IS_ERR(ret) && ERRNO(ret) != EEXIST) {
  220. if (ERRNO(ret) == ENOENT) {
  221. ret = INLINE_SYSCALL(mkdir, 2, (path = GRAPHENE_TEMPDIR), 0777);
  222. if (!IS_ERR(ret)) {
  223. INLINE_SYSCALL(chmod, 2, GRAPHENE_TEMPDIR, 0777);
  224. ret = INLINE_SYSCALL(mkdir, 2, (path = GRAPHENE_PIPEDIR), 0777);
  225. }
  226. }
  227. if (IS_ERR(ret)) {
  228. printf("Cannot create directory %s (%e), "
  229. "please check permission\n", path, ERRNO(ret));
  230. return -PAL_ERROR_DENIED;
  231. }
  232. }
  233. if (!IS_ERR(ret))
  234. INLINE_SYSCALL(chmod, 2, GRAPHENE_PIPEDIR, 0777);
  235. char * pipedir = __alloca(sizeof(GRAPHENE_PIPEDIR) + 10);
  236. unsigned int id;
  237. do {
  238. if (!getrand(&id, sizeof(unsigned int))) {
  239. printf("Unable to generate random numbers\n");
  240. return -PAL_ERROR_DENIED;
  241. }
  242. snprintf(pipedir, sizeof(GRAPHENE_PIPEDIR) + 10,
  243. GRAPHENE_PIPEDIR "/%08x", id);
  244. ret = INLINE_SYSCALL(mkdir, 2, pipedir, 0700);
  245. if (IS_ERR(ret) && ERRNO(ret) != -EEXIST) {
  246. printf("Cannot create directory %s (%e), "
  247. "please fix permission\n", pipedir, ERRNO(ret));
  248. return -PAL_ERROR_DENIED;
  249. }
  250. } while (IS_ERR(ret));
  251. pal_sec_info.domain_id = id;
  252. return 0;
  253. }
  254. #if USE_VDSO_GETTIME == 1
  255. void setup_vdso_map (ElfW(Addr) addr);
  256. #endif
  257. static int loader_filter (const char * key, int len)
  258. {
  259. return memcmp(key, "loader.", 7);
  260. }
  261. int _DkInitHost (int * pargc, const char *** pargv)
  262. {
  263. int argc = *pargc;
  264. const char ** argv = *pargv, * first_argv = NULL;
  265. int ret = 0;
  266. struct pal_proc_args proc_args;
  267. void * proc_data;
  268. bool in_child = false;
  269. ret = INLINE_SYSCALL(read, 3, PROC_INIT_FD, &proc_args,
  270. sizeof(proc_args));
  271. if (IS_ERR(ret) && ERRNO(ret) != EBADF)
  272. return -PAL_ERROR_DENIED;
  273. if (!IS_ERR(ret)) {
  274. in_child = true;
  275. proc_data = __alloca(proc_args.data_size);
  276. ret = INLINE_SYSCALL(read, 3, PROC_INIT_FD, proc_data,
  277. proc_args.data_size);
  278. if (IS_ERR(ret) || ret < proc_args.data_size)
  279. return -PAL_ERROR_DENIED;
  280. }
  281. if (!in_child && !argc) {
  282. printf("USAGE: libpal.so [executable|manifest] args ...\n");
  283. return -PAL_ERROR_INVAL;
  284. }
  285. pal_linux_config.pid = INLINE_SYSCALL(getpid, 0);
  286. pal_config.user_addr_end = (void *)
  287. ALLOC_ALIGNDOWN(pal_config.lib_text_start);
  288. /* look for lowest mappable address, starting at 0x400000 */
  289. if (pal_sec_info.user_addr_base) {
  290. pal_config.user_addr_start = pal_sec_info.user_addr_base;
  291. } else {
  292. void * base = (void *) 0x400000;
  293. for (; base < pal_config.user_addr_end ;
  294. base = (void *) ((unsigned long) base << 4)) {
  295. void * mem = (void *) ARCH_MMAP(base, allocsize,
  296. PROT_NONE,
  297. MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
  298. -1, 0);
  299. if (IS_ERR_P(mem))
  300. continue;
  301. INLINE_SYSCALL(munmap, 2, mem, allocsize);
  302. if (mem == base)
  303. break;
  304. }
  305. pal_sec_info.user_addr_base = pal_config.user_addr_start = base;
  306. }
  307. signal_setup();
  308. if (in_child) {
  309. if ((ret = init_child_process(&proc_args, proc_data)) < 0)
  310. return ret;
  311. goto read_manifest;
  312. }
  313. /* occupy PROC_INIT_FD so no one will use it */
  314. INLINE_SYSCALL(dup2, 2, 0, PROC_INIT_FD);
  315. if (!(ret = read_shebang(argv)) < 0)
  316. goto read_manifest;
  317. PAL_HANDLE file = NULL;
  318. const char * file_uri = NULL;
  319. if (argv[0][0] != '-') {
  320. file = try_open_runnable(argv[0], true, &file_uri);
  321. if (!file)
  322. return -PAL_ERROR_DENIED;
  323. first_argv = argv[0];
  324. argc--;
  325. argv++;
  326. /* the file laoded might be a executable */
  327. if (check_elf_object(file)) {
  328. pal_config.manifest = file_uri;
  329. pal_config.manifest_handle = file;
  330. goto read_manifest;
  331. }
  332. pal_config.exec = file_uri;
  333. pal_config.exec_handle = file;
  334. const char * manifest_uri;
  335. char manifest_path[80];
  336. snprintf(manifest_path, 80, "%s.manifest", pal_config.exec);
  337. if ((file = try_open_runnable(manifest_path, false, &manifest_uri))) {
  338. pal_config.manifest = manifest_uri;
  339. pal_config.manifest_handle = file;
  340. goto read_manifest;
  341. }
  342. }
  343. if ((file = try_open_runnable("file:manifest", false, NULL))) {
  344. pal_config.manifest = "file:manifest";
  345. pal_config.manifest_handle = file;
  346. goto read_manifest;
  347. }
  348. read_manifest:
  349. if (!pal_config.manifest_handle) {
  350. printf("Can't fine any manifest, going to run without one\n");
  351. goto done_init;
  352. }
  353. PAL_STREAM_ATTR attr;
  354. if ((ret = _DkStreamAttributesQuerybyHandle(pal_config.manifest_handle,
  355. &attr)) < 0)
  356. return ret;
  357. pal_config.user_addr_end -= ALLOC_ALIGNUP(attr.size);
  358. void * cfg_addr = pal_config.user_addr_end;
  359. size_t cfg_size = attr.size;
  360. if ((ret = _DkStreamMap(pal_config.manifest_handle, &cfg_addr,
  361. PAL_PROT_READ, 0,
  362. ALLOC_ALIGNUP(cfg_size))) < 0)
  363. return ret;
  364. struct config_store * root_config = malloc(sizeof(struct config_store));
  365. root_config->raw_data = cfg_addr;
  366. root_config->raw_size = cfg_size;
  367. root_config->malloc = malloc;
  368. root_config->free = free;
  369. const char * errstring = NULL;
  370. if ((ret = read_config(root_config, loader_filter, &errstring)) < 0) {
  371. printf("Can't read manifest: %s\n", errstring);
  372. return -PAL_ERROR_INVAL;
  373. }
  374. pal_config.root_config = root_config;
  375. char cfgbuf[CONFIG_MAX];
  376. int len;
  377. if (!pal_linux_config.noexec && !pal_config.exec_handle) {
  378. /* find executable in the manifest */
  379. if ((len = get_config(root_config, "loader.exec", cfgbuf,
  380. CONFIG_MAX)) > 0) {
  381. if (!(file = try_open_runnable(cfgbuf, false, NULL)))
  382. return -PAL_ERROR_DENIED;
  383. if ((ret = check_elf_object(file)) < 0)
  384. return ret;
  385. pal_config.exec = remalloc(cfgbuf, len + 1);
  386. pal_config.exec_handle = file;
  387. }
  388. }
  389. if (!in_child) {
  390. if ((len = get_config(root_config, "loader.execname", cfgbuf,
  391. CONFIG_MAX)) > 0)
  392. first_argv = remalloc(cfgbuf, len + 1);
  393. if (!first_argv)
  394. first_argv = pal_config.exec;
  395. }
  396. done_init:
  397. if (!in_child && !pal_sec_info.domain_id) {
  398. if ((ret = create_domain_dir()) < 0)
  399. return ret;
  400. }
  401. PAL_HANDLE thread = malloc(HANDLE_SIZE(thread));
  402. SET_HANDLE_TYPE(thread, thread);
  403. thread->thread.tid = pal_linux_config.pid;
  404. __pal_control.first_thread = thread;
  405. #if USE_VDSO_GETTIME == 1
  406. if (sysinfo_ehdr)
  407. setup_vdso_map(sysinfo_ehdr);
  408. #endif
  409. if (!pal_sec_info.mcast_port) {
  410. unsigned short mcast_port;
  411. getrand(&mcast_port, sizeof(unsigned short));
  412. if (mcast_port < 1024)
  413. mcast_port += 1024;
  414. pal_sec_info.mcast_port = mcast_port > 1024 ? mcast_port :
  415. mcast_port + 1204;
  416. }
  417. __pal_control.broadcast_stream =
  418. _DkBroadcastStreamOpen(pal_sec_info.mcast_port);
  419. if (first_argv) {
  420. argc++;
  421. argv--;
  422. argv[0] = first_argv;
  423. }
  424. *pargc = argc;
  425. *pargv = argv;
  426. return 0;
  427. }