2 * Copyright (c) 2013 Stacey D. Son
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/types.h>
29 #include <sys/imgact_binmisc.h>
30 #include <sys/linker.h>
31 #include <sys/module.h>
32 #include <sys/sysctl.h>
52 extern char *__progname;
54 typedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
56 int add_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
57 int name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
58 int noname_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
71 "Add a new binary image activator (requires 'root' privilege)",
72 "<name> --interpreter <path_and_arguments> \\\n"
73 "\t\t--magic <magic_bytes> [--mask <mask_bytes>] \\\n"
74 "\t\t--size <magic_size> [--offset <magic_offset>] \\\n"
75 "\t\t[--set-enabled] \\\n"
82 "Remove a binary image activator (requires 'root' privilege)",
89 "Disable a binary image activator (requires 'root' privilege)",
96 "Enable a binary image activator (requires 'root' privilege)",
103 "Lookup a binary image activator",
110 "List all the binary image activators",
115 static const struct option
117 { "set-enabled", no_argument, NULL, 'e' },
118 { "interpreter", required_argument, NULL, 'i' },
119 { "mask", required_argument, NULL, 'M' },
120 { "magic", required_argument, NULL, 'm' },
121 { "offset", required_argument, NULL, 'o' },
122 { "size", required_argument, NULL, 's' },
123 { "pre-open", no_argument, NULL, 'p' },
127 static char const *cmd_sysctl_name[] = {
129 IBE_SYSCTL_NAME_REMOVE,
130 IBE_SYSCTL_NAME_DISABLE,
131 IBE_SYSCTL_NAME_ENABLE,
132 IBE_SYSCTL_NAME_LOOKUP,
137 usage(const char *format, ...)
143 va_start(args, format);
145 vfprintf(stderr, format, args);
149 fprintf(stderr, "\n");
150 fprintf(stderr, "usage: %s command [args...]\n\n", __progname);
152 for(i = 0; i < nitems(cmds); i++) {
153 fprintf(stderr, "%s:\n", cmds[i].desc);
154 fprintf(stderr, "\t%s %s %s\n\n", __progname, cmds[i].name,
162 fatal(const char *format, ...)
166 va_start(args, format);
168 vfprintf(stderr, format, args);
169 fprintf(stderr, "\n");
175 getoptstr(char *str, size_t size, const char *argname)
177 if (strlen(optarg) > size)
178 usage("'%s' too large", argname);
179 strlcpy(str, optarg, size);
183 printxbe(ximgact_binmisc_entry_t *xbe)
185 uint32_t i, flags = xbe->xbe_flags;
187 if (xbe->xbe_version != IBE_VERSION) {
188 fprintf(stderr, "Error: XBE version mismatch\n");
192 printf("name: %s\n", xbe->xbe_name);
193 printf("interpreter: %s\n", xbe->xbe_interpreter);
194 printf("flags: %s%s%s\n", (flags & IBF_ENABLED) ? "ENABLED " : "",
195 (flags & IBF_USE_MASK) ? "USE_MASK " : "",
196 (flags & IBF_PRE_OPEN) ? "PRE_OPEN " : "");
197 printf("magic size: %u\n", xbe->xbe_msize);
198 printf("magic offset: %u\n", xbe->xbe_moffset);
201 for(i = 0; i < xbe->xbe_msize; i++) {
207 printf("0x%02x ", xbe->xbe_magic[i]);
211 if (flags & IBF_USE_MASK) {
213 for(i = 0; i < xbe->xbe_msize; i++) {
219 printf("0x%02x ", xbe->xbe_mask[i]);
228 demux_cmd(__unused int argc, char *const argv[])
235 for(i = 0; i < nitems(cmds); i++) {
236 if (!strcasecmp(cmds[i].name, argv[0])) {
241 /* Unknown command */
246 strlit2bin_cpy(uint8_t *d, char *s, size_t size)
251 while((c = *s++) != '\0') {
253 /* Do '\' escapes. */
262 *d = (c - (isdigit(c) ? '0' : ('A' - 10))) << 4;
264 *d++ |= c - (isdigit(c) ? '0' : ('A' - 10));
281 add_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
284 char *magic = NULL, *mask = NULL;
288 usage("Required argument missing\n");
289 if (strlen(argv[0]) > IBE_NAME_MAX)
290 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
292 strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
294 while ((ch = getopt_long(argc, argv, "epi:m:M:o:s:", add_opts, NULL))
299 getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
305 magic = strdup(optarg);
310 mask = strdup(optarg);
311 xbe->xbe_flags |= IBF_USE_MASK;
315 xbe->xbe_flags |= IBF_ENABLED;
319 xbe->xbe_moffset = atol(optarg);
323 xbe->xbe_msize = atol(optarg);
324 if (xbe->xbe_msize == 0 ||
325 xbe->xbe_msize > IBE_MAGIC_MAX)
326 usage("Error: Not valid '--size' value. "
327 "(Must be > 0 and < %u.)\n",
332 xbe->xbe_flags |= IBF_PRE_OPEN;
336 usage("Unknown argument: '%c'", ch);
340 if (xbe->xbe_msize == 0) {
345 usage("Error: Missing '--size' argument");
349 if (xbe->xbe_msize == 0) {
354 usage("Error: Missing magic size argument");
356 sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
358 if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
361 usage("Error: invalid magic argument");
364 sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
366 if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
367 usage("Error: invalid mask argument");
372 usage("Error: Missing magic argument");
375 if (!strnlen(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX)) {
376 usage("Error: Missing 'interpreter' argument");
383 name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
386 usage("Required argument missing\n");
387 if (strlen(argv[0]) > IBE_NAME_MAX)
388 usage("'%s' string length longer than IBE_NAME_MAX (%d)",
390 strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
396 noname_cmd(__unused int argc, __unused char *argv[],
397 __unused ximgact_binmisc_entry_t *xbe)
404 main(int argc, char **argv)
406 int error = 0, cmd = -1;
407 ximgact_binmisc_entry_t xbe_in, *xbe_inp = NULL;
408 ximgact_binmisc_entry_t xbe_out, *xbe_outp = NULL;
409 size_t xbe_in_sz = 0;
410 size_t xbe_out_sz = 0, *xbe_out_szp = NULL;
413 if (modfind(KMOD_NAME) == -1) {
414 if (kldload(KMOD_NAME) == -1)
415 fatal("Can't load %s kernel module: %s",
416 KMOD_NAME, strerror(errno));
419 bzero(&xbe_in, sizeof(xbe_in));
420 bzero(&xbe_out, sizeof(xbe_out));
421 xbe_in.xbe_version = IBE_VERSION;
424 usage("Error: requires at least one argument");
427 cmd = demux_cmd(argc, argv);
429 usage("Error: Unknown command \"%s\"", argv[0]);
432 error = (*cmds[cmd].func)(argc, argv, &xbe_in);
434 usage("Can't parse command-line for '%s' command",
437 if (cmd != CMD_LIST) {
439 xbe_in_sz = sizeof(xbe_in);
441 xbe_out_szp = &xbe_out_sz;
442 if (cmd == CMD_LOOKUP) {
443 xbe_out_sz = sizeof(xbe_out);
445 xbe_out_szp = &xbe_out_sz;
448 error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
454 usage("Invalid interpreter name or --interpreter, "
455 "--magic, --mask, or --size argument value");
459 usage("'%s' is not unique in activator list",
464 usage("'%s' is not found in activator list",
469 fatal("Fatal: no more room in the activator list "
470 "(limited to %d enties)", IBE_MAX_ENTRIES);
474 usage("Insufficient privileges for '%s' command",
479 fatal("Fatal: sysctlbyname() returned: %s",
485 if (cmd == CMD_LOOKUP)
488 if (cmd == CMD_LIST && xbe_out_sz > 0) {
489 xbe_outp = malloc(xbe_out_sz);
491 fatal("Fatal: out of memory");
493 size_t osize = xbe_out_sz;
494 error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
495 &xbe_out_sz, NULL, 0);
497 if (error == -1 && errno == ENOMEM &&
498 xbe_out_sz == osize) {
500 * Buffer too small. Increase it by one
503 xbe_out_sz += sizeof(xbe_out);
504 xbe_outp = realloc(xbe_outp, xbe_out_sz);
506 fatal("Fatal: out of memory");
512 fatal("Fatal: %s", strerror(errno));
514 for(i = 0; i < howmany(xbe_out_sz, sizeof(xbe_out)); i++)
515 printxbe(&xbe_outp[i]);