Changeset View
Standalone View
sys/kern/imgact_binmisc.c
Show First 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
#define ISM_OLD_ARGV0 'a' /* "#a" is replaced with the old argv0. */ | #define ISM_OLD_ARGV0 'a' /* "#a" is replaced with the old argv0. */ | ||||
MALLOC_DEFINE(M_BINMISC, KMOD_NAME, "misc binary image activator"); | MALLOC_DEFINE(M_BINMISC, KMOD_NAME, "misc binary image activator"); | ||||
/* The interpreter list. */ | /* The interpreter list. */ | ||||
static SLIST_HEAD(, imgact_binmisc_entry) interpreter_list = | static SLIST_HEAD(, imgact_binmisc_entry) interpreter_list = | ||||
SLIST_HEAD_INITIALIZER(interpreter_list); | SLIST_HEAD_INITIALIZER(interpreter_list); | ||||
static int interp_list_entry_count = 0; | static int interp_list_entry_count = 0; | ||||
static int interp_list_rcount = 0; | |||||
static struct mtx interp_list_mtx; | |||||
jhb: Maybe call it 'interp_list_lock'? | |||||
Not Done Inline ActionsI don't think I'm going to do this. sbruno: I don't think I'm going to do this. | |||||
static struct sx interp_list_sx; | |||||
int imgact_binmisc_exec(struct image_params *imgp); | int imgact_binmisc_exec(struct image_params *imgp); | ||||
static inline void | |||||
interp_list_rlock() | |||||
{ | |||||
/* Don't use atomic_add() here. We must block if the mutex is held. */ | |||||
mtx_lock(&interp_list_mtx); | |||||
interp_list_rcount++; | |||||
mtx_unlock(&interp_list_mtx); | |||||
} | |||||
static inline void | |||||
interp_list_runlock() | |||||
{ | |||||
/* Decrement the reader count and wake up one writer, if any. */ | |||||
atomic_subtract_int(&interp_list_rcount, 1); | |||||
if (interp_list_rcount == 0) | |||||
wakeup_one(&interp_list_rcount); | |||||
} | |||||
static inline void | |||||
interp_list_wlock() | |||||
{ | |||||
/* Wait until there are no readers. */ | |||||
mtx_lock(&interp_list_mtx); | |||||
while (interp_list_rcount) | |||||
mtx_sleep(&interp_list_rcount, &interp_list_mtx, 0, "IABM", 0); | |||||
} | |||||
static inline void | |||||
interp_list_wunlock() | |||||
{ | |||||
mtx_unlock(&interp_list_mtx); | |||||
} | |||||
#define interp_list_assert_rlocked() \ | |||||
KASSERT(interp_list_rcount > 0, ("%s: interp_list lock not held " \ | |||||
"for read", __func__)) | |||||
#define interp_list_assert_wlocked() mtx_assert(&interp_list_mtx, MA_OWNED) | |||||
#ifdef INVARIANTS | |||||
#define interp_list_assert_locked() do { \ | |||||
if (interp_list_rcount == 0) \ | |||||
mtx_assert(&interp_list_mtx, MA_OWNED); \ | |||||
else \ | |||||
KASSERT(interp_list_rcount > 0, \ | |||||
("%s: interp_list lock not held", __func__)); \ | |||||
} while(0) | |||||
#else /* ! INVARIANTS */ | |||||
#define interp_list_assert_locked() do { \ | |||||
} while(0) | |||||
#endif /* ! INVARIANTS */ | |||||
/* | /* | ||||
* Populate the entry with the information about the interpreter. | * Populate the entry with the information about the interpreter. | ||||
*/ | */ | ||||
static void | static void | ||||
imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe) | imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe) | ||||
{ | { | ||||
uint32_t len = 0, argc = 1; | uint32_t len = 0, argc = 1; | ||||
char t[IBE_INTERP_LEN_MAX]; | char t[IBE_INTERP_LEN_MAX]; | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
* Find the interpreter in the list by the given name. Return NULL if not | * Find the interpreter in the list by the given name. Return NULL if not | ||||
* found. | * found. | ||||
*/ | */ | ||||
static imgact_binmisc_entry_t * | static imgact_binmisc_entry_t * | ||||
imgact_binmisc_find_entry(char *name) | imgact_binmisc_find_entry(char *name) | ||||
{ | { | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
interp_list_assert_locked(); | sx_assert(&interp_list_sx, SA_LOCKED); | ||||
SLIST_FOREACH(ibe, &interpreter_list, link) { | SLIST_FOREACH(ibe, &interpreter_list, link) { | ||||
if (strncmp(name, ibe->ibe_name, IBE_NAME_MAX) == 0) | if (strncmp(name, ibe->ibe_name, IBE_NAME_MAX) == 0) | ||||
return (ibe); | return (ibe); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
Show All 40 Lines | while (1) { | ||||
case 0: | case 0: | ||||
default: | default: | ||||
/* Anything besides the above is invalid. */ | /* Anything besides the above is invalid. */ | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} | } | ||||
/* Preallocate a new entry. */ | /* Preallocate a new entry. */ | ||||
Done Inline ActionsWith an sx lock you can use the old logic order since you can hold it across the malloc(). jhb: With an sx lock you can use the old logic order since you can hold it across the malloc(). | |||||
Done Inline Actionsoh ... is this a potential race here if we *do not* hold the lock across the call to imgact_binmisc_new_entry() call (e.g. we don't restore the old lock order?) sbruno: oh ... is this a potential race here if we *do not* hold the lock across the call to… | |||||
Done Inline ActionsNo, there is no race here. It is just imgact_binmisc_new_entry() mallocs a new entry but if it doesn't need the entry it free()'s it. With sleep locks we can malloc() it while holding the lock and, therefore, don't have to go to the trouble of pre-allocating a new entry. sson: No, there is no race here. It is just imgact_binmisc_new_entry() mallocs a new entry but if it… | |||||
ibe = imgact_binmisc_new_entry(xbe); | ibe = imgact_binmisc_new_entry(xbe); | ||||
if (!ibe) | if (!ibe) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
interp_list_wlock(); | sx_xlock(&interp_list_sx); | ||||
if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) { | if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) { | ||||
interp_list_wunlock(); | sx_xunlock(&interp_list_sx); | ||||
imgact_binmisc_destroy_entry(ibe); | imgact_binmisc_destroy_entry(ibe); | ||||
return (EEXIST); | return (EEXIST); | ||||
} | } | ||||
SLIST_INSERT_HEAD(&interpreter_list, ibe, link); | SLIST_INSERT_HEAD(&interpreter_list, ibe, link); | ||||
interp_list_entry_count++; | interp_list_entry_count++; | ||||
interp_list_wunlock(); | sx_xunlock(&interp_list_sx); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Remove the interpreter in the list with the given name. Return ENOENT | * Remove the interpreter in the list with the given name. Return ENOENT | ||||
* if not found. | * if not found. | ||||
*/ | */ | ||||
static int | static int | ||||
imgact_binmisc_remove_entry(char *name) | imgact_binmisc_remove_entry(char *name) | ||||
{ | { | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
interp_list_wlock(); | sx_xlock(&interp_list_sx); | ||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | ||||
interp_list_wunlock(); | sx_xunlock(&interp_list_sx); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link); | SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link); | ||||
interp_list_entry_count--; | interp_list_entry_count--; | ||||
interp_list_wunlock(); | sx_xunlock(&interp_list_sx); | ||||
imgact_binmisc_destroy_entry(ibe); | imgact_binmisc_destroy_entry(ibe); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Disable the interpreter in the list with the given name. Return ENOENT | * Disable the interpreter in the list with the given name. Return ENOENT | ||||
* if not found. | * if not found. | ||||
*/ | */ | ||||
static int | static int | ||||
imgact_binmisc_disable_entry(char *name) | imgact_binmisc_disable_entry(char *name) | ||||
{ | { | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
interp_list_rlock(); | sx_slock(&interp_list_sx); | ||||
Done Inline ActionsIt would seem simpler to just use an xlock here and use plain ops for updating ibe_flags since my guess is that enabling/disabling entries isn't really a hot path? jhb: It would seem simpler to just use an xlock here and use plain ops for updating ibe_flags since… | |||||
Done Inline Actionshrm ... don't we need to make this atomic because we *REALLY* want to make sure this happens during a review of the interpret list? sbruno: hrm ... don't we need to make this atomic because we *REALLY* want to make sure this happens… | |||||
Done Inline ActionsYes, this is really a hot path and we could just exclusively lock it here and not use the atomics to clear the flag. sson: Yes, this is really a hot path and we could just exclusively lock it here and not use the… | |||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
atomic_clear_32(&ibe->ibe_flags, IBF_ENABLED); | atomic_clear_32(&ibe->ibe_flags, IBF_ENABLED); | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Enable the interpreter in the list with the given name. Return ENOENT | * Enable the interpreter in the list with the given name. Return ENOENT | ||||
* if not found. | * if not found. | ||||
*/ | */ | ||||
static int | static int | ||||
imgact_binmisc_enable_entry(char *name) | imgact_binmisc_enable_entry(char *name) | ||||
{ | { | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
interp_list_rlock(); | sx_slock(&interp_list_sx); | ||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
atomic_set_32(&ibe->ibe_flags, IBF_ENABLED); | atomic_set_32(&ibe->ibe_flags, IBF_ENABLED); | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe, | imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe, | ||||
imgact_binmisc_entry_t *ibe) | imgact_binmisc_entry_t *ibe) | ||||
{ | { | ||||
uint32_t i; | uint32_t i; | ||||
interp_list_assert_rlocked(); | sx_assert(&interp_list_sx, SA_LOCKED); | ||||
memset(xbe, 0, sizeof(*xbe)); | memset(xbe, 0, sizeof(*xbe)); | ||||
strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX); | strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX); | ||||
/* Copy interpreter string. Replace NULL breaks with space. */ | /* Copy interpreter string. Replace NULL breaks with space. */ | ||||
memcpy(xbe->xbe_interpreter, ibe->ibe_interpreter, | memcpy(xbe->xbe_interpreter, ibe->ibe_interpreter, | ||||
ibe->ibe_interp_length); | ibe->ibe_interp_length); | ||||
for(i = 0; i < (ibe->ibe_interp_length - 1); i++) | for(i = 0; i < (ibe->ibe_interp_length - 1); i++) | ||||
Show All 15 Lines | |||||
* ximgact_binmisc_entry structure. Return ENOENT if not found. | * ximgact_binmisc_entry structure. Return ENOENT if not found. | ||||
*/ | */ | ||||
static int | static int | ||||
imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe) | imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe) | ||||
{ | { | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
int error = 0; | int error = 0; | ||||
interp_list_rlock(); | sx_slock(&interp_list_sx); | ||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | if ((ibe = imgact_binmisc_find_entry(name)) == NULL) { | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
error = imgact_binmisc_populate_xbe(xbe, ibe); | error = imgact_binmisc_populate_xbe(xbe, ibe); | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Get a snapshot of all the interpreter entries in the list. | * Get a snapshot of all the interpreter entries in the list. | ||||
*/ | */ | ||||
static int | static int | ||||
imgact_binmisc_get_all_entries(struct sysctl_req *req) | imgact_binmisc_get_all_entries(struct sysctl_req *req) | ||||
{ | { | ||||
ximgact_binmisc_entry_t *xbe, *xbep; | ximgact_binmisc_entry_t *xbe, *xbep; | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
int error = 0, count; | int error = 0, count; | ||||
interp_list_rlock(); | sx_slock(&interp_list_sx); | ||||
count = interp_list_entry_count; | count = interp_list_entry_count; | ||||
/* Don't block in malloc() while holding lock. */ | /* Don't block in malloc() while holding lock. */ | ||||
xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_NOWAIT|M_ZERO); | xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_NOWAIT|M_ZERO); | ||||
if (!xbe) { | if (!xbe) { | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
xbep = xbe; | xbep = xbe; | ||||
SLIST_FOREACH(ibe, &interpreter_list, link) { | SLIST_FOREACH(ibe, &interpreter_list, link) { | ||||
error = imgact_binmisc_populate_xbe(xbep++, ibe); | error = imgact_binmisc_populate_xbe(xbep++, ibe); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
} | } | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
if (!error) | if (!error) | ||||
error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count); | error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count); | ||||
free(xbe, M_BINMISC); | free(xbe, M_BINMISC); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
static imgact_binmisc_entry_t * | static imgact_binmisc_entry_t * | ||||
imgact_binmisc_find_interpreter(const char *image_header) | imgact_binmisc_find_interpreter(const char *image_header) | ||||
{ | { | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
const char *p; | const char *p; | ||||
int i; | int i; | ||||
size_t sz; | size_t sz; | ||||
interp_list_assert_rlocked(); | sx_assert(&interp_list_sx, SA_LOCKED); | ||||
SLIST_FOREACH(ibe, &interpreter_list, link) { | SLIST_FOREACH(ibe, &interpreter_list, link) { | ||||
if (!(IBF_ENABLED & ibe->ibe_flags)) | if (!(IBF_ENABLED & ibe->ibe_flags)) | ||||
continue; | continue; | ||||
p = image_header + ibe->ibe_moffset; | p = image_header + ibe->ibe_moffset; | ||||
sz = ibe->ibe_msize; | sz = ibe->ibe_msize; | ||||
if (IBF_USE_MASK & ibe->ibe_flags) { | if (IBF_USE_MASK & ibe->ibe_flags) { | ||||
Show All 20 Lines | imgact_binmisc_exec(struct image_params *imgp) | ||||
const char *fname = NULL; | const char *fname = NULL; | ||||
int error = 0; | int error = 0; | ||||
size_t offset, l; | size_t offset, l; | ||||
imgact_binmisc_entry_t *ibe; | imgact_binmisc_entry_t *ibe; | ||||
struct sbuf *sname; | struct sbuf *sname; | ||||
char *s, *d; | char *s, *d; | ||||
/* Do we have an interpreter for the given image header? */ | /* Do we have an interpreter for the given image header? */ | ||||
interp_list_rlock(); | sx_slock(&interp_list_sx); | ||||
if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) { | if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) { | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* No interpreter nesting allowed. */ | /* No interpreter nesting allowed. */ | ||||
if (imgp->interpreted & IMGACT_BINMISC) { | if (imgp->interpreted & IMGACT_BINMISC) { | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
} | } | ||||
imgp->interpreted |= IMGACT_BINMISC; | imgp->interpreted |= IMGACT_BINMISC; | ||||
if (imgp->args->fname != NULL) { | if (imgp->args->fname != NULL) { | ||||
fname = imgp->args->fname; | fname = imgp->args->fname; | ||||
sname = NULL; | sname = NULL; | ||||
Show All 31 Lines | while (1) { | ||||
case ISM_OLD_ARGV0: | case ISM_OLD_ARGV0: | ||||
/* "#a" -> (old argv0): increase offset to fit fname */ | /* "#a" -> (old argv0): increase offset to fit fname */ | ||||
offset += strlen(fname) - 2; | offset += strlen(fname) - 2; | ||||
break; | break; | ||||
default: | default: | ||||
/* Hmm... This shouldn't happen. */ | /* Hmm... This shouldn't happen. */ | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
printf("%s: Unknown macro #%c sequence in " | printf("%s: Unknown macro #%c sequence in " | ||||
"interpreter string\n", KMOD_NAME, *(s + 1)); | "interpreter string\n", KMOD_NAME, *(s + 1)); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done; | goto done; | ||||
} | } | ||||
s++; | s++; | ||||
} | } | ||||
/* Check to make sure we won't overrun the stringspace. */ | /* Check to make sure we won't overrun the stringspace. */ | ||||
if (offset > imgp->args->stringspace) { | if (offset > imgp->args->stringspace) { | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
error = E2BIG; | error = E2BIG; | ||||
goto done; | goto done; | ||||
} | } | ||||
/* | /* Make room for the interpreter */ | ||||
* Make room for the interpreter. Doing an overlapping copy so | |||||
* bcopy() must be used. | |||||
*/ | |||||
bcopy(imgp->args->begin_argv, imgp->args->begin_argv + offset, | bcopy(imgp->args->begin_argv, imgp->args->begin_argv + offset, | ||||
Done Inline ActionsThis should stay a bcopy() since it is an overlaying copy. memcpy() doesn't do well with that. sson: This should stay a bcopy() since it is an overlaying copy. memcpy() doesn't do well with that. | |||||
sbrunoAuthorUnsubmitted Done Inline Actionsyepper, done. sbruno: yepper, done. | |||||
Done Inline ActionsWhitespace diff? jhb: Whitespace diff? | |||||
Done Inline ActionsNo, this was memcpy() but memcpy() doesn't do play well overlapping memory which is required here. Sean changed it to bcopy() so now it looks like a whitespace diff. sson: No, this was memcpy() but memcpy() doesn't do play well overlapping memory which is required… | |||||
imgp->args->endp - imgp->args->begin_argv); | imgp->args->endp - imgp->args->begin_argv); | ||||
/* Adjust everything by the offset. */ | /* Adjust everything by the offset. */ | ||||
imgp->args->begin_envv += offset; | imgp->args->begin_envv += offset; | ||||
imgp->args->endp += offset; | imgp->args->endp += offset; | ||||
imgp->args->stringspace -= offset; | imgp->args->stringspace -= offset; | ||||
/* Add the new argument(s) in the count. */ | /* Add the new argument(s) in the count. */ | ||||
Show All 37 Lines | while(*s != '\0') { | ||||
default: | default: | ||||
*d++ = *s; | *d++ = *s; | ||||
break; | break; | ||||
} | } | ||||
s++; | s++; | ||||
} | } | ||||
*d = '\0'; | *d = '\0'; | ||||
interp_list_runlock(); | sx_sunlock(&interp_list_sx); | ||||
if (!error) | if (!error) | ||||
imgp->interpreter_name = imgp->args->begin_argv; | imgp->interpreter_name = imgp->args->begin_argv; | ||||
done: | done: | ||||
if (sname) | if (sname) | ||||
sbuf_delete(sname); | sbuf_delete(sname); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
imgact_binmisc_init(void *arg) | imgact_binmisc_init(void *arg) | ||||
{ | { | ||||
mtx_init(&interp_list_mtx, KMOD_NAME, NULL, MTX_DEF); | sx_init(&interp_list_sx, KMOD_NAME); | ||||
} | } | ||||
static void | static void | ||||
imgact_binmisc_fini(void *arg) | imgact_binmisc_fini(void *arg) | ||||
{ | { | ||||
imgact_binmisc_entry_t *ibe, *ibe_tmp; | imgact_binmisc_entry_t *ibe, *ibe_tmp; | ||||
/* Free all the interpreters. */ | /* Free all the interpreters. */ | ||||
interp_list_wlock(); | sx_xlock(&interp_list_sx); | ||||
SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) { | SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) { | ||||
SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, | SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, | ||||
link); | link); | ||||
imgact_binmisc_destroy_entry(ibe); | imgact_binmisc_destroy_entry(ibe); | ||||
} | } | ||||
interp_list_wunlock(); | sx_xunlock(&interp_list_sx); | ||||
mtx_destroy(&interp_list_mtx); | sx_destroy(&interp_list_sx); | ||||
} | } | ||||
SYSINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_init, 0); | SYSINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_init, 0); | ||||
SYSUNINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_fini, 0); | SYSUNINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_fini, 0); | ||||
/* | /* | ||||
* Tell kern_execve.c about it, with a little help from the linker. | * Tell kern_execve.c about it, with a little help from the linker. | ||||
*/ | */ | ||||
static struct execsw imgact_binmisc_execsw = { imgact_binmisc_exec, KMOD_NAME }; | static struct execsw imgact_binmisc_execsw = { imgact_binmisc_exec, KMOD_NAME }; | ||||
EXEC_SET(imgact_binmisc, imgact_binmisc_execsw); | EXEC_SET(imgact_binmisc, imgact_binmisc_execsw); |
Maybe call it 'interp_list_lock'?