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
19 struct 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
loader_config(struct loader_state * state,const char * string,size_t len)27 static 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
try_load_object(struct loader_state * state,const char * name,size_t len,size_t prefix_len)41 static 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
load_object(struct loader_state * state,const char * name,size_t len)53 static 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
handle_loader_rpc(struct loader_state * state,zx_handle_t channel)62 static 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;
144 error_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
162 no_reply:
163 if (hcount == 1) {
164 zx_handle_close(reqhandle);
165 }
166 return false;
167 }
168
loader_service(zx_handle_t log,struct bootfs * bootfs,zx_handle_t channel)169 void 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