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