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 <loader-service/loader-service.h>
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <lib/fdio/io.h>
10 #include <inttypes.h>
11 #include <ldmsg/ldmsg.h>
12 #include <lib/async-loop/loop.h>
13 #include <lib/async/wait.h>
14 #include <limits.h>
15 #include <stdatomic.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <zircon/compiler.h>
22 #include <zircon/device/vfs.h>
23 #include <zircon/status.h>
24 #include <zircon/syscalls.h>
25 #include <zircon/types.h>
26
27 #define PREFIX_MAX 32
28
29 // State of a loader service instance.
30 typedef struct instance_state instance_state_t;
31 struct instance_state {
32 int root_dir_fd;
33 int data_sink_dir_fd;
34 // NULL-terminated list of paths from which objects will loaded.
35 const char* const* lib_paths;
36 };
37
38 // This represents an instance of the loader service. Each session in an
39 // instance has a session_state_t pointing to this. All sessions in
40 // the same instance behave the same.
41 struct loader_service {
42 atomic_int refcount;
43 async_dispatcher_t* dispatcher;
44
45 const loader_service_ops_t* ops;
46 void* ctx;
47 };
48
49 // Per-session state of a loader service instance.
50 typedef struct session_state session_state_t;
51 struct session_state {
52 async_wait_t wait; // Must be first.
53 char config_prefix[PREFIX_MAX];
54 bool config_exclusive;
55 loader_service_t* svc;
56 };
57
loader_service_addref(loader_service_t * svc)58 static void loader_service_addref(loader_service_t* svc) {
59 atomic_fetch_add(&svc->refcount, 1);
60 }
61
loader_service_deref(loader_service_t * svc)62 static void loader_service_deref(loader_service_t* svc) {
63 if (atomic_fetch_sub(&svc->refcount, 1) == 1) {
64 if (svc->ops->finalizer)
65 svc->ops->finalizer(svc->ctx);
66 free(svc);
67 }
68 }
69
70 // When loading a library object, search in the locations provided in
71 // |lib_paths|, which is required to be NULL-terminated.
open_from_lib_paths(int root_dir_fd,const char * const * lib_paths,const char * fn)72 static int open_from_lib_paths(int root_dir_fd, const char* const* lib_paths,
73 const char* fn) {
74 int fd = -1;
75 for (size_t n = 0; fd < 0 && lib_paths[n]; ++n) {
76 char path[PATH_MAX];
77 if (snprintf(path, sizeof(path), "%s/%s", lib_paths[n], fn) < 0) {
78 return -1;
79 }
80 fd = openat(root_dir_fd, path, O_RDONLY);
81 }
82 return fd;
83 }
84
85 // Always consumes the |fd|.
vmo_from_fd(int fd,const char * fn,zx_handle_t * out)86 static zx_handle_t vmo_from_fd(int fd, const char* fn, zx_handle_t* out) {
87 zx_status_t status = fdio_get_vmo_clone(fd, out);
88 close(fd);
89 if (status == ZX_OK) {
90 zx_object_set_property(*out, ZX_PROP_NAME, fn, strlen(fn));
91 }
92 return status;
93 }
94
fd_load_object(void * ctx,const char * name,zx_handle_t * out)95 static zx_status_t fd_load_object(void* ctx, const char* name, zx_handle_t* out) {
96 int root_dir_fd = ((instance_state_t*)ctx)->root_dir_fd;
97 const char* const* lib_paths = ((instance_state_t*)ctx)->lib_paths;
98
99 int fd = open_from_lib_paths(root_dir_fd, lib_paths, name);
100 if (fd >= 0) {
101 return vmo_from_fd(fd, name, out);
102 }
103 return ZX_ERR_NOT_FOUND;
104 }
105
fd_load_abspath(void * ctx,const char * path,zx_handle_t * out)106 static zx_status_t fd_load_abspath(void* ctx, const char* path, zx_handle_t* out) {
107 int root_dir_fd = ((instance_state_t*)ctx)->root_dir_fd;
108 int fd = openat(root_dir_fd, path, O_RDONLY);
109 if (fd >= 0) {
110 return vmo_from_fd(fd, path, out);
111 }
112 return ZX_ERR_NOT_FOUND;
113 }
114
fd_publish_data_sink(void * ctx,const char * sink_name,zx_handle_t vmo)115 zx_status_t fd_publish_data_sink(void* ctx, const char* sink_name, zx_handle_t vmo) {
116 zx_handle_close(vmo);
117 return ZX_ERR_NOT_SUPPORTED;
118 }
119
fd_finalizer(void * ctx)120 void fd_finalizer(void* ctx) {
121 instance_state_t* instance_state = (instance_state_t*)ctx;
122 int root_dir_fd = instance_state->root_dir_fd;
123 int data_sink_dir_fd = instance_state->data_sink_dir_fd;
124 close(root_dir_fd);
125 close(data_sink_dir_fd);
126 free(instance_state);
127 }
128
129 static const loader_service_ops_t fd_ops = {
130 .load_object = fd_load_object,
131 .load_abspath = fd_load_abspath,
132 .publish_data_sink = fd_publish_data_sink,
133 .finalizer = fd_finalizer,
134 };
135
loader_service_rpc(zx_handle_t h,session_state_t * session_state)136 static zx_status_t loader_service_rpc(zx_handle_t h, session_state_t* session_state) {
137 loader_service_t* svc = session_state->svc;
138 ldmsg_req_t req;
139 uint32_t req_len = sizeof(req);
140 zx_handle_t req_handle = ZX_HANDLE_INVALID;
141 uint32_t req_handle_len;
142 zx_status_t status =
143 zx_channel_read(h, 0, &req, &req_handle, req_len, 1, &req_len, &req_handle_len);
144 if (status != ZX_OK) {
145 // This is the normal error for the other end going away,
146 // which happens when the process dies.
147 if (status != ZX_ERR_PEER_CLOSED)
148 fprintf(stderr, "dlsvc: msg read error %d: %s\n", status, zx_status_get_string(status));
149 return status;
150 }
151
152 const char* data = NULL;
153 size_t len = 0;
154 status = ldmsg_req_decode(&req, req_len, &data, &len);
155
156 if (status != ZX_OK) {
157 zx_handle_close(req_handle);
158 fprintf(stderr, "dlsvc: invalid message\n");
159 return ZX_ERR_IO;
160 }
161
162 zx_handle_t rsp_handle = ZX_HANDLE_INVALID;
163 switch (req.header.ordinal) {
164 case LDMSG_OP_CONFIG: {
165 size_t len = strlen(data);
166 if (len < 2 || len >= sizeof(session_state->config_prefix) - 1 || strchr(data, '/') != NULL) {
167 status = ZX_ERR_INVALID_ARGS;
168 break;
169 }
170 memcpy(session_state->config_prefix, data, len + 1);
171 session_state->config_exclusive = false;
172 if (session_state->config_prefix[len - 1] == '!') {
173 --len;
174 session_state->config_exclusive = true;
175 }
176 session_state->config_prefix[len] = '/';
177 session_state->config_prefix[len + 1] = '\0';
178 status = ZX_OK;
179 break;
180 }
181 case LDMSG_OP_LOAD_OBJECT:
182 // If a prefix is configured, try loading with that prefix first
183 if (session_state->config_prefix[0] != '\0') {
184 size_t maxlen = PREFIX_MAX + strlen(data) + 1;
185 char prefixed_name[maxlen];
186 snprintf(prefixed_name, maxlen, "%s%s", session_state->config_prefix, data);
187 if (((status = svc->ops->load_object(svc->ctx, prefixed_name, &rsp_handle)) == ZX_OK) ||
188 session_state->config_exclusive) {
189 // if loading with prefix succeeds, or loading
190 // with prefix is configured to be exclusive of
191 // non-prefix loading, stop here
192 break;
193 }
194 // otherwise, if non-exclusive, try loading without the prefix
195 }
196 status = svc->ops->load_object(svc->ctx, data, &rsp_handle);
197 break;
198 case LDMSG_OP_LOAD_SCRIPT_INTERPRETER:
199 case LDMSG_OP_DEBUG_LOAD_CONFIG:
200 // When loading a script interpreter or debug configuration file,
201 // we expect an absolute path.
202 if (data[0] != '/') {
203 fprintf(stderr, "dlsvc: invalid %s '%s' is not an absolute path\n",
204 req.header.ordinal == LDMSG_OP_LOAD_SCRIPT_INTERPRETER ? "script interpreter" : "debug config file",
205 data);
206 status = ZX_ERR_NOT_FOUND;
207 break;
208 }
209 status = svc->ops->load_abspath(svc->ctx, data, &rsp_handle);
210 break;
211 case LDMSG_OP_DEBUG_PUBLISH_DATA_SINK:
212 status = svc->ops->publish_data_sink(svc->ctx, data, req_handle);
213 req_handle = ZX_HANDLE_INVALID;
214 break;
215 case LDMSG_OP_CLONE:
216 status = loader_service_attach(svc, req_handle);
217 req_handle = ZX_HANDLE_INVALID;
218 break;
219 case LDMSG_OP_DONE:
220 zx_handle_close(req_handle);
221 return ZX_ERR_PEER_CLOSED;
222 default:
223 // This case cannot happen because ldmsg_req_decode will return an
224 // error for invalid ordinals.
225 __builtin_trap();
226 }
227
228 if (status == ZX_ERR_NOT_FOUND) {
229 fprintf(stderr, "dlsvc: could not open '%s'\n", data);
230 }
231
232 if (req_handle != ZX_HANDLE_INVALID) {
233 fprintf(stderr, "dlsvc: unused handle (%#x) opcode=%#x data=\"%s\"\n",
234 req_handle, req.header.ordinal, data);
235 zx_handle_close(req_handle);
236 }
237
238 ldmsg_rsp_t rsp;
239 memset(&rsp, 0, sizeof(rsp));
240 rsp.header.txid = req.header.txid;
241 rsp.header.ordinal = req.header.ordinal;
242 rsp.rv = status;
243 rsp.object = rsp_handle == ZX_HANDLE_INVALID ? FIDL_HANDLE_ABSENT : FIDL_HANDLE_PRESENT;
244 if ((status = zx_channel_write(h, 0, &rsp, ldmsg_rsp_get_size(&rsp),
245 &rsp_handle, rsp_handle != ZX_HANDLE_INVALID ? 1 : 0)) < 0) {
246 fprintf(stderr, "dlsvc: msg write error: %d: %s\n", status, zx_status_get_string(status));
247 return status;
248 }
249 return ZX_OK;
250 }
251
loader_service_create(async_dispatcher_t * dispatcher,const loader_service_ops_t * ops,void * ctx,loader_service_t ** out)252 zx_status_t loader_service_create(async_dispatcher_t* dispatcher,
253 const loader_service_ops_t* ops,
254 void* ctx,
255 loader_service_t** out) {
256 if (out == NULL || ops == NULL) {
257 return ZX_ERR_INVALID_ARGS;
258 }
259
260 loader_service_t* svc = calloc(1, sizeof(loader_service_t));
261 if (svc == NULL) {
262 return ZX_ERR_NO_MEMORY;
263 }
264
265 if (!dispatcher) {
266 async_loop_t* loop;
267 zx_status_t status = async_loop_create(&kAsyncLoopConfigNoAttachToThread, &loop);
268 if (status != ZX_OK) {
269 free(svc);
270 return status;
271 }
272
273 status = async_loop_start_thread(loop, "loader-service", NULL);
274 if (status != ZX_OK) {
275 free(svc);
276 async_loop_destroy(loop);
277 return status;
278 }
279
280 dispatcher = async_loop_get_dispatcher(loop);
281 }
282
283 svc->dispatcher = dispatcher;
284 svc->ops = ops;
285 svc->ctx = ctx;
286
287 // When we create the loader service, we initialize the refcount to 1, which
288 // causes the loader service to stay alive at least until someone calls
289 // |loader_service_release|, at which point the service will be destroyed
290 // once the last client goes away.
291 loader_service_addref(svc);
292
293 *out = svc;
294 return ZX_OK;
295 }
296
297 // Default library paths for the fd- and fs- loader service implementations.
298 static const char* const fd_lib_paths[] = {"lib", NULL};
299 static const char* const fs_lib_paths[] = {"system/lib", "boot/lib", NULL};
300
301 // Create the default implementation of a loader service for which
302 // paths are loaded relative to |root_dir_fd| and among the array of
303 // subdirectories given by |lib_paths| (NULL-terminated), with data published
304 // in the location given by |data_sink_dir_fd|.
loader_service_create_default(async_dispatcher_t * dispatcher,int root_dir_fd,int data_sink_dir_fd,const char * const * lib_paths,loader_service_t ** out)305 zx_status_t loader_service_create_default(async_dispatcher_t* dispatcher,
306 int root_dir_fd,
307 int data_sink_dir_fd,
308 const char* const* lib_paths,
309 loader_service_t** out) {
310 instance_state_t* instance_state = calloc(1, sizeof(loader_service_t));
311 if (instance_state == NULL) {
312 return ZX_ERR_NO_MEMORY;
313 }
314 instance_state->root_dir_fd = root_dir_fd;
315 instance_state->data_sink_dir_fd = data_sink_dir_fd;
316 instance_state->lib_paths = lib_paths? lib_paths : fd_lib_paths;
317
318 loader_service_t* svc;
319 zx_status_t status = loader_service_create(dispatcher, &fd_ops, NULL, &svc);
320 if (status == ZX_OK) {
321 svc->ctx = instance_state;
322 *out = svc;
323 } else {
324 free(instance_state);
325 }
326 return status;
327 }
328
loader_service_create_fs(async_dispatcher_t * dispatcher,loader_service_t ** out)329 zx_status_t loader_service_create_fs(async_dispatcher_t* dispatcher, loader_service_t** out) {
330 int root_dir_fd = open("/", O_RDONLY | O_DIRECTORY);
331 if (root_dir_fd < 0){
332 return ZX_ERR_NOT_FOUND;
333 }
334 return loader_service_create_default(dispatcher, root_dir_fd, -1, fs_lib_paths,
335 out);
336 }
337
loader_service_create_fd(async_dispatcher_t * dispatcher,int root_dir_fd,int data_sink_dir_fd,loader_service_t ** out)338 zx_status_t loader_service_create_fd(async_dispatcher_t* dispatcher,
339 int root_dir_fd,
340 int data_sink_dir_fd,
341 loader_service_t** out) {
342 return loader_service_create_default(dispatcher, root_dir_fd, data_sink_dir_fd,
343 fd_lib_paths, out);
344 }
345
loader_service_release(loader_service_t * svc)346 zx_status_t loader_service_release(loader_service_t* svc) {
347 // This call to |loader_service_deref| balances the |loader_service_addref|
348 // call in |loader_service_create|. This reference prevents the loader
349 // service from being destroyed before its creator is done with it.
350 loader_service_deref(svc);
351 return ZX_OK;
352 }
353
loader_service_handler(async_dispatcher_t * dispatcher,async_wait_t * wait,zx_status_t status,const zx_packet_signal_t * signal)354 static void loader_service_handler(async_dispatcher_t* dispatcher,
355 async_wait_t* wait,
356 zx_status_t status,
357 const zx_packet_signal_t* signal) {
358 session_state_t* session_state = (session_state_t*)wait;
359 if (status != ZX_OK)
360 goto stop;
361 status = loader_service_rpc(wait->object, session_state);
362 if (status != ZX_OK)
363 goto stop;
364 status = async_begin_wait(dispatcher, wait);
365 if (status != ZX_OK)
366 goto stop;
367 return;
368 stop:
369 zx_handle_close(wait->object);
370 loader_service_t* svc = session_state->svc;
371 free(session_state);
372 loader_service_deref(svc); // Balanced in |loader_service_attach|.
373 }
374
loader_service_attach(loader_service_t * svc,zx_handle_t h)375 zx_status_t loader_service_attach(loader_service_t* svc, zx_handle_t h) {
376 zx_status_t status = ZX_OK;
377 session_state_t* session_state = NULL;
378
379 if (svc == NULL) {
380 status = ZX_ERR_INVALID_ARGS;
381 goto done;
382 }
383
384 session_state = calloc(1, sizeof(session_state_t));
385 if (session_state == NULL) {
386 status = ZX_ERR_NO_MEMORY;
387 goto done;
388 }
389
390 session_state->wait.handler = loader_service_handler;
391 session_state->wait.object = h;
392 session_state->wait.trigger = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
393 session_state->svc = svc;
394
395 status = async_begin_wait(svc->dispatcher, &session_state->wait);
396
397 if (status == ZX_OK) {
398 loader_service_addref(svc); // Balanced in |loader_service_handler|.
399 }
400
401 done:
402 if (status != ZX_OK) {
403 zx_handle_close(h);
404 free(session_state);
405 }
406 return status;
407 }
408
loader_service_connect(loader_service_t * svc,zx_handle_t * out)409 zx_status_t loader_service_connect(loader_service_t* svc, zx_handle_t* out) {
410 zx_handle_t h0, h1;
411 zx_status_t status;
412 if ((status = zx_channel_create(0, &h0, &h1)) != ZX_OK) {
413 return status;
414 }
415 if ((status = loader_service_attach(svc, h1)) != ZX_OK) {
416 zx_handle_close(h0);
417 return status;
418 }
419 *out = h0;
420 return ZX_OK;
421 }
422