elf.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2011-2018 K. Lange
  5. *
  6. * ELF Static Executable Loader
  7. *
  8. */
  9. #include <kernel/system.h>
  10. #include <kernel/fs.h>
  11. #include <kernel/elf.h>
  12. #include <kernel/process.h>
  13. #include <kernel/logging.h>
  14. int exec_elf(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp) {
  15. Elf32_Header header;
  16. read_fs(file, 0, sizeof(Elf32_Header), (uint8_t *)&header);
  17. if (header.e_ident[0] != ELFMAG0 ||
  18. header.e_ident[1] != ELFMAG1 ||
  19. header.e_ident[2] != ELFMAG2 ||
  20. header.e_ident[3] != ELFMAG3) {
  21. debug_print(ERROR, "Not a valid ELF executable.");
  22. close_fs(file);
  23. return -1;
  24. }
  25. if (file->mask & 0x800) {
  26. debug_print(WARNING, "setuid binary executed [%s, uid:%d]", file->name, file->uid);
  27. current_process->user = file->uid;
  28. }
  29. for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) {
  30. Elf32_Phdr phdr;
  31. read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr);
  32. if (phdr.p_type == PT_DYNAMIC) {
  33. /* Dynamic */
  34. close_fs(file);
  35. /* Find interpreter? */
  36. debug_print(INFO, "Dynamic executable");
  37. unsigned int nargc = argc + 3;
  38. char * args[nargc+1];
  39. args[0] = "ld.so";
  40. args[1] = "-e";
  41. args[2] = strdup(current_process->name);
  42. int j = 3;
  43. for (int i = 0; i < argc; ++i, ++j) {
  44. args[j] = argv[i];
  45. }
  46. args[j] = NULL;
  47. fs_node_t * file = kopen("/lib/ld.so",0);
  48. if (!file) return -1;
  49. return exec_elf(NULL, file, nargc, args, env, 1);
  50. }
  51. }
  52. uintptr_t entry = (uintptr_t)header.e_entry;
  53. uintptr_t base_addr = 0xFFFFFFFF;
  54. uintptr_t end_addr = 0x0;
  55. for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) {
  56. Elf32_Phdr phdr;
  57. read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr);
  58. if (phdr.p_type == PT_LOAD) {
  59. if (phdr.p_vaddr < base_addr) {
  60. base_addr = phdr.p_vaddr;
  61. }
  62. if (phdr.p_memsz + phdr.p_vaddr > end_addr) {
  63. end_addr = phdr.p_memsz + phdr.p_vaddr;
  64. }
  65. }
  66. }
  67. current_process->image.entry = base_addr;
  68. current_process->image.size = end_addr - base_addr;
  69. release_directory_for_exec(current_directory);
  70. invalidate_page_tables();
  71. for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) {
  72. Elf32_Phdr phdr;
  73. read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr);
  74. if (phdr.p_type == PT_LOAD) {
  75. /* TODO: These virtual address bounds should be in a header somewhere */
  76. if (phdr.p_vaddr < 0x20000000) return -EINVAL;
  77. /* TODO Upper bounds */
  78. for (uintptr_t i = phdr.p_vaddr; i < phdr.p_vaddr + phdr.p_memsz; i += 0x1000) {
  79. /* This doesn't care if we already allocated this page */
  80. alloc_frame(get_page(i, 1, current_directory), 0, 1);
  81. invalidate_tables_at(i);
  82. }
  83. IRQ_RES;
  84. read_fs(file, phdr.p_offset, phdr.p_filesz, (uint8_t *)phdr.p_vaddr);
  85. IRQ_OFF;
  86. size_t r = phdr.p_filesz;
  87. while (r < phdr.p_memsz) {
  88. *(char *)(phdr.p_vaddr + r) = 0;
  89. r++;
  90. }
  91. }
  92. }
  93. close_fs(file);
  94. for (uintptr_t stack_pointer = USER_STACK_BOTTOM; stack_pointer < USER_STACK_TOP; stack_pointer += 0x1000) {
  95. alloc_frame(get_page(stack_pointer, 1, current_directory), 0, 1);
  96. invalidate_tables_at(stack_pointer);
  97. }
  98. /* Collect arguments */
  99. int envc = 0;
  100. for (envc = 0; env[envc] != NULL; ++envc);
  101. /* Format auxv */
  102. Elf32_auxv auxv[] = {
  103. {256, 0xDEADBEEF},
  104. {0, 0}
  105. };
  106. int auxvc = 0;
  107. for (auxvc = 0; auxv[auxvc].id != 0; ++auxvc);
  108. auxvc++;
  109. uintptr_t heap = current_process->image.entry + current_process->image.size;
  110. while (heap & 0xFFF) heap++;
  111. alloc_frame(get_page(heap, 1, current_directory), 0, 1);
  112. invalidate_tables_at(heap);
  113. char ** argv_ = (char **)heap;
  114. heap += sizeof(char *) * (argc + 1);
  115. char ** env_ = (char **)heap;
  116. heap += sizeof(char *) * (envc + 1);
  117. void * auxv_ptr = (void *)heap;
  118. heap += sizeof(Elf32_auxv) * (auxvc);
  119. for (int i = 0; i < argc; ++i) {
  120. size_t size = strlen(argv[i]) * sizeof(char) + 1;
  121. for (uintptr_t x = heap; x < heap + size + 0x1000; x += 0x1000) {
  122. alloc_frame(get_page(x, 1, current_directory), 0, 1);
  123. }
  124. invalidate_tables_at(heap);
  125. argv_[i] = (char *)heap;
  126. memcpy((void *)heap, argv[i], size);
  127. heap += size;
  128. }
  129. /* Don't forget the NULL at the end of that... */
  130. argv_[argc] = 0;
  131. for (int i = 0; i < envc; ++i) {
  132. size_t size = strlen(env[i]) * sizeof(char) + 1;
  133. for (uintptr_t x = heap; x < heap + size + 0x1000; x += 0x1000) {
  134. alloc_frame(get_page(x, 1, current_directory), 0, 1);
  135. }
  136. invalidate_tables_at(heap);
  137. env_[i] = (char *)heap;
  138. memcpy((void *)heap, env[i], size);
  139. heap += size;
  140. }
  141. env_[envc] = 0;
  142. memcpy(auxv_ptr, auxv, sizeof(Elf32_auxv) * (auxvc));
  143. current_process->image.heap = heap; /* heap end */
  144. current_process->image.heap_actual = heap + (0x1000 - heap % 0x1000);
  145. alloc_frame(get_page(current_process->image.heap_actual, 1, current_directory), 0, 1);
  146. invalidate_tables_at(current_process->image.heap_actual);
  147. current_process->image.user_stack = USER_STACK_TOP;
  148. current_process->image.start = entry;
  149. /* Close all fds >= 3 */
  150. for (unsigned int i = 3; i < current_process->fds->length; ++i) {
  151. if (current_process->fds->entries[i]) {
  152. close_fs(current_process->fds->entries[i]);
  153. current_process->fds->entries[i] = NULL;
  154. }
  155. }
  156. /* Go go go */
  157. enter_user_jmp(entry, argc, argv_, USER_STACK_TOP);
  158. /* We should never reach this code */
  159. return -1;
  160. }
  161. int exec_shebang(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp) {
  162. /* Read MAX_LINE... */
  163. char tmp[100];
  164. read_fs(file, 0, 100, (unsigned char *)tmp); close_fs(file);
  165. char * cmd = (char *)&tmp[2];
  166. if (*cmd == ' ') cmd++; /* Handle a leading space */
  167. char * space_or_linefeed = strpbrk(cmd, " \n");
  168. char * arg = NULL;
  169. if (!space_or_linefeed) {
  170. debug_print(WARNING, "No space or linefeed found.");
  171. return -ENOEXEC;
  172. }
  173. if (*space_or_linefeed == ' ') {
  174. /* Oh lovely, an argument */
  175. *space_or_linefeed = '\0';
  176. space_or_linefeed++;
  177. arg = space_or_linefeed;
  178. space_or_linefeed = strpbrk(space_or_linefeed, "\n");
  179. if (!space_or_linefeed) {
  180. debug_print(WARNING, "Argument exceeded maximum length");
  181. return -ENOEXEC;
  182. }
  183. }
  184. *space_or_linefeed = '\0';
  185. char script[strlen(path)+1];
  186. memcpy(script, path, strlen(path)+1);
  187. unsigned int nargc = argc + (arg ? 2 : 1);
  188. char * args[nargc + 2];
  189. args[0] = cmd;
  190. args[1] = arg ? arg : script;
  191. args[2] = arg ? script : NULL;
  192. args[3] = NULL;
  193. int j = arg ? 3 : 2;
  194. for (int i = 1; i < argc; ++i, ++j) {
  195. args[j] = argv[i];
  196. }
  197. args[j] = NULL;
  198. return exec(cmd, nargc, args, env);
  199. }
  200. /* Consider exposing this and making it a list so it can be extended ... */
  201. typedef int (*exec_func)(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp);
  202. typedef struct {
  203. exec_func func;
  204. unsigned char bytes[4];
  205. unsigned int match;
  206. char * name;
  207. } exec_def_t;
  208. exec_def_t fmts[] = {
  209. {exec_elf, {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3}, 4, "ELF"},
  210. {exec_shebang, {'#', '!', 0, 0}, 2, "#!"},
  211. };
  212. static int matches(unsigned char * a, unsigned char * b, unsigned int len) {
  213. for (unsigned int i = 0; i < len; ++i) {
  214. if (a[i] != b[i]) return 0;
  215. }
  216. return 1;
  217. }
  218. /**
  219. * Load an execute a binary.
  220. *
  221. * This determines the binary type (eg., ELF binary, she-bang script, etc.)
  222. * and then calls the appropriate underlying exec function.
  223. *
  224. * @param path Path to the executable to attempt to execute.
  225. * @param argc Number of arguments (because I'm not counting for you)
  226. * @param argv Pointer to a string of arguments
  227. */
  228. int exec(
  229. char * path, /* Path to the executable to run */
  230. int argc, /* Argument count (ie, /bin/echo hello world = 3) */
  231. char ** argv, /* Argument strings (including executable path) */
  232. char ** env /* Environmen variables */
  233. ) {
  234. /* Open the file */
  235. fs_node_t * file = kopen(path,0);
  236. if (!file) {
  237. /* Command not found */
  238. return -ENOENT;
  239. }
  240. if (!has_permission(file, 01)) {
  241. return -EACCES;
  242. }
  243. /* Read four bytes of the file */
  244. unsigned char head[4];
  245. read_fs(file, 0, 4, head);
  246. debug_print(INFO, "First four bytes: %c%c%c%c", head[0], head[1], head[2], head[3]);
  247. current_process->name = strdup(path);
  248. gettimeofday((struct timeval *)&current_process->start, NULL);
  249. for (unsigned int i = 0; i < sizeof(fmts) / sizeof(exec_def_t); ++i) {
  250. if (matches(fmts[i].bytes, head, fmts[i].match)) {
  251. debug_print(NOTICE, "Matched executor: %s", fmts[i].name);
  252. return fmts[i].func(path, file, argc, argv, env, 0);
  253. }
  254. }
  255. debug_print(WARNING, "Exec failed?");
  256. return -ENOEXEC;
  257. }
  258. int
  259. system(
  260. char * path, /* Path to the executable to run */
  261. int argc, /* Argument count (ie, /bin/echo hello world = 3) */
  262. char ** argv, /* Argument strings (including executable path) */
  263. char ** envin
  264. ) {
  265. char ** argv_ = malloc(sizeof(char *) * (argc + 1));
  266. for (int j = 0; j < argc; ++j) {
  267. argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char));
  268. memcpy(argv_[j], argv[j], strlen(argv[j]) + 1);
  269. }
  270. argv_[argc] = 0;
  271. char * env[] = {NULL};
  272. set_process_environment((process_t*)current_process, clone_directory(current_directory));
  273. current_directory = current_process->thread.page_directory;
  274. switch_page_directory(current_directory);
  275. current_process->cmdline = argv_;
  276. exec(path,argc,argv_,envin ? envin : env);
  277. debug_print(ERROR, "Failed to execute process!");
  278. kexit(-1);
  279. return -1;
  280. }