1 /*- 2 * Copyright (c) 2013-16, Stacey D. Son 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/ctype.h> 32 #include <sys/exec.h> 33 #include <sys/imgact.h> 34 #include <sys/imgact_binmisc.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/mutex.h> 39 #include <sys/sbuf.h> 40 #include <sys/sysctl.h> 41 #include <sys/sx.h> 42 43 #include <machine/atomic.h> 44 45 /** 46 * Miscellaneous binary interpreter image activator. 47 * 48 * If the given target executable's header matches 'xbe_magic' field in the 49 * 'interpreter_list' then it will use the user-level interpreter specified in 50 * the 'xbe_interpreter' field to execute the binary. The 'xbe_magic' field may 51 * be adjusted to a given offset using the value in the 'xbe_moffset' field 52 * and bits of the header may be masked using the 'xbe_mask' field. The 53 * 'interpreter_list' entries are managed using sysctl(3) as described in the 54 * <sys/imgact_binmisc.h> file. 55 */ 56 57 /* 58 * Node of the interpreter list. 59 */ 60 typedef struct imgact_binmisc_entry { 61 SLIST_ENTRY(imgact_binmisc_entry) link; 62 char *ibe_name; 63 uint8_t *ibe_magic; 64 uint8_t *ibe_mask; 65 uint8_t *ibe_interpreter; 66 uint32_t ibe_interp_argcnt; 67 uint32_t ibe_interp_length; 68 uint32_t ibe_flags; 69 uint32_t ibe_moffset; 70 uint32_t ibe_msize; 71 } imgact_binmisc_entry_t; 72 73 /* 74 * sysctl() commands. 75 */ 76 #define IBC_ADD 1 /* Add given entry. */ 77 #define IBC_REMOVE 2 /* Remove entry for a given name. */ 78 #define IBC_DISABLE 3 /* Disable entry for a given name. */ 79 #define IBC_ENABLE 4 /* Enable entry for a given name. */ 80 #define IBC_LOOKUP 5 /* Lookup and return entry for given name. */ 81 #define IBC_LIST 6 /* Get a snapshot of the interpretor list. */ 82 83 /* 84 * Interpreter string macros. 85 * 86 * They all start with '#' followed by a single letter: 87 */ 88 #define ISM_POUND '#' /* "##" is the escape sequence for single #. */ 89 #define ISM_OLD_ARGV0 'a' /* "#a" is replaced with the old argv0. */ 90 91 MALLOC_DEFINE(M_BINMISC, KMOD_NAME, "misc binary image activator"); 92 93 /* The interpreter list. */ 94 static SLIST_HEAD(, imgact_binmisc_entry) interpreter_list = 95 SLIST_HEAD_INITIALIZER(interpreter_list); 96 97 static int interp_list_entry_count; 98 99 static struct sx interp_list_sx; 100 101 #define INTERP_LIST_WLOCK() sx_xlock(&interp_list_sx) 102 #define INTERP_LIST_RLOCK() sx_slock(&interp_list_sx) 103 #define INTERP_LIST_WUNLOCK() sx_xunlock(&interp_list_sx) 104 #define INTERP_LIST_RUNLOCK() sx_sunlock(&interp_list_sx) 105 106 #define INTERP_LIST_LOCK_INIT() sx_init(&interp_list_sx, KMOD_NAME) 107 #define INTERP_LIST_LOCK_DESTROY() sx_destroy(&interp_list_sx) 108 109 #define INTERP_LIST_ASSERT_LOCKED() sx_assert(&interp_list_sx, SA_LOCKED) 110 111 /* 112 * Populate the entry with the information about the interpreter. 113 */ 114 static void 115 imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe) 116 { 117 uint32_t len = 0, argc = 1; 118 char t[IBE_INTERP_LEN_MAX]; 119 char *sp, *tp; 120 121 memset(t, 0, sizeof(t)); 122 123 /* 124 * Normalize interpreter string. Replace white space between args with 125 * single space. 126 */ 127 sp = str; tp = t; 128 while (*sp != '\0') { 129 if (*sp == ' ' || *sp == '\t') { 130 if (++len >= IBE_INTERP_LEN_MAX) 131 break; 132 *tp++ = ' '; 133 argc++; 134 while (*sp == ' ' || *sp == '\t') 135 sp++; 136 continue; 137 } else { 138 *tp++ = *sp++; 139 len++; 140 } 141 } 142 *tp = '\0'; 143 len++; 144 145 ibe->ibe_interpreter = malloc(len, M_BINMISC, M_WAITOK|M_ZERO); 146 147 /* Populate all the ibe fields for the interpreter. */ 148 memcpy(ibe->ibe_interpreter, t, len); 149 ibe->ibe_interp_argcnt = argc; 150 ibe->ibe_interp_length = len; 151 } 152 153 /* 154 * Allocate memory and populate a new entry for the interpreter table. 155 */ 156 static imgact_binmisc_entry_t * 157 imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe) 158 { 159 imgact_binmisc_entry_t *ibe = NULL; 160 size_t namesz = min(strlen(xbe->xbe_name) + 1, IBE_NAME_MAX); 161 162 ibe = malloc(sizeof(*ibe), M_BINMISC, M_WAITOK|M_ZERO); 163 164 ibe->ibe_name = malloc(namesz, M_BINMISC, M_WAITOK|M_ZERO); 165 strlcpy(ibe->ibe_name, xbe->xbe_name, namesz); 166 167 imgact_binmisc_populate_interp(xbe->xbe_interpreter, ibe); 168 169 ibe->ibe_magic = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO); 170 memcpy(ibe->ibe_magic, xbe->xbe_magic, xbe->xbe_msize); 171 172 ibe->ibe_mask = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO); 173 memcpy(ibe->ibe_mask, xbe->xbe_mask, xbe->xbe_msize); 174 175 ibe->ibe_moffset = xbe->xbe_moffset; 176 ibe->ibe_msize = xbe->xbe_msize; 177 ibe->ibe_flags = xbe->xbe_flags; 178 179 return (ibe); 180 } 181 182 /* 183 * Free the allocated memory for a given list item. 184 */ 185 static void 186 imgact_binmisc_destroy_entry(imgact_binmisc_entry_t *ibe) 187 { 188 if (!ibe) 189 return; 190 if (ibe->ibe_magic) 191 free(ibe->ibe_magic, M_BINMISC); 192 if (ibe->ibe_mask) 193 free(ibe->ibe_mask, M_BINMISC); 194 if (ibe->ibe_interpreter) 195 free(ibe->ibe_interpreter, M_BINMISC); 196 if (ibe->ibe_name) 197 free(ibe->ibe_name, M_BINMISC); 198 if (ibe) 199 free(ibe, M_BINMISC); 200 } 201 202 /* 203 * Find the interpreter in the list by the given name. Return NULL if not 204 * found. 205 */ 206 static imgact_binmisc_entry_t * 207 imgact_binmisc_find_entry(char *name) 208 { 209 imgact_binmisc_entry_t *ibe; 210 211 INTERP_LIST_ASSERT_LOCKED(); 212 213 SLIST_FOREACH(ibe, &interpreter_list, link) { 214 if (strncmp(name, ibe->ibe_name, IBE_NAME_MAX) == 0) 215 return (ibe); 216 } 217 218 return (NULL); 219 } 220 221 /* 222 * Add the given interpreter if it doesn't already exist. Return EEXIST 223 * if the name already exist in the interpreter list. 224 */ 225 static int 226 imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe) 227 { 228 imgact_binmisc_entry_t *ibe; 229 char *p; 230 int cnt; 231 232 if (xbe->xbe_msize > IBE_MAGIC_MAX) 233 return (EINVAL); 234 235 for(cnt = 0, p = xbe->xbe_name; *p != 0; cnt++, p++) 236 if (cnt >= IBE_NAME_MAX || !isascii((int)*p)) 237 return (EINVAL); 238 239 for(cnt = 0, p = xbe->xbe_interpreter; *p != 0; cnt++, p++) 240 if (cnt >= IBE_INTERP_LEN_MAX || !isascii((int)*p)) 241 return (EINVAL); 242 243 /* Make sure we don't have any invalid #'s. */ 244 p = xbe->xbe_interpreter; 245 while (1) { 246 p = strchr(p, '#'); 247 if (!p) 248 break; 249 250 p++; 251 switch(*p) { 252 case ISM_POUND: 253 /* "##" */ 254 p++; 255 break; 256 257 case ISM_OLD_ARGV0: 258 /* "#a" */ 259 p++; 260 break; 261 262 case 0: 263 default: 264 /* Anything besides the above is invalid. */ 265 return (EINVAL); 266 } 267 } 268 269 INTERP_LIST_WLOCK(); 270 if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) { 271 INTERP_LIST_WUNLOCK(); 272 return (EEXIST); 273 } 274 275 /* Preallocate a new entry. */ 276 ibe = imgact_binmisc_new_entry(xbe); 277 278 SLIST_INSERT_HEAD(&interpreter_list, ibe, link); 279 interp_list_entry_count++; 280 INTERP_LIST_WUNLOCK(); 281 282 return (0); 283 } 284 285 /* 286 * Remove the interpreter in the list with the given name. Return ENOENT 287 * if not found. 288 */ 289 static int 290 imgact_binmisc_remove_entry(char *name) 291 { 292 imgact_binmisc_entry_t *ibe; 293 294 INTERP_LIST_WLOCK(); 295 if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 296 INTERP_LIST_WUNLOCK(); 297 return (ENOENT); 298 } 299 SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link); 300 interp_list_entry_count--; 301 INTERP_LIST_WUNLOCK(); 302 303 imgact_binmisc_destroy_entry(ibe); 304 305 return (0); 306 } 307 308 /* 309 * Disable the interpreter in the list with the given name. Return ENOENT 310 * if not found. 311 */ 312 static int 313 imgact_binmisc_disable_entry(char *name) 314 { 315 imgact_binmisc_entry_t *ibe; 316 317 INTERP_LIST_WLOCK(); 318 if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 319 INTERP_LIST_WUNLOCK(); 320 return (ENOENT); 321 } 322 323 ibe->ibe_flags &= ~IBF_ENABLED; 324 INTERP_LIST_WUNLOCK(); 325 326 return (0); 327 } 328 329 /* 330 * Enable the interpreter in the list with the given name. Return ENOENT 331 * if not found. 332 */ 333 static int 334 imgact_binmisc_enable_entry(char *name) 335 { 336 imgact_binmisc_entry_t *ibe; 337 338 INTERP_LIST_WLOCK(); 339 if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 340 INTERP_LIST_WUNLOCK(); 341 return (ENOENT); 342 } 343 344 ibe->ibe_flags |= IBF_ENABLED; 345 INTERP_LIST_WUNLOCK(); 346 347 return (0); 348 } 349 350 static int 351 imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe, 352 imgact_binmisc_entry_t *ibe) 353 { 354 uint32_t i; 355 356 INTERP_LIST_ASSERT_LOCKED(); 357 memset(xbe, 0, sizeof(*xbe)); 358 strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX); 359 360 /* Copy interpreter string. Replace NULL breaks with space. */ 361 memcpy(xbe->xbe_interpreter, ibe->ibe_interpreter, 362 ibe->ibe_interp_length); 363 for(i = 0; i < (ibe->ibe_interp_length - 1); i++) 364 if (xbe->xbe_interpreter[i] == '\0') 365 xbe->xbe_interpreter[i] = ' '; 366 367 memcpy(xbe->xbe_magic, ibe->ibe_magic, ibe->ibe_msize); 368 memcpy(xbe->xbe_mask, ibe->ibe_mask, ibe->ibe_msize); 369 xbe->xbe_version = IBE_VERSION; 370 xbe->xbe_flags = ibe->ibe_flags; 371 xbe->xbe_moffset = ibe->ibe_moffset; 372 xbe->xbe_msize = ibe->ibe_msize; 373 374 return (0); 375 } 376 377 /* 378 * Retrieve the interpreter with the give name and populate the 379 * ximgact_binmisc_entry structure. Return ENOENT if not found. 380 */ 381 static int 382 imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe) 383 { 384 imgact_binmisc_entry_t *ibe; 385 int error = 0; 386 387 INTERP_LIST_RLOCK(); 388 if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 389 INTERP_LIST_RUNLOCK(); 390 return (ENOENT); 391 } 392 393 error = imgact_binmisc_populate_xbe(xbe, ibe); 394 INTERP_LIST_RUNLOCK(); 395 396 return (error); 397 } 398 399 /* 400 * Get a snapshot of all the interpreter entries in the list. 401 */ 402 static int 403 imgact_binmisc_get_all_entries(struct sysctl_req *req) 404 { 405 ximgact_binmisc_entry_t *xbe, *xbep; 406 imgact_binmisc_entry_t *ibe; 407 int error = 0, count; 408 409 INTERP_LIST_RLOCK(); 410 count = interp_list_entry_count; 411 xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_WAITOK|M_ZERO); 412 413 xbep = xbe; 414 SLIST_FOREACH(ibe, &interpreter_list, link) { 415 error = imgact_binmisc_populate_xbe(xbep++, ibe); 416 if (error) 417 break; 418 } 419 INTERP_LIST_RUNLOCK(); 420 421 if (!error) 422 error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count); 423 424 free(xbe, M_BINMISC); 425 return (error); 426 } 427 428 /* 429 * sysctl() handler for munipulating interpretor table. 430 * Not MP safe (locked by sysctl). 431 */ 432 static int 433 sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS) 434 { 435 ximgact_binmisc_entry_t xbe; 436 int error = 0; 437 438 switch(arg2) { 439 case IBC_ADD: 440 /* Add an entry. Limited to IBE_MAX_ENTRIES. */ 441 error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 442 if (error) 443 return (error); 444 if (IBE_VERSION != xbe.xbe_version) 445 return (EINVAL); 446 if ((xbe.xbe_flags & ~IBF_VALID_UFLAGS) != 0) 447 return (EINVAL); 448 if (interp_list_entry_count == IBE_MAX_ENTRIES) 449 return (ENOSPC); 450 error = imgact_binmisc_add_entry(&xbe); 451 break; 452 453 case IBC_REMOVE: 454 /* Remove an entry. */ 455 error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 456 if (error) 457 return (error); 458 if (IBE_VERSION != xbe.xbe_version) 459 return (EINVAL); 460 error = imgact_binmisc_remove_entry(xbe.xbe_name); 461 break; 462 463 case IBC_DISABLE: 464 /* Disable an entry. */ 465 error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 466 if (error) 467 return (error); 468 if (IBE_VERSION != xbe.xbe_version) 469 return (EINVAL); 470 error = imgact_binmisc_disable_entry(xbe.xbe_name); 471 break; 472 473 case IBC_ENABLE: 474 /* Enable an entry. */ 475 error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 476 if (error) 477 return (error); 478 if (IBE_VERSION != xbe.xbe_version) 479 return (EINVAL); 480 error = imgact_binmisc_enable_entry(xbe.xbe_name); 481 break; 482 483 case IBC_LOOKUP: 484 /* Lookup an entry. */ 485 error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 486 if (error) 487 return (error); 488 if (IBE_VERSION != xbe.xbe_version) 489 return (EINVAL); 490 error = imgact_binmisc_lookup_entry(xbe.xbe_name, &xbe); 491 if (!error) 492 error = SYSCTL_OUT(req, &xbe, sizeof(xbe)); 493 break; 494 495 case IBC_LIST: 496 /* Return a snapshot of the interpretor list. */ 497 498 if (!req->oldptr) { 499 /* No pointer then just return the list size. */ 500 error = SYSCTL_OUT(req, 0, interp_list_entry_count * 501 sizeof(ximgact_binmisc_entry_t)); 502 return (error); 503 } else 504 if (!req->oldlen) 505 return (EINVAL); 506 507 error = imgact_binmisc_get_all_entries(req); 508 break; 509 510 default: 511 return (EINVAL); 512 } 513 514 return (error); 515 } 516 517 SYSCTL_NODE(_kern, OID_AUTO, binmisc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 518 "Image activator for miscellaneous binaries"); 519 520 SYSCTL_PROC(_kern_binmisc, OID_AUTO, add, 521 CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ADD, 522 sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 523 "Add an activator entry"); 524 525 SYSCTL_PROC(_kern_binmisc, OID_AUTO, remove, 526 CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_REMOVE, 527 sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 528 "Remove an activator entry"); 529 530 SYSCTL_PROC(_kern_binmisc, OID_AUTO, disable, 531 CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_DISABLE, 532 sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 533 "Disable an activator entry"); 534 535 SYSCTL_PROC(_kern_binmisc, OID_AUTO, enable, 536 CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ENABLE, 537 sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 538 "Enable an activator entry"); 539 540 SYSCTL_PROC(_kern_binmisc, OID_AUTO, lookup, 541 CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RW|CTLFLAG_ANYBODY, NULL, IBC_LOOKUP, 542 sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 543 "Lookup an activator entry"); 544 545 SYSCTL_PROC(_kern_binmisc, OID_AUTO, list, 546 CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RD|CTLFLAG_ANYBODY, NULL, IBC_LIST, 547 sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 548 "Get snapshot of all the activator entries"); 549 550 static imgact_binmisc_entry_t * 551 imgact_binmisc_find_interpreter(const char *image_header) 552 { 553 imgact_binmisc_entry_t *ibe; 554 const char *p; 555 int i; 556 size_t sz; 557 558 INTERP_LIST_ASSERT_LOCKED(); 559 560 SLIST_FOREACH(ibe, &interpreter_list, link) { 561 if (!(IBF_ENABLED & ibe->ibe_flags)) 562 continue; 563 564 p = image_header + ibe->ibe_moffset; 565 sz = ibe->ibe_msize; 566 if (IBF_USE_MASK & ibe->ibe_flags) { 567 /* Compare using mask. */ 568 for (i = 0; i < sz; i++) 569 if ((*p++ ^ ibe->ibe_magic[i]) & 570 ibe->ibe_mask[i]) 571 break; 572 } else { 573 for (i = 0; i < sz; i++) 574 if (*p++ ^ ibe->ibe_magic[i]) 575 break; 576 } 577 if (i == ibe->ibe_msize) 578 return (ibe); 579 } 580 return (NULL); 581 } 582 583 static int 584 imgact_binmisc_exec(struct image_params *imgp) 585 { 586 const char *image_header = imgp->image_header; 587 const char *fname = NULL; 588 int error = 0; 589 size_t offset, l; 590 imgact_binmisc_entry_t *ibe; 591 struct sbuf *sname; 592 char *s, *d; 593 594 sname = NULL; 595 /* Do we have an interpreter for the given image header? */ 596 INTERP_LIST_RLOCK(); 597 if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) { 598 error = -1; 599 goto done; 600 } 601 602 /* No interpreter nesting allowed. */ 603 if (imgp->interpreted & IMGACT_BINMISC) { 604 error = ENOEXEC; 605 goto done; 606 } 607 608 imgp->interpreted |= IMGACT_BINMISC; 609 610 if (imgp->args->fname != NULL) { 611 fname = imgp->args->fname; 612 } else { 613 /* Use the fdescfs(5) path for fexecve(2). */ 614 sname = sbuf_new_auto(); 615 sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd); 616 sbuf_finish(sname); 617 fname = sbuf_data(sname); 618 } 619 620 /* 621 * We need to "push" the interpreter in the arg[] list. To do this, 622 * we first shift all the other values in the `begin_argv' area to 623 * provide the exact amount of room for the values added. Set up 624 * `offset' as the number of bytes to be added to the `begin_argv' 625 * area. 626 */ 627 offset = ibe->ibe_interp_length; 628 629 /* Adjust the offset for #'s. */ 630 s = ibe->ibe_interpreter; 631 while (1) { 632 s = strchr(s, '#'); 633 if (!s) 634 break; 635 636 s++; 637 switch(*s) { 638 case ISM_POUND: 639 /* "##" -> "#": reduce offset by one. */ 640 offset--; 641 break; 642 643 case ISM_OLD_ARGV0: 644 /* "#a" -> (old argv0): increase offset to fit fname */ 645 offset += strlen(fname) - 2; 646 break; 647 648 default: 649 /* Hmm... This shouldn't happen. */ 650 printf("%s: Unknown macro #%c sequence in " 651 "interpreter string\n", KMOD_NAME, *(s + 1)); 652 error = EINVAL; 653 goto done; 654 } 655 s++; 656 } 657 658 /* Make room for the interpreter */ 659 error = exec_args_adjust_args(imgp->args, 0, offset); 660 if (error != 0) { 661 goto done; 662 } 663 664 /* Add the new argument(s) in the count. */ 665 imgp->args->argc += ibe->ibe_interp_argcnt; 666 667 /* 668 * The original arg[] list has been shifted appropriately. Copy in 669 * the interpreter path. 670 */ 671 s = ibe->ibe_interpreter; 672 d = imgp->args->begin_argv; 673 while(*s != '\0') { 674 switch (*s) { 675 case '#': 676 /* Handle "#" in interpreter string. */ 677 s++; 678 switch(*s) { 679 case ISM_POUND: 680 /* "##": Replace with a single '#' */ 681 *d++ = '#'; 682 break; 683 684 case ISM_OLD_ARGV0: 685 /* "#a": Replace with old arg0 (fname). */ 686 if ((l = strlen(fname)) != 0) { 687 memcpy(d, fname, l); 688 d += l; 689 } 690 break; 691 692 default: 693 /* Shouldn't happen but skip it if it does. */ 694 break; 695 } 696 break; 697 698 case ' ': 699 /* Replace space with NUL to separate arguments. */ 700 *d++ = '\0'; 701 break; 702 703 default: 704 *d++ = *s; 705 break; 706 } 707 s++; 708 } 709 *d = '\0'; 710 711 imgp->interpreter_name = imgp->args->begin_argv; 712 713 done: 714 INTERP_LIST_RUNLOCK(); 715 if (sname) 716 sbuf_delete(sname); 717 return (error); 718 } 719 720 static void 721 imgact_binmisc_init(void *arg) 722 { 723 724 INTERP_LIST_LOCK_INIT(); 725 } 726 727 static void 728 imgact_binmisc_fini(void *arg) 729 { 730 imgact_binmisc_entry_t *ibe, *ibe_tmp; 731 732 /* Free all the interpreters. */ 733 INTERP_LIST_WLOCK(); 734 SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) { 735 SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, 736 link); 737 imgact_binmisc_destroy_entry(ibe); 738 } 739 INTERP_LIST_WUNLOCK(); 740 741 INTERP_LIST_LOCK_DESTROY(); 742 } 743 744 SYSINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_init, 745 NULL); 746 SYSUNINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_fini, 747 NULL); 748 749 /* 750 * Tell kern_execve.c about it, with a little help from the linker. 751 */ 752 static struct execsw imgact_binmisc_execsw = { 753 .ex_imgact = imgact_binmisc_exec, 754 .ex_name = KMOD_NAME 755 }; 756 EXEC_SET(imgact_binmisc, imgact_binmisc_execsw); 757