1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #define NACL_LOG_MODULE_NAME "manifest_proxy"
8 :
9 : #include <string.h>
10 :
11 : #include "native_client/src/trusted/manifest_name_service_proxy/manifest_proxy.h"
12 :
13 : #include "native_client/src/public/name_service.h"
14 : #include "native_client/src/public/nacl_file_info.h"
15 : #include "native_client/src/shared/platform/nacl_log.h"
16 : #include "native_client/src/shared/platform/nacl_sync.h"
17 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
18 : #include "native_client/src/shared/srpc/nacl_srpc.h"
19 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
20 : #include "native_client/src/trusted/desc_cacheability/desc_cacheability.h"
21 : #include "native_client/src/trusted/reverse_service/manifest_rpc.h"
22 : #include "native_client/src/trusted/reverse_service/reverse_control_rpc.h"
23 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
24 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
25 : #include "native_client/src/trusted/service_runtime/nacl_secure_service.h"
26 : #include "native_client/src/trusted/validator/rich_file_info.h"
27 : #include "native_client/src/trusted/validator/validation_cache.h"
28 :
29 : static void NaClManifestWaitForChannel_yield_mu(
30 1 : struct NaClManifestProxyConnection *self) {
31 2 : NaClLog(4, "Entered NaClManifestWaitForChannel_yield_mu\n");
32 1 : NaClXMutexLock(&self->mu);
33 2 : NaClLog(4, "NaClManifestWaitForChannel_yield_mu: checking channel\n");
34 2 : while (!self->channel_initialized) {
35 0 : NaClLog(4, "NaClManifestWaitForChannel_yield_mu: waiting\n");
36 0 : NaClXCondVarWait(&self->cv, &self->mu);
37 0 : }
38 2 : NaClLog(4, "Leaving NaClManifestWaitForChannel_yield_mu\n");
39 1 : }
40 :
41 : static void NaClManifestReleaseChannel_release_mu(
42 1 : struct NaClManifestProxyConnection *self) {
43 2 : NaClLog(4, "NaClManifestReleaseChannel_release_mu\n");
44 1 : NaClXMutexUnlock(&self->mu);
45 1 : }
46 :
47 : static void NaClManifestNameServiceInsertRpc(
48 0 : struct NaClSrpcRpc *rpc,
49 0 : struct NaClSrpcArg **in_args,
50 0 : struct NaClSrpcArg **out_args,
51 0 : struct NaClSrpcClosure *done_cls) {
52 :
53 0 : UNREFERENCED_PARAMETER(in_args);
54 0 : NaClLog(4, "NaClManifestNameServiceInsertRpc\n");
55 0 : out_args[0]->u.ival = NACL_NAME_SERVICE_PERMISSION_DENIED;
56 : /* cannot add names to the manifest! */
57 0 : rpc->result = NACL_SRPC_RESULT_OK;
58 0 : (*done_cls->Run)(done_cls);
59 0 : }
60 :
61 : static void NaClManifestNameServiceLookupRpc(
62 1 : struct NaClSrpcRpc *rpc,
63 1 : struct NaClSrpcArg **in_args,
64 1 : struct NaClSrpcArg **out_args,
65 1 : struct NaClSrpcClosure *done_cls) {
66 1 : struct NaClManifestProxyConnection *proxy_conn =
67 : (struct NaClManifestProxyConnection *) rpc->channel->server_instance_data;
68 1 : char *name = in_args[0]->arrays.str;
69 1 : int flags = in_args[1]->u.ival;
70 1 : char cookie[20];
71 1 : uint32_t cookie_size = sizeof cookie;
72 1 : int status;
73 1 : struct NaClDesc *desc;
74 1 : struct NaClFileToken file_token;
75 1 : NaClSrpcError srpc_error;
76 :
77 2 : NaClLog(4, "NaClManifestNameServiceLookupRpc\n");
78 :
79 1 : NaClManifestWaitForChannel_yield_mu(proxy_conn);
80 :
81 2 : NaClLog(4,
82 : "NaClManifestNameServiceLookupRpc: name %s, flags %d\n",
83 : name, flags);
84 2 : NaClLog(4,
85 : "NaClManifestNameServiceLookupRpc: invoking %s\n",
86 : NACL_MANIFEST_LOOKUP);
87 :
88 : if (NACL_SRPC_RESULT_OK !=
89 : (srpc_error =
90 1 : NaClSrpcInvokeBySignature(&proxy_conn->client_channel,
91 : NACL_MANIFEST_LOOKUP,
92 : name,
93 : flags,
94 : &status,
95 : &desc,
96 : &file_token.lo,
97 : &file_token.hi,
98 : &cookie_size,
99 : cookie))) {
100 0 : NaClLog(LOG_ERROR,
101 : ("Manifest lookup via channel 0x%"NACL_PRIxPTR" with RPC "
102 : NACL_MANIFEST_LOOKUP" failed: %d\n"),
103 : (uintptr_t) &proxy_conn->client_channel,
104 : srpc_error);
105 0 : rpc->result = srpc_error;
106 0 : } else {
107 1 : struct NaClManifestProxy *proxy =
108 : (struct NaClManifestProxy *) proxy_conn->base.server;
109 1 : struct NaClValidationCache *validation_cache =
110 : proxy->server->nap->validation_cache;
111 1 : struct NaClDesc *replacement_desc;
112 :
113 : /*
114 : * The cookie is used to release renderer-side pepper file handle.
115 : * For now, we leak. We need on-close callbacks on NaClDesc
116 : * objects to do this properly, but even that is insufficient
117 : * since the manifest NaClDesc could, in principle, be transferred
118 : * to another process -- we would need distributed garbage
119 : * protection. If Pepper could take advantage of host-OS-side
120 : * reference counting that is already done, this wouldn't be a
121 : * problem.
122 : */
123 2 : NaClLog(4,
124 : "NaClManifestNameServiceLookupRpc: got cookie %.*s\n",
125 : cookie_size, cookie);
126 1 : replacement_desc = NaClExchangeFileTokenForMappableDesc(&file_token,
127 : validation_cache);
128 1 : if (NULL != replacement_desc) {
129 0 : NaClDescUnref(desc);
130 0 : desc = replacement_desc;
131 0 : }
132 :
133 1 : out_args[0]->u.ival = status;
134 1 : out_args[1]->u.hval = desc;
135 1 : rpc->result = NACL_SRPC_RESULT_OK;
136 : }
137 1 : (*done_cls->Run)(done_cls);
138 1 : NaClDescUnref(desc);
139 1 : NaClManifestReleaseChannel_release_mu(proxy_conn);
140 1 : }
141 :
142 : static void NaClManifestNameServiceDeleteRpc(
143 0 : struct NaClSrpcRpc *rpc,
144 0 : struct NaClSrpcArg **in_args,
145 0 : struct NaClSrpcArg **out_args,
146 0 : struct NaClSrpcClosure *done_cls) {
147 :
148 0 : UNREFERENCED_PARAMETER(in_args);
149 0 : NaClLog(4, "NaClManifestNameServiceDeleteRpc\n");
150 0 : out_args[0]->u.ival = NACL_NAME_SERVICE_PERMISSION_DENIED;
151 0 : rpc->result = NACL_SRPC_RESULT_OK;
152 0 : (*done_cls->Run)(done_cls);
153 0 : }
154 :
155 : struct NaClSrpcHandlerDesc const kNaClManifestProxyHandlers[] = {
156 : { NACL_NAME_SERVICE_INSERT, NaClManifestNameServiceInsertRpc, },
157 : { NACL_NAME_SERVICE_LOOKUP, NaClManifestNameServiceLookupRpc, },
158 : { NACL_NAME_SERVICE_DELETE, NaClManifestNameServiceDeleteRpc, },
159 : { (char const *) NULL, (NaClSrpcMethod) NULL, },
160 : };
161 :
162 :
163 3 : int NaClManifestProxyCtor(struct NaClManifestProxy *self,
164 3 : NaClThreadIfFactoryFunction thread_factory_fn,
165 3 : void *thread_factory_data,
166 3 : struct NaClSecureService *server) {
167 6 : NaClLog(4,
168 : ("Entered NaClManifestProxyCtor: self 0x%"NACL_PRIxPTR
169 : ", client 0x%"NACL_PRIxPTR"\n"),
170 : (uintptr_t) self,
171 : (uintptr_t) server);
172 3 : if (!NaClSimpleServiceCtor(&self->base,
173 : kNaClManifestProxyHandlers,
174 : thread_factory_fn,
175 : thread_factory_data)) {
176 0 : return 0;
177 : }
178 : self->server = (struct NaClSecureService *)
179 3 : NaClRefCountRef((struct NaClRefCount *) server);
180 3 : NACL_VTBL(NaClRefCount, self) =
181 : (struct NaClRefCountVtbl *) &kNaClManifestProxyVtbl;
182 3 : return 1;
183 3 : }
184 :
185 0 : static void NaClManifestProxyDtor(struct NaClRefCount *vself) {
186 0 : struct NaClManifestProxy *self =
187 : (struct NaClManifestProxy *) vself;
188 :
189 0 : NaClRefCountUnref((struct NaClRefCount *) self->server);
190 :
191 0 : NACL_VTBL(NaClRefCount, self) =
192 : (struct NaClRefCountVtbl *) &kNaClSimpleServiceVtbl;
193 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
194 0 : }
195 :
196 1 : int NaClManifestProxyConnectionCtor(struct NaClManifestProxyConnection *self,
197 1 : struct NaClManifestProxy *server,
198 1 : struct NaClDesc *conn) {
199 2 : NaClLog(4,
200 : "Entered NaClManifestProxyConnectionCtor, self 0x%"NACL_PRIxPTR"\n",
201 : (uintptr_t) self);
202 1 : if (!NaClSimpleServiceConnectionCtor(
203 : &self->base,
204 : (struct NaClSimpleService *) server,
205 : conn,
206 : (void *) self)) {
207 0 : NaClLog(4,
208 : ("NaClManifestProxyConnectionCtor: base class ctor"
209 : " NaClSimpleServiceConnectionCtor failed\n"));
210 0 : return 0;
211 : }
212 1 : NaClXMutexCtor(&self->mu);
213 1 : NaClXCondVarCtor(&self->cv);
214 1 : self->channel_initialized = 0;
215 1 : NACL_VTBL(NaClRefCount, self) =
216 : (struct NaClRefCountVtbl *) &kNaClManifestProxyConnectionVtbl;
217 1 : return 1;
218 1 : }
219 :
220 : void NaClManifestProxyConnectionRevHandleConnect(
221 1 : struct NaClManifestProxyConnection *self,
222 1 : struct NaClDesc *rev) {
223 2 : NaClLog(4, "Entered NaClManifestProxyConnectionRevHandleConnect\n");
224 1 : NaClXMutexLock(&self->mu);
225 1 : if (self->channel_initialized) {
226 0 : NaClLog(LOG_FATAL,
227 : "NaClManifestProxyConnectionRevHandleConnect: double connect?\n");
228 0 : }
229 : /*
230 : * If NaClSrpcClientCtor proves to take too long, we should spin off
231 : * another thread to do the initialization so that the reverse
232 : * client can accept additional reverse channels.
233 : */
234 2 : NaClLog(4,
235 : "NaClManifestProxyConnectionRevHandleConnect: Creating SrpcClient\n");
236 1 : if (NaClSrpcClientCtor(&self->client_channel, rev)) {
237 2 : NaClLog(4,
238 : ("NaClManifestProxyConnectionRevHandleConnect: SrpcClientCtor"
239 : " succeded, announcing.\n"));
240 1 : self->channel_initialized = 1;
241 1 : NaClXCondVarBroadcast(&self->cv);
242 : /* ownership of rev taken */
243 1 : } else {
244 0 : NaClLog(4,
245 : ("NaClManifestProxyConnectionRevHandleConnect: NaClSrpcClientCtor"
246 : " failed\n"));
247 : }
248 1 : NaClXMutexUnlock(&self->mu);
249 2 : NaClLog(4, "Leaving NaClManifestProxyConnectionRevHandleConnect\n");
250 1 : }
251 :
252 1 : static void NaClManifestProxyConnectionDtor(struct NaClRefCount *vself) {
253 1 : struct NaClManifestProxyConnection *self =
254 : (struct NaClManifestProxyConnection *) vself;
255 2 : NaClLog(4,
256 : "Entered NaClManifestProxyConnectionDtor: self 0x%"NACL_PRIxPTR"\n",
257 : (uintptr_t) self);
258 1 : NaClXMutexLock(&self->mu);
259 2 : while (!self->channel_initialized) {
260 0 : NaClLog(4,
261 : "NaClManifestProxyConnectionDtor:"
262 : " waiting for connection initialization\n");
263 0 : NaClXCondVarWait(&self->cv, &self->mu);
264 0 : }
265 1 : NaClXMutexUnlock(&self->mu);
266 :
267 2 : NaClLog(4, "NaClManifestProxyConnectionDtor: dtoring\n");
268 :
269 1 : NaClCondVarDtor(&self->cv);
270 1 : NaClMutexDtor(&self->mu);
271 :
272 1 : NaClSrpcDtor(&self->client_channel);
273 1 : NACL_VTBL(NaClSimpleServiceConnection, self) =
274 : &kNaClSimpleServiceConnectionVtbl;
275 1 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
276 1 : }
277 :
278 : /*
279 : * NaClManifestProxyConnection is a NaClSimpleServiceConnection
280 : */
281 : struct NaClSimpleServiceConnectionVtbl
282 : const kNaClManifestProxyConnectionVtbl = {
283 : {
284 : NaClManifestProxyConnectionDtor,
285 : },
286 : NaClSimpleServiceConnectionServerLoop,
287 : };
288 :
289 : static void NaClManifestReverseClientCallback(
290 1 : void *state,
291 1 : struct NaClThreadInterface *tif,
292 1 : struct NaClDesc *new_conn) {
293 1 : struct NaClManifestProxyConnection *mconn =
294 : (struct NaClManifestProxyConnection *) state;
295 :
296 2 : UNREFERENCED_PARAMETER(tif);
297 2 : NaClLog(4, "Entered NaClManifestReverseClientCallback\n");
298 1 : NaClManifestProxyConnectionRevHandleConnect(mconn, new_conn);
299 1 : }
300 :
301 : int NaClManifestProxyConnectionFactory(
302 1 : struct NaClSimpleService *vself,
303 1 : struct NaClDesc *conn,
304 1 : struct NaClSimpleServiceConnection **out) {
305 1 : struct NaClManifestProxy *self =
306 : (struct NaClManifestProxy *) vself;
307 1 : struct NaClManifestProxyConnection *mconn;
308 1 : NaClSrpcError rpc_result;
309 1 : int bool_status;
310 :
311 2 : NaClLog(4,
312 : ("Entered NaClManifestProxyConnectionFactory, self 0x%"NACL_PRIxPTR
313 : "\n"),
314 : (uintptr_t) self);
315 1 : mconn = (struct NaClManifestProxyConnection *) malloc(sizeof *mconn);
316 1 : if (NULL == mconn) {
317 0 : NaClLog(4, "NaClManifestProxyConnectionFactory: no memory\n");
318 0 : return -NACL_ABI_ENOMEM;
319 : }
320 2 : NaClLog(4, "NaClManifestProxyConnectionFactory: creating connection obj\n");
321 1 : if (!NaClManifestProxyConnectionCtor(mconn, self, conn)) {
322 0 : free(mconn);
323 0 : return -NACL_ABI_EIO;
324 : }
325 :
326 : /*
327 : * Construct via NaClSecureReverseClientCtor with a callback to
328 : * process the new reverse connection -- which should be stored in
329 : * the mconn object.
330 : *
331 : * Make reverse RPC to obtain a new reverse RPC connection.
332 : */
333 2 : NaClLog(4, "NaClManifestProxyConnectionFactory: locking reverse channel\n");
334 2 : NaClLog(4, "NaClManifestProxyConnectionFactory: client 0x%"NACL_PRIxPTR"\n",
335 : (uintptr_t) self->server);
336 1 : NaClXMutexLock(&self->server->mu);
337 1 : if (NACL_REVERSE_CHANNEL_INITIALIZED !=
338 : self->server->reverse_channel_initialization_state) {
339 0 : NaClLog(LOG_FATAL,
340 : "NaClManifestProxyConnectionFactory invoked w/o reverse channel\n");
341 0 : }
342 2 : NaClLog(4, "NaClManifestProxyConnectionFactory: inserting handler\n");
343 1 : if (!(*NACL_VTBL(NaClSecureReverseClient, self->server->reverse_client)->
344 : InsertHandler)(self->server->reverse_client,
345 : NaClManifestReverseClientCallback,
346 : (void *) mconn)) {
347 0 : NaClLog(LOG_FATAL,
348 : ("NaClManifestProxyConnectionFactory:"
349 : " NaClSecureReverseClientInsertHandler failed\n"));
350 0 : }
351 : /*
352 : * NaClSrpcInvokeBySignature(""); tell plugin to connect and create
353 : * a reverse channel
354 : */
355 2 : NaClLog(4,
356 : ("NaClManifestProxyConnectionFactory: making RPC"
357 : " to set up connection\n"));
358 1 : rpc_result = NaClSrpcInvokeBySignature(&self->server->reverse_channel,
359 : NACL_REVERSE_CONTROL_ADD_CHANNEL,
360 : &bool_status);
361 1 : if (NACL_SRPC_RESULT_OK != rpc_result) {
362 0 : NaClLog(LOG_FATAL,
363 : "NaClManifestProxyConnectionFactory: add channel RPC failed: %d",
364 : rpc_result);
365 0 : }
366 2 : NaClLog(4,
367 : "NaClManifestProxyConnectionFactory: Start status %d\n", bool_status);
368 :
369 1 : NaClXMutexUnlock(&self->server->mu);
370 :
371 1 : *out = (struct NaClSimpleServiceConnection *) mconn;
372 1 : return 0;
373 1 : }
374 :
375 : struct NaClSimpleServiceVtbl const kNaClManifestProxyVtbl = {
376 : {
377 : NaClManifestProxyDtor,
378 : },
379 : NaClManifestProxyConnectionFactory,
380 : /* see name_service.c vtbl for connection factory and ownership */
381 : /*
382 : * The NaClManifestProxyConnectionFactory creates a subclass of a
383 : * NaClSimpleServiceConnectionFactory object that uses the reverse
384 : * connection object self->server to obtain a new RPC channel
385 : * with each manifest connection.
386 : */
387 : NaClSimpleServiceAcceptConnection,
388 : NaClSimpleServiceAcceptAndSpawnHandler,
389 : NaClSimpleServiceRpcHandler,
390 : };
|