elf: do not use variable length arrays on the stack
[akaros.git] / kern / src / elf.c
1 #include <mm.h>
2 #include <string.h>
3 #include <kmalloc.h>
4 #include <syscall.h>
5 #include <elf.h>
6 #include <pmap.h>
7 #include <smp.h>
8 #include <arch/arch.h>
9 #include <umem.h>
10
11 #ifdef CONFIG_64BIT
12 # define elf_field(obj, field) (elf64 ? (obj##64)->field : (obj##32)->field)
13 #else
14 # define elf_field(obj, field) ((obj##32)->field)
15 #endif
16
17 /* Check if the file is valid elf file (i.e. by checking for ELF_MAGIC in the
18  * header) */
19 bool is_valid_elf(struct file_or_chan *foc)
20 {
21         elf64_t h;
22         uintptr_t c = switch_to_ktask();
23
24         if (foc_read(foc, (char*)&h, sizeof(elf64_t), 0) != sizeof(elf64_t))
25                 goto fail;
26         if (h.e_magic != ELF_MAGIC) {
27                 goto fail;
28         }
29 success:
30         switch_back_from_ktask(c);
31         return TRUE;
32 fail:
33         switch_back_from_ktask(c);
34         return FALSE;
35 }
36
37 /* Function to get the lengths of the argument and environment strings. */
38 static int get_lens(int argc, char *argv[], int *arg_lens)
39 {
40         int total = 0;
41
42         for (int i = 0; i < argc; i++) {
43                 arg_lens[i] = strlen(argv[i]) + 1;
44                 total += arg_lens[i];
45         }
46         return total;
47 }
48
49 /* Function to help map the argument and environment strings, to their
50  * final location. */
51 static int remap(struct proc *p, int argc, char *argv[], char *new_argv[],
52                  char new_argbuf[], int *arg_lens)
53 {
54         int offset = 0;
55         char *one_arg;
56         int i;
57
58         for (i = 0; i < argc; i++) {
59                 one_arg = new_argbuf + offset;
60                 if (memcpy_to_user(p, one_arg, argv[i], arg_lens[i]))
61                         return -1;
62                 if (memcpy_to_user(p, new_argv + i, &one_arg, sizeof(one_arg)))
63                         return -1;
64                 offset += arg_lens[i];
65         }
66         one_arg = NULL;
67         if (memcpy_to_user(p, new_argv + i, &one_arg, sizeof(one_arg)))
68                 return -1;
69         return offset;
70 }
71
72 static uintptr_t populate_stack(struct proc *p, int argc, char *argv[],
73                                                 int envc, char *envp[],
74                                                 int auxc, elf_aux_t auxv[])
75 {
76         uintptr_t ret = 0;
77         /* Map in pages for p's stack. */
78         int flags = MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE;
79         uintptr_t stacksz = USTACK_NUM_PAGES*PGSIZE;
80
81         if (do_mmap(p, USTACKTOP-stacksz, stacksz, PROT_READ | PROT_WRITE,
82                     flags, NULL, 0) == MAP_FAILED)
83                 return 0;
84
85         /* Start tracking the size of the buffer necessary to hold all of our
86          * data on the stack. Preallocate space for argc, argv, envp, and auxv
87          * in this buffer. */
88         int bufsize = 0;
89
90         bufsize += 1 * sizeof(size_t);
91         bufsize += (auxc + 1) * sizeof(elf_aux_t);
92         bufsize += (envc + 1) * sizeof(char**);
93         bufsize += (argc + 1) * sizeof(char**);
94
95         /* Add in the size of the env and arg strings. */
96         int *arg_lens = kzmalloc(sizeof(int) * argc, MEM_WAIT);
97         int *env_lens = kzmalloc(sizeof(int) * envc, MEM_WAIT);
98
99         bufsize += get_lens(argc, argv, arg_lens);
100         bufsize += get_lens(envc, envp, env_lens);
101
102         /* Adjust bufsize so that our buffer will ultimately be 16 byte aligned.
103          */
104         bufsize = ROUNDUP(bufsize, 16);
105
106         /* Set up pointers to all of the appropriate data regions we map to. */
107         size_t *new_argc = (size_t*)(USTACKTOP - bufsize);
108         char **new_argv = (char**)(new_argc + 1);
109         char **new_envp = new_argv + argc + 1;
110         elf_aux_t *new_auxv = (elf_aux_t*)(new_envp + envc + 1);
111         char *new_argbuf = (char*)(new_auxv + auxc + 1);
112
113         /* Verify that all data associated with our argv, envp, and auxv arrays
114          * (and any corresponding strings they point to) will fit in the space
115          * alloted. */
116         if (bufsize > ARG_MAX)
117                 goto out_lens;
118
119         /* Map argc into its final location. */
120         if (memcpy_to_user(p, new_argc, &argc, sizeof(size_t)))
121                 goto out_lens;
122
123         /* Map all data for argv and envp into its final location. */
124         int offset = 0;
125
126         offset = remap(p, argc, argv, new_argv, new_argbuf, arg_lens);
127         if (offset == -1)
128                 goto out_lens;
129         offset = remap(p, envc, envp, new_envp, new_argbuf + offset, env_lens);
130         if (offset == -1)
131                 goto out_lens;
132
133         /* Map auxv into its final location. */
134         elf_aux_t null_aux = {0, 0};
135         if (memcpy_to_user(p, new_auxv, auxv, auxc * sizeof(elf_aux_t)))
136                 goto out_lens;
137         if (memcpy_to_user(p, new_auxv + auxc, &null_aux, sizeof(elf_aux_t)))
138                 goto out_lens;
139
140         ret = USTACKTOP - bufsize;
141 out_lens:
142         kfree(arg_lens);
143         kfree(env_lens);
144         return ret;
145 }
146
147 /* We need the writable flag for ld.  Even though the elf header says it wants
148  * RX (and not W) for its main program header, it will page fault (eip 56f0,
149  * 46f0 after being relocated to 0x1000, va 0x20f4). */
150 static int load_one_elf(struct proc *p, struct file_or_chan *foc,
151                         uintptr_t pg_num, elf_info_t *ei, bool writable)
152 {
153         int ret = -1;
154         ei->phdr = -1;
155         ei->dynamic = 0;
156         ei->highest_addr = 0;
157         off64_t f_off = 0;
158         void* phdrs = 0;
159         int mm_perms, mm_flags;
160
161         /* When reading on behalf of the kernel, we need to switch to a ktask so
162          * the VFS (and maybe other places) know. (TODO: KFOP) */
163         uintptr_t old_ret = switch_to_ktask();
164
165         /* Read in ELF header. */
166         elf64_t elfhdr_storage;
167         elf32_t* elfhdr32 = (elf32_t*)&elfhdr_storage;
168         elf64_t* elfhdr64 = &elfhdr_storage;
169         if (foc_read(foc, (char*)elfhdr64, sizeof(elf64_t), f_off)
170                 != sizeof(elf64_t)) {
171                 /* if you ever debug this, be sure to 0 out elfhrd_storage in
172                  * advance */
173                 printk("[kernel] load_one_elf: failed to read file\n");
174                 goto fail;
175         }
176         if (elfhdr64->e_magic != ELF_MAGIC) {
177                 printk("[kernel] load_one_elf: file is not an elf!\n");
178                 goto fail;
179         }
180         bool elf32 = elfhdr32->e_ident[ELF_IDENT_CLASS] == ELFCLASS32;
181         bool elf64 = elfhdr64->e_ident[ELF_IDENT_CLASS] == ELFCLASS64;
182         if (elf64 == elf32) {
183                 printk("[kernel] load_one_elf: ID as both 32 and 64 bit\n");
184                 goto fail;
185         }
186         #ifndef CONFIG_64BIT
187         if (elf64) {
188                 printk("[kernel] load_one_elf: 64 bit elf on 32 bit kernel\n");
189                 goto fail;
190         }
191         #endif
192         /* Not sure what RISCV's 64 bit kernel can do here, so this check is x86
193          * only */
194         #ifdef CONFIG_X86
195         if (elf32) {
196                 printk("[kernel] load_one_elf: 32 bit elf on 64 bit kernel\n");
197                 goto fail;
198         }
199         #endif
200
201         size_t phsz = elf64 ? sizeof(proghdr64_t) : sizeof(proghdr32_t);
202         uint16_t e_phnum = elf_field(elfhdr, e_phnum);
203         uint16_t e_phoff = elf_field(elfhdr, e_phoff);
204
205         /* Read in program headers. */
206         if (e_phnum > 10000 || e_phoff % (elf32 ? 4 : 8) != 0) {
207                 printk("[kernel] load_one_elf: Bad program headers\n");
208                 goto fail;
209         }
210         phdrs = kmalloc(e_phnum * phsz, 0);
211         f_off = e_phoff;
212         if (!phdrs || foc_read(foc, phdrs, e_phnum * phsz, f_off) !=
213                       e_phnum * phsz) {
214                 printk("[kernel] load_one_elf: couldn't get program headers\n");
215                 goto fail;
216         }
217         for (int i = 0; i < e_phnum; i++) {
218                 proghdr32_t* ph32 = (proghdr32_t*)phdrs + i;
219                 proghdr64_t* ph64 = (proghdr64_t*)phdrs + i;
220                 uint16_t p_type = elf_field(ph, p_type);
221                 uintptr_t p_va = elf_field(ph, p_va);
222                 uintptr_t p_offset = elf_field(ph, p_offset);
223                 uintptr_t p_align = elf_field(ph, p_align);
224                 uintptr_t p_memsz = elf_field(ph, p_memsz);
225                 uintptr_t p_filesz = elf_field(ph, p_filesz);
226                 uintptr_t p_flags = elf_field(ph, p_flags);
227
228                 /* Here's the ld hack, mentioned above */
229                 p_flags |= (writable ? ELF_PROT_WRITE : 0);
230                 /* All mmaps need to be fixed to their VAs.  If the program
231                  * wants it to be a writable region, we also need the region to
232                  * be private. */
233                 mm_flags = MAP_FIXED | (p_flags & ELF_PROT_WRITE ? MAP_PRIVATE :
234                                         MAP_SHARED);
235
236                 if (p_type == ELF_PROG_PHDR)
237                         ei->phdr = p_va;
238                 else if (p_type == ELF_PROG_INTERP) {
239                         f_off = p_offset;
240                         ssize_t maxlen = sizeof(ei->interp);
241                         ssize_t bytes = foc_read(foc, ei->interp, maxlen,
242                                                  f_off);
243                         /* trying to catch errors.  don't know how big it could
244                          * be, but it should be at least 0. */
245                         if (bytes <= 0) {
246                                 printk("[kernel] load_one_elf: could not read ei->interp\n");
247                                 goto fail;
248                         }
249
250                         maxlen = MIN(maxlen, bytes);
251                         if (strnlen(ei->interp, maxlen) == maxlen) {
252                                 printk("[kernel] load_one_elf: interpreter name too long\n");
253                                 goto fail;
254                         }
255
256                         ei->dynamic = 1;
257                 }
258                 else if (p_type == ELF_PROG_LOAD && p_memsz) {
259                         if (p_align % PGSIZE) {
260                                 printk("[kernel] load_one_elf: not page aligned\n");
261                                 goto fail;
262                         }
263                         if (p_offset % PGSIZE != p_va % PGSIZE) {
264                                 printk("[kernel] load_one_elf: offset difference \n");
265                                 goto fail;
266                         }
267
268                         uintptr_t filestart = ROUNDDOWN(p_offset, PGSIZE);
269                         uintptr_t filesz = p_offset + p_filesz - filestart;
270
271                         uintptr_t memstart = ROUNDDOWN(p_va, PGSIZE);
272                         uintptr_t memsz = ROUNDUP(p_va + p_memsz, PGSIZE) -
273                                 memstart;
274                         memstart += pg_num * PGSIZE;
275
276                         if (memstart + memsz > ei->highest_addr)
277                                 ei->highest_addr = memstart + memsz;
278
279                         mm_perms = 0;
280                         mm_perms |= (p_flags & ELF_PROT_READ  ? PROT_READ : 0);
281                         mm_perms |= (p_flags & ELF_PROT_WRITE ? PROT_WRITE : 0);
282                         mm_perms |= (p_flags & ELF_PROT_EXEC  ? PROT_EXEC : 0);
283
284                         if (filesz) {
285                                 /* Due to elf-ghetto-ness, we need to zero the
286                                  * first part of the BSS from the last page of
287                                  * the data segment.  If we end on a partial
288                                  * page, we map it in separately with
289                                  * MAP_POPULATE so that we can zero the rest of
290                                  * it now. We translate to the KVA so we don't
291                                  * need to worry about using the proc's mapping
292                                  * */
293                                 uintptr_t partial = PGOFF(filesz);
294
295                                 if (filesz - partial) {
296                                         /* Map the complete pages. */
297                                         if (do_mmap(p, memstart, filesz -
298                                                     partial, mm_perms, mm_flags,
299                                                     foc, filestart) ==
300                                             MAP_FAILED) {
301                                                 printk("[kernel] load_one_elf: complete mmap failed\n");
302                                                 goto fail;
303                                         }
304                                 }
305                                 /* Note that we (probably) only need to do this
306                                  * zeroing the end of a partial file page when
307                                  * we are dealing with ELF_PROT_WRITE-able PHs,
308                                  * and not for all cases.  */
309                                 if (partial) {
310                                         /* Need our own populated, private copy
311                                          * of the page so that we can zero the
312                                          * remainder - and not zero chunks of
313                                          * the real file in the page cache. */
314                                         mm_flags &= ~MAP_SHARED;
315                                         mm_flags |= MAP_PRIVATE | MAP_POPULATE;
316
317                                         /* Map the final partial page. */
318                                         uintptr_t last_page = memstart + filesz
319                                                 - partial;
320                                         if (do_mmap(p, last_page, PGSIZE,
321                                                     mm_perms, mm_flags, foc,
322                                                     filestart + filesz -
323                                                     partial) == MAP_FAILED) {
324                                                 printk("[kernel] load_one_elf: partial mmap failed\n");
325                                                 goto fail;
326                                         }
327
328                                         pte_t pte = pgdir_walk(p->env_pgdir,
329                                                                (void*)last_page,
330                                                                0);
331                                         /* if we were able to get a PTE, then
332                                          * there is a real page backing the VMR,
333                                          * and we need to zero the excess.  if
334                                          * there isn't, then the page fault code
335                                          * should handle it.  since we set
336                                          * populate above, we should have a PTE,
337                                          * except in cases where the offset +
338                                          * len window exceeded the file size.
339                                          * in this case, we let them mmap it,
340                                          * but didn't populate it.  there will
341                                          * be a PF right away if someone tries
342                                          * to use this.  check out do_mmap for
343                                          * more info. */
344                                         if (pte_walk_okay(pte)) {
345                                                 void *last_page_kva =
346                                                     KADDR(pte_get_paddr(pte));
347                                                 memset(last_page_kva + partial,
348                                                        0, PGSIZE - partial);
349                                         }
350
351                                         filesz = ROUNDUP(filesz, PGSIZE);
352                                 }
353                         }
354                         /* Any extra pages are mapped anonymously... (a bit
355                          * weird) */
356                         if (filesz < memsz)
357                                 if (do_mmap(p, memstart + filesz, memsz-filesz,
358                                             PROT_READ | PROT_WRITE, MAP_PRIVATE,
359                                                 NULL, 0) == MAP_FAILED) {
360                                         printk("[kernel] load_one_elf: anon mmap failed\n");
361                                         goto fail;
362                                 }
363                 }
364         }
365         /* map in program headers anyway if not present in binary.
366          * useful for TLS in static programs. */
367         if (ei->phdr == -1) {
368                 uintptr_t filestart = ROUNDDOWN(e_phoff, PGSIZE);
369                 uintptr_t filesz = e_phoff + (e_phnum * phsz) - filestart;
370                 void *phdr_addr = do_mmap(p, 0, filesz, PROT_READ | PROT_WRITE,
371                                           MAP_PRIVATE, foc, filestart);
372                 if (phdr_addr == MAP_FAILED) {
373                         printk("[kernel] load_one_elf: prog header mmap failed\n");
374                         goto fail;
375                 }
376                 ei->phdr = (long)phdr_addr + e_phoff;
377         }
378         ei->entry = elf_field(elfhdr, e_entry) + pg_num * PGSIZE;
379         ei->phnum = e_phnum;
380         ei->elf64 = elf64;
381         ret = 0;
382         /* Fall-through */
383 fail:
384         if (phdrs)
385                 kfree(phdrs);
386         switch_back_from_ktask(old_ret);
387         return ret;
388 }
389
390 int load_elf(struct proc *p, struct file_or_chan *foc,
391              int argc, char *argv[], int envc, char *envp[])
392 {
393         elf_info_t ei, interp_ei;
394         if (load_one_elf(p, foc, 0, &ei, FALSE))
395                 return -1;
396
397         if (ei.dynamic) {
398                 struct file_or_chan *interp = foc_open(ei.interp, O_EXEC |
399                                                        O_READ, 0);
400
401                 if (!interp)
402                         return -1;
403                 /* Load dynamic linker at 1M. Obvious MIB joke avoided.
404                  * It used to be loaded at page 1, but the existence of valid
405                  * addresses that low masked bad derefs through NULL pointer
406                  * structs. This in turn helped us waste a full day debugging a
407                  * bug in the Go runtime. True!  Note that MMAP_LOWEST_VA also
408                  * has this value but we want to make this explicit. */
409                 int error = load_one_elf(p, interp, MMAP_LD_FIXED_VA >> PGSHIFT,
410                                          &interp_ei, TRUE);
411                 foc_decref(interp);
412                 if (error)
413                         return -1;
414         }
415
416         /* Set up the auxiliary info for dynamic linker/runtime */
417         elf_aux_t auxv[] = {{ELF_AUX_PHDR, ei.phdr},
418                             {ELF_AUX_PHENT, sizeof(proghdr32_t)},
419                             {ELF_AUX_PHNUM, ei.phnum},
420                             {ELF_AUX_ENTRY, ei.entry}};
421         int auxc = sizeof(auxv)/sizeof(auxv[0]);
422
423         /* Populate the stack with the required info. */
424         uintptr_t stack_top = populate_stack(p, argc, argv, envc, envp, auxc,
425                                              auxv);
426         if (!stack_top)
427                 return -1;
428
429         /* Initialize the process as an SCP. */
430         uintptr_t core0_entry = ei.dynamic ? interp_ei.entry : ei.entry;
431         proc_init_ctx(&p->scp_ctx, 0, core0_entry, stack_top, 0);
432
433         p->procinfo->program_end = ei.highest_addr;
434         p->args_base = (void *) stack_top;
435
436         return 0;
437 }
438
439 ssize_t get_startup_argc(struct proc *p)
440 {
441         const char *sptr = (const char *) p->args_base;
442         ssize_t argc = 0;
443
444         /* TODO,DL: Use copy_from_user() when available.
445          */
446         if (memcpy_from_user(p, &argc, sptr, sizeof(size_t)))
447                 return -1;
448
449         return argc;
450 }
451
452 char *get_startup_argv(struct proc *p, size_t idx, char *argp,
453                                            size_t max_size)
454 {
455         size_t stack_space = (const char *) USTACKTOP - (const char *)
456                 p->args_base;
457         const char *sptr = (const char *) p->args_base + sizeof(size_t) +
458                 idx * sizeof(char *);
459         const char *argv = NULL;
460
461         /* TODO,DL: Use copy_from_user() when available.
462          */
463         if (memcpy_from_user(p, &argv, sptr, sizeof(char *)))
464                 return NULL;
465
466         /* TODO,DL: Use strncpy_from_user() when available.
467          */
468         max_size = MIN(max_size, stack_space);
469         if (memcpy_from_user(p, argp, argv, max_size))
470                 return NULL;
471         argp[max_size - 1] = 0;
472
473         return argp;
474 }