Add Stacey Son's binary activation patches that allow remapping of
execution to a emumation program via parsing of ELF header information. With this kernel module and userland tool, poudriere is able to build ports packages via the QEMU userland tools (or another emulator program) in a different architecture chroot, e.g. TARGET=mips TARGET_ARCH=mips I'm not connecting this to GENERIC for obvious reasons, but this should allow the kernel module to be built by default and enable the building of the userland tool (which automatically loads the kernel module). Submitted by: sson@ Reviewed by: jhb@
This commit is contained in:
parent
9e61717ac8
commit
6d75644981
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=264269
@ -440,6 +440,7 @@ dev/virtio/scsi/virtio_scsi.c optional virtio_scsi
|
||||
dev/virtio/random/virtio_random.c optional virtio_random
|
||||
isa/syscons_isa.c optional sc
|
||||
isa/vga_isa.c optional vga
|
||||
kern/imgact_binmisc.c optional imagact_binmisc
|
||||
kern/kern_clocksource.c standard
|
||||
kern/link_elf_obj.c standard
|
||||
#
|
||||
|
@ -522,6 +522,7 @@ isa/syscons_isa.c optional sc
|
||||
isa/vga_isa.c optional vga
|
||||
kern/kern_clocksource.c standard
|
||||
kern/imgact_aout.c optional compat_aout
|
||||
kern/imgact_binmisc.c optional imagact_binmisc
|
||||
kern/imgact_gzip.c optional gzip
|
||||
libkern/divdi3.c standard
|
||||
libkern/flsll.c standard
|
||||
|
766
sys/kern/imgact_binmisc.c
Normal file
766
sys/kern/imgact_binmisc.c
Normal file
@ -0,0 +1,766 @@
|
||||
/*-
|
||||
* Copyright (c) 2013, Stacey D. Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ctype.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/imgact.h>
|
||||
#include <sys/imgact_binmisc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
/**
|
||||
* Miscellaneous binary interpreter image activator.
|
||||
*
|
||||
* If the given target executable's header matches 'xbe_magic' field in the
|
||||
* 'interpreter_list' then it will use the user-level interpreter specified in
|
||||
* the 'xbe_interpreter' field to execute the binary. The 'xbe_magic' field may
|
||||
* be adjusted to a given offset using the value in the 'xbe_moffset' field
|
||||
* and bits of the header may be masked using the 'xbe_mask' field. The
|
||||
* 'interpreter_list' entries are managed using sysctl(3) as described in the
|
||||
* <sys/imgact_binmisc.h> file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Node of the interpreter list.
|
||||
*/
|
||||
typedef struct imgact_binmisc_entry {
|
||||
char *ibe_name;
|
||||
uint8_t *ibe_magic;
|
||||
uint32_t ibe_moffset;
|
||||
uint32_t ibe_msize;
|
||||
uint8_t *ibe_mask;
|
||||
uint8_t *ibe_interpreter;
|
||||
uint32_t ibe_interp_argcnt;
|
||||
uint32_t ibe_interp_length;
|
||||
uint32_t ibe_flags;
|
||||
SLIST_ENTRY(imgact_binmisc_entry) link;
|
||||
} imgact_binmisc_entry_t;
|
||||
|
||||
/*
|
||||
* sysctl() commands.
|
||||
*/
|
||||
#define IBC_ADD 1 /* Add given entry. */
|
||||
#define IBC_REMOVE 2 /* Remove entry for a given name. */
|
||||
#define IBC_DISABLE 3 /* Disable entry for a given name. */
|
||||
#define IBC_ENABLE 4 /* Enable entry for a given name. */
|
||||
#define IBC_LOOKUP 5 /* Lookup and return entry for given name. */
|
||||
#define IBC_LIST 6 /* Get a snapshot of the interpretor list. */
|
||||
|
||||
/*
|
||||
* Interpreter string macros.
|
||||
*
|
||||
* They all start with '#' followed by a single letter:
|
||||
*/
|
||||
#define ISM_POUND '#' /* "##" is the escape sequence for single #. */
|
||||
#define ISM_OLD_ARGV0 'a' /* "#a" is replaced with the old argv0. */
|
||||
|
||||
MALLOC_DEFINE(M_BINMISC, KMOD_NAME, "misc binary image activator");
|
||||
|
||||
/* The interpreter list. */
|
||||
static SLIST_HEAD(, imgact_binmisc_entry) interpreter_list =
|
||||
SLIST_HEAD_INITIALIZER(interpreter_list);
|
||||
|
||||
static int interp_list_entry_count = 0;
|
||||
|
||||
static struct mtx interp_list_mtx;
|
||||
|
||||
int imgact_binmisc_exec(struct image_params *imgp);
|
||||
|
||||
|
||||
/*
|
||||
* Populate the entry with the information about the interpreter.
|
||||
*/
|
||||
static void
|
||||
imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe)
|
||||
{
|
||||
uint32_t len = 0, argc = 1;
|
||||
char t[IBE_INTERP_LEN_MAX];
|
||||
char *sp, *tp;
|
||||
|
||||
bzero(t, sizeof(t));
|
||||
|
||||
/*
|
||||
* Normalize interpreter string. Replace white space between args with
|
||||
* single space.
|
||||
*/
|
||||
sp = str; tp = t;
|
||||
while (*sp != '\0') {
|
||||
if (*sp == ' ' || *sp == '\t') {
|
||||
if (++len > IBE_INTERP_LEN_MAX)
|
||||
break;
|
||||
*tp++ = ' ';
|
||||
argc++;
|
||||
while (*sp == ' ' || *sp == '\t')
|
||||
sp++;
|
||||
continue;
|
||||
} else {
|
||||
*tp++ = *sp++;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
*tp = '\0';
|
||||
len++;
|
||||
|
||||
ibe->ibe_interpreter = malloc(len, M_BINMISC, M_WAITOK|M_ZERO);
|
||||
|
||||
/* Populate all the ibe fields for the interpreter. */
|
||||
memcpy(ibe->ibe_interpreter, t, len);
|
||||
ibe->ibe_interp_argcnt = argc;
|
||||
ibe->ibe_interp_length = len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate memory and populate a new entry for the interpreter table.
|
||||
*/
|
||||
static imgact_binmisc_entry_t *
|
||||
imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe = NULL;
|
||||
size_t namesz = min(strlen(xbe->xbe_name) + 1, IBE_NAME_MAX);
|
||||
|
||||
mtx_assert(&interp_list_mtx, MA_NOTOWNED);
|
||||
|
||||
ibe = malloc(sizeof(*ibe), M_BINMISC, M_WAITOK|M_ZERO);
|
||||
|
||||
ibe->ibe_name = malloc(namesz, M_BINMISC, M_WAITOK|M_ZERO);
|
||||
strlcpy(ibe->ibe_name, xbe->xbe_name, namesz);
|
||||
|
||||
imgact_binmisc_populate_interp(xbe->xbe_interpreter, ibe);
|
||||
|
||||
ibe->ibe_magic = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO);
|
||||
memcpy(ibe->ibe_magic, xbe->xbe_magic, xbe->xbe_msize);
|
||||
|
||||
ibe->ibe_mask = malloc(xbe->xbe_msize, M_BINMISC, M_WAITOK|M_ZERO);
|
||||
memcpy(ibe->ibe_mask, xbe->xbe_mask, xbe->xbe_msize);
|
||||
|
||||
ibe->ibe_moffset = xbe->xbe_moffset;
|
||||
ibe->ibe_msize = xbe->xbe_msize;
|
||||
ibe->ibe_flags = xbe->xbe_flags;
|
||||
|
||||
return (ibe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the allocated memory for a given list item.
|
||||
*/
|
||||
static void
|
||||
imgact_binmisc_destroy_entry(imgact_binmisc_entry_t *ibe)
|
||||
{
|
||||
if (!ibe)
|
||||
return;
|
||||
if (ibe->ibe_mask)
|
||||
free(ibe->ibe_magic, M_BINMISC);
|
||||
if (ibe->ibe_mask)
|
||||
free(ibe->ibe_mask, M_BINMISC);
|
||||
if (ibe->ibe_interpreter)
|
||||
free(ibe->ibe_interpreter, M_BINMISC);
|
||||
if (ibe->ibe_name)
|
||||
free(ibe->ibe_name, M_BINMISC);
|
||||
if (ibe)
|
||||
free(ibe, M_BINMISC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the interpreter in the list by the given name. Return NULL if not
|
||||
* found.
|
||||
*/
|
||||
static imgact_binmisc_entry_t *
|
||||
imgact_binmisc_find_entry(char *name)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
|
||||
mtx_assert(&interp_list_mtx, MA_OWNED);
|
||||
|
||||
SLIST_FOREACH(ibe, &interpreter_list, link) {
|
||||
if (strncmp(name, ibe->ibe_name, IBE_NAME_MAX) == 0)
|
||||
return (ibe);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the given interpreter if it doesn't already exist. Return EEXIST
|
||||
* if the name already exist in the interpreter list.
|
||||
*/
|
||||
static int
|
||||
imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
char *p;
|
||||
|
||||
if (xbe->xbe_msize > IBE_MAGIC_MAX)
|
||||
return (EINVAL);
|
||||
|
||||
for(p = xbe->xbe_name; *p != 0; p++)
|
||||
if (!isascii((int)*p))
|
||||
return (EINVAL);
|
||||
|
||||
for(p = xbe->xbe_interpreter; *p != 0; p++)
|
||||
if (!isascii((int)*p))
|
||||
return (EINVAL);
|
||||
|
||||
/* Make sure we don't have any invalid #'s. */
|
||||
p = xbe->xbe_interpreter;
|
||||
while (1) {
|
||||
p = strchr(p, '#');
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
p++;
|
||||
switch(*p) {
|
||||
case ISM_POUND:
|
||||
/* "##" */
|
||||
p++;
|
||||
break;
|
||||
|
||||
case ISM_OLD_ARGV0:
|
||||
/* "#a" */
|
||||
p++;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
/* Anything besides the above is invalid. */
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
mtx_lock(&interp_list_mtx);
|
||||
if (imgact_binmisc_find_entry(xbe->xbe_name) != NULL) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (EEXIST);
|
||||
}
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
ibe = imgact_binmisc_new_entry(xbe);
|
||||
if (!ibe)
|
||||
return (ENOMEM);
|
||||
|
||||
mtx_lock(&interp_list_mtx);
|
||||
SLIST_INSERT_HEAD(&interpreter_list, ibe, link);
|
||||
interp_list_entry_count++;
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the interpreter in the list with the given name. Return ENOENT
|
||||
* if not found.
|
||||
*/
|
||||
static int
|
||||
imgact_binmisc_remove_entry(char *name)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
|
||||
mtx_lock(&interp_list_mtx);
|
||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (ENOENT);
|
||||
}
|
||||
SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry, link);
|
||||
interp_list_entry_count--;
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
imgact_binmisc_destroy_entry(ibe);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the interpreter in the list with the given name. Return ENOENT
|
||||
* if not found.
|
||||
*/
|
||||
static int
|
||||
imgact_binmisc_disable_entry(char *name)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
|
||||
mtx_lock(&interp_list_mtx);
|
||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
ibe->ibe_flags &= ~IBF_ENABLED;
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the interpreter in the list with the given name. Return ENOENT
|
||||
* if not found.
|
||||
*/
|
||||
static int
|
||||
imgact_binmisc_enable_entry(char *name)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
|
||||
mtx_lock(&interp_list_mtx);
|
||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
ibe->ibe_flags |= IBF_ENABLED;
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
imgact_binmisc_populate_xbe(ximgact_binmisc_entry_t *xbe,
|
||||
imgact_binmisc_entry_t *ibe)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
mtx_assert(&interp_list_mtx, MA_OWNED);
|
||||
|
||||
bzero(xbe, sizeof(*xbe));
|
||||
strlcpy(xbe->xbe_name, ibe->ibe_name, IBE_NAME_MAX);
|
||||
|
||||
/* Copy interpreter string. Replace NULL breaks with space. */
|
||||
memcpy(xbe->xbe_interpreter, ibe->ibe_interpreter,
|
||||
ibe->ibe_interp_length);
|
||||
for(i = 0; i < (ibe->ibe_interp_length - 1); i++)
|
||||
if (xbe->xbe_interpreter[i] == '\0')
|
||||
xbe->xbe_interpreter[i] = ' ';
|
||||
|
||||
memcpy(xbe->xbe_magic, ibe->ibe_magic, ibe->ibe_msize);
|
||||
memcpy(xbe->xbe_mask, ibe->ibe_mask, ibe->ibe_msize);
|
||||
xbe->xbe_version = IBE_VERSION;
|
||||
xbe->xbe_flags = ibe->ibe_flags;
|
||||
xbe->xbe_moffset = ibe->ibe_moffset;
|
||||
xbe->xbe_msize = ibe->ibe_msize;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the interpreter with the give name and populate the
|
||||
* ximgact_binmisc_entry structure. Return ENOENT if not found.
|
||||
*/
|
||||
static int
|
||||
imgact_binmisc_lookup_entry(char *name, ximgact_binmisc_entry_t *xbe)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
int error = 0;
|
||||
|
||||
mtx_lock(&interp_list_mtx);
|
||||
if ((ibe = imgact_binmisc_find_entry(name)) == NULL) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
error = imgact_binmisc_populate_xbe(xbe, ibe);
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a snapshot of all the interpreter entries in the list.
|
||||
*/
|
||||
static int
|
||||
imgact_binmisc_get_all_entries(struct sysctl_req *req)
|
||||
{
|
||||
ximgact_binmisc_entry_t *xbe, *xbep;
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
int error = 0, count;
|
||||
|
||||
mtx_lock(&interp_list_mtx);
|
||||
count = interp_list_entry_count;
|
||||
/* Don't block in malloc() while holding lock. */
|
||||
xbe = malloc(sizeof(*xbe) * count, M_BINMISC, M_NOWAIT|M_ZERO);
|
||||
if (!xbe) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
xbep = xbe;
|
||||
SLIST_FOREACH(ibe, &interpreter_list, link) {
|
||||
error = imgact_binmisc_populate_xbe(xbep++, ibe);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
if (!error)
|
||||
error = SYSCTL_OUT(req, xbe, sizeof(*xbe) * count);
|
||||
|
||||
free(xbe, M_BINMISC);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* sysctl() handler for munipulating interpretor table.
|
||||
* Not MP safe (locked by sysctl).
|
||||
*/
|
||||
static int
|
||||
sysctl_kern_binmisc(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
ximgact_binmisc_entry_t xbe;
|
||||
int error = 0;
|
||||
|
||||
switch(arg2) {
|
||||
case IBC_ADD:
|
||||
/* Add an entry. Limited to IBE_MAX_ENTRIES. */
|
||||
error = SYSCTL_IN(req, &xbe, sizeof(xbe));
|
||||
if (error)
|
||||
return (error);
|
||||
if (IBE_VERSION != xbe.xbe_version)
|
||||
return (EINVAL);
|
||||
if (interp_list_entry_count == IBE_MAX_ENTRIES)
|
||||
return (ENOSPC);
|
||||
error = imgact_binmisc_add_entry(&xbe);
|
||||
break;
|
||||
|
||||
case IBC_REMOVE:
|
||||
/* Remove an entry. */
|
||||
error = SYSCTL_IN(req, &xbe, sizeof(xbe));
|
||||
if (error)
|
||||
return (error);
|
||||
if (IBE_VERSION != xbe.xbe_version)
|
||||
return (EINVAL);
|
||||
error = imgact_binmisc_remove_entry(xbe.xbe_name);
|
||||
break;
|
||||
|
||||
case IBC_DISABLE:
|
||||
/* Disable an entry. */
|
||||
error = SYSCTL_IN(req, &xbe, sizeof(xbe));
|
||||
if (error)
|
||||
return (error);
|
||||
if (IBE_VERSION != xbe.xbe_version)
|
||||
return (EINVAL);
|
||||
error = imgact_binmisc_disable_entry(xbe.xbe_name);
|
||||
break;
|
||||
|
||||
case IBC_ENABLE:
|
||||
/* Enable an entry. */
|
||||
error = SYSCTL_IN(req, &xbe, sizeof(xbe));
|
||||
if (error)
|
||||
return (error);
|
||||
if (IBE_VERSION != xbe.xbe_version)
|
||||
return (EINVAL);
|
||||
error = imgact_binmisc_enable_entry(xbe.xbe_name);
|
||||
break;
|
||||
|
||||
case IBC_LOOKUP:
|
||||
/* Lookup an entry. */
|
||||
error = SYSCTL_IN(req, &xbe, sizeof(xbe));
|
||||
if (error)
|
||||
return (error);
|
||||
if (IBE_VERSION != xbe.xbe_version)
|
||||
return (EINVAL);
|
||||
error = imgact_binmisc_lookup_entry(xbe.xbe_name, &xbe);
|
||||
if (!error)
|
||||
error = SYSCTL_OUT(req, &xbe, sizeof(xbe));
|
||||
break;
|
||||
|
||||
case IBC_LIST:
|
||||
/* Return a snapshot of the interpretor list. */
|
||||
|
||||
if (!req->oldptr) {
|
||||
/* No pointer then just return the list size. */
|
||||
error = SYSCTL_OUT(req, 0, interp_list_entry_count *
|
||||
sizeof(ximgact_binmisc_entry_t));
|
||||
return (error);
|
||||
} else
|
||||
if (!req->oldlen)
|
||||
return (EINVAL);
|
||||
|
||||
error = imgact_binmisc_get_all_entries(req);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSCTL_NODE(_kern, OID_AUTO, binmisc, CTLFLAG_RW, 0,
|
||||
"Image activator for miscellaneous binaries");
|
||||
|
||||
SYSCTL_PROC(_kern_binmisc, OID_AUTO, add,
|
||||
CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ADD,
|
||||
sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
|
||||
"Add an activator entry");
|
||||
|
||||
SYSCTL_PROC(_kern_binmisc, OID_AUTO, remove,
|
||||
CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_REMOVE,
|
||||
sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
|
||||
"Remove an activator entry");
|
||||
|
||||
SYSCTL_PROC(_kern_binmisc, OID_AUTO, disable,
|
||||
CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_DISABLE,
|
||||
sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
|
||||
"Disable an activator entry");
|
||||
|
||||
SYSCTL_PROC(_kern_binmisc, OID_AUTO, enable,
|
||||
CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_WR, NULL, IBC_ENABLE,
|
||||
sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
|
||||
"Enable an activator entry");
|
||||
|
||||
SYSCTL_PROC(_kern_binmisc, OID_AUTO, lookup,
|
||||
CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RW|CTLFLAG_ANYBODY, NULL, IBC_LOOKUP,
|
||||
sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
|
||||
"Lookup an activator entry");
|
||||
|
||||
SYSCTL_PROC(_kern_binmisc, OID_AUTO, list,
|
||||
CTLFLAG_MPSAFE|CTLTYPE_STRUCT|CTLFLAG_RD|CTLFLAG_ANYBODY, NULL, IBC_LIST,
|
||||
sysctl_kern_binmisc, "S,ximgact_binmisc_entry",
|
||||
"Get snapshot of all the activator entries");
|
||||
|
||||
static imgact_binmisc_entry_t *
|
||||
imgact_binmisc_find_interpreter(const char *image_header)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
const char *p;
|
||||
int i;
|
||||
size_t sz;
|
||||
|
||||
mtx_assert(&interp_list_mtx, MA_OWNED);
|
||||
|
||||
SLIST_FOREACH(ibe, &interpreter_list, link) {
|
||||
if (!(IBF_ENABLED & ibe->ibe_flags))
|
||||
continue;
|
||||
|
||||
p = image_header + ibe->ibe_moffset;
|
||||
sz = ibe->ibe_msize;
|
||||
if (IBF_USE_MASK & ibe->ibe_flags) {
|
||||
/* Compare using mask. */
|
||||
for (i = 0; i < sz; i++)
|
||||
if ((*p++ ^ ibe->ibe_magic[i]) &
|
||||
ibe->ibe_mask[i])
|
||||
break;
|
||||
} else {
|
||||
for (i = 0; i < sz; i++)
|
||||
if (*p++ ^ ibe->ibe_magic[i])
|
||||
break;
|
||||
}
|
||||
if (i == ibe->ibe_msize)
|
||||
return (ibe);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
imgact_binmisc_exec(struct image_params *imgp)
|
||||
{
|
||||
const char *image_header = imgp->image_header;
|
||||
const char *fname = NULL;
|
||||
int error = 0;
|
||||
size_t offset, l;
|
||||
imgact_binmisc_entry_t *ibe;
|
||||
struct sbuf *sname;
|
||||
char *s, *d;
|
||||
|
||||
/* Do we have an interpreter for the given image header? */
|
||||
mtx_lock(&interp_list_mtx);
|
||||
if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* No interpreter nesting allowed. */
|
||||
if (imgp->interpreted) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
return (ENOEXEC);
|
||||
}
|
||||
|
||||
imgp->interpreted = 1;
|
||||
|
||||
if (imgp->args->fname != NULL) {
|
||||
fname = imgp->args->fname;
|
||||
sname = NULL;
|
||||
} else {
|
||||
/* Use the fdescfs(5) path for fexecve(2). */
|
||||
sname = sbuf_new_auto();
|
||||
sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd);
|
||||
sbuf_finish(sname);
|
||||
fname = sbuf_data(sname);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We need to "push" the interpreter in the arg[] list. To do this,
|
||||
* we first shift all the other values in the `begin_argv' area to
|
||||
* provide the exact amount of room for the values added. Set up
|
||||
* `offset' as the number of bytes to be added to the `begin_argv'
|
||||
* area.
|
||||
*/
|
||||
offset = ibe->ibe_interp_length;
|
||||
|
||||
/* Adjust the offset for #'s. */
|
||||
s = ibe->ibe_interpreter;
|
||||
while (1) {
|
||||
s = strchr(s, '#');
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
s++;
|
||||
switch(*s) {
|
||||
case ISM_POUND:
|
||||
/* "##" -> "#": reduce offset by one. */
|
||||
offset--;
|
||||
break;
|
||||
|
||||
case ISM_OLD_ARGV0:
|
||||
/* "#a" -> (old argv0): increase offset to fit fname */
|
||||
offset += strlen(fname) - 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Hmm... This shouldn't happen. */
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
printf("%s: Unknown macro #%c sequence in "
|
||||
"interpreter string\n", KMOD_NAME, *(s + 1));
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
/* Check to make sure we won't overrun the stringspace. */
|
||||
if (offset > imgp->args->stringspace) {
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
error = E2BIG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Make room for the interpreter */
|
||||
bcopy(imgp->args->begin_argv, imgp->args->begin_argv + offset,
|
||||
imgp->args->endp - imgp->args->begin_argv);
|
||||
|
||||
/* Adjust everything by the offset. */
|
||||
imgp->args->begin_envv += offset;
|
||||
imgp->args->endp += offset;
|
||||
imgp->args->stringspace -= offset;
|
||||
|
||||
/* Add the new argument(s) in the count. */
|
||||
imgp->args->argc += ibe->ibe_interp_argcnt;
|
||||
|
||||
/*
|
||||
* The original arg[] list has been shifted appropriately. Copy in
|
||||
* the interpreter path.
|
||||
*/
|
||||
s = ibe->ibe_interpreter;
|
||||
d = imgp->args->begin_argv;
|
||||
while(*s != '\0') {
|
||||
switch (*s) {
|
||||
case '#':
|
||||
/* Handle "#" in interpreter string. */
|
||||
s++;
|
||||
switch(*s) {
|
||||
case ISM_POUND:
|
||||
/* "##": Replace with a single '#' */
|
||||
*d++ = '#';
|
||||
break;
|
||||
|
||||
case ISM_OLD_ARGV0:
|
||||
/* "#a": Replace with old arg0 (fname). */
|
||||
if ((l = strlen(fname)) != 0) {
|
||||
memcpy(d, fname, l);
|
||||
d += l;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Shouldn't happen but skip it if it does. */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
/* Replace space with NUL to seperate arguments. */
|
||||
*d++ = '\0';
|
||||
break;
|
||||
|
||||
default:
|
||||
*d++ = *s;
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
if (!error)
|
||||
imgp->interpreter_name = imgp->args->begin_argv;
|
||||
|
||||
|
||||
done:
|
||||
if (sname)
|
||||
sbuf_delete(sname);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
imgact_binmisc_init(void *arg)
|
||||
{
|
||||
|
||||
mtx_init(&interp_list_mtx, KMOD_NAME, NULL, MTX_DEF);
|
||||
}
|
||||
|
||||
static void
|
||||
imgact_binmisc_fini(void *arg)
|
||||
{
|
||||
imgact_binmisc_entry_t *ibe, *ibe_tmp;
|
||||
|
||||
/* Free all the interpreters. */
|
||||
mtx_lock(&interp_list_mtx);
|
||||
SLIST_FOREACH_SAFE(ibe, &interpreter_list, link, ibe_tmp) {
|
||||
SLIST_REMOVE(&interpreter_list, ibe, imgact_binmisc_entry,
|
||||
link);
|
||||
imgact_binmisc_destroy_entry(ibe);
|
||||
}
|
||||
mtx_unlock(&interp_list_mtx);
|
||||
|
||||
mtx_destroy(&interp_list_mtx);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Tell kern_execve.c about it, with a little help from the linker.
|
||||
*/
|
||||
static struct execsw imgact_binmisc_execsw = { imgact_binmisc_exec, KMOD_NAME };
|
||||
EXEC_SET(imgact_binmisc, imgact_binmisc_execsw);
|
@ -148,6 +148,7 @@ SUBDIR= \
|
||||
if_vlan \
|
||||
${_igb} \
|
||||
${_iir} \
|
||||
imgact_binmisc \
|
||||
${_io} \
|
||||
${_ipoib} \
|
||||
${_ipdivert} \
|
||||
|
8
sys/modules/imgact_binmisc/Makefile
Normal file
8
sys/modules/imgact_binmisc/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../kern
|
||||
|
||||
KMOD= imgact_binmisc
|
||||
SRCS= imgact_binmisc.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
172
sys/sys/imgact_binmisc.h
Normal file
172
sys/sys/imgact_binmisc.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*-
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _IMGACT_BINMISC_H_
|
||||
#define _IMGACT_BINMISC_H_
|
||||
|
||||
/**
|
||||
* Miscellaneous binary interpreter image activator.
|
||||
*/
|
||||
|
||||
#include <sys/param.h> /* for MAXPATHLEN */
|
||||
|
||||
/*
|
||||
* Imgact bin misc parameters.
|
||||
*/
|
||||
#define IBE_VERSION 1 /* struct ximgact_binmisc_entry version. */
|
||||
#define IBE_NAME_MAX 32 /* Max size for entry name. */
|
||||
#define IBE_MAGIC_MAX 256 /* Max size for header magic and mask. */
|
||||
#define IBE_ARG_LEN_MAX 256 /* Max space for optional interpreter command-
|
||||
line argruments seperated by white space */
|
||||
#define IBE_INTERP_LEN_MAX (MAXPATHLEN + IBE_ARG_LEN_MAX)
|
||||
#define IBE_MAX_ENTRIES 64 /* Max number of interpreter entries. */
|
||||
|
||||
/*
|
||||
* Imgact bin misc interpreter entry flags.
|
||||
*/
|
||||
#define IBF_ENABLED 0x0001 /* Entry is active. */
|
||||
#define IBF_USE_MASK 0x0002 /* Use mask on header magic field. */
|
||||
|
||||
/*
|
||||
* Used with sysctlbyname() to pass imgact bin misc entries in and out of the
|
||||
* kernel.
|
||||
*/
|
||||
typedef struct ximgact_binmisc_entry {
|
||||
uint32_t xbe_version; /* Struct version(IBE_VERSION) */
|
||||
uint32_t xbe_flags; /* Entry flags (IBF_*) */
|
||||
uint32_t xbe_moffset; /* Magic offset in header */
|
||||
uint32_t xbe_msize; /* Magic size */
|
||||
uint32_t spare[3]; /* Spare fields for future use */
|
||||
char xbe_name[IBE_NAME_MAX]; /* Unique interpreter name */
|
||||
char xbe_interpreter[IBE_INTERP_LEN_MAX]; /* Interpreter path + args */
|
||||
uint8_t xbe_magic[IBE_MAGIC_MAX]; /* Header Magic */
|
||||
uint8_t xbe_mask[IBE_MAGIC_MAX]; /* Magic Mask */
|
||||
} ximgact_binmisc_entry_t;
|
||||
|
||||
/*
|
||||
* sysctl() command names.
|
||||
*/
|
||||
#define IBE_SYSCTL_NAME "kern.binmisc"
|
||||
|
||||
#define IBE_SYSCTL_NAME_ADD IBE_SYSCTL_NAME ".add"
|
||||
#define IBE_SYSCTL_NAME_REMOVE IBE_SYSCTL_NAME ".remove"
|
||||
#define IBE_SYSCTL_NAME_DISABLE IBE_SYSCTL_NAME ".disable"
|
||||
#define IBE_SYSCTL_NAME_ENABLE IBE_SYSCTL_NAME ".enable"
|
||||
#define IBE_SYSCTL_NAME_LOOKUP IBE_SYSCTL_NAME ".lookup"
|
||||
#define IBE_SYSCTL_NAME_LIST IBE_SYSCTL_NAME ".list"
|
||||
|
||||
#define KMOD_NAME "imgact_binmisc"
|
||||
|
||||
/*
|
||||
* Examples of manipulating he interpreter table using sysctlbyname(3):
|
||||
*
|
||||
* #include <sys/imgact_binmisc.h>
|
||||
*
|
||||
* #define LLVM_MAGIC "BC\xc0\xde"
|
||||
*
|
||||
* #define MIPS64_ELF_MAGIC "\x7f\x45\x4c\x46\x02\x02\x01\x00\x00\x00" \
|
||||
* "\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08"
|
||||
* #define MIPS64_ELF_MASK "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff" \
|
||||
* "\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"
|
||||
*
|
||||
* ximgact_binmisc_entry_t xbe, *xbep, out_xbe;
|
||||
* size_t size = 0, osize;
|
||||
* int error, i;
|
||||
*
|
||||
* // Add image activator for LLVM byte code
|
||||
* bzero(&xbe, sizeof(xbe));
|
||||
* xbe.xbe_version = IBE_VERSION;
|
||||
* xbe.xbe_flags = IBF_ENABLED;
|
||||
* strlcpy(xbe.xbe_name, "llvm_bc", IBE_NAME_MAX);
|
||||
* strlcpy(xbe.xbe_interpreter, "/usr/bin/lli --fake-arg0=#a",
|
||||
* IBE_INTERP_LEN_MAX);
|
||||
* xbe.xbe_moffset = 0;
|
||||
* xbe.xbe_msize = 4;
|
||||
* memcpy(xbe.xbe_magic, LLVM_MAGIC, xbe.xbe_msize);
|
||||
* error = sysctlbyname(IBE_SYSCTL_NAME_ADD, NULL, NULL, &xbe, sizeof(xbe));
|
||||
*
|
||||
* // Add image activator for mips64 ELF binaries to use qemu user mode
|
||||
* bzero(&xbe, sizeof(xbe));
|
||||
* xbe.xbe_version = IBE_VERSION;
|
||||
* xbe.xbe_flags = IBF_ENABLED | IBF_USE_MASK;
|
||||
* strlcpy(xbe.xbe_name, "mips64elf", IBE_NAME_MAX);
|
||||
* strlcpy(xbe.xbe_interpreter, "/usr/local/bin/qemu-mips64",
|
||||
* IBE_INTERP_LEN_MAX);
|
||||
* xbe.xbe_moffset = 0;
|
||||
* xbe.xbe_msize = 20;
|
||||
* memcpy(xbe.xbe_magic, MIPS64_ELF_MAGIC, xbe.xbe_msize);
|
||||
* memcpy(xbe.xbe_mask, MIPS64_ELF_MASK, xbe.xbe_msize);
|
||||
* sysctlbyname(IBE_SYSCTL_NAME_ADD, NULL, NULL, &xbe, sizeof(xbe));
|
||||
*
|
||||
* // Disable (OR Enable OR Remove) image activator for LLVM byte code
|
||||
* bzero(&xbe, sizeof(xbe));
|
||||
* xbe.xbe_version = IBE_VERSION;
|
||||
* strlcpy(xbe.xbe_name, "llvm_bc", IBE_NAME_MAX);
|
||||
* error = sysctlbyname(IBE_SYSCTL_NAME_DISABLE, NULL, NULL, &xbe, sizeof(xbe));
|
||||
* // OR sysctlbyname(IBE_SYSCTL_NAME_ENABLE", NULL, NULL, &xbe, sizeof(xbe));
|
||||
* // OR sysctlbyname(IBE_SYSCTL_NAME_REMOVE, NULL, NULL, &xbe, sizeof(xbe));
|
||||
*
|
||||
* // Lookup image activator "llvm_bc"
|
||||
* bzero(&xbe, sizeof(xbe));
|
||||
* xbe.xbe_version = IBE_VERSION;
|
||||
* strlcpy(xbe.xbe_name, "llvm_bc", IBE_NAME_MAX);
|
||||
* size = sizeof(out_xbe);
|
||||
* error = sysctlbyname(IBE_SYSCTL_NAME_LOOKUP, &out_xbe, &size, &xbe,
|
||||
* sizeof(xbe));
|
||||
*
|
||||
* // Get all the currently configured image activators and report
|
||||
* error = sysctlbyname(IBE_SYSCTL_NAME_LIST, NULL, &size, NULL, 0);
|
||||
* if (0 == error && size > 0) {
|
||||
* xbep = malloc(size);
|
||||
* while(1) {
|
||||
* osize = size;
|
||||
* error = sysctlbyname("kern.binmisc.list", xbep, &size, NULL, 0);
|
||||
* if (-1 == error && ENOMEM == errno && size == osize) {
|
||||
* // The buffer too small and needs to grow
|
||||
* size += sizeof(xbe);
|
||||
* xbep = realloc(xbep, size);
|
||||
* } else
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* for(i = 0; i < (size / sizeof(xbe)); i++, xbep++)
|
||||
* printf("name: %s interpreter: %s flags: %s %s\n", xbep->xbe_name,
|
||||
* xbep->xbe_interpreter, (xbep->xbe_flags & IBF_ENABLED) ?
|
||||
* "ENABLED" : "", (xbep->xbe_flags & IBF_ENABLED) ? "USE_MASK" : "");
|
||||
*
|
||||
* The sysctlbyname() calls above may return the following errors in addition
|
||||
* to the standard ones:
|
||||
*
|
||||
* [EINVAL] Invalid argument in the input ximgact_binmisc_entry_t structure.
|
||||
* [EEXIST] Interpreter entry for given name already exist in kernel list.
|
||||
* [ENOMEM] Allocating memory in the kernel failed or, in the case of
|
||||
* kern.binmisc.list, the user buffer is too small.
|
||||
* [ENOENT] Interpreter entry for given name is not found.
|
||||
* [ENOSPC] Attempted to exceed maximum number of entries (IBE_MAX_ENTRIES).
|
||||
*/
|
||||
|
||||
#endif /* !_IMGACT_BINMISC_H_ */
|
@ -5,6 +5,7 @@
|
||||
|
||||
SUBDIR= adduser \
|
||||
arp \
|
||||
binmiscctl \
|
||||
bootparamd \
|
||||
bsdconfig \
|
||||
bsdinstall \
|
||||
|
10
usr.sbin/binmiscctl/Makefile
Normal file
10
usr.sbin/binmiscctl/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= binmiscctl
|
||||
MAN= binmiscctl.8
|
||||
|
||||
.include <bsd.prog.mk>
|
186
usr.sbin/binmiscctl/binmiscctl.8
Normal file
186
usr.sbin/binmiscctl/binmiscctl.8
Normal file
@ -0,0 +1,186 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2013 Stacey D. Son
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.\" Support for miscellaneous binary image activators
|
||||
.\"
|
||||
.Dd May 14, 2013
|
||||
.Dt 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm binmiscctl
|
||||
.Nd manage binary image activators
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Cm add
|
||||
.Ar name
|
||||
.Cm --interpreter
|
||||
.Ar path
|
||||
.Cm --magic
|
||||
.Ar magic
|
||||
.Cm --size
|
||||
.Ar size
|
||||
.Op --mask Ar mask
|
||||
.Op --offset Ar offset
|
||||
.Op --set-enabled
|
||||
.Nm
|
||||
.Cm remove
|
||||
.Ar name
|
||||
.Nm
|
||||
.Cm disable
|
||||
.Ar name
|
||||
.Nm
|
||||
.Cm enable
|
||||
.Ar name
|
||||
.Nm
|
||||
.Cm lookup
|
||||
.Ar name
|
||||
.Nm
|
||||
.Cm list
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility
|
||||
is the management utility for configuring miscellaneous binaries image
|
||||
activators in the kernel. It allows the adding, deleting, disabling,
|
||||
enabling, and looking up interpreters. Also, all the interpreters can
|
||||
be listed as well.
|
||||
.Pp
|
||||
The first argument on the command line indicates the operation to be
|
||||
performed.
|
||||
Operation must be one of the following:
|
||||
.Bl -tag -width indent
|
||||
.It Xo
|
||||
.Cm add
|
||||
.Ar name
|
||||
.Cm --interpreter
|
||||
.Ar path
|
||||
.Cm --magic
|
||||
.Ar magic
|
||||
.Cm --size
|
||||
.Ar size
|
||||
.Op --mask Ar mask
|
||||
.Op --offset Ar offset
|
||||
.Op --set-enabled
|
||||
.Xc
|
||||
Add a new activator entry in the kernel. You must specify an
|
||||
unique
|
||||
.Ar name,
|
||||
interpreter path and its arguments
|
||||
.Ar path,
|
||||
header
|
||||
.Ar magic
|
||||
bytes that uniquely identifies a suitable binary for the activator,
|
||||
and the
|
||||
.Ar size
|
||||
of the
|
||||
.Ar magic
|
||||
in bytes.
|
||||
.Pp
|
||||
Optionally you may specify a
|
||||
.Ar mask
|
||||
to do a bitwise AND with the header bytes.
|
||||
|
||||
This effectively allows you to ignore fields in the binary header that
|
||||
do not uniquely indentfy binary file's type.
|
||||
.Pp
|
||||
An
|
||||
.Ar offset
|
||||
may be specified for the magic bytes using the
|
||||
.Ar --offset
|
||||
argument. By default the
|
||||
.Ar offset
|
||||
is zero.
|
||||
.Pp
|
||||
To set the activator entry enabled the
|
||||
.Ar --set-enabled
|
||||
option is used. The activator default state is disabled.
|
||||
.Pp
|
||||
The interpreter
|
||||
.Ar path
|
||||
may also arguments for the interpreter including
|
||||
.Ar #a
|
||||
which gets replaced by the old argv0 value in the interpreter string.
|
||||
.It Cm remove Ar name
|
||||
Remove the activator entry identified with
|
||||
.Ar name .
|
||||
.It Cm disable Ar name
|
||||
Disable the activator entry identified with
|
||||
.Ar name .
|
||||
.It Cm enable Ar name
|
||||
Enable the activator entry identified with
|
||||
.Ar name .
|
||||
.It Cm lookup Ar name
|
||||
Lookup and print out the activator entry identified with
|
||||
.Ar name .
|
||||
.It Cm list
|
||||
Take a snapshot and print all the activator entries currently configured.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Dl binmiscctl add llvmbc --interpreter ''/usr/bin/lli --fake-argv0=#a''
|
||||
--magic ''BC\\xc0\\xde''
|
||||
--size 4 --set-enabled
|
||||
.Pp
|
||||
Add an image activator to run the the llvm interpreter (lli) on bitcode
|
||||
compiled files.
|
||||
.Ar #a
|
||||
gets replaced with the old argv0 value so that 'lli' can fake its argv0.
|
||||
Set its state to enabled.
|
||||
.Pp
|
||||
.Dl binmiscctl disable llvmbc
|
||||
.Pp
|
||||
Set the state of the
|
||||
.Ar llvmbc
|
||||
image activator to disabled.
|
||||
.Pp
|
||||
.Dl binmiscctl enable llvmbc
|
||||
.Pp
|
||||
Set the state of the
|
||||
.Ar llvmbc
|
||||
image activator to enabled.
|
||||
.Pp
|
||||
.Dl binmiscctl remove llvmbc
|
||||
.Pp
|
||||
Delete the
|
||||
.Ar llvmbc
|
||||
image activator.
|
||||
.Pp
|
||||
.Dl binmiscctl lookup llvmbc
|
||||
.Pp
|
||||
Lookup and list the record for the
|
||||
.Ar llvmbc
|
||||
image activator.
|
||||
.Sh SEE ALSO
|
||||
.Xr execve 2
|
||||
.Xr lli 1
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Cm binmiscctl
|
||||
command was added in
|
||||
.Fx 10.0 .
|
||||
It was developed to support the imgact_binmisc kernel module.
|
||||
.Sh AUTHORS
|
||||
Stacey D Son
|
508
usr.sbin/binmiscctl/binmiscctl.c
Normal file
508
usr.sbin/binmiscctl/binmiscctl.c
Normal file
@ -0,0 +1,508 @@
|
||||
/*-
|
||||
* Copyright (c) 2013 Stacey D. Son
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/imgact_binmisc.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
enum cmd {
|
||||
CMD_ADD = 0,
|
||||
CMD_REMOVE,
|
||||
CMD_DISABLE,
|
||||
CMD_ENABLE,
|
||||
CMD_LOOKUP,
|
||||
CMD_LIST,
|
||||
};
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
typedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
|
||||
|
||||
int add_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
|
||||
int name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
|
||||
int noname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
|
||||
|
||||
static const struct {
|
||||
const int token;
|
||||
const char *name;
|
||||
cmd_func_t func;
|
||||
const char *desc;
|
||||
const char *args;
|
||||
} cmds[] = {
|
||||
{
|
||||
CMD_ADD,
|
||||
"add",
|
||||
add_cmd,
|
||||
"Add a new binary image activator (requires 'root' privilege)",
|
||||
"<name> --interpreter <path_and_arguments> \\\n"
|
||||
"\t\t--magic <magic_bytes> [--mask <mask_bytes>] \\\n"
|
||||
"\t\t--size <magic_size> [--offset <magic_offset>] \\\n"
|
||||
"\t\t[--set-enabled]"
|
||||
},
|
||||
{
|
||||
CMD_REMOVE,
|
||||
"remove",
|
||||
name_cmd,
|
||||
"Remove a binary image activator (requires 'root' privilege)",
|
||||
"<name>"
|
||||
},
|
||||
{
|
||||
CMD_DISABLE,
|
||||
"disable",
|
||||
name_cmd,
|
||||
"Disable a binary image activator (requires 'root' privilege)",
|
||||
"<name>"
|
||||
},
|
||||
{
|
||||
CMD_ENABLE,
|
||||
"enable",
|
||||
name_cmd,
|
||||
"Enable a binary image activator (requires 'root' privilege)",
|
||||
"<name>"
|
||||
},
|
||||
{
|
||||
CMD_LOOKUP,
|
||||
"lookup",
|
||||
name_cmd,
|
||||
"Lookup a binary image activator",
|
||||
"<name>"
|
||||
},
|
||||
{
|
||||
CMD_LIST,
|
||||
"list",
|
||||
noname_cmd,
|
||||
"List all the binary image activators",
|
||||
""
|
||||
},
|
||||
};
|
||||
|
||||
static const struct option
|
||||
add_opts[] = {
|
||||
{ "set-enabled", no_argument, NULL, 'e' },
|
||||
{ "interpreter", required_argument, NULL, 'i' },
|
||||
{ "mask", required_argument, NULL, 'M' },
|
||||
{ "magic", required_argument, NULL, 'm' },
|
||||
{ "offset", required_argument, NULL, 'o' },
|
||||
{ "size", required_argument, NULL, 's' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static char const *cmd_sysctl_name[] = {
|
||||
IBE_SYSCTL_NAME_ADD,
|
||||
IBE_SYSCTL_NAME_REMOVE,
|
||||
IBE_SYSCTL_NAME_DISABLE,
|
||||
IBE_SYSCTL_NAME_ENABLE,
|
||||
IBE_SYSCTL_NAME_LOOKUP,
|
||||
IBE_SYSCTL_NAME_LIST
|
||||
};
|
||||
|
||||
static void
|
||||
usage(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
size_t i;
|
||||
int error = 0;
|
||||
|
||||
va_start(args, format);
|
||||
if (format) {
|
||||
vfprintf(stderr, format, args);
|
||||
error = -1;
|
||||
}
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "usage: %s command [args...]\n\n", __progname);
|
||||
|
||||
for(i = 0; i < ( sizeof (cmds) / sizeof (cmds[0])); i++) {
|
||||
fprintf(stderr, "%s:\n", cmds[i].desc);
|
||||
fprintf(stderr, "\t%s %s %s\n\n", __progname, cmds[i].name,
|
||||
cmds[i].args);
|
||||
}
|
||||
|
||||
exit (error);
|
||||
}
|
||||
|
||||
static void
|
||||
fatal(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
if (format)
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void
|
||||
getoptstr(char *str, size_t size, const char *argname)
|
||||
{
|
||||
if (strlen(optarg) > size)
|
||||
usage("'%s' too large", argname);
|
||||
strlcpy(str, optarg, size);
|
||||
}
|
||||
|
||||
static void
|
||||
printxbe(ximgact_binmisc_entry_t *xbe)
|
||||
{
|
||||
uint32_t i, flags = xbe->xbe_flags;
|
||||
|
||||
if (xbe->xbe_version != IBE_VERSION) {
|
||||
fprintf(stderr, "Error: XBE version mismatch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("name: %s\n", xbe->xbe_name);
|
||||
printf("interpreter: %s\n", xbe->xbe_interpreter);
|
||||
printf("flags: %s%s\n", (flags & IBF_ENABLED) ? "ENABLED " : "",
|
||||
(flags & IBF_USE_MASK) ? "USE_MASK " : "");
|
||||
printf("magic size: %u\n", xbe->xbe_msize);
|
||||
printf("magic offset: %u\n", xbe->xbe_moffset);
|
||||
|
||||
printf("magic: ");
|
||||
for(i = 0; i < xbe->xbe_msize; i++) {
|
||||
if (i && !(i % 12))
|
||||
printf("\n ");
|
||||
else
|
||||
if (i && !(i % 4))
|
||||
printf(" ");
|
||||
printf("0x%02x ", xbe->xbe_magic[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (flags & IBF_USE_MASK) {
|
||||
printf("mask: ");
|
||||
for(i = 0; i < xbe->xbe_msize; i++) {
|
||||
if (i && !(i % 12))
|
||||
printf("\n ");
|
||||
else
|
||||
if (i && !(i % 4))
|
||||
printf(" ");
|
||||
printf("0x%02x ", xbe->xbe_mask[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
demux_cmd(__unused int argc, char *const argv[])
|
||||
{
|
||||
size_t i;
|
||||
|
||||
optind = 1;
|
||||
optreset = 1;
|
||||
|
||||
for(i = 0; i < ( sizeof (cmds) / sizeof (cmds[0])); i++) {
|
||||
if (!strcasecmp(cmds[i].name, argv[0])) {
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unknown command */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
strlit2bin_cpy(uint8_t *d, char *s, size_t size)
|
||||
{
|
||||
int c;
|
||||
size_t cnt = 0;
|
||||
|
||||
while((c = *s++) != '\0') {
|
||||
if (c == '\\') {
|
||||
/* Do '\' escapes. */
|
||||
switch (*s) {
|
||||
case '\\':
|
||||
*d++ = '\\';
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
s++;
|
||||
c = toupper(*s++);
|
||||
*d = (c - (isdigit(c) ? '0' : ('A' - 10))) << 4;
|
||||
c = toupper(*s++);
|
||||
*d++ |= c - (isdigit(c) ? '0' : ('A' - 10));
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
} else
|
||||
*d++ = c;
|
||||
|
||||
if (++cnt > size)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
int
|
||||
add_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
|
||||
{
|
||||
int ch;
|
||||
char *magic = NULL, *mask = NULL;
|
||||
int sz;
|
||||
|
||||
if (strlen(argv[0]) > IBE_NAME_MAX)
|
||||
usage("'%s' string length longer than IBE_NAME_MAX (%d)",
|
||||
IBE_NAME_MAX);
|
||||
strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
|
||||
|
||||
while ((ch = getopt_long(argc, argv, "ei:m:M:o:s:", add_opts, NULL))
|
||||
!= -1) {
|
||||
|
||||
switch(ch) {
|
||||
case 'i':
|
||||
getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
|
||||
"interpreter");
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
magic = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
mask = strdup(optarg);
|
||||
xbe->xbe_flags |= IBF_USE_MASK;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
xbe->xbe_flags |= IBF_ENABLED;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
xbe->xbe_moffset = atol(optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
xbe->xbe_msize = atol(optarg);
|
||||
if (xbe->xbe_msize == 0 ||
|
||||
xbe->xbe_msize > IBE_MAGIC_MAX)
|
||||
usage("Error: Not valid '--size' value. "
|
||||
"(Must be > 0 and < %u.)\n",
|
||||
xbe->xbe_msize);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage("Unknown argument: '%c'", ch);
|
||||
}
|
||||
}
|
||||
|
||||
if (xbe->xbe_msize == 0) {
|
||||
if (NULL != magic)
|
||||
free(magic);
|
||||
if (NULL != mask)
|
||||
free(mask);
|
||||
usage("Error: Missing '--size' argument");
|
||||
}
|
||||
|
||||
if (NULL != magic) {
|
||||
if (xbe->xbe_msize == 0) {
|
||||
if (magic)
|
||||
free(magic);
|
||||
if (mask)
|
||||
free(mask);
|
||||
usage("Error: Missing magic size argument");
|
||||
}
|
||||
sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
|
||||
free(magic);
|
||||
if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
|
||||
if (mask)
|
||||
free(mask);
|
||||
usage("Error: invalid magic argument");
|
||||
}
|
||||
if (mask) {
|
||||
sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
|
||||
free(mask);
|
||||
if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
|
||||
usage("Error: invalid mask argument");
|
||||
}
|
||||
} else {
|
||||
if (mask)
|
||||
free(mask);
|
||||
usage("Error: Missing magic argument");
|
||||
}
|
||||
|
||||
if (!xbe->xbe_interpreter) {
|
||||
usage("Error: Missing 'interpreter' argument");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
name_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
|
||||
{
|
||||
if (strlen(argv[0]) > IBE_NAME_MAX)
|
||||
usage("'%s' string length longer than IBE_NAME_MAX (%d)",
|
||||
IBE_NAME_MAX);
|
||||
strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
noname_cmd(__unused int argc, __unused char *argv[],
|
||||
__unused ximgact_binmisc_entry_t *xbe)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int error = 0, cmd = -1;
|
||||
ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
|
||||
ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
|
||||
size_t xbe_in_sz = 0;
|
||||
size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
|
||||
uint32_t i;
|
||||
|
||||
if (kldfind(KMOD_NAME) == -1) {
|
||||
if (kldload(KMOD_NAME) == -1)
|
||||
fatal("Can't load %s kernel module: %s",
|
||||
KMOD_NAME, strerror(errno));
|
||||
}
|
||||
|
||||
bzero(&xbe_in, sizeof(xbe_in));
|
||||
bzero(&xbe_out, sizeof(xbe_out));
|
||||
xbe_in.xbe_version = IBE_VERSION;
|
||||
|
||||
if (argc < 2)
|
||||
usage("Error: requires at least one argument");
|
||||
|
||||
argc--, argv++;
|
||||
cmd = demux_cmd(argc, argv);
|
||||
if (cmd == -1)
|
||||
usage("Error: Unknown command \"%s\"", argv[0]);
|
||||
argc--, argv++;
|
||||
|
||||
error = (*cmds[cmd].func)(argc, argv, &xbe_in);
|
||||
if (error)
|
||||
usage("Can't parse command-line for '%s' command",
|
||||
cmds[cmd].name);
|
||||
|
||||
if (cmd != CMD_LIST) {
|
||||
xbe_inp = &xbe_in;
|
||||
xbe_in_sz = sizeof(xbe_in);
|
||||
} else
|
||||
xbe_out_szp = &xbe_out_sz;
|
||||
if (cmd == CMD_LOOKUP) {
|
||||
xbe_out_sz = sizeof(xbe_out);
|
||||
xbe_outp = &xbe_out;
|
||||
xbe_out_szp = &xbe_out_sz;
|
||||
}
|
||||
|
||||
error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
|
||||
xbe_inp, xbe_in_sz);
|
||||
|
||||
if (error)
|
||||
switch(errno) {
|
||||
case EINVAL:
|
||||
usage("Invalid interpreter name or --interpreter, "
|
||||
"--magic, --mask, or --size argument value");
|
||||
break;
|
||||
|
||||
case EEXIST:
|
||||
usage("'%s' is not unique in activator list",
|
||||
xbe_in.xbe_name);
|
||||
break;
|
||||
|
||||
case ENOENT:
|
||||
usage("'%s' is not found in activator list",
|
||||
xbe_in.xbe_name);
|
||||
break;
|
||||
|
||||
case ENOSPC:
|
||||
fatal("Fatal: no more room in the activator list "
|
||||
"(limited to %d enties)", IBE_MAX_ENTRIES);
|
||||
break;
|
||||
|
||||
case EPERM:
|
||||
usage("Insufficient privileges for '%s' command",
|
||||
cmds[cmd].name);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Fatal: sysctlbyname() returned: %s",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (cmd == CMD_LOOKUP)
|
||||
printxbe(xbe_outp);
|
||||
|
||||
if (cmd == CMD_LIST && xbe_out_sz > 0) {
|
||||
xbe_outp = malloc(xbe_out_sz);
|
||||
if (!xbe_outp)
|
||||
fatal("Fatal: out of memory");
|
||||
while(1) {
|
||||
size_t osize = xbe_out_sz;
|
||||
error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
|
||||
&xbe_out_sz, NULL, 0);
|
||||
|
||||
if (error == -1 && errno == ENOMEM &&
|
||||
xbe_out_sz == osize) {
|
||||
/*
|
||||
* Buffer too small. Increase it by one
|
||||
* entry.
|
||||
*/
|
||||
xbe_out_sz += sizeof(xbe_out);
|
||||
xbe_outp = realloc(xbe_outp, xbe_out_sz);
|
||||
if (!xbe_outp)
|
||||
fatal("Fatal: out of memory");
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (error) {
|
||||
free(xbe_outp);
|
||||
fatal("Fatal: %s", strerror(errno));
|
||||
}
|
||||
for(i = 0; i < (xbe_out_sz / sizeof(xbe_out)); i++)
|
||||
printxbe(&xbe_outp[i]);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
Loading…
Reference in New Issue
Block a user