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/param.h>
286d756449SSean Bruno #include <sys/ctype.h>
296d756449SSean Bruno #include <sys/exec.h>
305eeb4f73SDoug Rabson #include <sys/fcntl.h>
316d756449SSean Bruno #include <sys/imgact.h>
326d756449SSean Bruno #include <sys/imgact_binmisc.h>
336d756449SSean Bruno #include <sys/kernel.h>
346d756449SSean Bruno #include <sys/lock.h>
356d756449SSean Bruno #include <sys/malloc.h>
366d756449SSean Bruno #include <sys/mutex.h>
375eeb4f73SDoug Rabson #include <sys/namei.h>
38df69035dSKyle Evans #include <sys/sbuf.h>
396d756449SSean Bruno #include <sys/sysctl.h>
405f98711dSSean Bruno #include <sys/sx.h>
415eeb4f73SDoug Rabson #include <sys/vnode.h>
425f98711dSSean Bruno
435f98711dSSean Bruno #include <machine/atomic.h>
446d756449SSean Bruno
456d756449SSean Bruno /**
466d756449SSean Bruno * Miscellaneous binary interpreter image activator.
476d756449SSean Bruno *
486d756449SSean Bruno * If the given target executable's header matches 'xbe_magic' field in the
496d756449SSean Bruno * 'interpreter_list' then it will use the user-level interpreter specified in
506d756449SSean Bruno * the 'xbe_interpreter' field to execute the binary. The 'xbe_magic' field may
516d756449SSean Bruno * be adjusted to a given offset using the value in the 'xbe_moffset' field
526d756449SSean Bruno * and bits of the header may be masked using the 'xbe_mask' field. The
536d756449SSean Bruno * 'interpreter_list' entries are managed using sysctl(3) as described in the
546d756449SSean Bruno * <sys/imgact_binmisc.h> file.
556d756449SSean Bruno */
566d756449SSean Bruno
576d756449SSean Bruno /*
586d756449SSean Bruno * Node of the interpreter list.
596d756449SSean Bruno */
606d756449SSean Bruno typedef struct imgact_binmisc_entry {
61ecb4fdf9SKyle Evans SLIST_ENTRY(imgact_binmisc_entry) link;
626d756449SSean Bruno char *ibe_name;
636d756449SSean Bruno uint8_t *ibe_magic;
646d756449SSean Bruno uint8_t *ibe_mask;
656d756449SSean Bruno uint8_t *ibe_interpreter;
665eeb4f73SDoug Rabson struct vnode *ibe_interpreter_vnode;
671024ef27SKyle Evans ssize_t ibe_interp_offset;
686d756449SSean Bruno uint32_t ibe_interp_argcnt;
696d756449SSean Bruno uint32_t ibe_interp_length;
701024ef27SKyle Evans uint32_t ibe_argv0_cnt;
716d756449SSean Bruno uint32_t ibe_flags;
72ecb4fdf9SKyle Evans uint32_t ibe_moffset;
73ecb4fdf9SKyle Evans uint32_t ibe_msize;
746d756449SSean Bruno } imgact_binmisc_entry_t;
756d756449SSean Bruno
766d756449SSean Bruno /*
776d756449SSean Bruno * sysctl() commands.
786d756449SSean Bruno */
796d756449SSean Bruno #define IBC_ADD 1 /* Add given entry. */
806d756449SSean Bruno #define IBC_REMOVE 2 /* Remove entry for a given name. */
816d756449SSean Bruno #define IBC_DISABLE 3 /* Disable entry for a given name. */
826d756449SSean Bruno #define IBC_ENABLE 4 /* Enable entry for a given name. */
836d756449SSean Bruno #define IBC_LOOKUP 5 /* Lookup and return entry for given name. */
846d756449SSean Bruno #define IBC_LIST 6 /* Get a snapshot of the interpretor list. */
856d756449SSean Bruno
866d756449SSean Bruno /*
876d756449SSean Bruno * Interpreter string macros.
886d756449SSean Bruno *
896d756449SSean Bruno * They all start with '#' followed by a single letter:
906d756449SSean Bruno */
916d756449SSean Bruno #define ISM_POUND '#' /* "##" is the escape sequence for single #. */
926d756449SSean Bruno #define ISM_OLD_ARGV0 'a' /* "#a" is replaced with the old argv0. */
936d756449SSean Bruno
946d756449SSean Bruno MALLOC_DEFINE(M_BINMISC, KMOD_NAME, "misc binary image activator");
956d756449SSean Bruno
966d756449SSean Bruno /* The interpreter list. */
976d756449SSean Bruno static SLIST_HEAD(, imgact_binmisc_entry) interpreter_list =
986d756449SSean Bruno SLIST_HEAD_INITIALIZER(interpreter_list);
996d756449SSean Bruno
100df69035dSKyle Evans static int interp_list_entry_count;
101280b7169SSean Bruno
1025f98711dSSean Bruno static struct sx interp_list_sx;
1036d756449SSean Bruno
1042192cd12SKyle Evans #define INTERP_LIST_WLOCK() sx_xlock(&interp_list_sx)
1052192cd12SKyle Evans #define INTERP_LIST_RLOCK() sx_slock(&interp_list_sx)
1062192cd12SKyle Evans #define INTERP_LIST_WUNLOCK() sx_xunlock(&interp_list_sx)
1072192cd12SKyle Evans #define INTERP_LIST_RUNLOCK() sx_sunlock(&interp_list_sx)
1082192cd12SKyle Evans
1092192cd12SKyle Evans #define INTERP_LIST_LOCK_INIT() sx_init(&interp_list_sx, KMOD_NAME)
1102192cd12SKyle Evans #define INTERP_LIST_LOCK_DESTROY() sx_destroy(&interp_list_sx)
1112192cd12SKyle Evans
1122192cd12SKyle Evans #define INTERP_LIST_ASSERT_LOCKED() sx_assert(&interp_list_sx, SA_LOCKED)
1132192cd12SKyle Evans
1146d756449SSean Bruno /*
1156d756449SSean Bruno * Populate the entry with the information about the interpreter.
1166d756449SSean Bruno */
1176d756449SSean Bruno static void
imgact_binmisc_populate_interp(char * str,imgact_binmisc_entry_t * ibe,int flags)1185eeb4f73SDoug Rabson imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe, int flags)
1196d756449SSean Bruno {
1206d756449SSean Bruno uint32_t len = 0, argc = 1;
1216d756449SSean Bruno char t[IBE_INTERP_LEN_MAX];
1226d756449SSean Bruno char *sp, *tp;
1236d756449SSean Bruno
1245f98711dSSean Bruno memset(t, 0, sizeof(t));
1256d756449SSean Bruno
1266d756449SSean Bruno /*
1276d756449SSean Bruno * Normalize interpreter string. Replace white space between args with
1286d756449SSean Bruno * single space.
1296d756449SSean Bruno */
1306d756449SSean Bruno sp = str; tp = t;
1316d756449SSean Bruno while (*sp != '\0') {
1326d756449SSean Bruno if (*sp == ' ' || *sp == '\t') {
13326af6115SEd Maste if (++len >= IBE_INTERP_LEN_MAX)
1346d756449SSean Bruno break;
1356d756449SSean Bruno *tp++ = ' ';
1366d756449SSean Bruno argc++;
1376d756449SSean Bruno while (*sp == ' ' || *sp == '\t')
1386d756449SSean Bruno sp++;
1396d756449SSean Bruno continue;
1406d756449SSean Bruno } else {
1416d756449SSean Bruno *tp++ = *sp++;
1426d756449SSean Bruno len++;
1436d756449SSean Bruno }
1446d756449SSean Bruno }
1456d756449SSean Bruno *tp = '\0';
1466d756449SSean Bruno len++;
1476d756449SSean Bruno
1486d756449SSean Bruno ibe->ibe_interpreter = malloc(len, M_BINMISC, M_WAITOK|M_ZERO);
1496d756449SSean Bruno
1506d756449SSean Bruno /* Populate all the ibe fields for the interpreter. */
1516d756449SSean Bruno memcpy(ibe->ibe_interpreter, t, len);
1526d756449SSean Bruno ibe->ibe_interp_argcnt = argc;
1536d756449SSean Bruno ibe->ibe_interp_length = len;
1545eeb4f73SDoug Rabson
1555eeb4f73SDoug Rabson ibe->ibe_interpreter_vnode = NULL;
1565eeb4f73SDoug Rabson if (flags & IBF_PRE_OPEN) {
1575eeb4f73SDoug Rabson struct nameidata nd;
1585eeb4f73SDoug Rabson int error;
1595eeb4f73SDoug Rabson
1605eeb4f73SDoug Rabson tp = t;
1615eeb4f73SDoug Rabson while (*tp != '\0' && *tp != ' ') {
1625eeb4f73SDoug Rabson tp++;
1635eeb4f73SDoug Rabson }
1645eeb4f73SDoug Rabson *tp = '\0';
1655eeb4f73SDoug Rabson NDINIT(&nd, LOOKUP, FOLLOW | ISOPEN, UIO_SYSSPACE, t);
1665eeb4f73SDoug Rabson
1675eeb4f73SDoug Rabson /*
1685eeb4f73SDoug Rabson * If there is an error, just stop now and fall back
1695eeb4f73SDoug Rabson * to the non pre-open case where we lookup during
1705eeb4f73SDoug Rabson * exec.
1715eeb4f73SDoug Rabson */
1725eeb4f73SDoug Rabson error = namei(&nd);
1735eeb4f73SDoug Rabson if (error)
1745eeb4f73SDoug Rabson return;
1755eeb4f73SDoug Rabson
1765eeb4f73SDoug Rabson ibe->ibe_interpreter_vnode = nd.ni_vp;
1775eeb4f73SDoug Rabson }
1786d756449SSean Bruno }
1796d756449SSean Bruno
1806d756449SSean Bruno /*
1816d756449SSean Bruno * Allocate memory and populate a new entry for the interpreter table.
1826d756449SSean Bruno */
1836d756449SSean Bruno static imgact_binmisc_entry_t *
imgact_binmisc_new_entry(ximgact_binmisc_entry_t * xbe,ssize_t interp_offset,int argv0_cnt)1841024ef27SKyle Evans imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe, ssize_t interp_offset,
1851024ef27SKyle Evans int argv0_cnt)
1866d756449SSean Bruno {
1876d756449SSean Bruno imgact_binmisc_entry_t *ibe = NULL;
1886d756449SSean Bruno size_t namesz = min(strlen(xbe->xbe_name) + 1, IBE_NAME_MAX);
1896d756449SSean Bruno
1906d756449SSean Bruno ibe = malloc(sizeof(*ibe), M_BINMISC, M_WAITOK|M_ZERO);
1916d756449SSean Bruno
1926d756449SSean Bruno ibe->ibe_name = malloc(namesz, M_BINMISC, M_WAITOK|M_ZERO);
1936d756449SSean Bruno strlcpy(ibe->ibe_name, xbe->xbe_name, namesz);
1946d756449SSean Bruno
1955eeb4f73SDoug Rabson imgact_binmisc_populate_interp(xbe->xbe_interpreter, ibe, xbe->xbe_flags);
1966d756449SSean Bruno
1976d756449SSean Bruno ibe->ibe_magic = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO);
1986d756449SSean Bruno memcpy(ibe->ibe_magic, xbe->xbe_magic, xbe->xbe_msize);
1996d756449SSean Bruno
2006d756449SSean Bruno ibe->ibe_mask = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO);
2016d756449SSean Bruno memcpy(ibe->ibe_mask, xbe->xbe_mask, xbe->xbe_msize);
2026d756449SSean Bruno
2036d756449SSean Bruno ibe->ibe_moffset = xbe->xbe_moffset;
2046d756449SSean Bruno ibe->ibe_msize = xbe->xbe_msize;
2056d756449SSean Bruno ibe->ibe_flags = xbe->xbe_flags;
2061024ef27SKyle Evans ibe->ibe_interp_offset = interp_offset;
2071024ef27SKyle Evans ibe->ibe_argv0_cnt = argv0_cnt;
2086d756449SSean Bruno return (ibe);
2096d756449SSean Bruno }
2106d756449SSean Bruno
2116d756449SSean Bruno /*
2126d756449SSean Bruno * Free the allocated memory for a given list item.
2136d756449SSean Bruno */
2146d756449SSean Bruno static void
imgact_binmisc_destroy_entry(imgact_binmisc_entry_t * ibe)2156d756449SSean Bruno imgact_binmisc_destroy_entry(imgact_binmisc_entry_t *ibe)
2166d756449SSean Bruno {
2176d756449SSean Bruno if (!ibe)
2186d756449SSean Bruno return;
219b888dae4SSean Bruno if (ibe->ibe_magic)
2206d756449SSean Bruno free(ibe->ibe_magic, M_BINMISC);
2216d756449SSean Bruno if (ibe->ibe_mask)
2226d756449SSean Bruno free(ibe->ibe_mask, M_BINMISC);
2236d756449SSean Bruno if (ibe->ibe_interpreter)
2246d756449SSean Bruno free(ibe->ibe_interpreter, M_BINMISC);
2256d756449SSean Bruno if (ibe->ibe_name)
2266d756449SSean Bruno free(ibe->ibe_name, M_BINMISC);
2275eeb4f73SDoug Rabson if (ibe->ibe_interpreter_vnode)
2285eeb4f73SDoug Rabson vrele(ibe->ibe_interpreter_vnode);
2296d756449SSean Bruno if (ibe)
2306d756449SSean Bruno free(ibe, M_BINMISC);
2316d756449SSean Bruno }
2326d756449SSean Bruno
2336d756449SSean Bruno /*
2346d756449SSean Bruno * Find the interpreter in the list by the given name. Return NULL if not
2356d756449SSean Bruno * found.
2366d756449SSean Bruno */
2376d756449SSean Bruno static imgact_binmisc_entry_t *
imgact_binmisc_find_entry(char * name)2386d756449SSean Bruno imgact_binmisc_find_entry(char *name)
2396d756449SSean Bruno {
2406d756449SSean Bruno imgact_binmisc_entry_t *ibe;
2416d756449SSean Bruno
2422192cd12SKyle Evans INTERP_LIST_ASSERT_LOCKED();
2436d756449SSean Bruno
2446d756449SSean Bruno SLIST_FOREACH(ibe, &interpreter_list, link) {
2456d756449SSean Bruno if (strncmp(name, ibe->ibe_name, IBE_NAME_MAX) == 0)
2466d756449SSean Bruno return (ibe);
2476d756449SSean Bruno }
2486d756449SSean Bruno
2496d756449SSean Bruno return (NULL);
2506d756449SSean Bruno }
2516d756449SSean Bruno
2526d756449SSean Bruno /*
2536d756449SSean Bruno * Add the given interpreter if it doesn't already exist. Return EEXIST
2546d756449SSean Bruno * if the name already exist in the interpreter list.
2556d756449SSean Bruno */
2566d756449SSean Bruno static int
imgact_binmisc_add_entry(ximgact_binmisc_entry_t * xbe)2576d756449SSean Bruno imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe)
2586d756449SSean Bruno {
2596d756449SSean Bruno imgact_binmisc_entry_t *ibe;
2606d756449SSean Bruno char *p;
2611024ef27SKyle Evans ssize_t interp_offset;
2621024ef27SKyle Evans int argv0_cnt, cnt;
2636d756449SSean Bruno
2646d756449SSean Bruno if (xbe->xbe_msize > IBE_MAGIC_MAX)
2656d756449SSean Bruno return (EINVAL);
2668c28aa5eSKyle Evans if (xbe->xbe_moffset + xbe->xbe_msize > IBE_MATCH_MAX)
2678c28aa5eSKyle Evans return (EINVAL);
2686d756449SSean Bruno
269910938f0SSean Bruno for(cnt = 0, p = xbe->xbe_name; *p != 0; cnt++, p++)
270910938f0SSean Bruno if (cnt >= IBE_NAME_MAX || !isascii((int)*p))
2716d756449SSean Bruno return (EINVAL);
2726d756449SSean Bruno
273910938f0SSean Bruno for(cnt = 0, p = xbe->xbe_interpreter; *p != 0; cnt++, p++)
274910938f0SSean Bruno if (cnt >= IBE_INTERP_LEN_MAX || !isascii((int)*p))
2756d756449SSean Bruno return (EINVAL);
2766d756449SSean Bruno
2776d756449SSean Bruno /* Make sure we don't have any invalid #'s. */
2786d756449SSean Bruno p = xbe->xbe_interpreter;
2791024ef27SKyle Evans interp_offset = 0;
2801024ef27SKyle Evans argv0_cnt = 0;
2811024ef27SKyle Evans while ((p = strchr(p, '#')) != NULL) {
2826d756449SSean Bruno p++;
2836d756449SSean Bruno switch(*p) {
2846d756449SSean Bruno case ISM_POUND:
2856d756449SSean Bruno /* "##" */
2866d756449SSean Bruno p++;
2871024ef27SKyle Evans interp_offset--;
2886d756449SSean Bruno break;
2896d756449SSean Bruno case ISM_OLD_ARGV0:
2906d756449SSean Bruno /* "#a" */
2916d756449SSean Bruno p++;
2921024ef27SKyle Evans argv0_cnt++;
2936d756449SSean Bruno break;
2946d756449SSean Bruno case 0:
2956d756449SSean Bruno default:
2966d756449SSean Bruno /* Anything besides the above is invalid. */
2976d756449SSean Bruno return (EINVAL);
2986d756449SSean Bruno }
2996d756449SSean Bruno }
3006d756449SSean Bruno
3015eeb4f73SDoug Rabson /*
3025eeb4f73SDoug Rabson * Preallocate a new entry. We do this without holding the
3035eeb4f73SDoug Rabson * lock to avoid lock-order problems if IBF_PRE_OPEN is
3045eeb4f73SDoug Rabson * set.
3055eeb4f73SDoug Rabson */
3065eeb4f73SDoug Rabson ibe = imgact_binmisc_new_entry(xbe, interp_offset, argv0_cnt);
3075eeb4f73SDoug Rabson
3082192cd12SKyle Evans INTERP_LIST_WLOCK();
309280b7169SSean Bruno if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) {
3102192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3115eeb4f73SDoug Rabson imgact_binmisc_destroy_entry(ibe);
312280b7169SSean Bruno return (EEXIST);
313280b7169SSean Bruno }
314280b7169SSean Bruno
3156d756449SSean Bruno SLIST_INSERT_HEAD(&interpreter_list, ibe, link);
3166d756449SSean Bruno interp_list_entry_count++;
3172192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3186d756449SSean Bruno
3196d756449SSean Bruno return (0);
3206d756449SSean Bruno }
3216d756449SSean Bruno
3226d756449SSean Bruno /*
3236d756449SSean Bruno * Remove the interpreter in the list with the given name. Return ENOENT
3246d756449SSean Bruno * if not found.
3256d756449SSean Bruno */
3266d756449SSean Bruno static int
imgact_binmisc_remove_entry(char * name)3276d756449SSean Bruno imgact_binmisc_remove_entry(char *name)
3286d756449SSean Bruno {
3296d756449SSean Bruno imgact_binmisc_entry_t *ibe;
3306d756449SSean Bruno
3312192cd12SKyle Evans INTERP_LIST_WLOCK();
3326d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
3332192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3346d756449SSean Bruno return (ENOENT);
3356d756449SSean Bruno }
3366d756449SSean Bruno SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link);
3376d756449SSean Bruno interp_list_entry_count--;
3382192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3396d756449SSean Bruno
3406d756449SSean Bruno imgact_binmisc_destroy_entry(ibe);
3416d756449SSean Bruno
3426d756449SSean Bruno return (0);
3436d756449SSean Bruno }
3446d756449SSean Bruno
3456d756449SSean Bruno /*
3466d756449SSean Bruno * Disable the interpreter in the list with the given name. Return ENOENT
3476d756449SSean Bruno * if not found.
3486d756449SSean Bruno */
3496d756449SSean Bruno static int
imgact_binmisc_disable_entry(char * name)3506d756449SSean Bruno imgact_binmisc_disable_entry(char *name)
3516d756449SSean Bruno {
3526d756449SSean Bruno imgact_binmisc_entry_t *ibe;
3536d756449SSean Bruno
3542192cd12SKyle Evans INTERP_LIST_WLOCK();
3556d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
3562192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3576d756449SSean Bruno return (ENOENT);
3586d756449SSean Bruno }
3596d756449SSean Bruno
3604e83b32aSSean Bruno ibe->ibe_flags &= ~IBF_ENABLED;
3612192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3626d756449SSean Bruno
3636d756449SSean Bruno return (0);
3646d756449SSean Bruno }
3656d756449SSean Bruno
3666d756449SSean Bruno /*
3676d756449SSean Bruno * Enable the interpreter in the list with the given name. Return ENOENT
3686d756449SSean Bruno * if not found.
3696d756449SSean Bruno */
3706d756449SSean Bruno static int
imgact_binmisc_enable_entry(char * name)3716d756449SSean Bruno imgact_binmisc_enable_entry(char *name)
3726d756449SSean Bruno {
3736d756449SSean Bruno imgact_binmisc_entry_t *ibe;
3746d756449SSean Bruno
3752192cd12SKyle Evans INTERP_LIST_WLOCK();
3766d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
3772192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3786d756449SSean Bruno return (ENOENT);
3796d756449SSean Bruno }
3806d756449SSean Bruno
3814e83b32aSSean Bruno ibe->ibe_flags |= IBF_ENABLED;
3822192cd12SKyle Evans INTERP_LIST_WUNLOCK();
3836d756449SSean Bruno
3846d756449SSean Bruno return (0);
3856d756449SSean Bruno }
3866d756449SSean Bruno
3876d756449SSean Bruno static int
imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t * xbe,imgact_binmisc_entry_t * ibe)3886d756449SSean Bruno imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe,
3896d756449SSean Bruno imgact_binmisc_entry_t *ibe)
3906d756449SSean Bruno {
3916d756449SSean Bruno uint32_t i;
3926d756449SSean Bruno
3932192cd12SKyle Evans INTERP_LIST_ASSERT_LOCKED();
3945f98711dSSean Bruno memset(xbe, 0, sizeof(*xbe));
3956d756449SSean Bruno strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX);
3966d756449SSean Bruno
3976d756449SSean Bruno /* Copy interpreter string. Replace NULL breaks with space. */
3986d756449SSean Bruno memcpy(xbe->xbe_interpreter, ibe->ibe_interpreter,
3996d756449SSean Bruno ibe->ibe_interp_length);
4006d756449SSean Bruno for(i = 0; i < (ibe->ibe_interp_length - 1); i++)
4016d756449SSean Bruno if (xbe->xbe_interpreter[i] == '\0')
4026d756449SSean Bruno xbe->xbe_interpreter[i] = ' ';
4036d756449SSean Bruno
4046d756449SSean Bruno memcpy(xbe->xbe_magic, ibe->ibe_magic, ibe->ibe_msize);
4056d756449SSean Bruno memcpy(xbe->xbe_mask, ibe->ibe_mask, ibe->ibe_msize);
4066d756449SSean Bruno xbe->xbe_version = IBE_VERSION;
4076d756449SSean Bruno xbe->xbe_flags = ibe->ibe_flags;
4086d756449SSean Bruno xbe->xbe_moffset = ibe->ibe_moffset;
4096d756449SSean Bruno xbe->xbe_msize = ibe->ibe_msize;
4106d756449SSean Bruno
4116d756449SSean Bruno return (0);
4126d756449SSean Bruno }
4136d756449SSean Bruno
4146d756449SSean Bruno /*
4156d756449SSean Bruno * Retrieve the interpreter with the give name and populate the
4166d756449SSean Bruno * ximgact_binmisc_entry structure. Return ENOENT if not found.
4176d756449SSean Bruno */
4186d756449SSean Bruno static int
imgact_binmisc_lookup_entry(char * name,ximgact_binmisc_entry_t * xbe)4196d756449SSean Bruno imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe)
4206d756449SSean Bruno {
4216d756449SSean Bruno imgact_binmisc_entry_t *ibe;
4226d756449SSean Bruno int error = 0;
4236d756449SSean Bruno
4242192cd12SKyle Evans INTERP_LIST_RLOCK();
4256d756449SSean Bruno if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
4262192cd12SKyle Evans INTERP_LIST_RUNLOCK();
4276d756449SSean Bruno return (ENOENT);
4286d756449SSean Bruno }
4296d756449SSean Bruno
4306d756449SSean Bruno error = imgact_binmisc_populate_xbe(xbe, ibe);
4312192cd12SKyle Evans INTERP_LIST_RUNLOCK();
4326d756449SSean Bruno
4336d756449SSean Bruno return (error);
4346d756449SSean Bruno }
4356d756449SSean Bruno
4366d756449SSean Bruno /*
4376d756449SSean Bruno * Get a snapshot of all the interpreter entries in the list.
4386d756449SSean Bruno */
4396d756449SSean Bruno static int
imgact_binmisc_get_all_entries(struct sysctl_req * req)4406d756449SSean Bruno imgact_binmisc_get_all_entries(struct sysctl_req *req)
4416d756449SSean Bruno {
4426d756449SSean Bruno ximgact_binmisc_entry_t *xbe, *xbep;
4436d756449SSean Bruno imgact_binmisc_entry_t *ibe;
4446d756449SSean Bruno int error = 0, count;
4456d756449SSean Bruno
4462192cd12SKyle Evans INTERP_LIST_RLOCK();
4476d756449SSean Bruno count = interp_list_entry_count;
448e0ae213fSSean Bruno xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_WAITOK|M_ZERO);
4496d756449SSean Bruno
4506d756449SSean Bruno xbep = xbe;
4516d756449SSean Bruno SLIST_FOREACH(ibe, &interpreter_list, link) {
4526d756449SSean Bruno error = imgact_binmisc_populate_xbe(xbep++, ibe);
4536d756449SSean Bruno if (error)
4546d756449SSean Bruno break;
4556d756449SSean Bruno }
4562192cd12SKyle Evans INTERP_LIST_RUNLOCK();
4576d756449SSean Bruno
4586d756449SSean Bruno if (!error)
4596d756449SSean Bruno error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count);
4606d756449SSean Bruno
4616d756449SSean Bruno free(xbe, M_BINMISC);
4626d756449SSean Bruno return (error);
4636d756449SSean Bruno }
4646d756449SSean Bruno
4656d756449SSean Bruno /*
4666d756449SSean Bruno * sysctl() handler for munipulating interpretor table.
4676d756449SSean Bruno * Not MP safe (locked by sysctl).
4686d756449SSean Bruno */
4696d756449SSean Bruno static int
sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS)4706d756449SSean Bruno sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS)
4716d756449SSean Bruno {
4726d756449SSean Bruno ximgact_binmisc_entry_t xbe;
4736d756449SSean Bruno int error = 0;
4746d756449SSean Bruno
4756d756449SSean Bruno switch(arg2) {
4766d756449SSean Bruno case IBC_ADD:
4776d756449SSean Bruno /* Add an entry. Limited to IBE_MAX_ENTRIES. */
4786d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe));
4796d756449SSean Bruno if (error)
4806d756449SSean Bruno return (error);
4816d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version)
4826d756449SSean Bruno return (EINVAL);
4837d3ed977SKyle Evans if ((xbe.xbe_flags & ~IBF_VALID_UFLAGS) != 0)
4847d3ed977SKyle Evans return (EINVAL);
4856d756449SSean Bruno if (interp_list_entry_count == IBE_MAX_ENTRIES)
4866d756449SSean Bruno return (ENOSPC);
4876d756449SSean Bruno error = imgact_binmisc_add_entry(&xbe);
4886d756449SSean Bruno break;
4896d756449SSean Bruno
4906d756449SSean Bruno case IBC_REMOVE:
4916d756449SSean Bruno /* Remove an entry. */
4926d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe));
4936d756449SSean Bruno if (error)
4946d756449SSean Bruno return (error);
4956d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version)
4966d756449SSean Bruno return (EINVAL);
4976d756449SSean Bruno error = imgact_binmisc_remove_entry(xbe.xbe_name);
4986d756449SSean Bruno break;
4996d756449SSean Bruno
5006d756449SSean Bruno case IBC_DISABLE:
5016d756449SSean Bruno /* Disable an entry. */
5026d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe));
5036d756449SSean Bruno if (error)
5046d756449SSean Bruno return (error);
5056d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version)
5066d756449SSean Bruno return (EINVAL);
5076d756449SSean Bruno error = imgact_binmisc_disable_entry(xbe.xbe_name);
5086d756449SSean Bruno break;
5096d756449SSean Bruno
5106d756449SSean Bruno case IBC_ENABLE:
5116d756449SSean Bruno /* Enable an entry. */
5126d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe));
5136d756449SSean Bruno if (error)
5146d756449SSean Bruno return (error);
5156d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version)
5166d756449SSean Bruno return (EINVAL);
5176d756449SSean Bruno error = imgact_binmisc_enable_entry(xbe.xbe_name);
5186d756449SSean Bruno break;
5196d756449SSean Bruno
5206d756449SSean Bruno case IBC_LOOKUP:
5216d756449SSean Bruno /* Lookup an entry. */
5226d756449SSean Bruno error = SYSCTL_IN(req, &xbe, sizeof(xbe));
5236d756449SSean Bruno if (error)
5246d756449SSean Bruno return (error);
5256d756449SSean Bruno if (IBE_VERSION != xbe.xbe_version)
5266d756449SSean Bruno return (EINVAL);
5276d756449SSean Bruno error = imgact_binmisc_lookup_entry(xbe.xbe_name, &xbe);
5286d756449SSean Bruno if (!error)
5296d756449SSean Bruno error = SYSCTL_OUT(req, &xbe, sizeof(xbe));
5306d756449SSean Bruno break;
5316d756449SSean Bruno
5326d756449SSean Bruno case IBC_LIST:
5336d756449SSean Bruno /* Return a snapshot of the interpretor list. */
5346d756449SSean Bruno
5356d756449SSean Bruno if (!req->oldptr) {
5366d756449SSean Bruno /* No pointer then just return the list size. */
5376d756449SSean Bruno error = SYSCTL_OUT(req, 0, interp_list_entry_count *
5386d756449SSean Bruno sizeof(ximgact_binmisc_entry_t));
5396d756449SSean Bruno return (error);
5406d756449SSean Bruno } else
5416d756449SSean Bruno if (!req->oldlen)
5426d756449SSean Bruno return (EINVAL);
5436d756449SSean Bruno
5446d756449SSean Bruno error = imgact_binmisc_get_all_entries(req);
5456d756449SSean Bruno break;
5466d756449SSean Bruno
5476d756449SSean Bruno default:
5486d756449SSean Bruno return (EINVAL);
5496d756449SSean Bruno }
5506d756449SSean Bruno
5516d756449SSean Bruno return (error);
5526d756449SSean Bruno }
5536d756449SSean Bruno
5547029da5cSPawel Biernacki SYSCTL_NODE(_kern, OID_AUTO, binmisc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
5556d756449SSean Bruno "Image activator for miscellaneous binaries");
5566d756449SSean Bruno
5576d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, add,
5586d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ADD,
5596d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
5606d756449SSean Bruno "Add an activator entry");
5616d756449SSean Bruno
5626d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, remove,
5636d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_REMOVE,
5646d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
5656d756449SSean Bruno "Remove an activator entry");
5666d756449SSean Bruno
5676d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, disable,
5686d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_DISABLE,
5696d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
5706d756449SSean Bruno "Disable an activator entry");
5716d756449SSean Bruno
5726d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, enable,
5736d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ENABLE,
5746d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
5756d756449SSean Bruno "Enable an activator entry");
5766d756449SSean Bruno
5776d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, lookup,
5786d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RW|CTLFLAG_ANYBODY, NULL, IBC_LOOKUP,
5796d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
5806d756449SSean Bruno "Lookup an activator entry");
5816d756449SSean Bruno
5826d756449SSean Bruno SYSCTL_PROC(_kern_binmisc, OID_AUTO, list,
5836d756449SSean Bruno CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RD|CTLFLAG_ANYBODY, NULL, IBC_LIST,
5846d756449SSean Bruno sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
5856d756449SSean Bruno "Get snapshot of all the activator entries");
5866d756449SSean Bruno
5876d756449SSean Bruno static imgact_binmisc_entry_t *
imgact_binmisc_find_interpreter(const char * image_header)5886d756449SSean Bruno imgact_binmisc_find_interpreter(const char *image_header)
5896d756449SSean Bruno {
5906d756449SSean Bruno imgact_binmisc_entry_t *ibe;
5916d756449SSean Bruno const char *p;
5926d756449SSean Bruno int i;
5936d756449SSean Bruno size_t sz;
5946d756449SSean Bruno
5952192cd12SKyle Evans INTERP_LIST_ASSERT_LOCKED();
5966d756449SSean Bruno
5976d756449SSean Bruno SLIST_FOREACH(ibe, &interpreter_list, link) {
5986d756449SSean Bruno if (!(IBF_ENABLED & ibe->ibe_flags))
5996d756449SSean Bruno continue;
6006d756449SSean Bruno
6016d756449SSean Bruno p = image_header + ibe->ibe_moffset;
6026d756449SSean Bruno sz = ibe->ibe_msize;
6036d756449SSean Bruno if (IBF_USE_MASK & ibe->ibe_flags) {
6046d756449SSean Bruno /* Compare using mask. */
6056d756449SSean Bruno for (i = 0; i < sz; i++)
6066d756449SSean Bruno if ((*p++ ^ ibe->ibe_magic[i]) &
6076d756449SSean Bruno ibe->ibe_mask[i])
6086d756449SSean Bruno break;
6096d756449SSean Bruno } else {
6106d756449SSean Bruno for (i = 0; i < sz; i++)
6116d756449SSean Bruno if (*p++ ^ ibe->ibe_magic[i])
6126d756449SSean Bruno break;
6136d756449SSean Bruno }
6146d756449SSean Bruno if (i == ibe->ibe_msize)
6156d756449SSean Bruno return (ibe);
6166d756449SSean Bruno }
6176d756449SSean Bruno return (NULL);
6186d756449SSean Bruno }
6196d756449SSean Bruno
620945afa7cSSean Bruno static int
imgact_binmisc_exec(struct image_params * imgp)6216d756449SSean Bruno imgact_binmisc_exec(struct image_params *imgp)
6226d756449SSean Bruno {
6236d756449SSean Bruno const char *image_header = imgp->image_header;
6246d756449SSean Bruno const char *fname = NULL;
6256d756449SSean Bruno int error = 0;
6261024ef27SKyle Evans #ifdef INVARIANTS
6271024ef27SKyle Evans int argv0_cnt = 0;
6281024ef27SKyle Evans #endif
6291024ef27SKyle Evans size_t namelen, offset;
6306d756449SSean Bruno imgact_binmisc_entry_t *ibe;
6316d756449SSean Bruno struct sbuf *sname;
6326d756449SSean Bruno char *s, *d;
6336d756449SSean Bruno
63480083216SKyle Evans sname = NULL;
6351024ef27SKyle Evans namelen = 0;
6366d756449SSean Bruno /* Do we have an interpreter for the given image header? */
6372192cd12SKyle Evans INTERP_LIST_RLOCK();
6386d756449SSean Bruno if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) {
63980083216SKyle Evans error = -1;
64080083216SKyle Evans goto done;
6416d756449SSean Bruno }
6426d756449SSean Bruno
6436d756449SSean Bruno /* No interpreter nesting allowed. */
64465f20a89SSean Bruno if (imgp->interpreted & IMGACT_BINMISC) {
64580083216SKyle Evans error = ENOEXEC;
64680083216SKyle Evans goto done;
6476d756449SSean Bruno }
6486d756449SSean Bruno
64965f20a89SSean Bruno imgp->interpreted |= IMGACT_BINMISC;
6506d756449SSean Bruno
6511024ef27SKyle Evans /*
6521024ef27SKyle Evans * Don't bother with the overhead of putting fname together if we're not
6531024ef27SKyle Evans * using #a.
6541024ef27SKyle Evans */
6551024ef27SKyle Evans if (ibe->ibe_argv0_cnt != 0) {
6566d756449SSean Bruno if (imgp->args->fname != NULL) {
6576d756449SSean Bruno fname = imgp->args->fname;
6586d756449SSean Bruno } else {
659*088cc7d2SAlexander Ziaee /* Use the fdescfs(4) path for fexecve(2). */
6606d756449SSean Bruno sname = sbuf_new_auto();
6616d756449SSean Bruno sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd);
6626d756449SSean Bruno sbuf_finish(sname);
6636d756449SSean Bruno fname = sbuf_data(sname);
6646d756449SSean Bruno }
6656d756449SSean Bruno
6661024ef27SKyle Evans namelen = strlen(fname);
6671024ef27SKyle Evans }
6681024ef27SKyle Evans
6696d756449SSean Bruno /*
6706d756449SSean Bruno * We need to "push" the interpreter in the arg[] list. To do this,
6716d756449SSean Bruno * we first shift all the other values in the `begin_argv' area to
6726d756449SSean Bruno * provide the exact amount of room for the values added. Set up
6736d756449SSean Bruno * `offset' as the number of bytes to be added to the `begin_argv'
6741024ef27SKyle Evans * area. ibe_interp_offset is the fixed offset from macros present in
6751024ef27SKyle Evans * the interpreter string.
6766d756449SSean Bruno */
6771024ef27SKyle Evans offset = ibe->ibe_interp_length + ibe->ibe_interp_offset;
6786d756449SSean Bruno
6791024ef27SKyle Evans /* Variable offset to be added from macros to the interpreter string. */
6801024ef27SKyle Evans MPASS(ibe->ibe_argv0_cnt == 0 || namelen > 0);
6811024ef27SKyle Evans offset += ibe->ibe_argv0_cnt * (namelen - 2);
6826d756449SSean Bruno
683f373437aSBrooks Davis /* Make room for the interpreter */
684f373437aSBrooks Davis error = exec_args_adjust_args(imgp->args, 0, offset);
685f373437aSBrooks Davis if (error != 0) {
6866d756449SSean Bruno goto done;
6876d756449SSean Bruno }
6886d756449SSean Bruno
6896d756449SSean Bruno /* Add the new argument(s) in the count. */
6906d756449SSean Bruno imgp->args->argc += ibe->ibe_interp_argcnt;
6916d756449SSean Bruno
6926d756449SSean Bruno /*
6936d756449SSean Bruno * The original arg[] list has been shifted appropriately. Copy in
6946d756449SSean Bruno * the interpreter path.
6956d756449SSean Bruno */
6966d756449SSean Bruno s = ibe->ibe_interpreter;
6976d756449SSean Bruno d = imgp->args->begin_argv;
6986d756449SSean Bruno while(*s != '\0') {
6996d756449SSean Bruno switch (*s) {
7006d756449SSean Bruno case '#':
7016d756449SSean Bruno /* Handle "#" in interpreter string. */
7026d756449SSean Bruno s++;
7036d756449SSean Bruno switch(*s) {
7046d756449SSean Bruno case ISM_POUND:
7056d756449SSean Bruno /* "##": Replace with a single '#' */
7066d756449SSean Bruno *d++ = '#';
7076d756449SSean Bruno break;
7086d756449SSean Bruno case ISM_OLD_ARGV0:
7096d756449SSean Bruno /* "#a": Replace with old arg0 (fname). */
7101024ef27SKyle Evans MPASS(ibe->ibe_argv0_cnt >= ++argv0_cnt);
7111024ef27SKyle Evans memcpy(d, fname, namelen);
7121024ef27SKyle Evans d += namelen;
7136d756449SSean Bruno break;
7146d756449SSean Bruno default:
7151024ef27SKyle Evans __assert_unreachable();
7166d756449SSean Bruno }
7176d756449SSean Bruno break;
7186d756449SSean Bruno case ' ':
719e3043798SPedro F. Giffuni /* Replace space with NUL to separate arguments. */
7206d756449SSean Bruno *d++ = '\0';
7216d756449SSean Bruno break;
7226d756449SSean Bruno default:
7236d756449SSean Bruno *d++ = *s;
7246d756449SSean Bruno break;
7256d756449SSean Bruno }
7266d756449SSean Bruno s++;
7276d756449SSean Bruno }
7286d756449SSean Bruno *d = '\0';
7296d756449SSean Bruno
7301024ef27SKyle Evans /* Catch ibe->ibe_argv0_cnt counting more #a than we did. */
7311024ef27SKyle Evans MPASS(ibe->ibe_argv0_cnt == argv0_cnt);
7326d756449SSean Bruno imgp->interpreter_name = imgp->args->begin_argv;
7335eeb4f73SDoug Rabson if (ibe->ibe_interpreter_vnode) {
7345eeb4f73SDoug Rabson imgp->interpreter_vp = ibe->ibe_interpreter_vnode;
7355eeb4f73SDoug Rabson vref(imgp->interpreter_vp);
7365eeb4f73SDoug Rabson }
7376d756449SSean Bruno
7386d756449SSean Bruno done:
7392192cd12SKyle Evans INTERP_LIST_RUNLOCK();
7406d756449SSean Bruno if (sname)
7416d756449SSean Bruno sbuf_delete(sname);
7426d756449SSean Bruno return (error);
7436d756449SSean Bruno }
7446d756449SSean Bruno
7456d756449SSean Bruno static void
imgact_binmisc_init(void * arg)7466d756449SSean Bruno imgact_binmisc_init(void *arg)
7476d756449SSean Bruno {
7486d756449SSean Bruno
7492192cd12SKyle Evans INTERP_LIST_LOCK_INIT();
7506d756449SSean Bruno }
7516d756449SSean Bruno
7526d756449SSean Bruno static void
imgact_binmisc_fini(void * arg)7536d756449SSean Bruno imgact_binmisc_fini(void *arg)
7546d756449SSean Bruno {
7556d756449SSean Bruno imgact_binmisc_entry_t *ibe, *ibe_tmp;
7566d756449SSean Bruno
7576d756449SSean Bruno /* Free all the interpreters. */
7582192cd12SKyle Evans INTERP_LIST_WLOCK();
7596d756449SSean Bruno SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) {
7606d756449SSean Bruno SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry,
7616d756449SSean Bruno link);
7626d756449SSean Bruno imgact_binmisc_destroy_entry(ibe);
7636d756449SSean Bruno }
7642192cd12SKyle Evans INTERP_LIST_WUNLOCK();
7656d756449SSean Bruno
7662192cd12SKyle Evans INTERP_LIST_LOCK_DESTROY();
7676d756449SSean Bruno }
7686d756449SSean Bruno
769891cf3edSEd Maste SYSINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_init,
770891cf3edSEd Maste NULL);
771891cf3edSEd Maste SYSUNINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_fini,
772891cf3edSEd Maste NULL);
7736d756449SSean Bruno
7746d756449SSean Bruno /*
7756d756449SSean Bruno * Tell kern_execve.c about it, with a little help from the linker.
7766d756449SSean Bruno */
777b7feabf9SEd Maste static struct execsw imgact_binmisc_execsw = {
778b7feabf9SEd Maste .ex_imgact = imgact_binmisc_exec,
779b7feabf9SEd Maste .ex_name = KMOD_NAME
780b7feabf9SEd Maste };
7816d756449SSean Bruno EXEC_SET(imgact_binmisc, imgact_binmisc_execsw);
782