imgact_binmisc.c revision 266272
1/*-
2 * Copyright (c) 2013, 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: stable/10/sys/kern/imgact_binmisc.c 266272 2014-05-16 21:56:33Z sbruno $");
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
226	if (xbe->xbe_msize > IBE_MAGIC_MAX)
227		return (EINVAL);
228
229	for(p = xbe->xbe_name; *p != 0; p++)
230		if (!isascii((int)*p))
231			return (EINVAL);
232
233	for(p = xbe->xbe_interpreter; *p != 0; p++)
234		if (!isascii((int)*p))
235			return (EINVAL);
236
237	/* Make sure we don't have any invalid #'s. */
238	p = xbe->xbe_interpreter;
239	while (1) {
240		p = strchr(p, '#');
241		if (!p)
242			break;
243
244		p++;
245		switch(*p) {
246		case ISM_POUND:
247			/* "##" */
248			p++;
249			break;
250
251		case ISM_OLD_ARGV0:
252			/* "#a" */
253			p++;
254			break;
255
256		case 0:
257		default:
258			/* Anything besides the above is invalid. */
259			return (EINVAL);
260		}
261	}
262
263	mtx_lock(&interp_list_mtx);
264	if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) {
265		mtx_unlock(&interp_list_mtx);
266		return (EEXIST);
267	}
268	mtx_unlock(&interp_list_mtx);
269
270	ibe = imgact_binmisc_new_entry(xbe);
271	if (!ibe)
272		return (ENOMEM);
273
274	mtx_lock(&interp_list_mtx);
275	SLIST_INSERT_HEAD(&interpreter_list, ibe, link);
276	interp_list_entry_count++;
277	mtx_unlock(&interp_list_mtx);
278
279	return (0);
280}
281
282/*
283 * Remove the interpreter in the list with the given name. Return ENOENT
284 * if not found.
285 */
286static int
287imgact_binmisc_remove_entry(char *name)
288{
289	imgact_binmisc_entry_t *ibe;
290
291	mtx_lock(&interp_list_mtx);
292	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
293		mtx_unlock(&interp_list_mtx);
294		return (ENOENT);
295	}
296	SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link);
297	interp_list_entry_count--;
298	mtx_unlock(&interp_list_mtx);
299
300	imgact_binmisc_destroy_entry(ibe);
301
302	return (0);
303}
304
305/*
306 * Disable the interpreter in the list with the given name. Return ENOENT
307 * if not found.
308 */
309static int
310imgact_binmisc_disable_entry(char *name)
311{
312	imgact_binmisc_entry_t *ibe;
313
314	mtx_lock(&interp_list_mtx);
315	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
316		mtx_unlock(&interp_list_mtx);
317		return (ENOENT);
318	}
319
320	ibe->ibe_flags &= ~IBF_ENABLED;
321	mtx_unlock(&interp_list_mtx);
322
323	return (0);
324}
325
326/*
327 * Enable the interpreter in the list with the given name. Return ENOENT
328 * if not found.
329 */
330static int
331imgact_binmisc_enable_entry(char *name)
332{
333	imgact_binmisc_entry_t *ibe;
334
335	mtx_lock(&interp_list_mtx);
336	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
337		mtx_unlock(&interp_list_mtx);
338		return (ENOENT);
339	}
340
341	ibe->ibe_flags |= IBF_ENABLED;
342	mtx_unlock(&interp_list_mtx);
343
344	return (0);
345}
346
347static int
348imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe,
349    imgact_binmisc_entry_t *ibe)
350{
351	uint32_t i;
352
353	mtx_assert(&interp_list_mtx, MA_OWNED);
354
355	bzero(xbe, sizeof(*xbe));
356	strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX);
357
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] = ' ';
364
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;
371
372	return (0);
373}
374
375/*
376 * Retrieve the interpreter with the give name and populate the
377 * ximgact_binmisc_entry structure.  Return ENOENT if not found.
378 */
379static int
380imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe)
381{
382	imgact_binmisc_entry_t *ibe;
383	int error = 0;
384
385	mtx_lock(&interp_list_mtx);
386	if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
387		mtx_unlock(&interp_list_mtx);
388		return (ENOENT);
389	}
390
391	error = imgact_binmisc_populate_xbe(xbe, ibe);
392	mtx_unlock(&interp_list_mtx);
393
394	return (error);
395}
396
397/*
398 * Get a snapshot of all the interpreter entries in the list.
399 */
400static int
401imgact_binmisc_get_all_entries(struct sysctl_req *req)
402{
403	ximgact_binmisc_entry_t *xbe, *xbep;
404	imgact_binmisc_entry_t *ibe;
405	int error = 0, count;
406
407	mtx_lock(&interp_list_mtx);
408	count = interp_list_entry_count;
409	/* Don't block in malloc() while holding lock. */
410	xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_NOWAIT|M_ZERO);
411	if (!xbe) {
412		mtx_unlock(&interp_list_mtx);
413		return (ENOMEM);
414	}
415
416	xbep = xbe;
417	SLIST_FOREACH(ibe, &interpreter_list, link) {
418		error = imgact_binmisc_populate_xbe(xbep++, ibe);
419		if (error)
420			break;
421	}
422	mtx_unlock(&interp_list_mtx);
423
424	if (!error)
425		error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count);
426
427	free(xbe, M_BINMISC);
428	return (error);
429}
430
431/*
432 * sysctl() handler for munipulating interpretor table.
433 * Not MP safe (locked by sysctl).
434 */
435static int
436sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS)
437{
438	ximgact_binmisc_entry_t xbe;
439	int error = 0;
440
441	switch(arg2) {
442	case IBC_ADD:
443		/* Add an entry. Limited to IBE_MAX_ENTRIES. */
444		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
445		if (error)
446			return (error);
447		if (IBE_VERSION != xbe.xbe_version)
448			return (EINVAL);
449		if (interp_list_entry_count == IBE_MAX_ENTRIES)
450			return (ENOSPC);
451		error = imgact_binmisc_add_entry(&xbe);
452		break;
453
454	case IBC_REMOVE:
455		/* Remove an entry. */
456		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
457		if (error)
458			return (error);
459		if (IBE_VERSION != xbe.xbe_version)
460			return (EINVAL);
461		error = imgact_binmisc_remove_entry(xbe.xbe_name);
462		break;
463
464	case IBC_DISABLE:
465		/* Disable an entry. */
466		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
467		if (error)
468			return (error);
469		if (IBE_VERSION != xbe.xbe_version)
470			return (EINVAL);
471		error = imgact_binmisc_disable_entry(xbe.xbe_name);
472		break;
473
474	case IBC_ENABLE:
475		/* Enable an entry. */
476		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
477		if (error)
478			return (error);
479		if (IBE_VERSION != xbe.xbe_version)
480			return (EINVAL);
481		error = imgact_binmisc_enable_entry(xbe.xbe_name);
482		break;
483
484	case IBC_LOOKUP:
485		/* Lookup an entry. */
486		error = SYSCTL_IN(req, &xbe, sizeof(xbe));
487		if (error)
488			return (error);
489		if (IBE_VERSION != xbe.xbe_version)
490			return (EINVAL);
491		error = imgact_binmisc_lookup_entry(xbe.xbe_name, &xbe);
492		if (!error)
493			error = SYSCTL_OUT(req, &xbe, sizeof(xbe));
494		break;
495
496	case IBC_LIST:
497		/* Return a snapshot of the interpretor list. */
498
499		if (!req->oldptr) {
500			/* No pointer then just return the list size. */
501			error = SYSCTL_OUT(req, 0, interp_list_entry_count *
502			    sizeof(ximgact_binmisc_entry_t));
503			return (error);
504		} else
505			if (!req->oldlen)
506				return (EINVAL);
507
508		error = imgact_binmisc_get_all_entries(req);
509		break;
510
511	default:
512		return (EINVAL);
513	}
514
515	return (error);
516}
517
518SYSCTL_NODE(_kern, OID_AUTO, binmisc, CTLFLAG_RW, 0,
519    "Image activator for miscellaneous binaries");
520
521SYSCTL_PROC(_kern_binmisc, OID_AUTO, add,
522    CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ADD,
523    sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
524    "Add an activator entry");
525
526SYSCTL_PROC(_kern_binmisc, OID_AUTO, remove,
527    CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_REMOVE,
528    sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
529    "Remove an activator entry");
530
531SYSCTL_PROC(_kern_binmisc, OID_AUTO, disable,
532    CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_DISABLE,
533    sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
534    "Disable an activator entry");
535
536SYSCTL_PROC(_kern_binmisc, OID_AUTO, enable,
537    CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ENABLE,
538    sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
539    "Enable an activator entry");
540
541SYSCTL_PROC(_kern_binmisc, OID_AUTO, lookup,
542    CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RW|CTLFLAG_ANYBODY, NULL, IBC_LOOKUP,
543    sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
544    "Lookup an activator entry");
545
546SYSCTL_PROC(_kern_binmisc, OID_AUTO, list,
547    CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RD|CTLFLAG_ANYBODY, NULL, IBC_LIST,
548    sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
549    "Get snapshot of all the activator entries");
550
551static imgact_binmisc_entry_t *
552imgact_binmisc_find_interpreter(const char *image_header)
553{
554	imgact_binmisc_entry_t *ibe;
555	const char *p;
556	int i;
557	size_t sz;
558
559	mtx_assert(&interp_list_mtx, MA_OWNED);
560
561	SLIST_FOREACH(ibe, &interpreter_list, link) {
562		if (!(IBF_ENABLED & ibe->ibe_flags))
563			continue;
564
565		p = image_header + ibe->ibe_moffset;
566		sz = ibe->ibe_msize;
567		if (IBF_USE_MASK & ibe->ibe_flags) {
568			/* Compare using mask. */
569			for (i = 0; i < sz; i++)
570				if ((*p++ ^ ibe->ibe_magic[i]) &
571				    ibe->ibe_mask[i])
572					break;
573		} else {
574			for (i = 0; i < sz; i++)
575				if (*p++ ^ ibe->ibe_magic[i])
576					break;
577		}
578		if (i == ibe->ibe_msize)
579			return (ibe);
580	}
581	return (NULL);
582}
583
584int
585imgact_binmisc_exec(struct image_params *imgp)
586{
587	const char *image_header = imgp->image_header;
588	const char *fname = NULL;
589	int error = 0;
590	size_t offset, l;
591	imgact_binmisc_entry_t *ibe;
592	struct sbuf *sname;
593	char *s, *d;
594
595	/* Do we have an interpreter for the given image header? */
596	mtx_lock(&interp_list_mtx);
597	if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) {
598		mtx_unlock(&interp_list_mtx);
599		return (-1);
600	}
601
602	/* No interpreter nesting allowed. */
603	if (imgp->interpreted) {
604		mtx_unlock(&interp_list_mtx);
605		return (ENOEXEC);
606	}
607
608	imgp->interpreted = 1;
609
610	if (imgp->args->fname != NULL) {
611		fname = imgp->args->fname;
612		sname = NULL;
613	} else {
614		/* Use the fdescfs(5) path for fexecve(2). */
615		sname = sbuf_new_auto();
616		sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd);
617		sbuf_finish(sname);
618		fname = sbuf_data(sname);
619	}
620
621
622	/*
623	 * We need to "push" the interpreter in the arg[] list.  To do this,
624	 * we first shift all the other values in the `begin_argv' area to
625	 * provide the exact amount of room for the values added.  Set up
626	 * `offset' as the number of bytes to be added to the `begin_argv'
627	 * area.
628	 */
629	offset = ibe->ibe_interp_length;
630
631	/* Adjust the offset for #'s. */
632	s = ibe->ibe_interpreter;
633	while (1) {
634		s = strchr(s, '#');
635		if (!s)
636			break;
637
638		s++;
639		switch(*s) {
640		case ISM_POUND:
641			/* "##" -> "#": reduce offset by one. */
642			offset--;
643			break;
644
645		case ISM_OLD_ARGV0:
646			/* "#a" -> (old argv0): increase offset to fit fname */
647			offset += strlen(fname) - 2;
648			break;
649
650		default:
651			/* Hmm... This shouldn't happen. */
652			mtx_unlock(&interp_list_mtx);
653			printf("%s: Unknown macro #%c sequence in "
654			    "interpreter string\n", KMOD_NAME, *(s + 1));
655			error = EINVAL;
656			goto done;
657		}
658		s++;
659	}
660
661	/* Check to make sure we won't overrun the stringspace. */
662	if (offset > imgp->args->stringspace) {
663		mtx_unlock(&interp_list_mtx);
664		error = E2BIG;
665		goto done;
666	}
667
668	/* Make room for the interpreter */
669	bcopy(imgp->args->begin_argv, imgp->args->begin_argv + offset,
670	    imgp->args->endp - imgp->args->begin_argv);
671
672	/* Adjust everything by the offset. */
673	imgp->args->begin_envv += offset;
674	imgp->args->endp += offset;
675	imgp->args->stringspace -= offset;
676
677	/* Add the new argument(s) in the count. */
678	imgp->args->argc += ibe->ibe_interp_argcnt;
679
680	/*
681	 * The original arg[] list has been shifted appropriately.  Copy in
682	 * the interpreter path.
683	 */
684	s = ibe->ibe_interpreter;
685	d = imgp->args->begin_argv;
686	while(*s != '\0') {
687		switch (*s) {
688		case '#':
689			/* Handle "#" in interpreter string. */
690			s++;
691			switch(*s) {
692			case ISM_POUND:
693				/* "##": Replace with a single '#' */
694				*d++ = '#';
695				break;
696
697			case ISM_OLD_ARGV0:
698				/* "#a": Replace with old arg0 (fname). */
699				if ((l = strlen(fname)) != 0) {
700					memcpy(d, fname, l);
701					d += l;
702				}
703				break;
704
705			default:
706				/* Shouldn't happen but skip it if it does. */
707				break;
708			}
709			break;
710
711		case ' ':
712			/* Replace space with NUL to seperate arguments. */
713			*d++ = '\0';
714			break;
715
716		default:
717			*d++ = *s;
718			break;
719		}
720		s++;
721	}
722	*d = '\0';
723	mtx_unlock(&interp_list_mtx);
724
725	if (!error)
726		imgp->interpreter_name = imgp->args->begin_argv;
727
728
729done:
730	if (sname)
731		sbuf_delete(sname);
732	return (error);
733}
734
735static void
736imgact_binmisc_init(void *arg)
737{
738
739	mtx_init(&interp_list_mtx, KMOD_NAME, NULL, MTX_DEF);
740}
741
742static void
743imgact_binmisc_fini(void *arg)
744{
745	imgact_binmisc_entry_t *ibe, *ibe_tmp;
746
747	/* Free all the interpreters. */
748	mtx_lock(&interp_list_mtx);
749	SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) {
750		SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry,
751		    link);
752		imgact_binmisc_destroy_entry(ibe);
753	}
754	mtx_unlock(&interp_list_mtx);
755
756	mtx_destroy(&interp_list_mtx);
757}
758
759SYSINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_init, 0);
760SYSUNINIT(imgact_binmisc, SI_SUB_EXEC, SI_ORDER_MIDDLE, imgact_binmisc_fini, 0);
761
762/*
763 * Tell kern_execve.c about it, with a little help from the linker.
764 */
765static struct execsw imgact_binmisc_execsw = { imgact_binmisc_exec, KMOD_NAME };
766EXEC_SET(imgact_binmisc, imgact_binmisc_execsw);
767