16d756449SSean Bruno /*- 2910938f0SSean Bruno * Copyright (c) 2013-16, Stacey D. Son 36d756449SSean Bruno * All rights reserved. 46d756449SSean Bruno * 56d756449SSean Bruno * Redistribution and use in source and binary forms, with or without 66d756449SSean Bruno * modification, are permitted provided that the following conditions 76d756449SSean Bruno * are met: 86d756449SSean Bruno * 1. Redistributions of source code must retain the above copyright 96d756449SSean Bruno * notice, this list of conditions and the following disclaimer. 106d756449SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright 116d756449SSean Bruno * notice, this list of conditions and the following disclaimer in the 126d756449SSean Bruno * documentation and/or other materials provided with the distribution. 136d756449SSean Bruno * 146d756449SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156d756449SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166d756449SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176d756449SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 186d756449SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 196d756449SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 206d756449SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 216d756449SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226d756449SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236d756449SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 246d756449SSean Bruno * SUCH DAMAGE. 256d756449SSean Bruno */ 266d756449SSean Bruno 276d756449SSean Bruno #include <sys/cdefs.h> 286d756449SSean Bruno __FBSDID("$FreeBSD$"); 296d756449SSean Bruno 306d756449SSean Bruno #include <sys/param.h> 316d756449SSean Bruno #include <sys/ctype.h> 326d756449SSean Bruno #include <sys/exec.h> 33*5eeb4f73SDoug Rabson #include <sys/fcntl.h> 346d756449SSean Bruno #include <sys/imgact.h> 356d756449SSean Bruno #include <sys/imgact_binmisc.h> 366d756449SSean Bruno #include <sys/kernel.h> 376d756449SSean Bruno #include <sys/lock.h> 386d756449SSean Bruno #include <sys/malloc.h> 396d756449SSean Bruno #include <sys/mutex.h> 40*5eeb4f73SDoug Rabson #include <sys/namei.h> 41df69035dSKyle Evans #include <sys/sbuf.h> 426d756449SSean Bruno #include <sys/sysctl.h> 435f98711dSSean Bruno #include <sys/sx.h> 44*5eeb4f73SDoug Rabson #include <sys/vnode.h> 455f98711dSSean Bruno 465f98711dSSean Bruno #include <machine/atomic.h> 476d756449SSean Bruno 486d756449SSean Bruno /** 496d756449SSean Bruno * Miscellaneous binary interpreter image activator. 506d756449SSean Bruno * 516d756449SSean Bruno * If the given target executable's header matches 'xbe_magic' field in the 526d756449SSean Bruno * 'interpreter_list' then it will use the user-level interpreter specified in 536d756449SSean Bruno * the 'xbe_interpreter' field to execute the binary. The 'xbe_magic' field may 546d756449SSean Bruno * be adjusted to a given offset using the value in the 'xbe_moffset' field 556d756449SSean Bruno * and bits of the header may be masked using the 'xbe_mask' field. The 566d756449SSean Bruno * 'interpreter_list' entries are managed using sysctl(3) as described in the 576d756449SSean Bruno * <sys/imgact_binmisc.h> file. 586d756449SSean Bruno */ 596d756449SSean Bruno 606d756449SSean Bruno /* 616d756449SSean Bruno * Node of the interpreter list. 626d756449SSean Bruno */ 636d756449SSean Bruno typedef struct imgact_binmisc_entry { 64ecb4fdf9SKyle Evans SLIST_ENTRY(imgact_binmisc_entry) link; 656d756449SSean Bruno char *ibe_name; 666d756449SSean Bruno uint8_t *ibe_magic; 676d756449SSean Bruno uint8_t *ibe_mask; 686d756449SSean Bruno uint8_t *ibe_interpreter; 69*5eeb4f73SDoug Rabson struct vnode *ibe_interpreter_vnode; 701024ef27SKyle Evans ssize_t ibe_interp_offset; 716d756449SSean Bruno uint32_t ibe_interp_argcnt; 726d756449SSean Bruno uint32_t ibe_interp_length; 731024ef27SKyle Evans uint32_t ibe_argv0_cnt; 746d756449SSean Bruno uint32_t ibe_flags; 75ecb4fdf9SKyle Evans uint32_t ibe_moffset; 76ecb4fdf9SKyle Evans uint32_t ibe_msize; 776d756449SSean Bruno } imgact_binmisc_entry_t; 786d756449SSean Bruno 796d756449SSean Bruno /* 806d756449SSean Bruno * sysctl() commands. 816d756449SSean Bruno */ 826d756449SSean Bruno #define IBC_ADD 1 /* Add given entry. */ 836d756449SSean Bruno #define IBC_REMOVE 2 /* Remove entry for a given name. */ 846d756449SSean Bruno #define IBC_DISABLE 3 /* Disable entry for a given name. */ 856d756449SSean Bruno #define IBC_ENABLE 4 /* Enable entry for a given name. */ 866d756449SSean Bruno #define IBC_LOOKUP 5 /* Lookup and return entry for given name. */ 876d756449SSean Bruno #define IBC_LIST 6 /* Get a snapshot of the interpretor list. */ 886d756449SSean Bruno 896d756449SSean Bruno /* 906d756449SSean Bruno * Interpreter string macros. 916d756449SSean Bruno * 926d756449SSean Bruno * They all start with '#' followed by a single letter: 936d756449SSean Bruno */ 946d756449SSean Bruno #define ISM_POUND '#' /* "##" is the escape sequence for single #. */ 956d756449SSean Bruno #define ISM_OLD_ARGV0 'a' /* "#a" is replaced with the old argv0. */ 966d756449SSean Bruno 976d756449SSean Bruno MALLOC_DEFINE(M_BINMISC, KMOD_NAME, "misc binary image activator"); 986d756449SSean Bruno 996d756449SSean Bruno /* The interpreter list. */ 1006d756449SSean Bruno static SLIST_HEAD(, imgact_binmisc_entry) interpreter_list = 1016d756449SSean Bruno SLIST_HEAD_INITIALIZER(interpreter_list); 1026d756449SSean Bruno 103df69035dSKyle Evans static int interp_list_entry_count; 104280b7169SSean Bruno 1055f98711dSSean Bruno static struct sx interp_list_sx; 1066d756449SSean Bruno 1072192cd12SKyle Evans #define INTERP_LIST_WLOCK() sx_xlock(&interp_list_sx) 1082192cd12SKyle Evans #define INTERP_LIST_RLOCK() sx_slock(&interp_list_sx) 1092192cd12SKyle Evans #define INTERP_LIST_WUNLOCK() sx_xunlock(&interp_list_sx) 1102192cd12SKyle Evans #define INTERP_LIST_RUNLOCK() sx_sunlock(&interp_list_sx) 1112192cd12SKyle Evans 1122192cd12SKyle Evans #define INTERP_LIST_LOCK_INIT() sx_init(&interp_list_sx, KMOD_NAME) 1132192cd12SKyle Evans #define INTERP_LIST_LOCK_DESTROY() sx_destroy(&interp_list_sx) 1142192cd12SKyle Evans 1152192cd12SKyle Evans #define INTERP_LIST_ASSERT_LOCKED() sx_assert(&interp_list_sx, SA_LOCKED) 1162192cd12SKyle Evans 1176d756449SSean Bruno /* 1186d756449SSean Bruno * Populate the entry with the information about the interpreter. 1196d756449SSean Bruno */ 1206d756449SSean Bruno static void 121*5eeb4f73SDoug Rabson imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe, int flags) 1226d756449SSean Bruno { 1236d756449SSean Bruno uint32_t len = 0, argc = 1; 1246d756449SSean Bruno char t[IBE_INTERP_LEN_MAX]; 1256d756449SSean Bruno char *sp, *tp; 1266d756449SSean Bruno 1275f98711dSSean Bruno memset(t, 0, sizeof(t)); 1286d756449SSean Bruno 1296d756449SSean Bruno /* 1306d756449SSean Bruno * Normalize interpreter string. Replace white space between args with 1316d756449SSean Bruno * single space. 1326d756449SSean Bruno */ 1336d756449SSean Bruno sp = str; tp = t; 1346d756449SSean Bruno while (*sp != '\0') { 1356d756449SSean Bruno if (*sp == ' ' || *sp == '\t') { 13626af6115SEd Maste if (++len >= IBE_INTERP_LEN_MAX) 1376d756449SSean Bruno break; 1386d756449SSean Bruno *tp++ = ' '; 1396d756449SSean Bruno argc++; 1406d756449SSean Bruno while (*sp == ' ' || *sp == '\t') 1416d756449SSean Bruno sp++; 1426d756449SSean Bruno continue; 1436d756449SSean Bruno } else { 1446d756449SSean Bruno *tp++ = *sp++; 1456d756449SSean Bruno len++; 1466d756449SSean Bruno } 1476d756449SSean Bruno } 1486d756449SSean Bruno *tp = '\0'; 1496d756449SSean Bruno len++; 1506d756449SSean Bruno 1516d756449SSean Bruno ibe->ibe_interpreter = malloc(len, M_BINMISC, M_WAITOK|M_ZERO); 1526d756449SSean Bruno 1536d756449SSean Bruno /* Populate all the ibe fields for the interpreter. */ 1546d756449SSean Bruno memcpy(ibe->ibe_interpreter, t, len); 1556d756449SSean Bruno ibe->ibe_interp_argcnt = argc; 1566d756449SSean Bruno ibe->ibe_interp_length = len; 157*5eeb4f73SDoug Rabson 158*5eeb4f73SDoug Rabson ibe->ibe_interpreter_vnode = NULL; 159*5eeb4f73SDoug Rabson if (flags & IBF_PRE_OPEN) { 160*5eeb4f73SDoug Rabson struct nameidata nd; 161*5eeb4f73SDoug Rabson int error; 162*5eeb4f73SDoug Rabson 163*5eeb4f73SDoug Rabson tp = t; 164*5eeb4f73SDoug Rabson while (*tp != '\0' && *tp != ' ') { 165*5eeb4f73SDoug Rabson tp++; 166*5eeb4f73SDoug Rabson } 167*5eeb4f73SDoug Rabson *tp = '\0'; 168*5eeb4f73SDoug Rabson NDINIT(&nd, LOOKUP, FOLLOW | ISOPEN, UIO_SYSSPACE, t); 169*5eeb4f73SDoug Rabson 170*5eeb4f73SDoug Rabson /* 171*5eeb4f73SDoug Rabson * If there is an error, just stop now and fall back 172*5eeb4f73SDoug Rabson * to the non pre-open case where we lookup during 173*5eeb4f73SDoug Rabson * exec. 174*5eeb4f73SDoug Rabson */ 175*5eeb4f73SDoug Rabson error = namei(&nd); 176*5eeb4f73SDoug Rabson if (error) 177*5eeb4f73SDoug Rabson return; 178*5eeb4f73SDoug Rabson 179*5eeb4f73SDoug Rabson ibe->ibe_interpreter_vnode = nd.ni_vp; 180*5eeb4f73SDoug Rabson } 1816d756449SSean Bruno } 1826d756449SSean Bruno 1836d756449SSean Bruno /* 1846d756449SSean Bruno * Allocate memory and populate a new entry for the interpreter table. 1856d756449SSean Bruno */ 1866d756449SSean Bruno static imgact_binmisc_entry_t * 1871024ef27SKyle Evans imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe, ssize_t interp_offset, 1881024ef27SKyle Evans int argv0_cnt) 1896d756449SSean Bruno { 1906d756449SSean Bruno imgact_binmisc_entry_t *ibe = NULL; 1916d756449SSean Bruno size_t namesz = min(strlen(xbe->xbe_name) + 1, IBE_NAME_MAX); 1926d756449SSean Bruno 1936d756449SSean Bruno ibe = malloc(sizeof(*ibe), M_BINMISC, M_WAITOK|M_ZERO); 1946d756449SSean Bruno 1956d756449SSean Bruno ibe->ibe_name = malloc(namesz, M_BINMISC, M_WAITOK|M_ZERO); 1966d756449SSean Bruno strlcpy(ibe->ibe_name, xbe->xbe_name, namesz); 1976d756449SSean Bruno 198*5eeb4f73SDoug Rabson imgact_binmisc_populate_interp(xbe->xbe_interpreter, ibe, xbe->xbe_flags); 1996d756449SSean Bruno 2006d756449SSean Bruno ibe->ibe_magic = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO); 2016d756449SSean Bruno memcpy(ibe->ibe_magic, xbe->xbe_magic, xbe->xbe_msize); 2026d756449SSean Bruno 2036d756449SSean Bruno ibe->ibe_mask = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO); 2046d756449SSean Bruno memcpy(ibe->ibe_mask, xbe->xbe_mask, xbe->xbe_msize); 2056d756449SSean Bruno 2066d756449SSean Bruno ibe->ibe_moffset = xbe->xbe_moffset; 2076d756449SSean Bruno ibe->ibe_msize = xbe->xbe_msize; 2086d756449SSean Bruno ibe->ibe_flags = xbe->xbe_flags; 2091024ef27SKyle Evans ibe->ibe_interp_offset = interp_offset; 2101024ef27SKyle Evans ibe->ibe_argv0_cnt = argv0_cnt; 2116d756449SSean Bruno return (ibe); 2126d756449SSean Bruno } 2136d756449SSean Bruno 2146d756449SSean Bruno /* 2156d756449SSean Bruno * Free the allocated memory for a given list item. 2166d756449SSean Bruno */ 2176d756449SSean Bruno static void 2186d756449SSean Bruno imgact_binmisc_destroy_entry(imgact_binmisc_entry_t *ibe) 2196d756449SSean Bruno { 2206d756449SSean Bruno if (!ibe) 2216d756449SSean Bruno return; 222b888dae4SSean Bruno if (ibe->ibe_magic) 2236d756449SSean Bruno free(ibe->ibe_magic, M_BINMISC); 2246d756449SSean Bruno if (ibe->ibe_mask) 2256d756449SSean Bruno free(ibe->ibe_mask, M_BINMISC); 2266d756449SSean Bruno if (ibe->ibe_interpreter) 2276d756449SSean Bruno free(ibe->ibe_interpreter, M_BINMISC); 2286d756449SSean Bruno if (ibe->ibe_name) 2296d756449SSean Bruno free(ibe->ibe_name, M_BINMISC); 230*5eeb4f73SDoug Rabson if (ibe->ibe_interpreter_vnode) 231*5eeb4f73SDoug Rabson vrele(ibe->ibe_interpreter_vnode); 2326d756449SSean Bruno if (ibe) 2336d756449SSean Bruno free(ibe, M_BINMISC); 2346d756449SSean Bruno } 2356d756449SSean Bruno 2366d756449SSean Bruno /* 2376d756449SSean Bruno * Find the interpreter in the list by the given name. Return NULL if not 2386d756449SSean Bruno * found. 2396d756449SSean Bruno */ 2406d756449SSean Bruno static imgact_binmisc_entry_t * 2416d756449SSean Bruno imgact_binmisc_find_entry(char *name) 2426d756449SSean Bruno { 2436d756449SSean Bruno imgact_binmisc_entry_t *ibe; 2446d756449SSean Bruno 2452192cd12SKyle Evans INTERP_LIST_ASSERT_LOCKED(); 2466d756449SSean Bruno 2476d756449SSean Bruno SLIST_FOREACH(ibe, &interpreter_list, link) { 2486d756449SSean Bruno if (strncmp(name, ibe->ibe_name, IBE_NAME_MAX) == 0) 2496d756449SSean Bruno return (ibe); 2506d756449SSean Bruno } 2516d756449SSean Bruno 2526d756449SSean Bruno return (NULL); 2536d756449SSean Bruno } 2546d756449SSean Bruno 2556d756449SSean Bruno /* 2566d756449SSean Bruno * Add the given interpreter if it doesn't already exist. Return EEXIST 2576d756449SSean Bruno * if the name already exist in the interpreter list. 2586d756449SSean Bruno */ 2596d756449SSean Bruno static int 2606d756449SSean Bruno imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe) 2616d756449SSean Bruno { 2626d756449SSean Bruno imgact_binmisc_entry_t *ibe; 2636d756449SSean Bruno char *p; 2641024ef27SKyle Evans ssize_t interp_offset; 2651024ef27SKyle Evans int argv0_cnt, cnt; 2666d756449SSean Bruno 2676d756449SSean Bruno if (xbe->xbe_msize > IBE_MAGIC_MAX) 2686d756449SSean Bruno return (EINVAL); 2698c28aa5eSKyle Evans if (xbe->xbe_moffset + xbe->xbe_msize > IBE_MATCH_MAX) 2708c28aa5eSKyle Evans return (EINVAL); 2716d756449SSean Bruno 272910938f0SSean Bruno for(cnt = 0, p = xbe->xbe_name; *p != 0; cnt++, p++) 273910938f0SSean Bruno if (cnt >= IBE_NAME_MAX || !isascii((int)*p)) 2746d756449SSean Bruno return (EINVAL); 2756d756449SSean Bruno 276910938f0SSean Bruno for(cnt = 0, p = xbe->xbe_interpreter; *p != 0; cnt++, p++) 277910938f0SSean Bruno if (cnt >= IBE_INTERP_LEN_MAX || !isascii((int)*p)) 2786d756449SSean Bruno return (EINVAL); 2796d756449SSean Bruno 2806d756449SSean Bruno /* Make sure we don't have any invalid #'s. */ 2816d756449SSean Bruno p = xbe->xbe_interpreter; 2821024ef27SKyle Evans interp_offset = 0; 2831024ef27SKyle Evans argv0_cnt = 0; 2841024ef27SKyle Evans while ((p = strchr(p, '#')) != NULL) { 2856d756449SSean Bruno p++; 2866d756449SSean Bruno switch(*p) { 2876d756449SSean Bruno case ISM_POUND: 2886d756449SSean Bruno /* "##" */ 2896d756449SSean Bruno p++; 2901024ef27SKyle Evans interp_offset--; 2916d756449SSean Bruno break; 2926d756449SSean Bruno case ISM_OLD_ARGV0: 2936d756449SSean Bruno /* "#a" */ 2946d756449SSean Bruno p++; 2951024ef27SKyle Evans argv0_cnt++; 2966d756449SSean Bruno break; 2976d756449SSean Bruno case 0: 2986d756449SSean Bruno default: 2996d756449SSean Bruno /* Anything besides the above is invalid. */ 3006d756449SSean Bruno return (EINVAL); 3016d756449SSean Bruno } 3026d756449SSean Bruno } 3036d756449SSean Bruno 304*5eeb4f73SDoug Rabson /* 305*5eeb4f73SDoug Rabson * Preallocate a new entry. We do this without holding the 306*5eeb4f73SDoug Rabson * lock to avoid lock-order problems if IBF_PRE_OPEN is 307*5eeb4f73SDoug Rabson * set. 308*5eeb4f73SDoug Rabson */ 309*5eeb4f73SDoug Rabson ibe = imgact_binmisc_new_entry(xbe, interp_offset, argv0_cnt); 310*5eeb4f73SDoug Rabson 3112192cd12SKyle Evans INTERP_LIST_WLOCK(); 312280b7169SSean Bruno if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) { 3132192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 314*5eeb4f73SDoug Rabson imgact_binmisc_destroy_entry(ibe); 315280b7169SSean Bruno return (EEXIST); 316280b7169SSean Bruno } 317280b7169SSean Bruno 3186d756449SSean Bruno SLIST_INSERT_HEAD(&interpreter_list, ibe, link); 3196d756449SSean Bruno interp_list_entry_count++; 3202192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 3216d756449SSean Bruno 3226d756449SSean Bruno return (0); 3236d756449SSean Bruno } 3246d756449SSean Bruno 3256d756449SSean Bruno /* 3266d756449SSean Bruno * Remove the interpreter in the list with the given name. Return ENOENT 3276d756449SSean Bruno * if not found. 3286d756449SSean Bruno */ 3296d756449SSean Bruno static int 3306d756449SSean Bruno imgact_binmisc_remove_entry(char *name) 3316d756449SSean Bruno { 3326d756449SSean Bruno imgact_binmisc_entry_t *ibe; 3336d756449SSean Bruno 3342192cd12SKyle Evans INTERP_LIST_WLOCK(); 3356d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 3362192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 3376d756449SSean Bruno return (ENOENT); 3386d756449SSean Bruno } 3396d756449SSean Bruno SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link); 3406d756449SSean Bruno interp_list_entry_count--; 3412192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 3426d756449SSean Bruno 3436d756449SSean Bruno imgact_binmisc_destroy_entry(ibe); 3446d756449SSean Bruno 3456d756449SSean Bruno return (0); 3466d756449SSean Bruno } 3476d756449SSean Bruno 3486d756449SSean Bruno /* 3496d756449SSean Bruno * Disable the interpreter in the list with the given name. Return ENOENT 3506d756449SSean Bruno * if not found. 3516d756449SSean Bruno */ 3526d756449SSean Bruno static int 3536d756449SSean Bruno imgact_binmisc_disable_entry(char *name) 3546d756449SSean Bruno { 3556d756449SSean Bruno imgact_binmisc_entry_t *ibe; 3566d756449SSean Bruno 3572192cd12SKyle Evans INTERP_LIST_WLOCK(); 3586d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 3592192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 3606d756449SSean Bruno return (ENOENT); 3616d756449SSean Bruno } 3626d756449SSean Bruno 3634e83b32aSSean Bruno ibe->ibe_flags &= ~IBF_ENABLED; 3642192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 3656d756449SSean Bruno 3666d756449SSean Bruno return (0); 3676d756449SSean Bruno } 3686d756449SSean Bruno 3696d756449SSean Bruno /* 3706d756449SSean Bruno * Enable the interpreter in the list with the given name. Return ENOENT 3716d756449SSean Bruno * if not found. 3726d756449SSean Bruno */ 3736d756449SSean Bruno static int 3746d756449SSean Bruno imgact_binmisc_enable_entry(char *name) 3756d756449SSean Bruno { 3766d756449SSean Bruno imgact_binmisc_entry_t *ibe; 3776d756449SSean Bruno 3782192cd12SKyle Evans INTERP_LIST_WLOCK(); 3796d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 3802192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 3816d756449SSean Bruno return (ENOENT); 3826d756449SSean Bruno } 3836d756449SSean Bruno 3844e83b32aSSean Bruno ibe->ibe_flags |= IBF_ENABLED; 3852192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 3866d756449SSean Bruno 3876d756449SSean Bruno return (0); 3886d756449SSean Bruno } 3896d756449SSean Bruno 3906d756449SSean Bruno static int 3916d756449SSean Bruno imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe, 3926d756449SSean Bruno imgact_binmisc_entry_t *ibe) 3936d756449SSean Bruno { 3946d756449SSean Bruno uint32_t i; 3956d756449SSean Bruno 3962192cd12SKyle Evans INTERP_LIST_ASSERT_LOCKED(); 3975f98711dSSean Bruno memset(xbe, 0, sizeof(*xbe)); 3986d756449SSean Bruno strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX); 3996d756449SSean Bruno 4006d756449SSean Bruno /* Copy interpreter string. Replace NULL breaks with space. */ 4016d756449SSean Bruno memcpy(xbe->xbe_interpreter, ibe->ibe_interpreter, 4026d756449SSean Bruno ibe->ibe_interp_length); 4036d756449SSean Bruno for(i = 0; i < (ibe->ibe_interp_length - 1); i++) 4046d756449SSean Bruno if (xbe->xbe_interpreter[i] == '\0') 4056d756449SSean Bruno xbe->xbe_interpreter[i] = ' '; 4066d756449SSean Bruno 4076d756449SSean Bruno memcpy(xbe->xbe_magic, ibe->ibe_magic, ibe->ibe_msize); 4086d756449SSean Bruno memcpy(xbe->xbe_mask, ibe->ibe_mask, ibe->ibe_msize); 4096d756449SSean Bruno xbe->xbe_version = IBE_VERSION; 4106d756449SSean Bruno xbe->xbe_flags = ibe->ibe_flags; 4116d756449SSean Bruno xbe->xbe_moffset = ibe->ibe_moffset; 4126d756449SSean Bruno xbe->xbe_msize = ibe->ibe_msize; 4136d756449SSean Bruno 4146d756449SSean Bruno return (0); 4156d756449SSean Bruno } 4166d756449SSean Bruno 4176d756449SSean Bruno /* 4186d756449SSean Bruno * Retrieve the interpreter with the give name and populate the 4196d756449SSean Bruno * ximgact_binmisc_entry structure. Return ENOENT if not found. 4206d756449SSean Bruno */ 4216d756449SSean Bruno static int 4226d756449SSean Bruno imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe) 4236d756449SSean Bruno { 4246d756449SSean Bruno imgact_binmisc_entry_t *ibe; 4256d756449SSean Bruno int error = 0; 4266d756449SSean Bruno 4272192cd12SKyle Evans INTERP_LIST_RLOCK(); 4286d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { 4292192cd12SKyle Evans INTERP_LIST_RUNLOCK(); 4306d756449SSean Bruno return (ENOENT); 4316d756449SSean Bruno } 4326d756449SSean Bruno 4336d756449SSean Bruno error = imgact_binmisc_populate_xbe(xbe, ibe); 4342192cd12SKyle Evans INTERP_LIST_RUNLOCK(); 4356d756449SSean Bruno 4366d756449SSean Bruno return (error); 4376d756449SSean Bruno } 4386d756449SSean Bruno 4396d756449SSean Bruno /* 4406d756449SSean Bruno * Get a snapshot of all the interpreter entries in the list. 4416d756449SSean Bruno */ 4426d756449SSean Bruno static int 4436d756449SSean Bruno imgact_binmisc_get_all_entries(struct sysctl_req *req) 4446d756449SSean Bruno { 4456d756449SSean Bruno ximgact_binmisc_entry_t *xbe, *xbep; 4466d756449SSean Bruno imgact_binmisc_entry_t *ibe; 4476d756449SSean Bruno int error = 0, count; 4486d756449SSean Bruno 4492192cd12SKyle Evans INTERP_LIST_RLOCK(); 4506d756449SSean Bruno count = interp_list_entry_count; 451e0ae213fSSean Bruno xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_WAITOK|M_ZERO); 4526d756449SSean Bruno 4536d756449SSean Bruno xbep = xbe; 4546d756449SSean Bruno SLIST_FOREACH(ibe, &interpreter_list, link) { 4556d756449SSean Bruno error = imgact_binmisc_populate_xbe(xbep++, ibe); 4566d756449SSean Bruno if (error) 4576d756449SSean Bruno break; 4586d756449SSean Bruno } 4592192cd12SKyle Evans INTERP_LIST_RUNLOCK(); 4606d756449SSean Bruno 4616d756449SSean Bruno if (!error) 4626d756449SSean Bruno error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count); 4636d756449SSean Bruno 4646d756449SSean Bruno free(xbe, M_BINMISC); 4656d756449SSean Bruno return (error); 4666d756449SSean Bruno } 4676d756449SSean Bruno 4686d756449SSean Bruno /* 4696d756449SSean Bruno * sysctl() handler for munipulating interpretor table. 4706d756449SSean Bruno * Not MP safe (locked by sysctl). 4716d756449SSean Bruno */ 4726d756449SSean Bruno static int 4736d756449SSean Bruno sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS) 4746d756449SSean Bruno { 4756d756449SSean Bruno ximgact_binmisc_entry_t xbe; 4766d756449SSean Bruno int error = 0; 4776d756449SSean Bruno 4786d756449SSean Bruno switch(arg2) { 4796d756449SSean Bruno case IBC_ADD: 4806d756449SSean Bruno /* Add an entry. Limited to IBE_MAX_ENTRIES. */ 4816d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 4826d756449SSean Bruno if (error) 4836d756449SSean Bruno return (error); 4846d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version) 4856d756449SSean Bruno return (EINVAL); 4867d3ed977SKyle Evans if ((xbe.xbe_flags & ~IBF_VALID_UFLAGS) != 0) 4877d3ed977SKyle Evans return (EINVAL); 4886d756449SSean Bruno if (interp_list_entry_count == IBE_MAX_ENTRIES) 4896d756449SSean Bruno return (ENOSPC); 4906d756449SSean Bruno error = imgact_binmisc_add_entry(&xbe); 4916d756449SSean Bruno break; 4926d756449SSean Bruno 4936d756449SSean Bruno case IBC_REMOVE: 4946d756449SSean Bruno /* Remove an entry. */ 4956d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 4966d756449SSean Bruno if (error) 4976d756449SSean Bruno return (error); 4986d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version) 4996d756449SSean Bruno return (EINVAL); 5006d756449SSean Bruno error = imgact_binmisc_remove_entry(xbe.xbe_name); 5016d756449SSean Bruno break; 5026d756449SSean Bruno 5036d756449SSean Bruno case IBC_DISABLE: 5046d756449SSean Bruno /* Disable an entry. */ 5056d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 5066d756449SSean Bruno if (error) 5076d756449SSean Bruno return (error); 5086d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version) 5096d756449SSean Bruno return (EINVAL); 5106d756449SSean Bruno error = imgact_binmisc_disable_entry(xbe.xbe_name); 5116d756449SSean Bruno break; 5126d756449SSean Bruno 5136d756449SSean Bruno case IBC_ENABLE: 5146d756449SSean Bruno /* Enable an entry. */ 5156d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 5166d756449SSean Bruno if (error) 5176d756449SSean Bruno return (error); 5186d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version) 5196d756449SSean Bruno return (EINVAL); 5206d756449SSean Bruno error = imgact_binmisc_enable_entry(xbe.xbe_name); 5216d756449SSean Bruno break; 5226d756449SSean Bruno 5236d756449SSean Bruno case IBC_LOOKUP: 5246d756449SSean Bruno /* Lookup an entry. */ 5256d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe)); 5266d756449SSean Bruno if (error) 5276d756449SSean Bruno return (error); 5286d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version) 5296d756449SSean Bruno return (EINVAL); 5306d756449SSean Bruno error = imgact_binmisc_lookup_entry(xbe.xbe_name, &xbe); 5316d756449SSean Bruno if (!error) 5326d756449SSean Bruno error = SYSCTL_OUT(req, &xbe, sizeof(xbe)); 5336d756449SSean Bruno break; 5346d756449SSean Bruno 5356d756449SSean Bruno case IBC_LIST: 5366d756449SSean Bruno /* Return a snapshot of the interpretor list. */ 5376d756449SSean Bruno 5386d756449SSean Bruno if (!req->oldptr) { 5396d756449SSean Bruno /* No pointer then just return the list size. */ 5406d756449SSean Bruno error = SYSCTL_OUT(req, 0, interp_list_entry_count * 5416d756449SSean Bruno sizeof(ximgact_binmisc_entry_t)); 5426d756449SSean Bruno return (error); 5436d756449SSean Bruno } else 5446d756449SSean Bruno if (!req->oldlen) 5456d756449SSean Bruno return (EINVAL); 5466d756449SSean Bruno 5476d756449SSean Bruno error = imgact_binmisc_get_all_entries(req); 5486d756449SSean Bruno break; 5496d756449SSean Bruno 5506d756449SSean Bruno default: 5516d756449SSean Bruno return (EINVAL); 5526d756449SSean Bruno } 5536d756449SSean Bruno 5546d756449SSean Bruno return (error); 5556d756449SSean Bruno } 5566d756449SSean Bruno 5577029da5cSPawel Biernacki SYSCTL_NODE(_kern, OID_AUTO, binmisc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 5586d756449SSean Bruno "Image activator for miscellaneous binaries"); 5596d756449SSean Bruno 5606d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, add, 5616d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ADD, 5626d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 5636d756449SSean Bruno "Add an activator entry"); 5646d756449SSean Bruno 5656d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, remove, 5666d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_REMOVE, 5676d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 5686d756449SSean Bruno "Remove an activator entry"); 5696d756449SSean Bruno 5706d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, disable, 5716d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_DISABLE, 5726d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 5736d756449SSean Bruno "Disable an activator entry"); 5746d756449SSean Bruno 5756d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, enable, 5766d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ENABLE, 5776d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 5786d756449SSean Bruno "Enable an activator entry"); 5796d756449SSean Bruno 5806d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, lookup, 5816d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RW|CTLFLAG_ANYBODY, NULL, IBC_LOOKUP, 5826d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 5836d756449SSean Bruno "Lookup an activator entry"); 5846d756449SSean Bruno 5856d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, list, 5866d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RD|CTLFLAG_ANYBODY, NULL, IBC_LIST, 5876d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry", 5886d756449SSean Bruno "Get snapshot of all the activator entries"); 5896d756449SSean Bruno 5906d756449SSean Bruno static imgact_binmisc_entry_t * 5916d756449SSean Bruno imgact_binmisc_find_interpreter(const char *image_header) 5926d756449SSean Bruno { 5936d756449SSean Bruno imgact_binmisc_entry_t *ibe; 5946d756449SSean Bruno const char *p; 5956d756449SSean Bruno int i; 5966d756449SSean Bruno size_t sz; 5976d756449SSean Bruno 5982192cd12SKyle Evans INTERP_LIST_ASSERT_LOCKED(); 5996d756449SSean Bruno 6006d756449SSean Bruno SLIST_FOREACH(ibe, &interpreter_list, link) { 6016d756449SSean Bruno if (!(IBF_ENABLED & ibe->ibe_flags)) 6026d756449SSean Bruno continue; 6036d756449SSean Bruno 6046d756449SSean Bruno p = image_header + ibe->ibe_moffset; 6056d756449SSean Bruno sz = ibe->ibe_msize; 6066d756449SSean Bruno if (IBF_USE_MASK & ibe->ibe_flags) { 6076d756449SSean Bruno /* Compare using mask. */ 6086d756449SSean Bruno for (i = 0; i < sz; i++) 6096d756449SSean Bruno if ((*p++ ^ ibe->ibe_magic[i]) & 6106d756449SSean Bruno ibe->ibe_mask[i]) 6116d756449SSean Bruno break; 6126d756449SSean Bruno } else { 6136d756449SSean Bruno for (i = 0; i < sz; i++) 6146d756449SSean Bruno if (*p++ ^ ibe->ibe_magic[i]) 6156d756449SSean Bruno break; 6166d756449SSean Bruno } 6176d756449SSean Bruno if (i == ibe->ibe_msize) 6186d756449SSean Bruno return (ibe); 6196d756449SSean Bruno } 6206d756449SSean Bruno return (NULL); 6216d756449SSean Bruno } 6226d756449SSean Bruno 623945afa7cSSean Bruno static int 6246d756449SSean Bruno imgact_binmisc_exec(struct image_params *imgp) 6256d756449SSean Bruno { 6266d756449SSean Bruno const char *image_header = imgp->image_header; 6276d756449SSean Bruno const char *fname = NULL; 6286d756449SSean Bruno int error = 0; 6291024ef27SKyle Evans #ifdef INVARIANTS 6301024ef27SKyle Evans int argv0_cnt = 0; 6311024ef27SKyle Evans #endif 6321024ef27SKyle Evans size_t namelen, offset; 6336d756449SSean Bruno imgact_binmisc_entry_t *ibe; 6346d756449SSean Bruno struct sbuf *sname; 6356d756449SSean Bruno char *s, *d; 6366d756449SSean Bruno 63780083216SKyle Evans sname = NULL; 6381024ef27SKyle Evans namelen = 0; 6396d756449SSean Bruno /* Do we have an interpreter for the given image header? */ 6402192cd12SKyle Evans INTERP_LIST_RLOCK(); 6416d756449SSean Bruno if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) { 64280083216SKyle Evans error = -1; 64380083216SKyle Evans goto done; 6446d756449SSean Bruno } 6456d756449SSean Bruno 6466d756449SSean Bruno /* No interpreter nesting allowed. */ 64765f20a89SSean Bruno if (imgp->interpreted & IMGACT_BINMISC) { 64880083216SKyle Evans error = ENOEXEC; 64980083216SKyle Evans goto done; 6506d756449SSean Bruno } 6516d756449SSean Bruno 65265f20a89SSean Bruno imgp->interpreted |= IMGACT_BINMISC; 6536d756449SSean Bruno 6541024ef27SKyle Evans /* 6551024ef27SKyle Evans * Don't bother with the overhead of putting fname together if we're not 6561024ef27SKyle Evans * using #a. 6571024ef27SKyle Evans */ 6581024ef27SKyle Evans if (ibe->ibe_argv0_cnt != 0) { 6596d756449SSean Bruno if (imgp->args->fname != NULL) { 6606d756449SSean Bruno fname = imgp->args->fname; 6616d756449SSean Bruno } else { 6626d756449SSean Bruno /* Use the fdescfs(5) path for fexecve(2). */ 6636d756449SSean Bruno sname = sbuf_new_auto(); 6646d756449SSean Bruno sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd); 6656d756449SSean Bruno sbuf_finish(sname); 6666d756449SSean Bruno fname = sbuf_data(sname); 6676d756449SSean Bruno } 6686d756449SSean Bruno 6691024ef27SKyle Evans namelen = strlen(fname); 6701024ef27SKyle Evans } 6711024ef27SKyle Evans 6726d756449SSean Bruno /* 6736d756449SSean Bruno * We need to "push" the interpreter in the arg[] list. To do this, 6746d756449SSean Bruno * we first shift all the other values in the `begin_argv' area to 6756d756449SSean Bruno * provide the exact amount of room for the values added. Set up 6766d756449SSean Bruno * `offset' as the number of bytes to be added to the `begin_argv' 6771024ef27SKyle Evans * area. ibe_interp_offset is the fixed offset from macros present in 6781024ef27SKyle Evans * the interpreter string. 6796d756449SSean Bruno */ 6801024ef27SKyle Evans offset = ibe->ibe_interp_length + ibe->ibe_interp_offset; 6816d756449SSean Bruno 6821024ef27SKyle Evans /* Variable offset to be added from macros to the interpreter string. */ 6831024ef27SKyle Evans MPASS(ibe->ibe_argv0_cnt == 0 || namelen > 0); 6841024ef27SKyle Evans offset += ibe->ibe_argv0_cnt * (namelen - 2); 6856d756449SSean Bruno 686f373437aSBrooks Davis /* Make room for the interpreter */ 687f373437aSBrooks Davis error = exec_args_adjust_args(imgp->args, 0, offset); 688f373437aSBrooks Davis if (error != 0) { 6896d756449SSean Bruno goto done; 6906d756449SSean Bruno } 6916d756449SSean Bruno 6926d756449SSean Bruno /* Add the new argument(s) in the count. */ 6936d756449SSean Bruno imgp->args->argc += ibe->ibe_interp_argcnt; 6946d756449SSean Bruno 6956d756449SSean Bruno /* 6966d756449SSean Bruno * The original arg[] list has been shifted appropriately. Copy in 6976d756449SSean Bruno * the interpreter path. 6986d756449SSean Bruno */ 6996d756449SSean Bruno s = ibe->ibe_interpreter; 7006d756449SSean Bruno d = imgp->args->begin_argv; 7016d756449SSean Bruno while(*s != '\0') { 7026d756449SSean Bruno switch (*s) { 7036d756449SSean Bruno case '#': 7046d756449SSean Bruno /* Handle "#" in interpreter string. */ 7056d756449SSean Bruno s++; 7066d756449SSean Bruno switch(*s) { 7076d756449SSean Bruno case ISM_POUND: 7086d756449SSean Bruno /* "##": Replace with a single '#' */ 7096d756449SSean Bruno *d++ = '#'; 7106d756449SSean Bruno break; 7116d756449SSean Bruno case ISM_OLD_ARGV0: 7126d756449SSean Bruno /* "#a": Replace with old arg0 (fname). */ 7131024ef27SKyle Evans MPASS(ibe->ibe_argv0_cnt >= ++argv0_cnt); 7141024ef27SKyle Evans memcpy(d, fname, namelen); 7151024ef27SKyle Evans d += namelen; 7166d756449SSean Bruno break; 7176d756449SSean Bruno default: 7181024ef27SKyle Evans __assert_unreachable(); 7196d756449SSean Bruno } 7206d756449SSean Bruno break; 7216d756449SSean Bruno case ' ': 722e3043798SPedro F. Giffuni /* Replace space with NUL to separate arguments. */ 7236d756449SSean Bruno *d++ = '\0'; 7246d756449SSean Bruno break; 7256d756449SSean Bruno default: 7266d756449SSean Bruno *d++ = *s; 7276d756449SSean Bruno break; 7286d756449SSean Bruno } 7296d756449SSean Bruno s++; 7306d756449SSean Bruno } 7316d756449SSean Bruno *d = '\0'; 7326d756449SSean Bruno 7331024ef27SKyle Evans /* Catch ibe->ibe_argv0_cnt counting more #a than we did. */ 7341024ef27SKyle Evans MPASS(ibe->ibe_argv0_cnt == argv0_cnt); 7356d756449SSean Bruno imgp->interpreter_name = imgp->args->begin_argv; 736*5eeb4f73SDoug Rabson if (ibe->ibe_interpreter_vnode) { 737*5eeb4f73SDoug Rabson imgp->interpreter_vp = ibe->ibe_interpreter_vnode; 738*5eeb4f73SDoug Rabson vref(imgp->interpreter_vp); 739*5eeb4f73SDoug Rabson } 7406d756449SSean Bruno 7416d756449SSean Bruno done: 7422192cd12SKyle Evans INTERP_LIST_RUNLOCK(); 7436d756449SSean Bruno if (sname) 7446d756449SSean Bruno sbuf_delete(sname); 7456d756449SSean Bruno return (error); 7466d756449SSean Bruno } 7476d756449SSean Bruno 7486d756449SSean Bruno static void 7496d756449SSean Bruno imgact_binmisc_init(void *arg) 7506d756449SSean Bruno { 7516d756449SSean Bruno 7522192cd12SKyle Evans INTERP_LIST_LOCK_INIT(); 7536d756449SSean Bruno } 7546d756449SSean Bruno 7556d756449SSean Bruno static void 7566d756449SSean Bruno imgact_binmisc_fini(void *arg) 7576d756449SSean Bruno { 7586d756449SSean Bruno imgact_binmisc_entry_t *ibe, *ibe_tmp; 7596d756449SSean Bruno 7606d756449SSean Bruno /* Free all the interpreters. */ 7612192cd12SKyle Evans INTERP_LIST_WLOCK(); 7626d756449SSean Bruno SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) { 7636d756449SSean Bruno SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, 7646d756449SSean Bruno link); 7656d756449SSean Bruno imgact_binmisc_destroy_entry(ibe); 7666d756449SSean Bruno } 7672192cd12SKyle Evans INTERP_LIST_WUNLOCK(); 7686d756449SSean Bruno 7692192cd12SKyle Evans INTERP_LIST_LOCK_DESTROY(); 7706d756449SSean Bruno } 7716d756449SSean Bruno 772891cf3edSEd Maste SYSINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_init, 773891cf3edSEd Maste NULL); 774891cf3edSEd Maste SYSUNINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_fini, 775891cf3edSEd Maste NULL); 7766d756449SSean Bruno 7776d756449SSean Bruno /* 7786d756449SSean Bruno * Tell kern_execve.c about it, with a little help from the linker. 7796d756449SSean Bruno */ 780b7feabf9SEd Maste static struct execsw imgact_binmisc_execsw = { 781b7feabf9SEd Maste .ex_imgact = imgact_binmisc_exec, 782b7feabf9SEd Maste .ex_name = KMOD_NAME 783b7feabf9SEd Maste }; 7846d756449SSean Bruno EXEC_SET(imgact_binmisc, imgact_binmisc_execsw); 785