2 * Copyright (c) 2013-15, Stacey D. Son
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/ctype.h>
33 #include <sys/systm.h>
34 #include <sys/sysproto.h>
36 #include <sys/imgact.h>
37 #include <sys/imgact_binmisc.h>
38 #include <sys/kernel.h>
39 #include <sys/libkern.h>
41 #include <sys/malloc.h>
42 #include <sys/mutex.h>
43 #include <sys/sysctl.h>
46 #include <machine/atomic.h>
49 * Miscellaneous binary interpreter image activator.
51 * If the given target executable's header matches 'xbe_magic' field in the
52 * 'interpreter_list' then it will use the user-level interpreter specified in
53 * the 'xbe_interpreter' field to execute the binary. The 'xbe_magic' field may
54 * be adjusted to a given offset using the value in the 'xbe_moffset' field
55 * and bits of the header may be masked using the 'xbe_mask' field. The
56 * 'interpreter_list' entries are managed using sysctl(3) as described in the
57 * <sys/imgact_binmisc.h> file.
61 * Node of the interpreter list.
63 typedef struct imgact_binmisc_entry
{
69 uint8_t *ibe_interpreter
;
70 uint32_t ibe_interp_argcnt
;
71 uint32_t ibe_interp_length
;
73 SLIST_ENTRY(imgact_binmisc_entry
) link
;
74 } imgact_binmisc_entry_t
;
79 #define IBC_ADD 1 /* Add given entry. */
80 #define IBC_REMOVE 2 /* Remove entry for a given name. */
81 #define IBC_DISABLE 3 /* Disable entry for a given name. */
82 #define IBC_ENABLE 4 /* Enable entry for a given name. */
83 #define IBC_LOOKUP 5 /* Lookup and return entry for given name. */
84 #define IBC_LIST 6 /* Get a snapshot of the interpretor list. */
87 * Interpreter string macros.
89 * They all start with '#' followed by a single letter:
91 #define ISM_POUND '#' /* "##" is the escape sequence for single #. */
92 #define ISM_OLD_ARGV0 'a' /* "#a" is replaced with the old argv0. */
94 MALLOC_DEFINE(M_BINMISC
, KMOD_NAME
, "misc binary image activator");
96 /* The interpreter list. */
97 static SLIST_HEAD(, imgact_binmisc_entry
) interpreter_list
=
98 SLIST_HEAD_INITIALIZER(interpreter_list
);
100 static int interp_list_entry_count
= 0;
102 static struct sx interp_list_sx
;
104 int imgact_binmisc_exec(struct image_params
*imgp
);
108 * Populate the entry with the information about the interpreter.
111 imgact_binmisc_populate_interp(char *str
, imgact_binmisc_entry_t
*ibe
)
113 uint32_t len
= 0, argc
= 1;
114 char t
[IBE_INTERP_LEN_MAX
];
117 memset(t
, 0, sizeof(t
));
120 * Normalize interpreter string. Replace white space between args with
124 while (*sp
!= '\0') {
125 if (*sp
== ' ' || *sp
== '\t') {
126 if (++len
> IBE_INTERP_LEN_MAX
)
130 while (*sp
== ' ' || *sp
== '\t')
141 ibe
->ibe_interpreter
= malloc(len
, M_BINMISC
, M_WAITOK
|M_ZERO
);
143 /* Populate all the ibe fields for the interpreter. */
144 memcpy(ibe
->ibe_interpreter
, t
, len
);
145 ibe
->ibe_interp_argcnt
= argc
;
146 ibe
->ibe_interp_length
= len
;
150 * Allocate memory and populate a new entry for the interpreter table.
152 static imgact_binmisc_entry_t
*
153 imgact_binmisc_new_entry(ximgact_binmisc_entry_t
*xbe
)
155 imgact_binmisc_entry_t
*ibe
= NULL
;
156 size_t namesz
= min(strlen(xbe
->xbe_name
) + 1, IBE_NAME_MAX
);
158 ibe
= malloc(sizeof(*ibe
), M_BINMISC
, M_WAITOK
|M_ZERO
);
160 ibe
->ibe_name
= malloc(namesz
, M_BINMISC
, M_WAITOK
|M_ZERO
);
161 strlcpy(ibe
->ibe_name
, xbe
->xbe_name
, namesz
);
163 imgact_binmisc_populate_interp(xbe
->xbe_interpreter
, ibe
);
165 ibe
->ibe_magic
= malloc(xbe
->xbe_msize
, M_BINMISC
, M_WAITOK
|M_ZERO
);
166 memcpy(ibe
->ibe_magic
, xbe
->xbe_magic
, xbe
->xbe_msize
);
168 ibe
->ibe_mask
= malloc(xbe
->xbe_msize
, M_BINMISC
, M_WAITOK
|M_ZERO
);
169 memcpy(ibe
->ibe_mask
, xbe
->xbe_mask
, xbe
->xbe_msize
);
171 ibe
->ibe_moffset
= xbe
->xbe_moffset
;
172 ibe
->ibe_msize
= xbe
->xbe_msize
;
173 ibe
->ibe_flags
= xbe
->xbe_flags
;
179 * Free the allocated memory for a given list item.
182 imgact_binmisc_destroy_entry(imgact_binmisc_entry_t
*ibe
)
187 free(ibe
->ibe_magic
, M_BINMISC
);
189 free(ibe
->ibe_mask
, M_BINMISC
);
190 if (ibe
->ibe_interpreter
)
191 free(ibe
->ibe_interpreter
, M_BINMISC
);
193 free(ibe
->ibe_name
, M_BINMISC
);
195 free(ibe
, M_BINMISC
);
199 * Find the interpreter in the list by the given name. Return NULL if not
202 static imgact_binmisc_entry_t
*
203 imgact_binmisc_find_entry(char *name
)
205 imgact_binmisc_entry_t
*ibe
;
207 sx_assert(&interp_list_sx
, SA_LOCKED
);
209 SLIST_FOREACH(ibe
, &interpreter_list
, link
) {
210 if (strncmp(name
, ibe
->ibe_name
, IBE_NAME_MAX
) == 0)
218 * Add the given interpreter if it doesn't already exist. Return EEXIST
219 * if the name already exist in the interpreter list.
222 imgact_binmisc_add_entry(ximgact_binmisc_entry_t
*xbe
)
224 imgact_binmisc_entry_t
*ibe
;
227 if (xbe
->xbe_msize
> IBE_MAGIC_MAX
)
230 for(p
= xbe
->xbe_name
; *p
!= 0; p
++)
231 if (!isascii((int)*p
))
234 for(p
= xbe
->xbe_interpreter
; *p
!= 0; p
++)
235 if (!isascii((int)*p
))
238 /* Make sure we don't have any invalid #'s. */
239 p
= xbe
->xbe_interpreter
;
259 /* Anything besides the above is invalid. */
264 sx_xlock(&interp_list_sx
);
265 if (imgact_binmisc_find_entry(xbe
->xbe_name
) != NULL
) {
266 sx_xunlock(&interp_list_sx
);
270 /* Preallocate a new entry. */
271 ibe
= imgact_binmisc_new_entry(xbe
);
275 SLIST_INSERT_HEAD(&interpreter_list
, ibe
, link
);
276 interp_list_entry_count
++;
277 sx_xunlock(&interp_list_sx
);
283 * Remove the interpreter in the list with the given name. Return ENOENT
287 imgact_binmisc_remove_entry(char *name
)
289 imgact_binmisc_entry_t
*ibe
;
291 sx_xlock(&interp_list_sx
);
292 if ((ibe
= imgact_binmisc_find_entry(name
)) == NULL
) {
293 sx_xunlock(&interp_list_sx
);
296 SLIST_REMOVE(&interpreter_list
, ibe
, imgact_binmisc_entry
, link
);
297 interp_list_entry_count
--;
298 sx_xunlock(&interp_list_sx
);
300 imgact_binmisc_destroy_entry(ibe
);
306 * Disable the interpreter in the list with the given name. Return ENOENT
310 imgact_binmisc_disable_entry(char *name
)
312 imgact_binmisc_entry_t
*ibe
;
314 sx_slock(&interp_list_sx
);
315 if ((ibe
= imgact_binmisc_find_entry(name
)) == NULL
) {
316 sx_sunlock(&interp_list_sx
);
320 atomic_clear_32(&ibe
->ibe_flags
, IBF_ENABLED
);
321 sx_sunlock(&interp_list_sx
);
327 * Enable the interpreter in the list with the given name. Return ENOENT
331 imgact_binmisc_enable_entry(char *name
)
333 imgact_binmisc_entry_t
*ibe
;
335 sx_slock(&interp_list_sx
);
336 if ((ibe
= imgact_binmisc_find_entry(name
)) == NULL
) {
337 sx_sunlock(&interp_list_sx
);
341 atomic_set_32(&ibe
->ibe_flags
, IBF_ENABLED
);
342 sx_sunlock(&interp_list_sx
);
348 imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t
*xbe
,
349 imgact_binmisc_entry_t
*ibe
)
353 sx_assert(&interp_list_sx
, SA_LOCKED
);
355 memset(xbe
, 0, sizeof(*xbe
));
356 strlcpy(xbe
->xbe_name
, ibe
->ibe_name
, IBE_NAME_MAX
);
358 /* Copy interpreter string. Replace NULL breaks with space. */
359 memcpy(xbe
->xbe_interpreter
, ibe
->ibe_interpreter
,
360 ibe
->ibe_interp_length
);
361 for(i
= 0; i
< (ibe
->ibe_interp_length
- 1); i
++)
362 if (xbe
->xbe_interpreter
[i
] == '\0')
363 xbe
->xbe_interpreter
[i
] = ' ';
365 memcpy(xbe
->xbe_magic
, ibe
->ibe_magic
, ibe
->ibe_msize
);
366 memcpy(xbe
->xbe_mask
, ibe
->ibe_mask
, ibe
->ibe_msize
);
367 xbe
->xbe_version
= IBE_VERSION
;
368 xbe
->xbe_flags
= ibe
->ibe_flags
;
369 xbe
->xbe_moffset
= ibe
->ibe_moffset
;
370 xbe
->xbe_msize
= ibe
->ibe_msize
;
376 * Retrieve the interpreter with the give name and populate the
377 * ximgact_binmisc_entry structure. Return ENOENT if not found.
380 imgact_binmisc_lookup_entry(char *name
, ximgact_binmisc_entry_t
*xbe
)
382 imgact_binmisc_entry_t
*ibe
;
385 sx_slock(&interp_list_sx
);
386 if ((ibe
= imgact_binmisc_find_entry(name
)) == NULL
) {
387 sx_sunlock(&interp_list_sx
);
391 error
= imgact_binmisc_populate_xbe(xbe
, ibe
);
392 sx_sunlock(&interp_list_sx
);
398 * Get a snapshot of all the interpreter entries in the list.
401 imgact_binmisc_get_all_entries(struct sysctl_req
*req
)
403 ximgact_binmisc_entry_t
*xbe
, *xbep
;
404 imgact_binmisc_entry_t
*ibe
;
405 int error
= 0, count
;
407 sx_slock(&interp_list_sx
);
408 count
= interp_list_entry_count
;
409 xbe
= malloc(sizeof(*xbe
) * count
, M_BINMISC
, M_ZERO
);
411 sx_sunlock(&interp_list_sx
);
416 SLIST_FOREACH(ibe
, &interpreter_list
, link
) {
417 error
= imgact_binmisc_populate_xbe(xbep
++, ibe
);
421 sx_sunlock(&interp_list_sx
);
424 error
= SYSCTL_OUT(req
, xbe
, sizeof(*xbe
) * count
);
426 free(xbe
, M_BINMISC
);
431 * sysctl() handler for munipulating interpretor table.
432 * Not MP safe (locked by sysctl).
435 sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS
)
437 ximgact_binmisc_entry_t xbe
;
442 /* Add an entry. Limited to IBE_MAX_ENTRIES. */
443 error
= SYSCTL_IN(req
, &xbe
, sizeof(xbe
));
446 if (IBE_VERSION
!= xbe
.xbe_version
)
448 if (interp_list_entry_count
== IBE_MAX_ENTRIES
)
450 error
= imgact_binmisc_add_entry(&xbe
);
454 /* Remove an entry. */
455 error
= SYSCTL_IN(req
, &xbe
, sizeof(xbe
));
458 if (IBE_VERSION
!= xbe
.xbe_version
)
460 error
= imgact_binmisc_remove_entry(xbe
.xbe_name
);
464 /* Disable an entry. */
465 error
= SYSCTL_IN(req
, &xbe
, sizeof(xbe
));
468 if (IBE_VERSION
!= xbe
.xbe_version
)
470 error
= imgact_binmisc_disable_entry(xbe
.xbe_name
);
474 /* Enable an entry. */
475 error
= SYSCTL_IN(req
, &xbe
, sizeof(xbe
));
478 if (IBE_VERSION
!= xbe
.xbe_version
)
480 error
= imgact_binmisc_enable_entry(xbe
.xbe_name
);
484 /* Lookup an entry. */
485 error
= SYSCTL_IN(req
, &xbe
, sizeof(xbe
));
488 if (IBE_VERSION
!= xbe
.xbe_version
)
490 error
= imgact_binmisc_lookup_entry(xbe
.xbe_name
, &xbe
);
492 error
= SYSCTL_OUT(req
, &xbe
, sizeof(xbe
));
496 /* Return a snapshot of the interpretor list. */
499 /* No pointer then just return the list size. */
500 error
= SYSCTL_OUT(req
, 0, interp_list_entry_count
*
501 sizeof(ximgact_binmisc_entry_t
));
507 error
= imgact_binmisc_get_all_entries(req
);
517 SYSCTL_NODE(_kern
, OID_AUTO
, binmisc
, CTLFLAG_RW
, 0,
518 "Image activator for miscellaneous binaries");
520 SYSCTL_PROC(_kern_binmisc
, OID_AUTO
, add
,
521 CTLFLAG_MPSAFE
|CTLTYPE_STRUCT
|CTLFLAG_WR
, NULL
, IBC_ADD
,
522 sysctl_kern_binmisc
, "S,ximgact_binmisc_entry",
523 "Add an activator entry");
525 SYSCTL_PROC(_kern_binmisc
, OID_AUTO
, remove
,
526 CTLFLAG_MPSAFE
|CTLTYPE_STRUCT
|CTLFLAG_WR
, NULL
, IBC_REMOVE
,
527 sysctl_kern_binmisc
, "S,ximgact_binmisc_entry",
528 "Remove an activator entry");
530 SYSCTL_PROC(_kern_binmisc
, OID_AUTO
, disable
,
531 CTLFLAG_MPSAFE
|CTLTYPE_STRUCT
|CTLFLAG_WR
, NULL
, IBC_DISABLE
,
532 sysctl_kern_binmisc
, "S,ximgact_binmisc_entry",
533 "Disable an activator entry");
535 SYSCTL_PROC(_kern_binmisc
, OID_AUTO
, enable
,
536 CTLFLAG_MPSAFE
|CTLTYPE_STRUCT
|CTLFLAG_WR
, NULL
, IBC_ENABLE
,
537 sysctl_kern_binmisc
, "S,ximgact_binmisc_entry",
538 "Enable an activator entry");
540 SYSCTL_PROC(_kern_binmisc
, OID_AUTO
, lookup
,
541 CTLFLAG_MPSAFE
|CTLTYPE_STRUCT
|CTLFLAG_RW
|CTLFLAG_ANYBODY
, NULL
, IBC_LOOKUP
,
542 sysctl_kern_binmisc
, "S,ximgact_binmisc_entry",
543 "Lookup an activator entry");
545 SYSCTL_PROC(_kern_binmisc
, OID_AUTO
, list
,
546 CTLFLAG_MPSAFE
|CTLTYPE_STRUCT
|CTLFLAG_RD
|CTLFLAG_ANYBODY
, NULL
, IBC_LIST
,
547 sysctl_kern_binmisc
, "S,ximgact_binmisc_entry",
548 "Get snapshot of all the activator entries");
550 static imgact_binmisc_entry_t
*
551 imgact_binmisc_find_interpreter(const char *image_header
)
553 imgact_binmisc_entry_t
*ibe
;
558 sx_assert(&interp_list_sx
, SA_LOCKED
);
560 SLIST_FOREACH(ibe
, &interpreter_list
, link
) {
561 if (!(IBF_ENABLED
& ibe
->ibe_flags
))
564 p
= image_header
+ ibe
->ibe_moffset
;
566 if (IBF_USE_MASK
& ibe
->ibe_flags
) {
567 /* Compare using mask. */
568 for (i
= 0; i
< sz
; i
++)
569 if ((*p
++ ^ ibe
->ibe_magic
[i
]) &
573 for (i
= 0; i
< sz
; i
++)
574 if (*p
++ ^ ibe
->ibe_magic
[i
])
577 if (i
== ibe
->ibe_msize
)
584 imgact_binmisc_exec(struct image_params
*imgp
)
586 const char *image_header
= imgp
->image_header
;
587 const char *fname
= NULL
;
590 imgact_binmisc_entry_t
*ibe
;
594 /* Do we have an interpreter for the given image header? */
595 sx_slock(&interp_list_sx
);
596 if ((ibe
= imgact_binmisc_find_interpreter(image_header
)) == NULL
) {
597 sx_sunlock(&interp_list_sx
);
601 /* No interpreter nesting allowed. */
602 if (imgp
->interpreted
& IMGACT_BINMISC
) {
603 sx_sunlock(&interp_list_sx
);
607 imgp
->interpreted
|= IMGACT_BINMISC
;
609 if (imgp
->args
->fname
!= NULL
) {
610 fname
= imgp
->args
->fname
;
613 /* Use the fdescfs(5) path for fexecve(2). */
614 sname
= sbuf_new_auto();
615 sbuf_printf(sname
, "/dev/fd/%d", imgp
->args
->fd
);
617 fname
= sbuf_data(sname
);
622 * We need to "push" the interpreter in the arg[] list. To do this,
623 * we first shift all the other values in the `begin_argv' area to
624 * provide the exact amount of room for the values added. Set up
625 * `offset' as the number of bytes to be added to the `begin_argv'
628 offset
= ibe
->ibe_interp_length
;
630 /* Adjust the offset for #'s. */
631 s
= ibe
->ibe_interpreter
;
640 /* "##" -> "#": reduce offset by one. */
645 /* "#a" -> (old argv0): increase offset to fit fname */
646 offset
+= strlen(fname
) - 2;
650 /* Hmm... This shouldn't happen. */
651 sx_sunlock(&interp_list_sx
);
652 printf("%s: Unknown macro #%c sequence in "
653 "interpreter string\n", KMOD_NAME
, *(s
+ 1));
660 /* Check to make sure we won't overrun the stringspace. */
661 if (offset
> imgp
->args
->stringspace
) {
662 sx_sunlock(&interp_list_sx
);
667 /* Make room for the interpreter */
668 bcopy(imgp
->args
->begin_argv
, imgp
->args
->begin_argv
+ offset
,
669 imgp
->args
->endp
- imgp
->args
->begin_argv
);
671 /* Adjust everything by the offset. */
672 imgp
->args
->begin_envv
+= offset
;
673 imgp
->args
->endp
+= offset
;
674 imgp
->args
->stringspace
-= offset
;
676 /* Add the new argument(s) in the count. */
677 imgp
->args
->argc
+= ibe
->ibe_interp_argcnt
;
680 * The original arg[] list has been shifted appropriately. Copy in
681 * the interpreter path.
683 s
= ibe
->ibe_interpreter
;
684 d
= imgp
->args
->begin_argv
;
688 /* Handle "#" in interpreter string. */
692 /* "##": Replace with a single '#' */
697 /* "#a": Replace with old arg0 (fname). */
698 if ((l
= strlen(fname
)) != 0) {
705 /* Shouldn't happen but skip it if it does. */
711 /* Replace space with NUL to seperate arguments. */
722 sx_sunlock(&interp_list_sx
);
725 imgp
->interpreter_name
= imgp
->args
->begin_argv
;
735 imgact_binmisc_init(void *arg
)
738 sx_init(&interp_list_sx
, KMOD_NAME
);
742 imgact_binmisc_fini(void *arg
)
744 imgact_binmisc_entry_t
*ibe
, *ibe_tmp
;
746 /* Free all the interpreters. */
747 sx_xlock(&interp_list_sx
);
748 SLIST_FOREACH_SAFE(ibe
, &interpreter_list
, link
, ibe_tmp
) {
749 SLIST_REMOVE(&interpreter_list
, ibe
, imgact_binmisc_entry
,
751 imgact_binmisc_destroy_entry(ibe
);
753 sx_xunlock(&interp_list_sx
);
755 sx_destroy(&interp_list_sx
);
758 SYSINIT(imgact_binmisc
, SI_SUB_EXEC
, SI_ORDER_MIDDLE
, imgact_binmisc_init
, 0);
759 SYSUNINIT(imgact_binmisc
, SI_SUB_EXEC
, SI_ORDER_MIDDLE
, imgact_binmisc_fini
, 0);
762 * Tell kern_execve.c about it, with a little help from the linker.
764 static struct execsw imgact_binmisc_execsw
= { imgact_binmisc_exec
, KMOD_NAME
};
765 EXEC_SET(imgact_binmisc
, imgact_binmisc_execsw
);