1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "userboot-elf.h"
6 
7 #include "bootfs.h"
8 #include "util.h"
9 
10 #pragma GCC visibility push(hidden)
11 
12 #include <elf.h>
13 #include <elfload/elfload.h>
14 #include <zircon/compiler.h>
15 #include <zircon/processargs.h>
16 #include <zircon/syscalls.h>
17 #include <stdbool.h>
18 #include <string.h>
19 
20 #pragma GCC visibility pop
21 
22 #define INTERP_PREFIX "lib/"
23 
load(zx_handle_t log,const char * what,zx_handle_t vmar,zx_handle_t vmo,uintptr_t * interp_off,size_t * interp_len,zx_handle_t * segments_vmar,size_t * stack_size,bool close_vmo,bool return_entry)24 static zx_vaddr_t load(zx_handle_t log, const char* what,
25                        zx_handle_t vmar, zx_handle_t vmo,
26                        uintptr_t* interp_off, size_t* interp_len,
27                        zx_handle_t* segments_vmar, size_t* stack_size,
28                        bool close_vmo, bool return_entry) {
29     elf_load_header_t header;
30     uintptr_t phoff;
31     zx_status_t status = elf_load_prepare(vmo, NULL, 0, &header, &phoff);
32     check(log, status, "elf_load_prepare failed");
33 
34     elf_phdr_t phdrs[header.e_phnum];
35     status = elf_load_read_phdrs(vmo, phdrs, phoff, header.e_phnum);
36     check(log, status, "elf_load_read_phdrs failed");
37 
38     if (interp_off != NULL &&
39         elf_load_find_interp(phdrs, header.e_phnum, interp_off, interp_len))
40         return 0;
41 
42     if (stack_size != NULL) {
43         for (size_t i = 0; i < header.e_phnum; ++i) {
44             if (phdrs[i].p_type == PT_GNU_STACK && phdrs[i].p_memsz > 0)
45                 *stack_size = phdrs[i].p_memsz;
46         }
47     }
48 
49     zx_vaddr_t base, entry;
50     status = elf_load_map_segments(vmar, &header, phdrs, vmo,
51                                    segments_vmar, &base, &entry);
52     check(log, status, "elf_load_map_segments failed");
53 
54     if (close_vmo)
55         zx_handle_close(vmo);
56 
57     printl(log, "userboot: loaded %s at %p, entry point %p\n",
58            what, (void*)base, (void*)entry);
59     return return_entry ? entry : base;
60 }
61 
elf_load_vmo(zx_handle_t log,zx_handle_t vmar,zx_handle_t vmo)62 zx_vaddr_t elf_load_vmo(zx_handle_t log, zx_handle_t vmar, zx_handle_t vmo) {
63     return load(log, "vDSO", vmar, vmo, NULL, NULL, NULL, NULL, false, false);
64 }
65 
66 enum loader_bootstrap_handle_index {
67     BOOTSTRAP_EXEC_VMO,
68     BOOTSTRAP_LOGGER,
69     BOOTSTRAP_PROC,
70     BOOTSTRAP_ROOT_VMAR,
71     BOOTSTRAP_SEGMENTS_VMAR,
72     BOOTSTRAP_THREAD,
73     BOOTSTRAP_LOADER_SVC,
74     BOOTSTRAP_HANDLES
75 };
76 
77 #define LOADER_BOOTSTRAP_ENVIRON "LD_DEBUG=1"
78 #define LOADER_BOOTSTRAP_ENVIRON_NUM 1
79 
80 struct loader_bootstrap_message {
81     zx_proc_args_t header;
82     uint32_t handle_info[BOOTSTRAP_HANDLES];
83     char env[sizeof(LOADER_BOOTSTRAP_ENVIRON)];
84 };
85 
stuff_loader_bootstrap(zx_handle_t log,zx_handle_t proc,zx_handle_t root_vmar,zx_handle_t thread,zx_handle_t to_child,zx_handle_t segments_vmar,zx_handle_t vmo,zx_handle_t * loader_svc)86 static void stuff_loader_bootstrap(zx_handle_t log,
87                                    zx_handle_t proc, zx_handle_t root_vmar,
88                                    zx_handle_t thread,
89                                    zx_handle_t to_child,
90                                    zx_handle_t segments_vmar,
91                                    zx_handle_t vmo,
92                                    zx_handle_t* loader_svc) {
93     struct loader_bootstrap_message msg = {
94         .header = {
95             .protocol = ZX_PROCARGS_PROTOCOL,
96             .version = ZX_PROCARGS_VERSION,
97             .handle_info_off = offsetof(struct loader_bootstrap_message,
98                                         handle_info),
99             .environ_num = LOADER_BOOTSTRAP_ENVIRON_NUM,
100             .environ_off = offsetof(struct loader_bootstrap_message, env),
101         },
102         .handle_info = {
103             [BOOTSTRAP_EXEC_VMO] = PA_HND(PA_VMO_EXECUTABLE, 0),
104             [BOOTSTRAP_LOGGER] = PA_HND(PA_FDIO_LOGGER, 0),
105             [BOOTSTRAP_PROC] = PA_HND(PA_PROC_SELF, 0),
106             [BOOTSTRAP_ROOT_VMAR] = PA_HND(PA_VMAR_ROOT, 0),
107             [BOOTSTRAP_SEGMENTS_VMAR] = PA_HND(PA_VMAR_LOADED, 0),
108             [BOOTSTRAP_THREAD] = PA_HND(PA_THREAD_SELF, 0),
109             [BOOTSTRAP_LOADER_SVC] = PA_HND(PA_LDSVC_LOADER, 0),
110         },
111         .env = LOADER_BOOTSTRAP_ENVIRON,
112     };
113     zx_handle_t handles[] = {
114         [BOOTSTRAP_EXEC_VMO] = vmo,
115         [BOOTSTRAP_LOGGER] = ZX_HANDLE_INVALID,
116         [BOOTSTRAP_PROC] = ZX_HANDLE_INVALID,
117         [BOOTSTRAP_ROOT_VMAR] = ZX_HANDLE_INVALID,
118         [BOOTSTRAP_SEGMENTS_VMAR] = segments_vmar,
119         [BOOTSTRAP_THREAD] = ZX_HANDLE_INVALID,
120         [BOOTSTRAP_LOADER_SVC] = ZX_HANDLE_INVALID,
121     };
122     check(log, zx_handle_duplicate(log, ZX_RIGHT_SAME_RIGHTS,
123                                    &handles[BOOTSTRAP_LOGGER]),
124           "zx_handle_duplicate failed");
125     check(log, zx_handle_duplicate(proc, ZX_RIGHT_SAME_RIGHTS,
126                                    &handles[BOOTSTRAP_PROC]),
127           "zx_handle_duplicate failed");
128     check(log, zx_handle_duplicate(root_vmar, ZX_RIGHT_SAME_RIGHTS,
129                                    &handles[BOOTSTRAP_ROOT_VMAR]),
130           "zx_handle_duplicate failed");
131     check(log, zx_handle_duplicate(thread, ZX_RIGHT_SAME_RIGHTS,
132                                    &handles[BOOTSTRAP_THREAD]),
133           "zx_handle_duplicate failed");
134     check(log, zx_channel_create(0, loader_svc,
135                                  &handles[BOOTSTRAP_LOADER_SVC]),
136           "zx_channel_create failed");
137 
138     zx_status_t status = zx_channel_write(
139         to_child, 0, &msg, sizeof(msg), handles, countof(handles));
140     check(log, status,
141           "zx_channel_write of loader bootstrap message failed");
142 }
143 
elf_load_bootfs(zx_handle_t log,struct bootfs * fs,zx_handle_t proc,zx_handle_t vmar,zx_handle_t thread,const char * filename,zx_handle_t to_child,size_t * stack_size,zx_handle_t * loader_svc)144 zx_vaddr_t elf_load_bootfs(zx_handle_t log, struct bootfs *fs, zx_handle_t proc,
145                            zx_handle_t vmar, zx_handle_t thread,
146                            const char* filename, zx_handle_t to_child,
147                            size_t* stack_size, zx_handle_t* loader_svc) {
148     zx_handle_t vmo = bootfs_open(log, "program", fs, filename);
149 
150     uintptr_t interp_off = 0;
151     size_t interp_len = 0;
152     zx_vaddr_t entry = load(log, filename,
153                             vmar, vmo, &interp_off, &interp_len,
154                             NULL, stack_size, true, true);
155     if (interp_len > 0) {
156         char interp[sizeof(INTERP_PREFIX) + interp_len];
157         memcpy(interp, INTERP_PREFIX, sizeof(INTERP_PREFIX) - 1);
158         zx_status_t status = zx_vmo_read(
159             vmo, &interp[sizeof(INTERP_PREFIX) - 1],
160             interp_off, interp_len);
161         if (status < 0)
162             fail(log, "zx_vmo_read failed: %d", status);
163         interp[sizeof(INTERP_PREFIX) - 1 + interp_len] = '\0';
164 
165         printl(log, "'%s' has PT_INTERP \"%s\"", filename, interp);
166 
167         zx_handle_t interp_vmo =
168             bootfs_open(log, "dynamic linker", fs, interp);
169         zx_handle_t interp_vmar;
170         entry = load(log, interp, vmar, interp_vmo,
171                      NULL, NULL, &interp_vmar, NULL, true, true);
172 
173         stuff_loader_bootstrap(log, proc, vmar, thread, to_child,
174                                interp_vmar, vmo, loader_svc);
175     }
176     return entry;
177 }
178