shim_init.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. /* Copyright (C) 2014 Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * shim_init.c
  15. *
  16. * This file contains entry and exit functions of library OS.
  17. */
  18. #include <shim_internal.h>
  19. #include <shim_table.h>
  20. #include <shim_tls.h>
  21. #include <shim_thread.h>
  22. #include <shim_handle.h>
  23. #include <shim_vma.h>
  24. #include <shim_checkpoint.h>
  25. #include <shim_fs.h>
  26. #include <shim_ipc.h>
  27. #include <shim_profile.h>
  28. #include <pal.h>
  29. #include <pal_debug.h>
  30. #include <pal_error.h>
  31. #include <sys/mman.h>
  32. #include <asm/unistd.h>
  33. #include <asm/fcntl.h>
  34. unsigned long allocsize;
  35. unsigned long allocshift;
  36. unsigned long allocmask;
  37. /* The following constants will help matching glibc version with compatible
  38. SHIM libraries */
  39. #include "glibc-version.h"
  40. const unsigned int glibc_version = GLIBC_VERSION;
  41. static void handle_failure (PAL_PTR event, PAL_NUM arg, PAL_CONTEXT * context)
  42. {
  43. __UNUSED(event);
  44. __UNUSED(context);
  45. shim_get_tls()->pal_errno = (arg <= PAL_ERROR_BOUND) ? arg : 0;
  46. }
  47. noreturn void __abort(void) {
  48. PAUSE();
  49. shim_terminate(-ENOTRECOVERABLE);
  50. }
  51. void warn (const char *format, ...)
  52. {
  53. va_list args;
  54. va_start (args, format);
  55. __SYS_VPRINTF(format, args);
  56. va_end (args);
  57. }
  58. void __stack_chk_fail (void)
  59. {
  60. }
  61. static int pal_errno_to_unix_errno [PAL_ERROR_BOUND + 1] = {
  62. /* reserved */ 0,
  63. /* PAL_ERROR_NOTIMPLEMENTED */ ENOSYS,
  64. /* PAL_ERROR_NOTDEFINED */ ENOSYS,
  65. /* PAL_ERROR_NOTSUPPORT */ EACCES,
  66. /* PAL_ERROR_INVAL */ EINVAL,
  67. /* PAL_ERROR_TOOLONG */ ENAMETOOLONG,
  68. /* PAL_ERROR_DENIED */ EACCES,
  69. /* PAL_ERROR_BADHANDLE */ EFAULT,
  70. /* PAL_ERROR_STREAMEXIST */ EEXIST,
  71. /* PAL_ERROR_STREAMNOTEXIST */ ENOENT,
  72. /* PAL_ERROR_STREAMISFILE */ ENOTDIR,
  73. /* PAL_ERROR_STREAMISDIR */ EISDIR,
  74. /* PAL_ERROR_STREAMISDEVICE */ ESPIPE,
  75. /* PAL_ERROR_INTERRUPTED */ EINTR,
  76. /* PAL_ERROR_OVERFLOW */ EFAULT,
  77. /* PAL_ERROR_BADADDR */ EFAULT,
  78. /* PAL_ERROR_NOMEM */ ENOMEM,
  79. /* PAL_ERROR_NOTKILLABLE */ EACCES,
  80. /* PAL_ERROR_INCONSIST */ EFAULT,
  81. /* PAL_ERROR_TRYAGAIN */ EAGAIN,
  82. /* PAL_ERROR_ENDOFSTREAM */ 0,
  83. /* PAL_ERROR_NOTSERVER */ EINVAL,
  84. /* PAL_ERROR_NOTCONNECTION */ ENOTCONN,
  85. /* PAL_ERROR_ZEROSIZE */ 0,
  86. /* PAL_ERROR_CONNFAILED */ ECONNRESET,
  87. /* PAL_ERROR_ADDRNOTEXIST */ EADDRNOTAVAIL,
  88. };
  89. long convert_pal_errno (long err)
  90. {
  91. return (err >= 0 && err <= PAL_ERROR_BOUND) ?
  92. pal_errno_to_unix_errno[err] : 0;
  93. }
  94. unsigned long parse_int (const char * str)
  95. {
  96. unsigned long num = 0;
  97. int radix = 10;
  98. char c;
  99. if (str[0] == '0') {
  100. str++;
  101. radix = 8;
  102. if (str[0] == 'x') {
  103. str++;
  104. radix = 16;
  105. }
  106. }
  107. while ((c = *(str++))) {
  108. int val;
  109. if (c >= 'A' && c <= 'F')
  110. val = c - 'A' + 10;
  111. else if (c >= 'a' && c <= 'f')
  112. val = c - 'a' + 10;
  113. else if (c >= '0' && c <= '9')
  114. val = c - '0';
  115. else
  116. break;
  117. if (val >= radix)
  118. break;
  119. num = num * radix + val;
  120. }
  121. if (c == 'G' || c == 'g')
  122. num *= 1024 * 1024 * 1024;
  123. else if (c == 'M' || c == 'm')
  124. num *= 1024 * 1024;
  125. else if (c == 'K' || c == 'k')
  126. num *= 1024;
  127. return num;
  128. }
  129. long int glibc_option (const char * opt)
  130. {
  131. char cfg[CONFIG_MAX];
  132. if (strcmp_static(opt, "heap_size")) {
  133. ssize_t ret = get_config(root_config, "glibc.heap_size", cfg, CONFIG_MAX);
  134. if (ret <= 0) {
  135. debug("no glibc option: %s (err=%ld)\n", opt, ret);
  136. return -ENOENT;
  137. }
  138. long int heap_size = parse_int(cfg);
  139. debug("glibc option: heap_size = %ld\n", heap_size);
  140. return (long int) heap_size;
  141. }
  142. return -EINVAL;
  143. }
  144. void * migrated_memory_start;
  145. void * migrated_memory_end;
  146. const char ** initial_envp __attribute_migratable;
  147. /* library_paths is populated with LD_PRELOAD entries once during LibOS
  148. * initialization and is used in __load_interp_object() to search for ELF
  149. * program interpreter in specific paths. Once allocated, its memory is
  150. * never freed or updated. */
  151. char ** library_paths = NULL;
  152. struct shim_lock __master_lock;
  153. bool lock_enabled;
  154. void init_tcb (shim_tcb_t * tcb)
  155. {
  156. tcb->canary = SHIM_TLS_CANARY;
  157. tcb->self = tcb;
  158. }
  159. void copy_tcb (shim_tcb_t * new_tcb, const shim_tcb_t * old_tcb)
  160. {
  161. memset(new_tcb, 0, sizeof(shim_tcb_t));
  162. new_tcb->canary = SHIM_TLS_CANARY;
  163. new_tcb->self = new_tcb;
  164. new_tcb->tp = old_tcb->tp;
  165. memcpy(&new_tcb->context, &old_tcb->context, sizeof(struct shim_context));
  166. new_tcb->tid = old_tcb->tid;
  167. new_tcb->debug_buf = old_tcb->debug_buf;
  168. }
  169. /* This function is used to allocate tls before interpreter start running */
  170. void allocate_tls (__libc_tcb_t * tcb, bool user, struct shim_thread * thread)
  171. {
  172. assert(tcb);
  173. tcb->tcb = tcb;
  174. init_tcb(&tcb->shim_tcb);
  175. if (thread) {
  176. thread->tcb = tcb;
  177. thread->user_tcb = user;
  178. tcb->shim_tcb.tp = thread;
  179. tcb->shim_tcb.tid = thread->tid;
  180. } else {
  181. tcb->shim_tcb.tp = NULL;
  182. tcb->shim_tcb.tid = 0;
  183. }
  184. DkSegmentRegister(PAL_SEGMENT_FS, tcb);
  185. assert(shim_tls_check_canary());
  186. }
  187. void populate_tls (__libc_tcb_t * tcb, bool user)
  188. {
  189. assert(tcb);
  190. tcb->tcb = tcb;
  191. copy_tcb(&tcb->shim_tcb, shim_get_tls());
  192. struct shim_thread * thread = (struct shim_thread *) tcb->shim_tcb.tp;
  193. if (thread) {
  194. thread->tcb = tcb;
  195. thread->user_tcb = user;
  196. }
  197. DkSegmentRegister(PAL_SEGMENT_FS, tcb);
  198. assert(shim_tls_check_canary());
  199. }
  200. DEFINE_PROFILE_OCCURENCE(alloc_stack, memory);
  201. DEFINE_PROFILE_OCCURENCE(alloc_stack_count, memory);
  202. #define STACK_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
  203. void * allocate_stack (size_t size, size_t protect_size, bool user)
  204. {
  205. size = ALIGN_UP(size);
  206. protect_size = ALIGN_UP(protect_size);
  207. /* preserve a non-readable, non-writable page below the user
  208. stack to stop user program to clobber other vmas */
  209. void * stack = NULL;
  210. int flags = STACK_FLAGS|(user ? 0 : VMA_INTERNAL);
  211. if (user) {
  212. stack = bkeep_unmapped_heap(size + protect_size, PROT_NONE,
  213. flags, NULL, 0, "stack");
  214. if (!stack)
  215. return NULL;
  216. stack = (void *)
  217. DkVirtualMemoryAlloc(stack, size + protect_size,
  218. 0, PAL_PROT_NONE);
  219. } else {
  220. stack = system_malloc(size + protect_size);
  221. }
  222. if (!stack)
  223. return NULL;
  224. ADD_PROFILE_OCCURENCE(alloc_stack, size + protect_size);
  225. INC_PROFILE_OCCURENCE(alloc_stack_count);
  226. stack += protect_size;
  227. // Ensure proper alignment for process' initial stack pointer value.
  228. stack += (16 - (uintptr_t)stack % 16) % 16;
  229. DkVirtualMemoryProtect(stack, size, PAL_PROT_READ|PAL_PROT_WRITE);
  230. if (bkeep_mprotect(stack, size, PROT_READ|PROT_WRITE, flags) < 0)
  231. return NULL;
  232. debug("allocated stack at %p (size = %ld)\n", stack, size);
  233. return stack;
  234. }
  235. static int populate_user_stack (void * stack, size_t stack_size,
  236. elf_auxv_t ** auxpp, int ** argcpp,
  237. const char *** argvp, const char *** envpp)
  238. {
  239. const int argc = **argcpp;
  240. const char ** argv = *argvp, ** envp = *envpp;
  241. const char ** new_argv = NULL, ** new_envp = NULL;
  242. elf_auxv_t *new_auxp = NULL;
  243. void * stack_bottom = stack;
  244. void * stack_top = stack + stack_size;
  245. #define ALLOCATE_TOP(size) \
  246. ({ if ((stack_top -= (size)) < stack_bottom) return -ENOMEM; \
  247. stack_top; })
  248. #define ALLOCATE_BOTTOM(size) \
  249. ({ if ((stack_bottom += (size)) > stack_top) return -ENOMEM; \
  250. stack_bottom - (size); })
  251. /* ld.so expects argc as long on stack, not int. */
  252. long * argcp = ALLOCATE_BOTTOM(sizeof(long));
  253. *argcp = **argcpp;
  254. if (!argv) {
  255. *(const char **) ALLOCATE_BOTTOM(sizeof(const char *)) = NULL;
  256. goto copy_envp;
  257. }
  258. new_argv = stack_bottom;
  259. while (argv) {
  260. for (const char ** a = argv ; *a ; a++) {
  261. const char ** t = ALLOCATE_BOTTOM(sizeof(const char *));
  262. int len = strlen(*a) + 1;
  263. char * abuf = ALLOCATE_TOP(len);
  264. memcpy(abuf, *a, len);
  265. *t = abuf;
  266. }
  267. *((const char **) ALLOCATE_BOTTOM(sizeof(const char *))) = NULL;
  268. copy_envp:
  269. if (!envp)
  270. break;
  271. new_envp = stack_bottom;
  272. argv = envp;
  273. envp = NULL;
  274. }
  275. if (!new_envp)
  276. *(const char **) ALLOCATE_BOTTOM(sizeof(const char *)) = NULL;
  277. /* reserve space for ELF aux vectors, populated later by LibOS */
  278. new_auxp = ALLOCATE_BOTTOM(REQUIRED_ELF_AUXV * sizeof(elf_auxv_t) +
  279. REQUIRED_ELF_AUXV_SPACE);
  280. /* x86_64 ABI requires 16 bytes alignment on stack on every function
  281. call. */
  282. size_t move_size = stack_bottom - stack;
  283. *argcpp = stack_top - move_size;
  284. *argcpp = ALIGN_DOWN_PTR(*argcpp, 16UL);
  285. **argcpp = argc;
  286. size_t shift = (void*)(*argcpp) - stack;
  287. memmove(*argcpp, stack, move_size);
  288. *argvp = new_argv ? (void *) new_argv + shift : NULL;
  289. *envpp = new_envp ? (void *) new_envp + shift : NULL;
  290. *auxpp = new_auxp ? (void *) new_auxp + shift : NULL;
  291. /* clear working area at the bottom */
  292. memset(stack, 0, shift);
  293. return 0;
  294. }
  295. unsigned long sys_stack_size = 0;
  296. int init_stack (const char ** argv, const char ** envp,
  297. int ** argcpp, const char *** argpp,
  298. elf_auxv_t ** auxpp)
  299. {
  300. if (!sys_stack_size) {
  301. sys_stack_size = DEFAULT_SYS_STACK_SIZE;
  302. if (root_config) {
  303. char stack_cfg[CONFIG_MAX];
  304. if (get_config(root_config, "sys.stack.size", stack_cfg,
  305. CONFIG_MAX) > 0)
  306. sys_stack_size = ALIGN_UP(parse_int(stack_cfg));
  307. }
  308. }
  309. struct shim_thread * cur_thread = get_cur_thread();
  310. if (!cur_thread || cur_thread->stack)
  311. return 0;
  312. void * stack = allocate_stack(sys_stack_size, allocsize, true);
  313. if (!stack)
  314. return -ENOMEM;
  315. if (initial_envp)
  316. envp = initial_envp;
  317. int ret = populate_user_stack(stack, sys_stack_size, auxpp, argcpp, &argv, &envp);
  318. if (ret < 0)
  319. return ret;
  320. *argpp = argv;
  321. initial_envp = envp;
  322. cur_thread->stack_top = stack + sys_stack_size;
  323. cur_thread->stack = stack;
  324. cur_thread->stack_red = stack - allocsize;
  325. return 0;
  326. }
  327. int read_environs (const char ** envp)
  328. {
  329. for (const char ** e = envp ; *e ; e++) {
  330. if (strpartcmp_static(*e, "LD_LIBRARY_PATH=")) {
  331. /* populate library_paths with entries from LD_LIBRARY_PATH envvar */
  332. const char * s = *e + static_strlen("LD_LIBRARY_PATH=");
  333. size_t npaths = 2; // One for the first entry, one for the last
  334. // NULL.
  335. for (const char * tmp = s ; *tmp ; tmp++)
  336. if (*tmp == ':')
  337. npaths++;
  338. char** paths = malloc(sizeof(const char *) *
  339. npaths);
  340. if (!paths)
  341. return -ENOMEM;
  342. size_t cnt = 0;
  343. while (*s) {
  344. const char * next;
  345. for (next = s ; *next && *next != ':' ; next++);
  346. size_t len = next - s;
  347. char * str = malloc(len + 1);
  348. if (!str) {
  349. for (size_t i = 0; i < cnt; i++)
  350. free(paths[i]);
  351. free(paths);
  352. return -ENOMEM;
  353. }
  354. memcpy(str, s, len);
  355. str[len] = 0;
  356. paths[cnt++] = str;
  357. s = *next ? next + 1 : next;
  358. }
  359. paths[cnt] = NULL;
  360. assert(!library_paths);
  361. library_paths = paths;
  362. return 0;
  363. }
  364. }
  365. return 0;
  366. }
  367. struct config_store * root_config = NULL;
  368. static void * __malloc (size_t size)
  369. {
  370. return malloc(size);
  371. }
  372. static void __free (void * mem)
  373. {
  374. free(mem);
  375. }
  376. int init_manifest (PAL_HANDLE manifest_handle)
  377. {
  378. int ret = 0;
  379. void * addr = NULL;
  380. size_t size = 0, map_size = 0;
  381. #define MAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS|VMA_INTERNAL)
  382. if (PAL_CB(manifest_preload.start)) {
  383. addr = PAL_CB(manifest_preload.start);
  384. size = PAL_CB(manifest_preload.end) - PAL_CB(manifest_preload.start);
  385. } else {
  386. PAL_STREAM_ATTR attr;
  387. if (!DkStreamAttributesQueryByHandle(manifest_handle, &attr))
  388. return -PAL_ERRNO;
  389. size = attr.pending_size;
  390. map_size = ALIGN_UP(size);
  391. addr = bkeep_unmapped_any(map_size, PROT_READ, MAP_FLAGS,
  392. NULL, 0, "manifest");
  393. if (!addr)
  394. return -ENOMEM;
  395. void * ret_addr = DkStreamMap(manifest_handle, addr,
  396. PAL_PROT_READ, 0,
  397. ALIGN_UP(size));
  398. if (!ret_addr) {
  399. bkeep_munmap(addr, map_size, MAP_FLAGS);
  400. return -ENOMEM;
  401. } else {
  402. assert(addr == ret_addr);
  403. }
  404. }
  405. struct config_store * new_root_config = malloc(sizeof(struct config_store));
  406. if (!new_root_config) {
  407. ret = -ENOMEM;
  408. goto fail;
  409. }
  410. new_root_config->raw_data = addr;
  411. new_root_config->raw_size = size;
  412. new_root_config->malloc = __malloc;
  413. new_root_config->free = __free;
  414. const char * errstring = "Unexpected error";
  415. if ((ret = read_config(new_root_config, NULL, &errstring)) < 0) {
  416. SYS_PRINTF("Unable to read manifest file: %s\n", errstring);
  417. goto fail;
  418. }
  419. root_config = new_root_config;
  420. return 0;
  421. fail:
  422. if (map_size) {
  423. DkStreamUnmap(addr, map_size);
  424. if (bkeep_munmap(addr, map_size, MAP_FLAGS) < 0)
  425. BUG();
  426. }
  427. free(new_root_config);
  428. return ret;
  429. }
  430. #ifdef PROFILE
  431. struct shim_profile profile_root;
  432. #endif
  433. # define FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
  434. do { \
  435. void *_tmp = (cookie); \
  436. (argv) = _tmp; \
  437. _tmp += sizeof(char *) * ((argc) + 1); \
  438. (envp) = _tmp; \
  439. for ( ; *(char **) _tmp; _tmp += sizeof(char *)); \
  440. (auxp) = _tmp + sizeof(char *); \
  441. } while (0)
  442. #ifdef PROFILE
  443. static void set_profile_enabled (const char ** envp)
  444. {
  445. const char ** p;
  446. for (p = envp ; (*p) ; p++)
  447. if (strpartcmp_static(*p, "PROFILE_ENABLED="))
  448. break;
  449. if (!(*p))
  450. return;
  451. for (size_t i = 0 ; i < N_PROFILE ; i++)
  452. PROFILES[i].disabled = true;
  453. const char * str = (*p) + 16;
  454. bool enabled = false;
  455. while (*str) {
  456. const char * next = str;
  457. for ( ; (*next) && (*next) != ',' ; next++);
  458. if (next > str) {
  459. size_t len = next - str;
  460. for (size_t i = 0 ; i < N_PROFILE ; i++) {
  461. struct shim_profile * profile = &PROFILES[i];
  462. if (!memcmp(profile->name, str, len) && !profile->name[len]) {
  463. profile->disabled = false;
  464. if (profile->type == CATEGORY)
  465. enabled = true;
  466. }
  467. }
  468. }
  469. str = (*next) ? next + 1 : next;
  470. }
  471. while (enabled) {
  472. enabled = false;
  473. for (size_t i = 0 ; i < N_PROFILE ; i++) {
  474. struct shim_profile * profile = &PROFILES[i];
  475. if (!profile->disabled || profile->root == &profile_)
  476. continue;
  477. if (!profile->root->disabled) {
  478. profile->disabled = false;
  479. if (profile->type == CATEGORY)
  480. enabled = true;
  481. }
  482. }
  483. }
  484. for (size_t i = 0 ; i < N_PROFILE ; i++) {
  485. struct shim_profile * profile = &PROFILES[i];
  486. if (profile->type == CATEGORY || profile->disabled)
  487. continue;
  488. for (profile = profile->root ;
  489. profile != &profile_ && profile->disabled ;
  490. profile = profile->root)
  491. profile->disabled = false;
  492. }
  493. }
  494. #endif
  495. static int init_newproc (struct newproc_header * hdr)
  496. {
  497. BEGIN_PROFILE_INTERVAL();
  498. int bytes = DkStreamRead(PAL_CB(parent_process), 0,
  499. sizeof(struct newproc_header), hdr,
  500. NULL, 0);
  501. if (!bytes)
  502. return -PAL_ERRNO;
  503. SAVE_PROFILE_INTERVAL(child_wait_header);
  504. SAVE_PROFILE_INTERVAL_SINCE(child_receive_header, hdr->write_proc_time);
  505. return hdr->failure;
  506. }
  507. DEFINE_PROFILE_CATEGORY(pal, );
  508. DEFINE_PROFILE_INTERVAL(pal_startup_time, pal);
  509. DEFINE_PROFILE_INTERVAL(pal_host_specific_startup_time, pal);
  510. DEFINE_PROFILE_INTERVAL(pal_relocation_time, pal);
  511. DEFINE_PROFILE_INTERVAL(pal_linking_time, pal);
  512. DEFINE_PROFILE_INTERVAL(pal_manifest_loading_time, pal);
  513. DEFINE_PROFILE_INTERVAL(pal_allocation_time, pal);
  514. DEFINE_PROFILE_INTERVAL(pal_tail_startup_time, pal);
  515. DEFINE_PROFILE_INTERVAL(pal_child_creation_time, pal);
  516. DEFINE_PROFILE_CATEGORY(init, );
  517. DEFINE_PROFILE_INTERVAL(init_vma, init);
  518. DEFINE_PROFILE_INTERVAL(init_slab, init);
  519. DEFINE_PROFILE_INTERVAL(init_str_mgr, init);
  520. DEFINE_PROFILE_INTERVAL(init_internal_map, init);
  521. DEFINE_PROFILE_INTERVAL(init_fs, init);
  522. DEFINE_PROFILE_INTERVAL(init_dcache, init);
  523. DEFINE_PROFILE_INTERVAL(init_handle, init);
  524. DEFINE_PROFILE_INTERVAL(read_from_checkpoint, init);
  525. DEFINE_PROFILE_INTERVAL(read_from_file, init);
  526. DEFINE_PROFILE_INTERVAL(init_newproc, init);
  527. DEFINE_PROFILE_INTERVAL(init_mount_root, init);
  528. DEFINE_PROFILE_INTERVAL(init_from_checkpoint_file, init);
  529. DEFINE_PROFILE_INTERVAL(restore_from_file, init);
  530. DEFINE_PROFILE_INTERVAL(init_manifest, init);
  531. DEFINE_PROFILE_INTERVAL(init_ipc, init);
  532. DEFINE_PROFILE_INTERVAL(init_thread, init);
  533. DEFINE_PROFILE_INTERVAL(init_important_handles, init);
  534. DEFINE_PROFILE_INTERVAL(init_mount, init);
  535. DEFINE_PROFILE_INTERVAL(init_async, init);
  536. DEFINE_PROFILE_INTERVAL(init_stack, init);
  537. DEFINE_PROFILE_INTERVAL(read_environs, init);
  538. DEFINE_PROFILE_INTERVAL(init_loader, init);
  539. DEFINE_PROFILE_INTERVAL(init_ipc_helper, init);
  540. DEFINE_PROFILE_INTERVAL(init_signal, init);
  541. #define CALL_INIT(func, args ...) func(args)
  542. #define RUN_INIT(func, ...) \
  543. do { \
  544. int _err = CALL_INIT(func, ##__VA_ARGS__); \
  545. if (_err < 0) { \
  546. SYS_PRINTF("shim_init() in " #func " (%d)\n", _err); \
  547. shim_terminate(_err); \
  548. } \
  549. SAVE_PROFILE_INTERVAL(func); \
  550. } while (0)
  551. extern PAL_HANDLE thread_start_event;
  552. noreturn void* shim_init (int argc, void * args)
  553. {
  554. debug_handle = PAL_CB(debug_stream);
  555. cur_process.vmid = (IDTYPE) PAL_CB(process_id);
  556. /* create the initial TCB, shim can not be run without a tcb */
  557. __libc_tcb_t tcb;
  558. memset(&tcb, 0, sizeof(__libc_tcb_t));
  559. allocate_tls(&tcb, false, NULL);
  560. __disable_preempt(&tcb.shim_tcb); // Temporarily disable preemption for delaying any signal
  561. // that arrives during initialization
  562. debug_setbuf(&tcb.shim_tcb, true);
  563. debug("set tcb to %p\n", &tcb);
  564. #ifdef PROFILE
  565. unsigned long begin_time = GET_PROFILE_INTERVAL();
  566. #endif
  567. debug("host: %s\n", PAL_CB(host_type));
  568. DkSetExceptionHandler(&handle_failure, PAL_EVENT_FAILURE);
  569. allocsize = PAL_CB(alloc_align);
  570. allocshift = allocsize - 1;
  571. allocmask = ~allocshift;
  572. create_lock(&__master_lock);
  573. int * argcp = &argc;
  574. const char ** argv, ** envp, ** argp = NULL;
  575. elf_auxv_t * auxp;
  576. /* call to figure out where the arguments are */
  577. FIND_ARG_COMPONENTS(args, argc, argv, envp, auxp);
  578. #ifdef PROFILE
  579. set_profile_enabled(envp);
  580. #endif
  581. struct newproc_header hdr;
  582. void * cpaddr = NULL;
  583. #ifdef PROFILE
  584. unsigned long begin_create_time = 0;
  585. #endif
  586. BEGIN_PROFILE_INTERVAL();
  587. RUN_INIT(init_vma);
  588. RUN_INIT(init_slab);
  589. RUN_INIT(read_environs, envp);
  590. RUN_INIT(init_str_mgr);
  591. RUN_INIT(init_internal_map);
  592. RUN_INIT(init_fs);
  593. RUN_INIT(init_dcache);
  594. RUN_INIT(init_handle);
  595. debug("shim loaded at %p, ready to initialize\n", &__load_address);
  596. if (argc && argv[0][0] == '-') {
  597. if (strcmp_static(argv[0], "-resume") && argc >= 2) {
  598. const char * filename = *(argv + 1);
  599. argc -= 2;
  600. argv += 2;
  601. RUN_INIT(init_mount_root);
  602. RUN_INIT(init_from_checkpoint_file, filename, &hdr.checkpoint,
  603. &cpaddr);
  604. goto restore;
  605. }
  606. }
  607. if (PAL_CB(parent_process)) {
  608. RUN_INIT(init_newproc, &hdr);
  609. SAVE_PROFILE_INTERVAL_SET(child_created_in_new_process,
  610. hdr.create_time, begin_time);
  611. #ifdef PROFILE
  612. begin_create_time = hdr.begin_create_time;
  613. #endif
  614. if (hdr.checkpoint.hdr.size)
  615. RUN_INIT(do_migration, &hdr.checkpoint, &cpaddr);
  616. }
  617. if (cpaddr) {
  618. restore:
  619. thread_start_event = DkNotificationEventCreate(PAL_FALSE);
  620. RUN_INIT(restore_checkpoint,
  621. &hdr.checkpoint.hdr, &hdr.checkpoint.mem,
  622. (ptr_t) cpaddr, 0);
  623. }
  624. if (PAL_CB(manifest_handle))
  625. RUN_INIT(init_manifest, PAL_CB(manifest_handle));
  626. RUN_INIT(init_mount_root);
  627. RUN_INIT(init_ipc);
  628. RUN_INIT(init_thread);
  629. RUN_INIT(init_mount);
  630. RUN_INIT(init_important_handles);
  631. RUN_INIT(init_async);
  632. RUN_INIT(init_stack, argv, envp, &argcp, &argp, &auxp);
  633. RUN_INIT(init_loader);
  634. RUN_INIT(init_ipc_helper);
  635. RUN_INIT(init_signal);
  636. if (PAL_CB(parent_process)) {
  637. /* Notify the parent process */
  638. struct newproc_response res;
  639. res.child_vmid = cur_process.vmid;
  640. res.failure = 0;
  641. if (!DkStreamWrite(PAL_CB(parent_process), 0,
  642. sizeof(struct newproc_response),
  643. &res, NULL))
  644. shim_do_exit(-PAL_ERRNO);
  645. }
  646. debug("shim process initialized\n");
  647. #ifdef PROFILE
  648. if (begin_create_time)
  649. SAVE_PROFILE_INTERVAL_SINCE(child_total_migration_time,
  650. begin_create_time);
  651. #endif
  652. SAVE_PROFILE_INTERVAL_SET(pal_startup_time, 0, pal_control.startup_time);
  653. SAVE_PROFILE_INTERVAL_SET(pal_host_specific_startup_time, 0,
  654. pal_control.host_specific_startup_time);
  655. SAVE_PROFILE_INTERVAL_SET(pal_relocation_time, 0,
  656. pal_control.relocation_time);
  657. SAVE_PROFILE_INTERVAL_SET(pal_linking_time, 0, pal_control.linking_time);
  658. SAVE_PROFILE_INTERVAL_SET(pal_manifest_loading_time, 0,
  659. pal_control.manifest_loading_time);
  660. SAVE_PROFILE_INTERVAL_SET(pal_allocation_time, 0,
  661. pal_control.allocation_time);
  662. SAVE_PROFILE_INTERVAL_SET(pal_tail_startup_time, 0,
  663. pal_control.tail_startup_time);
  664. SAVE_PROFILE_INTERVAL_SET(pal_child_creation_time, 0,
  665. pal_control.child_creation_time);
  666. if (thread_start_event)
  667. DkEventSet(thread_start_event);
  668. shim_tcb_t * cur_tcb = shim_get_tls();
  669. struct shim_thread * cur_thread = (struct shim_thread *) cur_tcb->tp;
  670. if (cur_tcb->context.regs && cur_tcb->context.regs->rsp)
  671. restore_context(&cur_tcb->context);
  672. if (cur_thread->exec)
  673. execute_elf_object(cur_thread->exec, argcp, argp, auxp);
  674. shim_do_exit(0);
  675. }
  676. static int create_unique (int (*mkname) (char *, size_t, void *),
  677. int (*create) (const char *, void *),
  678. int (*output) (char *, size_t, const void *,
  679. struct shim_qstr *),
  680. char * name, size_t size, void * id, void * obj,
  681. struct shim_qstr * qstr)
  682. {
  683. int ret, len;
  684. while (1) {
  685. len = mkname(name, size, id);
  686. if (len < 0)
  687. return len;
  688. if ((ret = create(name, obj)) < 0)
  689. return ret;
  690. if (ret)
  691. continue;
  692. if (output)
  693. return output(name, size, id, qstr);
  694. if (qstr)
  695. qstrsetstr(qstr, name, len);
  696. return len;
  697. }
  698. }
  699. static int name_pipe (char * uri, size_t size, void * id)
  700. {
  701. IDTYPE pipeid;
  702. size_t len;
  703. int ret = DkRandomBitsRead(&pipeid, sizeof(pipeid));
  704. if (ret < 0)
  705. return -convert_pal_errno(-ret);
  706. debug("creating pipe: pipe.srv:%u\n", pipeid);
  707. if ((len = snprintf(uri, size, "pipe.srv:%u", pipeid)) == size)
  708. return -ERANGE;
  709. *((IDTYPE *) id) = pipeid;
  710. return len;
  711. }
  712. static int open_pipe (const char * uri, void * obj)
  713. {
  714. PAL_HANDLE pipe = DkStreamOpen(uri, 0, 0, 0, 0);
  715. if (!pipe)
  716. return PAL_NATIVE_ERRNO == PAL_ERROR_STREAMEXIST ? 1 :
  717. -PAL_ERRNO;
  718. if (obj)
  719. *((PAL_HANDLE *) obj) = pipe;
  720. else
  721. DkObjectClose(pipe);
  722. return 0;
  723. }
  724. static int pipe_addr (char * uri, size_t size, const void * id,
  725. struct shim_qstr * qstr)
  726. {
  727. IDTYPE pipeid = *((IDTYPE *) id);
  728. size_t len;
  729. if ((len = snprintf(uri, size, "pipe:%u", pipeid)) == size)
  730. return -ERANGE;
  731. if (qstr)
  732. qstrsetstr(qstr, uri, len);
  733. return len;
  734. }
  735. int create_pipe (IDTYPE * id, char * uri, size_t size, PAL_HANDLE * hdl,
  736. struct shim_qstr * qstr)
  737. {
  738. IDTYPE pipeid;
  739. int ret = create_unique(&name_pipe, &open_pipe, &pipe_addr,
  740. uri, size, &pipeid, hdl, qstr);
  741. if (ret > 0 && id)
  742. *id = pipeid;
  743. return ret;
  744. }
  745. static int name_path (char * path, size_t size, void * id)
  746. {
  747. unsigned int suffix;
  748. int prefix_len = strlen(path);
  749. size_t len;
  750. int ret = DkRandomBitsRead(&suffix, sizeof(suffix));
  751. if (ret < 0)
  752. return -convert_pal_errno(-ret);
  753. len = snprintf(path + prefix_len, size - prefix_len, "%08x", suffix);
  754. if (len == size)
  755. return -ERANGE;
  756. *((unsigned int *) id) = suffix;
  757. return prefix_len + len;
  758. }
  759. static int open_dir (const char * path, void * obj)
  760. {
  761. struct shim_handle * dir = NULL;
  762. if (obj) {
  763. dir = get_new_handle();
  764. if (!dir)
  765. return -ENOMEM;
  766. }
  767. int ret = open_namei(dir, NULL, path, O_CREAT|O_EXCL|O_DIRECTORY, 0700,
  768. NULL);
  769. if (ret < 0)
  770. return ret = -EEXIST ? 1 : ret;
  771. if (obj)
  772. *((struct shim_handle **) obj) = dir;
  773. return 0;
  774. }
  775. static int open_file (const char * path, void * obj)
  776. {
  777. struct shim_handle * file = NULL;
  778. if (obj) {
  779. file = get_new_handle();
  780. if (!file)
  781. return -ENOMEM;
  782. }
  783. int ret = open_namei(file, NULL, path, O_CREAT|O_EXCL|O_RDWR, 0600,
  784. NULL);
  785. if (ret < 0)
  786. return ret = -EEXIST ? 1 : ret;
  787. if (obj)
  788. *((struct shim_handle **) obj) = file;
  789. return 0;
  790. }
  791. static int open_pal_handle (const char * uri, void * obj)
  792. {
  793. PAL_HANDLE hdl;
  794. if (strpartcmp_static(uri, "dev:"))
  795. hdl = DkStreamOpen(uri, 0,
  796. PAL_SHARE_OWNER_X|PAL_SHARE_OWNER_W|
  797. PAL_SHARE_OWNER_R,
  798. PAL_CREATE_TRY|PAL_CREATE_ALWAYS,
  799. 0);
  800. else
  801. hdl = DkStreamOpen(uri, PAL_ACCESS_RDWR,
  802. PAL_SHARE_OWNER_W|PAL_SHARE_OWNER_R,
  803. PAL_CREATE_TRY|PAL_CREATE_ALWAYS,
  804. 0);
  805. if (!hdl) {
  806. if (PAL_NATIVE_ERRNO == PAL_ERROR_STREAMEXIST)
  807. return 0;
  808. else
  809. return -PAL_ERRNO;
  810. }
  811. if (obj) {
  812. *((PAL_HANDLE *) obj) = hdl;
  813. } else {
  814. DkObjectClose(hdl);
  815. }
  816. return 0;
  817. }
  818. static int output_path (char * path, size_t size, const void * id,
  819. struct shim_qstr * qstr)
  820. {
  821. size_t len = strlen(path);
  822. // API compatibility
  823. __UNUSED(size);
  824. __UNUSED(id);
  825. if (qstr)
  826. qstrsetstr(qstr, path, len);
  827. return len;
  828. }
  829. int create_dir (const char * prefix, char * path, size_t size,
  830. struct shim_handle ** hdl)
  831. {
  832. unsigned int suffix;
  833. if (prefix) {
  834. size_t len = strlen(prefix);
  835. if (len >= size)
  836. return -ERANGE;
  837. memcpy(path, prefix, len + 1);
  838. }
  839. return create_unique(&name_path, &open_dir, &output_path, path, size,
  840. &suffix, hdl, NULL);
  841. }
  842. int create_file (const char * prefix, char * path, size_t size,
  843. struct shim_handle ** hdl)
  844. {
  845. unsigned int suffix;
  846. if (prefix) {
  847. size_t len = strlen(prefix);
  848. if (len >= size)
  849. return -ERANGE;
  850. memcpy(path, prefix, len + 1);
  851. }
  852. return create_unique(&name_path, &open_file, &output_path, path, size,
  853. &suffix, hdl, NULL);
  854. }
  855. int create_handle (const char * prefix, char * uri, size_t size,
  856. PAL_HANDLE * hdl, unsigned int * id)
  857. {
  858. unsigned int suffix;
  859. if (prefix) {
  860. size_t len = strlen(prefix);
  861. if (len >= size)
  862. return -ERANGE;
  863. memcpy(uri, prefix, len + 1);
  864. }
  865. return create_unique(&name_path, &open_pal_handle, &output_path, uri, size,
  866. id ? : &suffix, hdl, NULL);
  867. }
  868. void check_stack_hook (void)
  869. {
  870. struct shim_thread * cur_thread = get_cur_thread();
  871. void * rsp;
  872. __asm__ volatile ("movq %%rsp, %0" : "=r"(rsp) :: "memory");
  873. if (rsp <= cur_thread->stack_top && rsp > cur_thread->stack) {
  874. if ((uintptr_t) rsp - (uintptr_t) cur_thread->stack < PAL_CB(pagesize))
  875. SYS_PRINTF("*** stack is almost drained (RSP = %p, stack = %p-%p) ***\n",
  876. rsp, cur_thread->stack, cur_thread->stack_top);
  877. } else {
  878. SYS_PRINTF("*** context dismatched with thread stack (RSP = %p, stack = %p-%p) ***\n",
  879. rsp, cur_thread->stack, cur_thread->stack_top);
  880. }
  881. }
  882. #ifdef PROFILE
  883. static void print_profile_result (PAL_HANDLE hdl, struct shim_profile * root,
  884. int level)
  885. {
  886. unsigned long total_interval_time = 0;
  887. unsigned long total_interval_count = 0;
  888. for (size_t i = 0 ; i < N_PROFILE ; i++) {
  889. struct shim_profile * profile = &PROFILES[i];
  890. if (profile->root != root || profile->disabled)
  891. continue;
  892. switch (profile->type) {
  893. case OCCURENCE: {
  894. unsigned int count =
  895. atomic_read(&profile->val.occurence.count);
  896. if (count) {
  897. for (int j = 0 ; j < level ; j++)
  898. __SYS_FPRINTF(hdl, " ");
  899. __SYS_FPRINTF(hdl, "- %s: %u times\n", profile->name, count);
  900. }
  901. break;
  902. }
  903. case INTERVAL: {
  904. unsigned int count =
  905. atomic_read(&profile->val.interval.count);
  906. if (count) {
  907. unsigned long time =
  908. atomic_read(&profile->val.interval.time);
  909. unsigned long ind_time = time / count;
  910. total_interval_time += time;
  911. total_interval_count += count;
  912. for (int j = 0 ; j < level ; j++)
  913. __SYS_FPRINTF(hdl, " ");
  914. __SYS_FPRINTF(hdl, "- (%11.11lu) %s: %u times, %lu msec\n",
  915. time, profile->name, count, ind_time);
  916. }
  917. break;
  918. }
  919. case CATEGORY:
  920. for (int j = 0 ; j < level ; j++)
  921. __SYS_FPRINTF(hdl, " ");
  922. __SYS_FPRINTF(hdl, "- %s:\n", profile->name);
  923. print_profile_result(hdl, profile, level + 1);
  924. break;
  925. }
  926. }
  927. if (total_interval_count) {
  928. __SYS_FPRINTF(hdl, " - (%11.11lu) total: %lu times, %lu msec\n",
  929. total_interval_time, total_interval_count,
  930. total_interval_time / total_interval_count);
  931. }
  932. }
  933. #endif /* PROFILE */
  934. static struct atomic_int in_terminate = { .counter = 0, };
  935. noreturn void shim_terminate (int err)
  936. {
  937. debug("teminating the whole process (%d)\n", err);
  938. /* do last clean-up of the process */
  939. shim_clean(err);
  940. DkProcessExit(err);
  941. }
  942. /* cleanup and terminate process, preserve exit code if err == 0 */
  943. int shim_clean (int err)
  944. {
  945. /* preventing multiple cleanup, this is mostly caused by
  946. assertion in shim_clean */
  947. if (atomic_inc_return(&in_terminate) > 1)
  948. return 0;
  949. if (err != 0)
  950. cur_process.exit_code = err;
  951. store_all_msg_persist();
  952. #ifdef PROFILE
  953. if (ENTER_TIME) {
  954. switch (shim_get_tls()->context.orig_rax) {
  955. case __NR_exit_group:
  956. SAVE_PROFILE_INTERVAL_SINCE(syscall_exit_group, ENTER_TIME);
  957. break;
  958. case __NR_exit:
  959. SAVE_PROFILE_INTERVAL_SINCE(syscall_exit, ENTER_TIME);
  960. break;
  961. }
  962. }
  963. if (ipc_cld_profile_send()) {
  964. MASTER_LOCK();
  965. PAL_HANDLE hdl = __open_shim_stdio();
  966. if (hdl) {
  967. __SYS_FPRINTF(hdl, "******************************\n");
  968. __SYS_FPRINTF(hdl, "profiling:\n");
  969. print_profile_result(hdl, &profile_root, 0);
  970. __SYS_FPRINTF(hdl, "******************************\n");
  971. }
  972. MASTER_UNLOCK();
  973. DkObjectClose(hdl);
  974. }
  975. #endif
  976. del_all_ipc_ports(0);
  977. if (shim_stdio && shim_stdio != (PAL_HANDLE) -1)
  978. DkObjectClose(shim_stdio);
  979. shim_stdio = NULL;
  980. debug("process %u exited with status %d\n", cur_process.vmid & 0xFFFF, cur_process.exit_code);
  981. MASTER_LOCK();
  982. DkProcessExit(cur_process.exit_code);
  983. return 0;
  984. }
  985. int message_confirm (const char * message, const char * options)
  986. {
  987. char answer;
  988. int noptions = strlen(options);
  989. char * option_str = __alloca(noptions * 2 + 3), * str = option_str;
  990. int ret = 0;
  991. *(str++) = ' ';
  992. *(str++) = '[';
  993. for (int i = 0 ; i < noptions ; i++) {
  994. *(str++) = options[i];
  995. *(str++) = '/';
  996. }
  997. str--;
  998. *(str++) = ']';
  999. *(str++) = ' ';
  1000. MASTER_LOCK();
  1001. PAL_HANDLE hdl = __open_shim_stdio();
  1002. if (!hdl) {
  1003. MASTER_UNLOCK();
  1004. return -EACCES;
  1005. }
  1006. #define WRITE(buf, len) \
  1007. ({ int _ret = DkStreamWrite(hdl, 0, len, (void*)(buf), NULL); \
  1008. _ret ? : -PAL_ERRNO; })
  1009. #define READ(buf, len) \
  1010. ({ int _ret = DkStreamRead(hdl, 0, len, buf, NULL, 0); \
  1011. _ret ? : -PAL_ERRNO; })
  1012. if ((ret = WRITE(message, strlen(message))) < 0)
  1013. goto out;
  1014. if ((ret = WRITE(option_str, noptions * 2 + 3)) < 0)
  1015. goto out;
  1016. if ((ret = READ(&answer, 1)) < 0)
  1017. goto out;
  1018. out:
  1019. DkObjectClose(hdl);
  1020. MASTER_UNLOCK();
  1021. return (ret < 0) ? ret : answer;
  1022. }