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