Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/binmiscctl/binmiscctl.c
102644 views
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
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>
33
34
#include <ctype.h>
35
#include <errno.h>
36
#include <getopt.h>
37
#include <stdio.h>
38
#include <stdarg.h>
39
#include <stdint.h>
40
#include <stdlib.h>
41
#include <string.h>
42
43
enum cmd {
44
CMD_ADD = 0,
45
CMD_REMOVE,
46
CMD_DISABLE,
47
CMD_ENABLE,
48
CMD_LOOKUP,
49
CMD_LIST,
50
};
51
52
extern char *__progname;
53
54
typedef int (*cmd_func_t)(int argc, char *argv[], ximgact_binmisc_entry_t *xbe);
55
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);
59
60
static const struct {
61
const int token;
62
const char *name;
63
cmd_func_t func;
64
const char *desc;
65
const char *args;
66
} cmds[] = {
67
{
68
CMD_ADD,
69
"add",
70
add_cmd,
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"
76
"\t\t[--pre-open]"
77
},
78
{
79
CMD_REMOVE,
80
"remove",
81
name_cmd,
82
"Remove a binary image activator (requires 'root' privilege)",
83
"<name>"
84
},
85
{
86
CMD_DISABLE,
87
"disable",
88
name_cmd,
89
"Disable a binary image activator (requires 'root' privilege)",
90
"<name>"
91
},
92
{
93
CMD_ENABLE,
94
"enable",
95
name_cmd,
96
"Enable a binary image activator (requires 'root' privilege)",
97
"<name>"
98
},
99
{
100
CMD_LOOKUP,
101
"lookup",
102
name_cmd,
103
"Lookup a binary image activator",
104
"<name>"
105
},
106
{
107
CMD_LIST,
108
"list",
109
noname_cmd,
110
"List all the binary image activators",
111
""
112
},
113
};
114
115
static const struct option
116
add_opts[] = {
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' },
124
{ NULL, 0, NULL, 0 }
125
};
126
127
static char const *cmd_sysctl_name[] = {
128
IBE_SYSCTL_NAME_ADD,
129
IBE_SYSCTL_NAME_REMOVE,
130
IBE_SYSCTL_NAME_DISABLE,
131
IBE_SYSCTL_NAME_ENABLE,
132
IBE_SYSCTL_NAME_LOOKUP,
133
IBE_SYSCTL_NAME_LIST
134
};
135
136
static void __dead2
137
usage(const char *format, ...)
138
{
139
va_list args;
140
size_t i;
141
int error = 0;
142
143
va_start(args, format);
144
if (format) {
145
vfprintf(stderr, format, args);
146
error = -1;
147
}
148
va_end(args);
149
fprintf(stderr, "\n");
150
fprintf(stderr, "usage: %s command [args...]\n\n", __progname);
151
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,
155
cmds[i].args);
156
}
157
158
exit (error);
159
}
160
161
static void __dead2
162
fatal(const char *format, ...)
163
{
164
va_list args;
165
166
va_start(args, format);
167
if (format)
168
vfprintf(stderr, format, args);
169
fprintf(stderr, "\n");
170
171
exit(-1);
172
}
173
174
static void
175
getoptstr(char *str, size_t size, const char *argname)
176
{
177
if (strlen(optarg) > size)
178
usage("'%s' too large", argname);
179
strlcpy(str, optarg, size);
180
}
181
182
static void
183
printxbe(ximgact_binmisc_entry_t *xbe)
184
{
185
uint32_t i, flags = xbe->xbe_flags;
186
187
if (xbe->xbe_version != IBE_VERSION) {
188
fprintf(stderr, "Error: XBE version mismatch\n");
189
return;
190
}
191
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);
199
200
printf("magic: ");
201
for(i = 0; i < xbe->xbe_msize; i++) {
202
if (i && !(i % 12))
203
printf("\n ");
204
else
205
if (i && !(i % 4))
206
printf(" ");
207
printf("0x%02x ", xbe->xbe_magic[i]);
208
}
209
printf("\n");
210
211
if (flags & IBF_USE_MASK) {
212
printf("mask: ");
213
for(i = 0; i < xbe->xbe_msize; i++) {
214
if (i && !(i % 12))
215
printf("\n ");
216
else
217
if (i && !(i % 4))
218
printf(" ");
219
printf("0x%02x ", xbe->xbe_mask[i]);
220
}
221
printf("\n");
222
}
223
224
printf("\n");
225
}
226
227
static int
228
demux_cmd(__unused int argc, char *const argv[])
229
{
230
size_t i;
231
232
optind = 1;
233
optreset = 1;
234
235
for(i = 0; i < nitems(cmds); i++) {
236
if (!strcasecmp(cmds[i].name, argv[0])) {
237
return (i);
238
}
239
}
240
241
/* Unknown command */
242
return (-1);
243
}
244
245
static int
246
strlit2bin_cpy(uint8_t *d, char *s, size_t size)
247
{
248
int c;
249
size_t cnt = 0;
250
251
while((c = *s++) != '\0') {
252
if (c == '\\') {
253
/* Do '\' escapes. */
254
switch (*s) {
255
case '\\':
256
*d++ = '\\';
257
break;
258
259
case 'x':
260
s++;
261
c = toupper(*s++);
262
*d = (c - (isdigit(c) ? '0' : ('A' - 10))) << 4;
263
c = toupper(*s++);
264
*d++ |= c - (isdigit(c) ? '0' : ('A' - 10));
265
break;
266
267
default:
268
return (-1);
269
}
270
} else
271
*d++ = c;
272
273
if (++cnt > size)
274
return (-1);
275
}
276
277
return (cnt);
278
}
279
280
int
281
add_cmd(__unused int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
282
{
283
int ch;
284
char *magic = NULL, *mask = NULL;
285
int sz;
286
287
if (argc == 0)
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)",
291
IBE_NAME_MAX);
292
strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
293
294
while ((ch = getopt_long(argc, argv, "epi:m:M:o:s:", add_opts, NULL))
295
!= -1) {
296
297
switch(ch) {
298
case 'i':
299
getoptstr(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX,
300
"interpreter");
301
break;
302
303
case 'm':
304
free(magic);
305
magic = strdup(optarg);
306
break;
307
308
case 'M':
309
free(mask);
310
mask = strdup(optarg);
311
xbe->xbe_flags |= IBF_USE_MASK;
312
break;
313
314
case 'e':
315
xbe->xbe_flags |= IBF_ENABLED;
316
break;
317
318
case 'o':
319
xbe->xbe_moffset = atol(optarg);
320
break;
321
322
case 's':
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",
328
xbe->xbe_msize);
329
break;
330
331
case 'p':
332
xbe->xbe_flags |= IBF_PRE_OPEN;
333
break;
334
335
default:
336
usage("Unknown argument: '%c'", ch);
337
}
338
}
339
340
if (xbe->xbe_msize == 0) {
341
if (NULL != magic)
342
free(magic);
343
if (NULL != mask)
344
free(mask);
345
usage("Error: Missing '--size' argument");
346
}
347
348
if (NULL != magic) {
349
if (xbe->xbe_msize == 0) {
350
if (magic)
351
free(magic);
352
if (mask)
353
free(mask);
354
usage("Error: Missing magic size argument");
355
}
356
sz = strlit2bin_cpy(xbe->xbe_magic, magic, IBE_MAGIC_MAX);
357
free(magic);
358
if (sz == -1 || (uint32_t)sz != xbe->xbe_msize) {
359
if (mask)
360
free(mask);
361
usage("Error: invalid magic argument");
362
}
363
if (mask) {
364
sz = strlit2bin_cpy(xbe->xbe_mask, mask, IBE_MAGIC_MAX);
365
free(mask);
366
if (sz == -1 || (uint32_t)sz != xbe->xbe_msize)
367
usage("Error: invalid mask argument");
368
}
369
} else {
370
if (mask)
371
free(mask);
372
usage("Error: Missing magic argument");
373
}
374
375
if (!strnlen(xbe->xbe_interpreter, IBE_INTERP_LEN_MAX)) {
376
usage("Error: Missing 'interpreter' argument");
377
}
378
379
return (0);
380
}
381
382
int
383
name_cmd(int argc, char *argv[], ximgact_binmisc_entry_t *xbe)
384
{
385
if (argc == 0)
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)",
389
IBE_NAME_MAX);
390
strlcpy(&xbe->xbe_name[0], argv[0], IBE_NAME_MAX);
391
392
return (0);
393
}
394
395
int
396
noname_cmd(__unused int argc, __unused char *argv[],
397
__unused ximgact_binmisc_entry_t *xbe)
398
{
399
400
return (0);
401
}
402
403
int
404
main(int argc, char **argv)
405
{
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;
411
uint32_t i;
412
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));
417
}
418
419
bzero(&xbe_in, sizeof(xbe_in));
420
bzero(&xbe_out, sizeof(xbe_out));
421
xbe_in.xbe_version = IBE_VERSION;
422
423
if (argc < 2)
424
usage("Error: requires at least one argument");
425
426
argc--, argv++;
427
cmd = demux_cmd(argc, argv);
428
if (cmd < 0)
429
usage("Error: Unknown command \"%s\"", argv[0]);
430
argc--, argv++;
431
432
error = (*cmds[cmd].func)(argc, argv, &xbe_in);
433
if (error)
434
usage("Can't parse command-line for '%s' command",
435
cmds[cmd].name);
436
437
if (cmd != CMD_LIST) {
438
xbe_inp = &xbe_in;
439
xbe_in_sz = sizeof(xbe_in);
440
} else
441
xbe_out_szp = &xbe_out_sz;
442
if (cmd == CMD_LOOKUP) {
443
xbe_out_sz = sizeof(xbe_out);
444
xbe_outp = &xbe_out;
445
xbe_out_szp = &xbe_out_sz;
446
}
447
448
error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp, xbe_out_szp,
449
xbe_inp, xbe_in_sz);
450
451
if (error)
452
switch(errno) {
453
case EINVAL:
454
usage("Invalid interpreter name or --interpreter, "
455
"--magic, --mask, or --size argument value");
456
break;
457
458
case EEXIST:
459
usage("'%s' is not unique in activator list",
460
xbe_in.xbe_name);
461
break;
462
463
case ENOENT:
464
usage("'%s' is not found in activator list",
465
xbe_in.xbe_name);
466
break;
467
468
case ENOSPC:
469
fatal("Fatal: no more room in the activator list "
470
"(limited to %d enties)", IBE_MAX_ENTRIES);
471
break;
472
473
case EPERM:
474
usage("Insufficient privileges for '%s' command",
475
cmds[cmd].name);
476
break;
477
478
default:
479
fatal("Fatal: sysctlbyname() returned: %s",
480
strerror(errno));
481
break;
482
}
483
484
485
if (cmd == CMD_LOOKUP)
486
printxbe(xbe_outp);
487
488
if (cmd == CMD_LIST && xbe_out_sz > 0) {
489
xbe_outp = malloc(xbe_out_sz);
490
if (!xbe_outp)
491
fatal("Fatal: out of memory");
492
while(1) {
493
size_t osize = xbe_out_sz;
494
error = sysctlbyname(cmd_sysctl_name[cmd], xbe_outp,
495
&xbe_out_sz, NULL, 0);
496
497
if (error == -1 && errno == ENOMEM &&
498
xbe_out_sz == osize) {
499
/*
500
* Buffer too small. Increase it by one
501
* entry.
502
*/
503
xbe_out_sz += sizeof(xbe_out);
504
xbe_outp = realloc(xbe_outp, xbe_out_sz);
505
if (!xbe_outp)
506
fatal("Fatal: out of memory");
507
} else
508
break;
509
}
510
if (error) {
511
free(xbe_outp);
512
fatal("Fatal: %s", strerror(errno));
513
}
514
for(i = 0; i < howmany(xbe_out_sz, sizeof(xbe_out)); i++)
515
printxbe(&xbe_outp[i]);
516
}
517
518
return (error);
519
}
520
521