1/*
2 * Copyright (c) 2013-16, Stacey D. Son
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/param.h>
31#include <sys/ctype.h>
32#include <sys/sbuf.h>
33#include <sys/systm.h>
34#include <sys/sysproto.h>
35#include <sys/exec.h>
36#include <sys/imgact.h>
37#include <sys/imgact_binmisc.h>
38#include <sys/kernel.h>
39#include <sys/libkern.h>
40#include <sys/lock.h>
41#include <sys/malloc.h>
42#include <sys/mutex.h>
43#include <sys/sysctl.h>
44
45/**
46 * Miscellaneous binary interpreter image activator.
47 *
48 * If the given target executable's header matches 'xbe_magic' field in the
49 * 'interpreter_list' then it will use the user-level interpreter specified in
50 * the 'xbe_interpreter' field to execute the binary. The 'xbe_magic' field may
51 * be adjusted to a given offset using the value in the 'xbe_moffset' field
52 * and bits of the header may be masked using the 'xbe_mask' field.  The
53 * 'interpreter_list' entries are managed using sysctl(3) as described in the
54 * <sys/imgact_binmisc.h> file.
55 */
56
57/*
58 * Node of the interpreter list.
59 */
60typedef struct imgact_binmisc_entry {
61	char				 *ibe_name;
62	uint8_t				 *ibe_magic;
63	uint32_t			  ibe_moffset;
64	uint32_t			  ibe_msize;
65	uint8_t				 *ibe_mask;
66	uint8_t				 *ibe_interpreter;
67	uint32_t			  ibe_interp_argcnt;
68	uint32_t			  ibe_interp_length;
69	uint32_t			  ibe_flags;
70	SLIST_ENTRY(imgact_binmisc_entry) link;
71} imgact_binmisc_entry_t;
72
73/*
74 * sysctl() commands.
75 */
76#define IBC_ADD		1	/* Add given entry. */
77#define IBC_REMOVE	2	/* Remove entry for a given name. */
78#define IBC_DISABLE	3	/* Disable entry for a given name. */
79#define IBC_ENABLE	4	/* Enable entry for a given name. */
80#define IBC_LOOKUP	5	/* Lookup and return entry for given name. */
81#define IBC_LIST	6	/* Get a snapshot of the interpretor list. */
82
83/*
84 * Interpreter string macros.
85 *
86 * They all start with '#' followed by a single letter:
87 */
88#define	ISM_POUND	'#'	/* "##" is the escape sequence for single #. */
89#define	ISM_OLD_ARGV0	'a'	/* "#a" is replaced with the old argv0. */
90
91MALLOC_DEFINE(M_BINMISC, KMOD_NAME, "misc binary image activator");
92
93/* The interpreter list. */
94static SLIST_HEAD(, imgact_binmisc_entry) interpreter_list =
95	SLIST_HEAD_INITIALIZER(interpreter_list);
96
97static int interp_list_entry_count = 0;
98
99static struct mtx interp_list_mtx;
100
101int imgact_binmisc_exec(struct image_params *imgp);
102
103
104/*
105 * Populate the entry with the information about the interpreter.
106 */
107static void
108imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe)
109{
110	uint32_t len = 0, argc = 1;
111	char t[IBE_INTERP_LEN_MAX];
112	char *sp, *tp;
113
114	bzero(t, sizeof(t));
115
116	/*
117	 * Normalize interpreter string. Replace white space between args with
118	 * single space.
119	 */
120	sp = str; tp = t;
121	while (*sp != '\0') {
122		if (*sp == ' ' || *sp == '\t') {
123			if (++len > IBE_INTERP_LEN_MAX)
124				break;
125			*tp++ = ' ';
126			argc++;
127			while (*sp == ' ' || *sp == '\t')
128				sp++;
129			continue;
130		} else {
131			*tp++ = *sp++;
132			len++;
133		}
134	}
135	*tp = '\0';
136	len++;
137
138	ibe->ibe_interpreter = malloc(len, M_BINMISC, M_WAITOK|M_ZERO);
139
140	/* Populate all the ibe fields for the interpreter. */
141	memcpy(ibe->ibe_interpreter, t, len);
142	ibe->ibe_interp_argcnt = argc;
143	ibe->ibe_interp_length = len;
144}
145
146/*
147 * Allocate memory and populate a new entry for the interpreter table.
148 */
149static imgact_binmisc_entry_t *
150imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe)
151{
152	imgact_binmisc_entry_t *ibe = NULL;
153	size_t namesz = min(strlen(xbe->xbe_name) + 1, IBE_NAME_MAX);
154
155	mtx_assert(&interp_list_mtx, MA_NOTOWNED);
156
157	ibe = malloc(sizeof(*ibe), M_BINMISC, M_WAITOK|M_ZERO);
158
159	ibe->ibe_name = malloc(namesz, M_BINMISC, M_WAITOK|M_ZERO);
160	strlcpy(ibe->ibe_name, xbe->xbe_name, namesz);
161
162	imgact_binmisc_populate_interp(xbe->xbe_interpreter, ibe);
163
164	ibe->ibe_magic = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO);
165	memcpy(ibe->ibe_magic, xbe->xbe_magic, xbe->xbe_msize);
166
167	ibe->ibe_mask = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO);
168	memcpy(ibe->ibe_mask, xbe->xbe_mask, xbe->xbe_msize);
169
170	ibe->ibe_moffset = xbe->xbe_moffset;
171	ibe->ibe_msize = xbe->xbe_msize;
172	ibe->ibe_flags = xbe->xbe_flags;
173
174	return (ibe);
175}
176
177/*
178 * Free the allocated memory for a given list item.
179 */
180static void
181imgact_binmisc_destroy_entry(imgact_binmisc_entry_t *ibe)
182{
183	if (!ibe)
184		return;
185	if (ibe->ibe_magic)
186		free(ibe->ibe_magic, M_BINMISC);
187	if (ibe->ibe_mask)
188		free(ibe->ibe_mask, M_BINMISC);
189	if (ibe->ibe_interpreter)
190		free(ibe->ibe_interpreter, M_BINMISC);
191	if (ibe->ibe_name)
192		free(ibe->ibe_name, M_BINMISC);
193	if (ibe)
194		free(ibe, M_BINMISC);
195}
196
197/*
198 * Find the interpreter in the list by the given name.  Return NULL if not
199 * found.
200 */
201static imgact_binmisc_entry_t *
202imgact_binmisc_find_entry(char *name)
203{
204	imgact_binmisc_entry_t *ibe;
205
206	mtx_assert(&interp_list_mtx, MA_OWNED);
207
208	SLIST_FOREACH(ibe, &interpreter_list, link) {
209		if (strncmp(name, ibe->ibe_name, IBE_NAME_MAX) == 0)
210			return (ibe);
211	}
212
213	return (NULL);
214}
215
216/*
217 * Add the given interpreter if it doesn't already exist.  Return EEXIST
218 * if the name already exist in the interpreter list.
219 */
220static int
221imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe)
222{
223	imgact_binmisc_entry_t *ibe;
224	char *p;
225	int cnt;
226
227	if (xbe->xbe_msize > IBE_MAGIC_MAX)
228		return (EINVAL);
229
230	for(cnt = 0, p = xbe->xbe_name; *p != 0; cnt++, p++)
231		if (cnt >= IBE_NAME_MAX || !isascii((int)*p))
232			return (EINVAL);
233
234	for(cnt = 0, p = xbe->xbe_interpreter; *p != 0; cnt++, p++)
235		if (cnt >= IBE_INTERP_LEN_MAX || !isascii((int)*p))
236			return (EINVAL);
237
238	/* Make sure we don't have any invalid #'s. */
239	p = xbe->xbe_interpreter;
240	while (1) {
241		p = strchr(p, '#');
242		if (!p)
243			break;
244
245		p++;
246		switch(*p) {
247		case ISM_POUND:
248			/* "##" */
249			p++;
250			break;
251
252		case ISM_OLD_ARGV0:
253			/* "#a" */
254			p++;
255			break;
256
257		case 0:
258		default:
259			/* Anything besides the above is invalid. */
260			return (EINVAL);
261		}
262	}
263
264	mtx_lock(&interp_list_mtx);
265	if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) {
266		mtx_unlock(&interp_list_mtx);
267		return (EEXIST);
268	}
269	mtx_unlock(&interp_list_mtx);
270
271	ibe = imgact_binmisc_new_entry(xbe);
272
273	mtx_lock(&interp_list_mtx);
274	SLIST_INSERT_HEAD(&interpreter_list, ibe, link);
275	interp_list_entry_count++;
276	mtx_unlock(&interp_list_mtx);
277
278	return (0);
279}
280
281/*
282 * Remove the interpreter in the list with the given name. Return ENOENT
283 * if not found.
284 */
285static int
286imgact_binmisc_remove_entry(char *name)
287{
288	imgact_binmisc_entry_t *ibe;
289
290	mtx_lock(&interp_list_mtx);
291	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
292		mtx_unlock(&interp_list_mtx);
293		return (ENOENT);
294	}
295	SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link);
296	interp_list_entry_count--;
297	mtx_unlock(&interp_list_mtx);
298
299	imgact_binmisc_destroy_entry(ibe);
300
301	return (0);
302}
303
304/*
305 * Disable the interpreter in the list with the given name. Return ENOENT
306 * if not found.
307 */
308static int
309imgact_binmisc_disable_entry(char *name)
310{
311	imgact_binmisc_entry_t *ibe;
312
313	mtx_lock(&interp_list_mtx);
314	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
315		mtx_unlock(&interp_list_mtx);
316		return (ENOENT);
317	}
318
319	ibe->ibe_flags &= ~IBF_ENABLED;
320	mtx_unlock(&interp_list_mtx);
321
322	return (0);
323}
324
325/*
326 * Enable the interpreter in the list with the given name. Return ENOENT
327 * if not found.
328 */
329static int
330imgact_binmisc_enable_entry(char *name)
331{
332	imgact_binmisc_entry_t *ibe;
333
334	mtx_lock(&interp_list_mtx);
335	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
336		mtx_unlock(&interp_list_mtx);
337		return (ENOENT);
338	}
339
340	ibe->ibe_flags |= IBF_ENABLED;
341	mtx_unlock(&interp_list_mtx);
342
343	return (0);
344}
345
346static int
347imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe,
348    imgact_binmisc_entry_t *ibe)
349{
350	uint32_t i;
351
352	mtx_assert(&interp_list_mtx, MA_OWNED);
353
354	bzero(xbe, sizeof(*xbe));
355	strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX);
356
357	/* Copy interpreter string.  Replace NULL breaks with space. */
358	memcpy(xbe->xbe_interpreter, ibe->ibe_interpreter,
359	    ibe->ibe_interp_length);
360	for(i = 0; i < (ibe->ibe_interp_length - 1); i++)
361		if (xbe->xbe_interpreter[i] == '\0')
362			xbe->xbe_interpreter[i] = ' ';
363
364	memcpy(xbe->xbe_magic, ibe->ibe_magic, ibe->ibe_msize);
365	memcpy(xbe->xbe_mask, ibe->ibe_mask, ibe->ibe_msize);
366	xbe->xbe_version = IBE_VERSION;
367	xbe->xbe_flags = ibe->ibe_flags;
368	xbe->xbe_moffset = ibe->ibe_moffset;
369	xbe->xbe_msize = ibe->ibe_msize;
370
371	return (0);
372}
373
374/*
375 * Retrieve the interpreter with the give name and populate the
376 * ximgact_binmisc_entry structure.  Return ENOENT if not found.
377 */
378static int
379imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe)
380{
381	imgact_binmisc_entry_t *ibe;
382	int error = 0;
383
384	mtx_lock(&interp_list_mtx);
385	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
386		mtx_unlock(&interp_list_mtx);
387		return (ENOENT);
388	}
389
390	error = imgact_binmisc_populate_xbe(xbe, ibe);
391	mtx_unlock(&interp_list_mtx);
392
393	return (error);
394}
395
396/*
397 * Get a snapshot of all the interpreter entries in the list.
398 */
399static int
400imgact_binmisc_get_all_entries(struct sysctl_req *req)
401{
402	ximgact_binmisc_entry_t *xbe, *xbep;
403	imgact_binmisc_entry_t *ibe;
404	int error = 0, count;
405
406	mtx_lock(&interp_list_mtx);
407	count = interp_list_entry_count;
408	/* Don't block in malloc() while holding lock. */
409	xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_NOWAIT|M_ZERO);
410	if (!xbe) {
411		mtx_unlock(&interp_list_mtx);
412		return (ENOMEM);
413	}
414
415	xbep = xbe;
416	SLIST_FOREACH(ibe, &interpreter_list, link) {
417		error = imgact_binmisc_populate_xbe(xbep++, ibe);
418		if (error)
419			break;
420	}
421	mtx_unlock(&interp_list_mtx);
422
423	if (!error)
424		error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count);
425
426	free(xbe, M_BINMISC);
427	return (error);
428}
429
430/*
431 * sysctl() handler for munipulating interpretor table.
432 * Not MP safe (locked by sysctl).
433 */
434static int
435sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS)
436{
437	ximgact_binmisc_entry_t xbe;
438	int error = 0;
439
440	switch(arg2) {
441	case IBC_ADD:
442		/* Add an entry. Limited to IBE_MAX_ENTRIES. */
443		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
444		if (error)
445			return (error);
446		if (IBE_VERSION != xbe.xbe_version)
447			return (EINVAL);
448		if (interp_list_entry_count == IBE_MAX_ENTRIES)
449			return (ENOSPC);
450		error = imgact_binmisc_add_entry(&xbe);
451		break;
452
453	case IBC_REMOVE:
454		/* Remove an entry. */
455		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
456		if (error)
457			return (error);
458		if (IBE_VERSION != xbe.xbe_version)
459			return (EINVAL);
460		error = imgact_binmisc_remove_entry(xbe.xbe_name);
461		break;
462
463	case IBC_DISABLE:
464		/* Disable an entry. */
465		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
466		if (error)
467			return (error);
468		if (IBE_VERSION != xbe.xbe_version)
469			return (EINVAL);
470		error = imgact_binmisc_disable_entry(xbe.xbe_name);
471		break;
472
473	case IBC_ENABLE:
474		/* Enable an entry. */
475		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
476		if (error)
477			return (error);
478		if (IBE_VERSION != xbe.xbe_version)
479			return (EINVAL);
480		error = imgact_binmisc_enable_entry(xbe.xbe_name);
481		break;
482
483	case IBC_LOOKUP:
484		/* Lookup an entry. */
485		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
486		if (error)
487			return (error);
488		if (IBE_VERSION != xbe.xbe_version)
489			return (EINVAL);
490		error = imgact_binmisc_lookup_entry(xbe.xbe_name, &xbe);
491		if (!error)
492			error = SYSCTL_OUT(req, &xbe, sizeof(xbe));
493		break;
494
495	case IBC_LIST:
496		/* Return a snapshot of the interpretor list. */
497
498		if (!req->oldptr) {
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));
502			return (error);
503		} else
504			if (!req->oldlen)
505				return (EINVAL);
506
507		error = imgact_binmisc_get_all_entries(req);
508		break;
509
510	default:
511		return (EINVAL);
512	}
513
514	return (error);
515}
516
517SYSCTL_NODE(_kern, OID_AUTO, binmisc, CTLFLAG_RW, 0,
518    "Image activator for miscellaneous binaries");
519
520SYSCTL_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");
524
525SYSCTL_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");
529
530SYSCTL_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");
534
535SYSCTL_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");
539
540SYSCTL_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");
544
545SYSCTL_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");
549
550static imgact_binmisc_entry_t *
551imgact_binmisc_find_interpreter(const char *image_header)
552{
553	imgact_binmisc_entry_t *ibe;
554	const char *p;
555	int i;
556	size_t sz;
557
558	mtx_assert(&interp_list_mtx, MA_OWNED);
559
560	SLIST_FOREACH(ibe, &interpreter_list, link) {
561		if (!(IBF_ENABLED & ibe->ibe_flags))
562			continue;
563
564		p = image_header + ibe->ibe_moffset;
565		sz = ibe->ibe_msize;
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]) &
570				    ibe->ibe_mask[i])
571					break;
572		} else {
573			for (i = 0; i < sz; i++)
574				if (*p++ ^ ibe->ibe_magic[i])
575					break;
576		}
577		if (i == ibe->ibe_msize)
578			return (ibe);
579	}
580	return (NULL);
581}
582
583int
584imgact_binmisc_exec(struct image_params *imgp)
585{
586	const char *image_header = imgp->image_header;
587	const char *fname = NULL;
588	int error = 0;
589	size_t offset, l;
590	imgact_binmisc_entry_t *ibe;
591	struct sbuf *sname;
592	char *s, *d;
593
594	/* Do we have an interpreter for the given image header? */
595	mtx_lock(&interp_list_mtx);
596	if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) {
597		mtx_unlock(&interp_list_mtx);
598		return (-1);
599	}
600
601	/* No interpreter nesting allowed. */
602	if (imgp->interpreted & IMGACT_BINMISC) {
603		mtx_unlock(&interp_list_mtx);
604		return (ENOEXEC);
605	}
606
607	imgp->interpreted |= IMGACT_BINMISC;
608
609	if (imgp->args->fname != NULL) {
610		fname = imgp->args->fname;
611		sname = NULL;
612	} else {
613		/* Use the fdescfs(5) path for fexecve(2). */
614		sname = sbuf_new_auto();
615		sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd);
616		sbuf_finish(sname);
617		fname = sbuf_data(sname);
618	}
619
620
621	/*
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'
626	 * area.
627	 */
628	offset = ibe->ibe_interp_length;
629
630	/* Adjust the offset for #'s. */
631	s = ibe->ibe_interpreter;
632	while (1) {
633		s = strchr(s, '#');
634		if (!s)
635			break;
636
637		s++;
638		switch(*s) {
639		case ISM_POUND:
640			/* "##" -> "#": reduce offset by one. */
641			offset--;
642			break;
643
644		case ISM_OLD_ARGV0:
645			/* "#a" -> (old argv0): increase offset to fit fname */
646			offset += strlen(fname) - 2;
647			break;
648
649		default:
650			/* Hmm... This shouldn't happen. */
651			mtx_unlock(&interp_list_mtx);
652			printf("%s: Unknown macro #%c sequence in "
653			    "interpreter string\n", KMOD_NAME, *(s + 1));
654			error = EINVAL;
655			goto done;
656		}
657		s++;
658	}
659
660	/* Check to make sure we won't overrun the stringspace. */
661	if (offset > imgp->args->stringspace) {
662		mtx_unlock(&interp_list_mtx);
663		error = E2BIG;
664		goto done;
665	}
666
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);
670
671	/* Adjust everything by the offset. */
672	imgp->args->begin_envv += offset;
673	imgp->args->endp += offset;
674	imgp->args->stringspace -= offset;
675
676	/* Add the new argument(s) in the count. */
677	imgp->args->argc += ibe->ibe_interp_argcnt;
678
679	/*
680	 * The original arg[] list has been shifted appropriately.  Copy in
681	 * the interpreter path.
682	 */
683	s = ibe->ibe_interpreter;
684	d = imgp->args->begin_argv;
685	while(*s != '\0') {
686		switch (*s) {
687		case '#':
688			/* Handle "#" in interpreter string. */
689			s++;
690			switch(*s) {
691			case ISM_POUND:
692				/* "##": Replace with a single '#' */
693				*d++ = '#';
694				break;
695
696			case ISM_OLD_ARGV0:
697				/* "#a": Replace with old arg0 (fname). */
698				if ((l = strlen(fname)) != 0) {
699					memcpy(d, fname, l);
700					d += l;
701				}
702				break;
703
704			default:
705				/* Shouldn't happen but skip it if it does. */
706				break;
707			}
708			break;
709
710		case ' ':
711			/* Replace space with NUL to separate arguments. */
712			*d++ = '\0';
713			break;
714
715		default:
716			*d++ = *s;
717			break;
718		}
719		s++;
720	}
721	*d = '\0';
722	mtx_unlock(&interp_list_mtx);
723
724	if (!error)
725		imgp->interpreter_name = imgp->args->begin_argv;
726
727
728done:
729	if (sname)
730		sbuf_delete(sname);
731	return (error);
732}
733
734static void
735imgact_binmisc_init(void *arg)
736{
737
738	mtx_init(&interp_list_mtx, KMOD_NAME, NULL, MTX_DEF);
739}
740
741static void
742imgact_binmisc_fini(void *arg)
743{
744	imgact_binmisc_entry_t *ibe, *ibe_tmp;
745
746	/* Free all the interpreters. */
747	mtx_lock(&interp_list_mtx);
748	SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) {
749		SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry,
750		    link);
751		imgact_binmisc_destroy_entry(ibe);
752	}
753	mtx_unlock(&interp_list_mtx);
754
755	mtx_destroy(&interp_list_mtx);
756}
757
758SYSINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_init, 0);
759SYSUNINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_fini, 0);
760
761/*
762 * Tell kern_execve.c about it, with a little help from the linker.
763 */
764static struct execsw imgact_binmisc_execsw = { imgact_binmisc_exec, KMOD_NAME };
765EXEC_SET(imgact_binmisc, imgact_binmisc_execsw);
766