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 }