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