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 24static 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 62zx_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 66enum 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 80struct 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 86static 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 144zx_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