1// Copyright 2017 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 "bootfs.h" 6#include "util.h" 7 8#pragma GCC visibility push(hidden) 9 10#include <ldmsg/ldmsg.h> 11#include <string.h> 12#include <zircon/processargs.h> 13#include <zircon/syscalls.h> 14 15#pragma GCC visibility pop 16 17#define LOAD_OBJECT_FILE_PREFIX "lib/" 18 19struct loader_state { 20 zx_handle_t log; 21 struct bootfs* bootfs; 22 char prefix[32]; 23 size_t prefix_len; 24 bool exclusive; 25}; 26 27static void loader_config(struct loader_state* state, const char* string, size_t len) { 28 state->exclusive = false; 29 if (string[len - 1] == '!') { 30 --len; 31 state->exclusive = true; 32 } 33 if (len >= sizeof(state->prefix) - 1) { 34 fail(state->log, "loader-service config string too long"); 35 } 36 memcpy(state->prefix, string, len); 37 state->prefix[len++] = '/'; 38 state->prefix_len = len; 39} 40 41static zx_handle_t try_load_object(struct loader_state* state, 42 const char* name, size_t len, 43 size_t prefix_len) { 44 char file[len + sizeof(LOAD_OBJECT_FILE_PREFIX) + prefix_len + 1]; 45 memcpy(file, LOAD_OBJECT_FILE_PREFIX, sizeof(LOAD_OBJECT_FILE_PREFIX) - 1); 46 memcpy(&file[sizeof(LOAD_OBJECT_FILE_PREFIX) - 1], 47 state->prefix, prefix_len); 48 memcpy(&file[sizeof(LOAD_OBJECT_FILE_PREFIX) - 1 + prefix_len], name, len); 49 file[sizeof(LOAD_OBJECT_FILE_PREFIX) - 1 + prefix_len + len] = '\0'; 50 return bootfs_open(state->log, "shared library", state->bootfs, file); 51} 52 53static zx_handle_t load_object(struct loader_state* state, const char* name, size_t len) { 54 zx_handle_t vmo = try_load_object(state, name, len, state->prefix_len); 55 if (vmo == ZX_HANDLE_INVALID && state->prefix_len > 0 && !state->exclusive) 56 vmo = try_load_object(state, name, len, 0); 57 if (vmo == ZX_HANDLE_INVALID) 58 fail(state->log, "cannot find shared library '%s'", name); 59 return vmo; 60} 61 62static bool handle_loader_rpc(struct loader_state* state, 63 zx_handle_t channel) { 64 ldmsg_req_t req; 65 zx_handle_t reqhandle; 66 67 uint32_t size; 68 uint32_t hcount; 69 zx_status_t status = zx_channel_read( 70 channel, 0, &req, &reqhandle, sizeof(req), 1, &size, &hcount); 71 72 // This is the normal error for the other end going away, 73 // which happens when the process dies. 74 if (status == ZX_ERR_PEER_CLOSED) { 75 printl(state->log, "loader-service channel peer closed on read"); 76 return false; 77 } 78 79 check(state->log, status, 80 "zx_channel_read on loader-service channel failed"); 81 82 const char* string; 83 size_t string_len; 84 status = ldmsg_req_decode(&req, size, &string, &string_len); 85 if (status != ZX_OK) { 86 fail(state->log, "loader-service request invalid"); 87 } 88 89 ldmsg_rsp_t rsp; 90 memset(&rsp, 0, sizeof(rsp)); 91 92 zx_handle_t handle = ZX_HANDLE_INVALID; 93 switch (req.header.ordinal) { 94 case LDMSG_OP_DONE: 95 printl(state->log, "loader-service received DONE request"); 96 goto no_reply; 97 98 case LDMSG_OP_CONFIG: 99 loader_config(state, string, string_len); 100 break; 101 102 case LDMSG_OP_LOAD_OBJECT: 103 handle = load_object(state, string, string_len); 104 break; 105 106 case LDMSG_OP_CLONE: 107 rsp.rv = ZX_ERR_NOT_SUPPORTED; 108 goto error_reply; 109 110 case LDMSG_OP_LOAD_SCRIPT_INTERPRETER: 111 fail(state->log, "loader-service received LOAD_SCRIPT_INTERP request"); 112 break; 113 114 case LDMSG_OP_DEBUG_PUBLISH_DATA_SINK: { 115 if (hcount != 1) { 116 fail(state->log, "loader-service received DEBUG_PUBLISH_DATA_SINK request without VMO"); 117 } 118 119 char name[ZX_MAX_NAME_LEN]; 120 status = zx_object_get_property(reqhandle, ZX_PROP_NAME, name, sizeof(name)); 121 if (status != ZX_OK) { 122 fail(state->log, "zx_object_get_property failed"); 123 } 124 125 uint64_t size; 126 status = zx_vmo_get_size(reqhandle, &size); 127 if (status != ZX_OK) { 128 fail(state->log, "zx_vmo_get_size failed"); 129 } 130 131 printl(state->log, "loader-service data-sink \"%s\" DATA DROPPED: \"%s\", " 132 "%zu bytes", string, name, (size_t)size); 133 break; 134 } 135 136 default: 137 fail(state->log, "loader-service received invalid opcode"); 138 break; 139 } 140 141 rsp.rv = ZX_OK; 142 rsp.object = handle == ZX_HANDLE_INVALID ? 143 FIDL_HANDLE_ABSENT : FIDL_HANDLE_PRESENT; 144error_reply: 145 rsp.header.txid = req.header.txid; 146 rsp.header.ordinal = req.header.ordinal; 147 148 // no opcodes which receive a handle are supported, but 149 // we need to receive (and discard) the handle to politely 150 // NAK clone requests 151 if (hcount == 1) { 152 zx_handle_close(reqhandle); 153 } 154 155 status = zx_channel_write(channel, 0, &rsp, ldmsg_rsp_get_size(&rsp), 156 &handle, handle == ZX_HANDLE_INVALID ? 0 : 1); 157 check(state->log, status, 158 "zx_channel_write on loader-service channel failed"); 159 160 return true; 161 162no_reply: 163 if (hcount == 1) { 164 zx_handle_close(reqhandle); 165 } 166 return false; 167} 168 169void loader_service(zx_handle_t log, struct bootfs* bootfs, 170 zx_handle_t channel) { 171 printl(log, "waiting for loader-service requests..."); 172 173 struct loader_state state = { 174 .log = log, 175 .bootfs = bootfs, 176 }; 177 178 do { 179 zx_signals_t signals; 180 zx_status_t status = zx_object_wait_one( 181 channel, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, 182 ZX_TIME_INFINITE, &signals); 183 if (status == ZX_ERR_BAD_STATE) { 184 // This is the normal error for the other end going away, 185 // which happens when the process dies. 186 break; 187 } 188 check(log, status, 189 "zx_object_wait_one failed on loader-service channel"); 190 if (signals & ZX_CHANNEL_PEER_CLOSED) { 191 printl(log, "loader-service channel peer closed"); 192 break; 193 } 194 if (!(signals & ZX_CHANNEL_READABLE)) { 195 fail(log, "unexpected signal state on loader-service channel"); 196 } 197 } while (handle_loader_rpc(&state, channel)); 198 199 check(log, zx_handle_close(channel), 200 "zx_handle_close failed on loader-service channel"); 201} 202