1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * The BrandZ Linux thunking server.
31 *
32 * The interfaces defined in this file form the server side of a bridge
33 * to allow native solaris process to access Linux services. Currently
34 * the Linux services that is made accessible by these interfaces here
35 * are:
36 * - Linux host <-> address naming services
37 * - Linux service <-> port naming services
38 * - Linux syslog
39 *
40 * Access to all these services is provided through a doors server.
41 * Currently the only client of these interfaces and the process that
42 * initially starts up the doors server is lx_thunk.so.
43 *
44 * lx_thunk.so is a native solaris library that is loaded into native
45 * solaris process that need to run inside a Linux zone and have access
46 * to Linux services. When lx_thunk.so receives a request that requires
47 * accessing Linux services it creates a "thunk server" process by
48 * forking and executing the following shell script (which runs as
49 * a native /bin/sh Linux process):
50 * /native/usr/lib/brand/lx/lx_thunk
51 *
52 * The first and only thing this shell script attempts to do is re-exec
53 * itself. The brand library will detect when this script attempts to
54 * re-exec itself and take control of the process. The exec() system
55 * call made by the Linux shell will never return.
56 *
57 * At this point the process becomes a "thunk server" process.
58 * The first thing it does is a bunch of initialization:
59 *
60 * - Sanity check that a file descriptor based communication mechanism
61 * needed talk to the parent process is correctly initialized.
62 *
63 * - Verify that two predetermined file descriptors are FIFOs.
64 * These FIFOs will be used to establish communications with
65 * the client program that spawned us and which will be sending
66 * us requests.
67 *
68 * - Use existing debugging libraries (libproc.so, librtld_db.so,
69 * and the BrandZ lx plug-in to librtld_db.so) and /native/proc to
70 * walk the Linux link maps in our own address space to determine
71 * the address of the Linux dlsym() function.
72 *
73 * - Use the native Linux dlsym() function to look up other symbols
74 * (for both functions and variables) that we will need access
75 * to service thunking requests.
76 *
77 * - Create a doors server and notify the parent process that we
78 * are ready to service requests.
79 *
80 * - Enter a service loop and wait for requests.
81 *
82 * At this point the lx_thunk process is ready to service door
83 * based requests. When door service request is received the
84 * following happens inside the lx_thunk process:
85 *
86 * - The doors server function is is invoked on a new solaris thread
87 * that the kernel injects into the lx_thunk process. We sanity
88 * check the incoming request, place it on a service queue, and
89 * wait for notification that the request has been completed.
90 *
91 * - A Linux thread takes this request off the service queue
92 * and dispatches it to a service function that will:
93 * - Decode the request.
94 * - Handle the request by invoking native Linux interfaces.
95 * - Encode the results for the request.
96 *
97 * - The Linux thread then notifies the requesting doors server
98 * thread that the request has been completed and goes to sleep
99 * until it receives another request.
100 *
101 * - the solaris door server thread returns the results of the
102 * operation to the caller.
103 *
104 * Notes:
105 *
106 * - The service request hand off operation from the solaris doors thread to
107 * the "Linux thread" is required because only "Linux threads" can call
108 * into Linux code. In this context a "Linux thread" is a thread that
109 * is either the initial thread of a Linux process or a thread that was
110 * created by calling the Linux version of thread_create(). The reason
111 * for this restriction is that any thread that invokes Linux code needs
112 * to have been initialized in the Linux threading libraries and have
113 * things like Linux thread local storage properly setup.
114 *
115 * But under solaris all door server threads are created and destroyed
116 * dynamically. This means that when a doors server function is invoked,
117 * it is invoked via a thread that hasn't been initialized in the Linux
118 * environment and there for can't call directly into Linux code.
119 *
120 * - Currently when a thunk server process is starting up, it communicated
121 * with it's parent via two FIFOs. These FIFOs are setup by the
122 * lx_thunk.so library. After creating the FIFOs and starting the lx_thunk
123 * server, lx_thunk.so writes the name of the file that the door should
124 * be attached to to the first pipe. The lx_thunk server reads in this
125 * value, initialized the server, fattach()s it to the file request by
126 * lx_thunk.so and does a write to the second FIFO to let lx_thunk.so
127 * know that the server is ready to take requests.
128 *
129 * This negotiation could be simplified to use only use one FIFO.
130 * lx_thunk.so would attempt to read from the FIFO and the lx_thunk
131 * server process could send the new door server file descriptor
132 * to this process via an I_SENDFD ioctl (see streamio.7I).
133 *
134 * - The lx_thunk server process will exit when the client process
135 * that it's handling requests for exists. (ie, when there are no
136 * more open file handles to the doors server.)
137 */
138
139 #include <assert.h>
140 #include <door.h>
141 #include <errno.h>
142 #include <libproc.h>
143 #include <stdio.h>
144 #include <stdlib.h>
145 #include <strings.h>
146 #include <sys/lx_debug.h>
147 #include <sys/lx_misc.h>
148 #include <sys/lx_thread.h>
149 #include <sys/lx_thunk_server.h>
150 #include <sys/varargs.h>
151 #include <thread.h>
152 #include <unistd.h>
153
154 /*
155 * Generic interfaces used for looking up and calling Linux functions.
156 */
157 typedef struct __lx_handle_dlsym *lx_handle_dlsym_t;
158 typedef struct __lx_handle_sym *lx_handle_sym_t;
159
160 uintptr_t lx_call0(lx_handle_sym_t);
161 uintptr_t lx_call1(lx_handle_sym_t, uintptr_t);
162 uintptr_t lx_call2(lx_handle_sym_t, uintptr_t, uintptr_t);
163 uintptr_t lx_call3(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t);
164 uintptr_t lx_call4(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
165 uintptr_t);
166 uintptr_t lx_call5(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
167 uintptr_t, uintptr_t);
168 uintptr_t lx_call6(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
169 uintptr_t, uintptr_t, uintptr_t);
170 uintptr_t lx_call7(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
171 uintptr_t, uintptr_t, uintptr_t, uintptr_t);
172 uintptr_t lx_call8(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
173 uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
174
175 /*
176 * Flag indicating if this process is destined to become a thunking
177 * server process.
178 */
179 static int lxt_server_processes = 0;
180
181 /*
182 * Linux function call defines and handles.
183 */
184 static lx_handle_dlsym_t lxh_init = NULL;
185
186 #define LXTH_GETHOSTBYNAME_R 0
187 #define LXTH_GETHOSTBYADDR_R 1
188 #define LXTH_GETSERVBYNAME_R 2
189 #define LXTH_GETSERVBYPORT_R 3
190 #define LXTH_OPENLOG 4
191 #define LXTH_SYSLOG 5
192 #define LXTH_CLOSELOG 6
193 #define LXTH_PROGNAME 7
194
195 static struct lxt_handles {
196 int lxth_index;
197 char *lxth_name;
198 lx_handle_sym_t lxth_handle;
199 } lxt_handles[] = {
200 { LXTH_GETHOSTBYNAME_R, "gethostbyname_r", NULL },
201 { LXTH_GETHOSTBYADDR_R, "gethostbyaddr_r", NULL },
202 { LXTH_GETSERVBYNAME_R, "getservbyname_r", NULL },
203 { LXTH_GETSERVBYPORT_R, "getservbyport_r", NULL },
204 { LXTH_OPENLOG, "openlog", NULL },
205 { LXTH_SYSLOG, "syslog", NULL },
206 { LXTH_CLOSELOG, "closelog", NULL },
207 { LXTH_PROGNAME, "__progname", NULL },
208 { -1, NULL, NULL },
209 };
210
211 /*
212 * Door server operations dispatch functions and table.
213 *
214 * When the doors server get's a request for a particlar operation
215 * this dispatch table controls what function will be invoked to
216 * service the request. The function is invoked via Linux thread
217 * so that it can call into native Linux code if necessary.
218 */
219 static void lxt_server_gethost(lxt_server_arg_t *request, size_t request_size,
220 char **door_result, size_t *door_result_size);
221 static void lxt_server_getserv(lxt_server_arg_t *request, size_t request_size,
222 char **door_result, size_t *door_result_size);
223 static void lxt_server_openlog(lxt_server_arg_t *request, size_t request_size,
224 char **door_result, size_t *door_result_size);
225 static void lxt_server_syslog(lxt_server_arg_t *request, size_t request_size,
226 char **door_result, size_t *door_result_size);
227 static void lxt_server_closelog(lxt_server_arg_t *request, size_t request_size,
228 char **door_result, size_t *door_result_size);
229
230 typedef void (*lxt_op_func_t)(lxt_server_arg_t *request, size_t request_size,
231 char **door_result, size_t *door_result_size);
232
233 static struct lxt_operations {
234 int lxto_index;
235 lxt_op_func_t lxto_fp;
236 } lxt_operations[] = {
237 { LXT_SERVER_OP_PING, NULL },
238 { LXT_SERVER_OP_NAME2HOST, lxt_server_gethost },
239 { LXT_SERVER_OP_ADDR2HOST, lxt_server_gethost },
240 { LXT_SERVER_OP_NAME2SERV, lxt_server_getserv },
241 { LXT_SERVER_OP_PORT2SERV, lxt_server_getserv },
242 { LXT_SERVER_OP_OPENLOG, lxt_server_openlog },
243 { LXT_SERVER_OP_SYSLOG, lxt_server_syslog },
244 { LXT_SERVER_OP_CLOSELOG, lxt_server_closelog },
245 };
246
247 /*
248 * Structures for passing off requests from doors threads (which are
249 * solaris threads) to a Linux thread that that can handle them.
250 */
251 typedef struct lxt_req {
252 lxt_server_arg_t *lxtr_request;
253 size_t lxtr_request_size;
254 char *lxtr_result;
255 size_t lxtr_result_size;
256 int lxtr_complete;
257 cond_t lxtr_complete_cv;
258 } lxt_req_t;
259
260 static mutex_t lxt_req_lock = DEFAULTMUTEX;
261 static cond_t lxt_req_cv = DEFAULTCV;
262 static lxt_req_t *lxt_req_ptr = NULL;
263
264 static mutex_t lxt_pid_lock = DEFAULTMUTEX;
265 static pid_t lxt_pid = NULL;
266
267 /*
268 * Interfaces used to call from lx_brand.so into Linux code.
269 */
270 typedef struct lookup_cb_arg {
271 struct ps_prochandle *lca_ph;
272 caddr_t lca_ptr;
273 } lookup_cb_arg_t;
274
275 static int
276 /*ARGSUSED*/
277 lookup_cb(void *data, const prmap_t *pmp, const char *object)
278 {
279 lookup_cb_arg_t *lcap = (lookup_cb_arg_t *)data;
280 prsyminfo_t si;
281 GElf_Sym sym;
282
283 if (Pxlookup_by_name(lcap->lca_ph,
284 LM_ID_BASE, object, "dlsym", &sym, &si) != 0)
285 return (0);
286
287 if (sym.st_shndx == SHN_UNDEF)
288 return (0);
289
290 /*
291 * XXX: we should be more paranoid and verify that the symbol
292 * we just looked up is libdl.so.2`dlsym
293 */
294 lcap->lca_ptr = (caddr_t)(uintptr_t)sym.st_value;
295 return (1);
296 }
297
298 lx_handle_dlsym_t
299 lx_call_init(void)
300 {
301 struct ps_prochandle *ph;
302 lookup_cb_arg_t lca;
303 extern int __libc_threaded;
304 int err;
305
306 lx_debug("lx_call_init(): looking up Linux dlsym");
307
308 /*
309 * The handle is really the address of the Linux "dlsym" function.
310 * Once we have this address we can call into the Linux "dlsym"
311 * function to lookup other functions. It's the initial lookup
312 * of "dlsym" that's difficult. To do this we'll leverage the
313 * brand support that we added to librtld_db. We're going
314 * to fire up a seperate native solaris process that will
315 * attach to us via libproc/librtld_db and lookup the symbol
316 * for us.
317 */
318
319 /* Make sure we're single threaded. */
320 if (__libc_threaded) {
321 lx_debug("lx_call_init() fail: "
322 "process must be single threaded");
323 return (NULL);
324 }
325
326 /* Tell libproc.so where the real procfs is mounted. */
327 Pset_procfs_path("/native/proc");
328
329 /* Tell librtld_db.so where the real /native is */
330 (void) rd_ctl(RD_CTL_SET_HELPPATH, "/native");
331
332 /* Grab ourselves but don't stop ourselves. */
333 if ((ph = Pgrab(getpid(),
334 PGRAB_FORCE | PGRAB_RDONLY | PGRAB_NOSTOP, &err)) == NULL) {
335 lx_debug("lx_call_init() fail: Pgrab failed: %s",
336 Pgrab_error(err));
337 return (NULL);
338 }
339
340 lca.lca_ph = ph;
341 if (Pobject_iter(ph, lookup_cb, &lca) == -1) {
342 lx_debug("lx_call_init() fail: couldn't find Linux dlsym");
343 return (NULL);
344 }
345
346 lx_debug("lx_call_init(): Linux dlsym = 0x%p", lca.lca_ptr);
347 return ((lx_handle_dlsym_t)lca.lca_ptr);
348 }
349
350 #define LX_RTLD_DEFAULT ((void *)0)
351 #define LX_RTLD_NEXT ((void *) -1l)
352
353 lx_handle_sym_t
354 lx_call_dlsym(lx_handle_dlsym_t lxh_dlsym, const char *str)
355 {
356 lx_handle_sym_t result;
357 lx_debug("lx_call_dlsym: calling Linux dlsym for: %s", str);
358 result = (lx_handle_sym_t)lx_call2((lx_handle_sym_t)lxh_dlsym,
359 (uintptr_t)LX_RTLD_DEFAULT, (uintptr_t)str);
360 lx_debug("lx_call_dlsym: Linux sym: \"%s\" = 0x%p", str, result);
361 return (result);
362 }
363
364 static uintptr_t
365 /*ARGSUSED*/
366 lx_call(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2,
367 uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6, uintptr_t p7,
368 uintptr_t p8)
369 {
370 typedef uintptr_t (*fp8_t)(uintptr_t, uintptr_t, uintptr_t,
371 uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
372 lx_regs_t *rp;
373 uintptr_t ret;
374 fp8_t lx_funcp = (fp8_t)lx_ch;
375 long cur_gs;
376
377 rp = lx_syscall_regs();
378
379 lx_debug("lx_call: calling to Linux code at 0x%p", lx_ch);
380 lx_debug("lx_call: loading Linux gs, rp = 0x%p, gs = 0x%p",
381 rp, rp->lxr_gs);
382
383 lx_swap_gs(rp->lxr_gs, &cur_gs);
384 ret = lx_funcp(p1, p2, p3, p4, p5, p6, p7, p8);
385 lx_swap_gs(cur_gs, &rp->lxr_gs);
386
387 lx_debug("lx_call: returned from Linux code at 0x%p (%p)", lx_ch, ret);
388 lx_debug("lx_call: restored solaris gs 0x%p", cur_gs);
389 return (ret);
390 }
391
392 uintptr_t
393 lx_call0(lx_handle_sym_t lx_ch)
394 {
395 return (lx_call(lx_ch, 0, 0, 0, 0, 0, 0, 0, 0));
396 }
397
398 uintptr_t
399 lx_call1(lx_handle_sym_t lx_ch, uintptr_t p1)
400 {
401 return (lx_call(lx_ch, p1, 0, 0, 0, 0, 0, 0, 0));
402 }
403
404 uintptr_t
405 lx_call2(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2)
406 {
407 return (lx_call(lx_ch, p1, p2, 0, 0, 0, 0, 0, 0));
408 }
409
410 uintptr_t
411 lx_call3(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3)
412 {
413 return (lx_call(lx_ch, p1, p2, p3, 0, 0, 0, 0, 0));
414 }
415
416 uintptr_t
417 lx_call4(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
418 uintptr_t p4)
419 {
420 return (lx_call(lx_ch, p1, p2, p3, p4, 0, 0, 0, 0));
421 }
422
423 uintptr_t
424 lx_call5(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
425 uintptr_t p4, uintptr_t p5)
426 {
427 return (lx_call(lx_ch, p1, p2, p3, p4, p5, 0, 0, 0));
428 }
429
430 uintptr_t
431 lx_call6(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
432 uintptr_t p4, uintptr_t p5, uintptr_t p6)
433 {
434 return (lx_call(lx_ch, p1, p2, p3, p4, p5, p6, 0, 0));
435 }
436
437 uintptr_t
438 lx_call7(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
439 uintptr_t p4, uintptr_t p5, uintptr_t p6, uintptr_t p7)
440 {
441 return (lx_call(lx_ch, p1, p2, p3, p4, p5, p6, p7, 0));
442 }
443
444 uintptr_t
445 lx_call8(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
446 uintptr_t p4, uintptr_t p5, uintptr_t p6, uintptr_t p7, uintptr_t p8)
447 {
448 return (lx_call(lx_ch, p1, p2, p3, p4, p5, p6, p7, p8));
449 }
450
451 /*
452 * Linux Thunking Interfaces - Server Side
453 */
454 static int
455 lxt_gethost_arg_check(lxt_gethost_arg_t *x, int x_size)
456 {
457 if (x_size != sizeof (*x) + x->lxt_gh_buf_len - 1)
458 return (-1);
459
460 if ((x->lxt_gh_token_len < 0) || (x->lxt_gh_buf_len < 0))
461 return (-1);
462
463 /* Token and buf should use up all the storage. */
464 if ((x->lxt_gh_token_len + x->lxt_gh_buf_len) != x->lxt_gh_storage_len)
465 return (-1);
466
467 return (0);
468 }
469
470 static void
471 lxt_server_gethost(lxt_server_arg_t *request, size_t request_size,
472 char **door_result, size_t *door_result_size)
473 {
474 lxt_gethost_arg_t *data;
475 struct hostent *result, *rv;
476 int token_len, buf_len, type, data_size, i;
477 char *token, *buf;
478 int h_errnop;
479
480 assert((request->lxt_sa_op == LXT_SERVER_OP_NAME2HOST) ||
481 (request->lxt_sa_op == LXT_SERVER_OP_ADDR2HOST));
482
483 /*LINTED*/
484 data = (lxt_gethost_arg_t *)&request->lxt_sa_data[0];
485 data_size = request_size - sizeof (*request) - 1;
486
487 if (!lxt_gethost_arg_check(data, data_size)) {
488 lx_debug("lxt_server_gethost: invalid request");
489 *door_result = NULL;
490 *door_result_size = 0;
491 return;
492 }
493
494 /* Unpack the arguments. */
495 type = data->lxt_gh_type;
496 token = &data->lxt_gh_storage[0];
497 token_len = data->lxt_gh_token_len;
498 result = &data->lxt_gh_result;
499 buf = &data->lxt_gh_storage[data->lxt_gh_token_len];
500 buf_len = data->lxt_gh_buf_len - data->lxt_gh_token_len;
501
502 if (request->lxt_sa_op == LXT_SERVER_OP_NAME2HOST) {
503 (void) lx_call6(lxt_handles[LXTH_GETHOSTBYNAME_R].lxth_handle,
504 (uintptr_t)token, (uintptr_t)result,
505 (uintptr_t)buf, buf_len, (uintptr_t)&rv,
506 (uintptr_t)&h_errnop);
507 } else {
508 (void) lx_call8(lxt_handles[LXTH_GETHOSTBYADDR_R].lxth_handle,
509 (uintptr_t)token, token_len, type, (uintptr_t)result,
510 (uintptr_t)buf, buf_len, (uintptr_t)&rv,
511 (uintptr_t)&h_errnop);
512 }
513
514 if (rv == NULL) {
515 /* the lookup failed */
516 request->lxt_sa_success = 0;
517 request->lxt_sa_errno = errno;
518 data->lxt_gh_h_errno = h_errnop;
519 *door_result = (char *)request;
520 *door_result_size = request_size;
521 return;
522 }
523 request->lxt_sa_success = 1;
524 request->lxt_sa_errno = 0;
525 data->lxt_gh_h_errno = 0;
526
527 /*
528 * The result structure that we would normally return contains a
529 * bunch of pointers, but those pointers are useless to our caller
530 * since they are in a different address space. So before returning
531 * we'll convert all the result pointers into offsets. The caller
532 * can then map the offsets back into pointers.
533 */
534 for (i = 0; result->h_aliases[i] != NULL; i++) {
535 result->h_aliases[i] =
536 LXT_PTR_TO_OFFSET(result->h_aliases[i], buf);
537 }
538 for (i = 0; result->h_addr_list[i] != NULL; i++) {
539 result->h_addr_list[i] =
540 LXT_PTR_TO_OFFSET(result->h_addr_list[i], buf);
541 }
542 result->h_name = LXT_PTR_TO_OFFSET(result->h_name, buf);
543 result->h_aliases = LXT_PTR_TO_OFFSET(result->h_aliases, buf);
544 result->h_addr_list = LXT_PTR_TO_OFFSET(result->h_addr_list, buf);
545
546 *door_result = (char *)request;
547 *door_result_size = request_size;
548 }
549
550 static int
551 lxt_getserv_arg_check(lxt_getserv_arg_t *x, int x_size)
552 {
553 if (x_size != sizeof (*x) + x->lxt_gs_buf_len - 1)
554 return (-1);
555
556 if ((x->lxt_gs_token_len < 0) || (x->lxt_gs_buf_len < 0))
557 return (-1);
558
559 /* Token and buf should use up all the storage. */
560 if ((x->lxt_gs_token_len + x->lxt_gs_buf_len) != x->lxt_gs_storage_len)
561 return (-1);
562
563 return (0);
564 }
565
566 static void
567 lxt_server_getserv(lxt_server_arg_t *request, size_t request_size,
568 char **door_result, size_t *door_result_size)
569 {
570 lxt_getserv_arg_t *data;
571 struct servent *result, *rv;
572 int token_len, buf_len, data_size, i, port;
573 char *token, *buf, *proto = NULL;
574
575 assert((request->lxt_sa_op == LXT_SERVER_OP_NAME2SERV) ||
576 (request->lxt_sa_op == LXT_SERVER_OP_PORT2SERV));
577
578 /*LINTED*/
579 data = (lxt_getserv_arg_t *)&request->lxt_sa_data[0];
580 data_size = request_size - sizeof (*request) - 1;
581
582 if (!lxt_getserv_arg_check(data, data_size)) {
583 lx_debug("lxt_server_getserv: invalid request");
584 *door_result = NULL;
585 *door_result_size = 0;
586 return;
587 }
588
589 /* Unpack the arguments. */
590 token = &data->lxt_gs_storage[0];
591 token_len = data->lxt_gs_token_len;
592 result = &data->lxt_gs_result;
593 buf = &data->lxt_gs_storage[data->lxt_gs_token_len];
594 buf_len = data->lxt_gs_buf_len - data->lxt_gs_token_len;
595 if (strlen(data->lxt_gs_proto) > 0)
596 proto = data->lxt_gs_proto;
597
598 /* Do more sanity checks */
599 if ((request->lxt_sa_op == LXT_SERVER_OP_PORT2SERV) &&
600 (token_len != sizeof (int))) {
601 lx_debug("lxt_server_getserv: invalid request");
602 *door_result = NULL;
603 *door_result_size = 0;
604 return;
605 }
606
607 if (request->lxt_sa_op == LXT_SERVER_OP_NAME2SERV) {
608 (void) lx_call6(lxt_handles[LXTH_GETSERVBYNAME_R].lxth_handle,
609 (uintptr_t)token, (uintptr_t)proto, (uintptr_t)result,
610 (uintptr_t)buf, buf_len, (uintptr_t)&rv);
611 } else {
612 bcopy(token, &port, sizeof (int));
613 (void) lx_call6(lxt_handles[LXTH_GETSERVBYPORT_R].lxth_handle,
614 port, (uintptr_t)proto, (uintptr_t)result,
615 (uintptr_t)buf, buf_len, (uintptr_t)&rv);
616 }
617
618 if (rv == NULL) {
619 /* the lookup failed */
620 request->lxt_sa_success = 0;
621 request->lxt_sa_errno = errno;
622 *door_result = (char *)request;
623 *door_result_size = request_size;
624 return;
625 }
626 request->lxt_sa_success = 1;
627 request->lxt_sa_errno = 0;
628
629 /*
630 * The result structure that we would normally return contains a
631 * bunch of pointers, but those pointers are useless to our caller
632 * since they are in a different address space. So before returning
633 * we'll convert all the result pointers into offsets. The caller
634 * can then map the offsets back into pointers.
635 */
636 for (i = 0; result->s_aliases[i] != NULL; i++) {
637 result->s_aliases[i] =
638 LXT_PTR_TO_OFFSET(result->s_aliases[i], buf);
639 }
640 result->s_proto = LXT_PTR_TO_OFFSET(result->s_proto, buf);
641 result->s_aliases = LXT_PTR_TO_OFFSET(result->s_aliases, buf);
642 result->s_name = LXT_PTR_TO_OFFSET(result->s_name, buf);
643
644 *door_result = (char *)request;
645 *door_result_size = request_size;
646 }
647
648 static void
649 /*ARGSUSED*/
650 lxt_server_openlog(lxt_server_arg_t *request, size_t request_size,
651 char **door_result, size_t *door_result_size)
652 {
653 lxt_openlog_arg_t *data;
654 int data_size;
655 static char ident[128];
656
657 assert(request->lxt_sa_op == LXT_SERVER_OP_OPENLOG);
658
659 /*LINTED*/
660 data = (lxt_openlog_arg_t *)&request->lxt_sa_data[0];
661 data_size = request_size - sizeof (*request);
662
663 if (data_size != sizeof (*data)) {
664 lx_debug("lxt_server_openlog: invalid request");
665 *door_result = NULL;
666 *door_result_size = 0;
667 return;
668 }
669
670 /*
671 * Linux expects that the ident pointer passed to openlog()
672 * points to a static string that won't go away. Linux
673 * saves the pointer and references with syslog() is called.
674 * Hence we'll make a local copy of the ident string here.
675 */
676 (void) mutex_lock(&lxt_pid_lock);
677 (void) strlcpy(ident, data->lxt_ol_ident, sizeof (ident));
678 (void) mutex_unlock(&lxt_pid_lock);
679
680 /* Call Linx openlog(). */
681 (void) lx_call3(lxt_handles[LXTH_OPENLOG].lxth_handle,
682 (uintptr_t)ident, data->lxt_ol_logopt, data->lxt_ol_facility);
683
684 request->lxt_sa_success = 1;
685 request->lxt_sa_errno = 0;
686 *door_result = (char *)request;
687 *door_result_size = request_size;
688 }
689
690 static void
691 /*ARGSUSED*/
692 lxt_server_syslog(lxt_server_arg_t *request, size_t request_size,
693 char **door_result, size_t *door_result_size)
694 {
695 lxt_syslog_arg_t *data;
696 int data_size;
697 char *progname_ptr_new;
698 char *progname_ptr_old;
699
700 assert(request->lxt_sa_op == LXT_SERVER_OP_SYSLOG);
701
702 /*LINTED*/
703 data = (lxt_syslog_arg_t *)&request->lxt_sa_data[0];
704 data_size = request_size - sizeof (*request);
705
706 if (data_size != sizeof (*data)) {
707 lx_debug("lxt_server_openlog: invalid request");
708 *door_result = NULL;
709 *door_result_size = 0;
710 return;
711 }
712 progname_ptr_new = data->lxt_sl_progname;
713
714 (void) mutex_lock(&lxt_pid_lock);
715
716 /*
717 * Ensure the message has the correct pid.
718 * We do this by telling our getpid() system call to return a
719 * different value.
720 */
721 lxt_pid = data->lxt_sl_pid;
722
723 /*
724 * Ensure the message has the correct program name.
725 * Normally instead of a program name an "ident" string is
726 * used, this is the string passed to openlog(). But if
727 * openlog() wasn't called before syslog() then Linux
728 * syslog() will attempt to use the program name as
729 * the ident string, and the program name is determined
730 * by looking at the __progname variable. So we'll just
731 * update the Linux __progname variable while we do the
732 * call.
733 */
734 (void) uucopy(lxt_handles[LXTH_PROGNAME].lxth_handle,
735 &progname_ptr_old, sizeof (char *));
736 (void) uucopy(&progname_ptr_new,
737 lxt_handles[LXTH_PROGNAME].lxth_handle, sizeof (char *));
738
739 /* Call Linux syslog(). */
740 (void) lx_call2(lxt_handles[LXTH_SYSLOG].lxth_handle,
741 data->lxt_sl_priority, (uintptr_t)data->lxt_sl_message);
742
743 /* Restore pid and program name. */
744 (void) uucopy(&progname_ptr_old,
745 lxt_handles[LXTH_PROGNAME].lxth_handle, sizeof (char *));
746 lxt_pid = NULL;
747
748 (void) mutex_unlock(&lxt_pid_lock);
749
750 request->lxt_sa_success = 1;
751 request->lxt_sa_errno = 0;
752 *door_result = (char *)request;
753 *door_result_size = request_size;
754 }
755
756 static void
757 /*ARGSUSED*/
758 lxt_server_closelog(lxt_server_arg_t *request, size_t request_size,
759 char **door_result, size_t *door_result_size)
760 {
761 int data_size;
762
763 assert(request->lxt_sa_op == LXT_SERVER_OP_CLOSELOG);
764
765 data_size = request_size - sizeof (*request);
766 if (data_size != 0) {
767 lx_debug("lxt_server_closelog: invalid request");
768 *door_result = NULL;
769 *door_result_size = 0;
770 return;
771 }
772
773 /* Call Linux closelog(). */
774 (void) lx_call0(lxt_handles[LXTH_CLOSELOG].lxth_handle);
775
776 request->lxt_sa_success = 1;
777 request->lxt_sa_errno = 0;
778 *door_result = (char *)request;
779 *door_result_size = request_size;
780 }
781
782 static void
783 /*ARGSUSED*/
784 lxt_server(void *cookie, char *argp, size_t request_size,
785 door_desc_t *dp, uint_t n_desc)
786 {
787 /*LINTED*/
788 lxt_server_arg_t *request = (lxt_server_arg_t *)argp;
789 lxt_req_t lxt_req;
790 char *door_path = cookie;
791
792 /* Check if there's no callers left */
793 if (argp == DOOR_UNREF_DATA) {
794 (void) fdetach(door_path);
795 (void) unlink(door_path);
796 lx_debug("lxt_thunk_server: no clients, exiting");
797 exit(0);
798 }
799
800 /* Sanity check the incomming request. */
801 if (request_size < sizeof (*request)) {
802 /* the lookup failed */
803 lx_debug("lxt_thunk_server: invalid request size");
804 (void) door_return(NULL, 0, NULL, 0);
805 return;
806 }
807
808 if ((request->lxt_sa_op < LXT_SERVER_OP_MIN) ||
809 (request->lxt_sa_op > LXT_SERVER_OP_MAX)) {
810 lx_debug("lxt_thunk_server: invalid request op");
811 (void) door_return(NULL, 0, NULL, 0);
812 return;
813 }
814
815 /* Handle ping requests immediatly, return here. */
816 if (request->lxt_sa_op == LXT_SERVER_OP_PING) {
817 lx_debug("lxt_thunk_server: handling ping request");
818 request->lxt_sa_success = 1;
819 (void) door_return((char *)request, request_size, NULL, 0);
820 return;
821 }
822
823 lx_debug("lxt_thunk_server: hand off request to Linux thread, "
824 "request = 0x%p", request);
825
826 /* Pack the request up so we can pass it to a Linux thread. */
827 lxt_req.lxtr_request = request;
828 lxt_req.lxtr_request_size = request_size;
829 lxt_req.lxtr_result = NULL;
830 lxt_req.lxtr_result_size = 0;
831 lxt_req.lxtr_complete = 0;
832 (void) cond_init(&lxt_req.lxtr_complete_cv, USYNC_THREAD, NULL);
833
834 /* Pass the request onto a Linux thread. */
835 (void) mutex_lock(&lxt_req_lock);
836 while (lxt_req_ptr != NULL)
837 (void) cond_wait(&lxt_req_cv, &lxt_req_lock);
838 lxt_req_ptr = &lxt_req;
839 (void) cond_broadcast(&lxt_req_cv);
840
841 /* Wait for the request to be completed. */
842 while (lxt_req.lxtr_complete == 0)
843 (void) cond_wait(&lxt_req.lxtr_complete_cv, &lxt_req_lock);
844 assert(lxt_req_ptr != &lxt_req);
845 (void) mutex_unlock(&lxt_req_lock);
846
847 lx_debug("lxt_thunk_server: hand off request completed, "
848 "request = 0x%p", request);
849
850 /*
851 * If door_return() is successfull it never returns, so if we made
852 * it here there was some kind of error, but there's nothing we can
853 * really do about it.
854 */
855 (void) door_return(
856 lxt_req.lxtr_result, lxt_req.lxtr_result_size, NULL, 0);
857 }
858
859 static void
860 lxt_server_loop(void)
861 {
862 lxt_req_t *lxt_req;
863 lxt_server_arg_t *request;
864 size_t request_size;
865 char *door_result;
866 size_t door_result_size;
867
868 for (;;) {
869 /* Wait for a request from a doors server thread. */
870 (void) mutex_lock(&lxt_req_lock);
871 while (lxt_req_ptr == NULL)
872 (void) cond_wait(&lxt_req_cv, &lxt_req_lock);
873
874 /* We got a request, get a local pointer to it. */
875 lxt_req = lxt_req_ptr;
876 lxt_req_ptr = NULL;
877 (void) cond_broadcast(&lxt_req_cv);
878 (void) mutex_unlock(&lxt_req_lock);
879
880 /* Get a pointer to the request. */
881 request = lxt_req->lxtr_request;
882 request_size = lxt_req->lxtr_request_size;
883
884 lx_debug("lxt_server_loop: Linux thread request recieved, "
885 "request = %p", request);
886
887 /* Dispatch the request. */
888 assert((request->lxt_sa_op > LXT_SERVER_OP_PING) ||
889 (request->lxt_sa_op < LXT_SERVER_OP_MAX));
890 lxt_operations[request->lxt_sa_op].lxto_fp(
891 request, request_size, &door_result, &door_result_size);
892
893 lx_debug("lxt_server_loop: Linux thread request completed, "
894 "request = %p", request);
895
896 (void) mutex_lock(&lxt_req_lock);
897
898 /* Set the result pointers for the calling door thread. */
899 lxt_req->lxtr_result = door_result;
900 lxt_req->lxtr_result_size = door_result_size;
901
902 /* Let the door thread know we're done. */
903 lxt_req->lxtr_complete = 1;
904 (void) cond_signal(&lxt_req->lxtr_complete_cv);
905
906 (void) mutex_unlock(&lxt_req_lock);
907 }
908 /*NOTREACHED*/
909 }
910
911 static void
912 lxt_server_enter(int fifo1_wr, int fifo2_rd)
913 {
914 struct stat stat;
915 char door_path[MAXPATHLEN];
916 int i, dfd, junk = 0;
917
918 /*
919 * Do some sanity checks. Make sure we've got the fifos
920 * we need passed to us on the correct file descriptors.
921 */
922 if ((fstat(fifo1_wr, &stat) != 0) ||
923 ((stat.st_mode & S_IFMT) != S_IFIFO) ||
924 (fstat(fifo2_rd, &stat) != 0) ||
925 ((stat.st_mode & S_IFMT) != S_IFIFO)) {
926 lx_err("lx_thunk server aborting, can't contact parent");
927 exit(-1);
928 }
929
930 /*
931 * Get the initial Linux call handle so we can invoke other
932 * Linux calls.
933 */
934 lxh_init = lx_call_init();
935 if (lxh_init == NULL) {
936 lx_err("lx_thunk server aborting, failed Linux call init");
937 exit(-1);
938 }
939
940 /* Now lookup other Linux symbols we'll need access to. */
941 for (i = 0; lxt_handles[i].lxth_name != NULL; i++) {
942 assert(lxt_handles[i].lxth_index == i);
943 if ((lxt_handles[i].lxth_handle = lx_call_dlsym(lxh_init,
944 lxt_handles[i].lxth_name)) == NULL) {
945 lx_err("lx_thunk server aborting, "
946 "failed Linux symbol lookup: %s",
947 lxt_handles[i].lxth_name);
948 exit(-1);
949 }
950 }
951
952 /* get the path to the door server */
953 if (read(fifo2_rd, door_path, sizeof (door_path)) < 0) {
954 lx_err("lxt_server_enter: failed to get door path");
955 exit(-1);
956 }
957 (void) close(fifo2_rd);
958
959 /* Create the door server. */
960 if ((dfd = door_create(lxt_server, door_path,
961 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
962 lx_err("lxt_server_enter: door_create() failed");
963 exit(-1);
964 }
965
966 /* Attach the door to a file system path. */
967 (void) fdetach(door_path);
968 if (fattach(dfd, door_path) < 0) {
969 lx_err("lxt_server_enter: fattach() failed");
970 exit(-1);
971 }
972
973 /* The door server is ready, signal this via a fifo write */
974 (void) write(fifo1_wr, &junk, 1);
975 (void) close(fifo1_wr);
976
977 lx_debug("lxt_server_enter: doors server initialized");
978 lxt_server_loop();
979 /*NOTREACHED*/
980 }
981
982 void
983 lxt_server_exec_check(void)
984 {
985 if (lxt_server_processes == 0)
986 return;
987
988 /*
989 * We're a thunk server process, so we take over control of
990 * the current Linux process here.
991 */
992 lx_debug("lx_thunk server initalization starting");
993 lxt_server_enter(LXT_SERVER_FIFO_WR_FD, LXT_SERVER_FIFO_RD_FD);
994 /*NOTREACHED*/
995 }
996
997 void
998 lxt_server_init(int argc, char *argv[])
999 {
1000 /*
1001 * The thunk server process is a shell script named LXT_SERVER_BINARY.
1002 * It is executed without any parameters. Since it's a shell script
1003 * the arguments passed to the shell's main entry point are:
1004 * 1) the name of the shell
1005 * 2) the name of the script to execute
1006 *
1007 * So to check if we're the thunk server process we first check
1008 * for the expected number of arduments and then we'll look at
1009 * the second parameter to see if it's LXT_SERVER_BINARY.
1010 */
1011 if ((argc != 2) ||
1012 (strcmp(argv[1], LXT_SERVER_BINARY) != 0))
1013 return;
1014
1015 lxt_server_processes = 1;
1016 lx_debug("lx_thunk server detected, delaying initalization");
1017 }
1018
1019 int
1020 lxt_server_pid(int *pid)
1021 {
1022 if (lxt_server_processes == 0)
1023 return (0);
1024 *pid = lxt_pid;
1025 return (1);
1026 }