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