1*4b9c6d91SCole Faust /* Copyright 2012 The ChromiumOS Authors
2*4b9c6d91SCole Faust * Use of this source code is governed by a BSD-style license that can be
3*4b9c6d91SCole Faust * found in the LICENSE file.
4*4b9c6d91SCole Faust */
5*4b9c6d91SCole Faust
6*4b9c6d91SCole Faust #define _GNU_SOURCE
7*4b9c6d91SCole Faust
8*4b9c6d91SCole Faust #include "util.h"
9*4b9c6d91SCole Faust
10*4b9c6d91SCole Faust #include <ctype.h>
11*4b9c6d91SCole Faust #include <errno.h>
12*4b9c6d91SCole Faust #include <limits.h>
13*4b9c6d91SCole Faust #include <stdarg.h>
14*4b9c6d91SCole Faust #include <stdbool.h>
15*4b9c6d91SCole Faust #include <stdint.h>
16*4b9c6d91SCole Faust #include <stdio.h>
17*4b9c6d91SCole Faust #include <string.h>
18*4b9c6d91SCole Faust
19*4b9c6d91SCole Faust #include "libconstants.h"
20*4b9c6d91SCole Faust #include "libsyscalls.h"
21*4b9c6d91SCole Faust
22*4b9c6d91SCole Faust /*
23*4b9c6d91SCole Faust * These are syscalls used by the syslog() C library call. You can find them
24*4b9c6d91SCole Faust * by running a simple test program. See below for x86_64 behavior:
25*4b9c6d91SCole Faust * $ cat test.c
26*4b9c6d91SCole Faust * #include <syslog.h>
27*4b9c6d91SCole Faust * main() { syslog(0, "foo"); }
28*4b9c6d91SCole Faust * $ gcc test.c -static
29*4b9c6d91SCole Faust * $ strace ./a.out
30*4b9c6d91SCole Faust * ...
31*4b9c6d91SCole Faust * socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3 <- look for socket connection
32*4b9c6d91SCole Faust * connect(...) <- important
33*4b9c6d91SCole Faust * sendto(...) <- important
34*4b9c6d91SCole Faust * exit_group(0) <- finish!
35*4b9c6d91SCole Faust */
36*4b9c6d91SCole Faust const char *const log_syscalls[] = {
37*4b9c6d91SCole Faust #if defined(__x86_64__)
38*4b9c6d91SCole Faust # if defined(__ANDROID__)
39*4b9c6d91SCole Faust "socket", "connect", "fcntl", "writev",
40*4b9c6d91SCole Faust # else
41*4b9c6d91SCole Faust "socket", "connect", "sendto", "writev",
42*4b9c6d91SCole Faust # endif
43*4b9c6d91SCole Faust #elif defined(__i386__)
44*4b9c6d91SCole Faust # if defined(__ANDROID__)
45*4b9c6d91SCole Faust "socketcall", "writev", "fcntl64", "clock_gettime",
46*4b9c6d91SCole Faust # else
47*4b9c6d91SCole Faust "socketcall", "time", "writev",
48*4b9c6d91SCole Faust # endif
49*4b9c6d91SCole Faust #elif defined(__arm__)
50*4b9c6d91SCole Faust # if defined(__ANDROID__)
51*4b9c6d91SCole Faust "clock_gettime", "connect", "fcntl64", "socket", "writev",
52*4b9c6d91SCole Faust # else
53*4b9c6d91SCole Faust "socket", "connect", "gettimeofday", "send", "writev",
54*4b9c6d91SCole Faust # endif
55*4b9c6d91SCole Faust #elif defined(__aarch64__)
56*4b9c6d91SCole Faust # if defined(__ANDROID__)
57*4b9c6d91SCole Faust "connect", "fcntl", "sendto", "socket", "writev",
58*4b9c6d91SCole Faust # else
59*4b9c6d91SCole Faust "socket", "connect", "send", "writev",
60*4b9c6d91SCole Faust # endif
61*4b9c6d91SCole Faust #elif defined(__hppa__) || \
62*4b9c6d91SCole Faust defined(__ia64__) || \
63*4b9c6d91SCole Faust defined(__mips__) || \
64*4b9c6d91SCole Faust defined(__powerpc__) || \
65*4b9c6d91SCole Faust defined(__sparc__)
66*4b9c6d91SCole Faust "socket", "connect", "send",
67*4b9c6d91SCole Faust #elif defined(__riscv)
68*4b9c6d91SCole Faust # if defined(__ANDROID__)
69*4b9c6d91SCole Faust "connect", "fcntl", "sendto", "socket", "writev",
70*4b9c6d91SCole Faust # else
71*4b9c6d91SCole Faust "socket", "connect", "sendto",
72*4b9c6d91SCole Faust # endif
73*4b9c6d91SCole Faust #else
74*4b9c6d91SCole Faust # error "Unsupported platform"
75*4b9c6d91SCole Faust #endif
76*4b9c6d91SCole Faust };
77*4b9c6d91SCole Faust
78*4b9c6d91SCole Faust const size_t log_syscalls_len = ARRAY_SIZE(log_syscalls);
79*4b9c6d91SCole Faust
80*4b9c6d91SCole Faust /* clang-format off */
81*4b9c6d91SCole Faust static struct logging_config_t {
82*4b9c6d91SCole Faust /* The logging system to use. The default is syslog. */
83*4b9c6d91SCole Faust enum logging_system_t logger;
84*4b9c6d91SCole Faust
85*4b9c6d91SCole Faust /* File descriptor to log to. Only used when logger is LOG_TO_FD. */
86*4b9c6d91SCole Faust int fd;
87*4b9c6d91SCole Faust
88*4b9c6d91SCole Faust /* Minimum priority to log. Only used when logger is LOG_TO_FD. */
89*4b9c6d91SCole Faust int min_priority;
90*4b9c6d91SCole Faust } logging_config = {
91*4b9c6d91SCole Faust .logger = LOG_TO_SYSLOG,
92*4b9c6d91SCole Faust };
93*4b9c6d91SCole Faust /* clang-format on */
94*4b9c6d91SCole Faust
95*4b9c6d91SCole Faust #if defined(USE_EXIT_ON_DIE)
96*4b9c6d91SCole Faust #define do_abort() exit(1)
97*4b9c6d91SCole Faust #else
98*4b9c6d91SCole Faust #define do_abort() abort()
99*4b9c6d91SCole Faust #endif
100*4b9c6d91SCole Faust
101*4b9c6d91SCole Faust #if defined(__clang__)
102*4b9c6d91SCole Faust #define attribute_no_optimize __attribute__((optnone))
103*4b9c6d91SCole Faust #else
104*4b9c6d91SCole Faust #define attribute_no_optimize __attribute__((__optimize__(0)))
105*4b9c6d91SCole Faust #endif
106*4b9c6d91SCole Faust
107*4b9c6d91SCole Faust /* Forces the compiler to perform no optimizations on |var|. */
alias(const void * var)108*4b9c6d91SCole Faust static void attribute_no_optimize alias(const void *var)
109*4b9c6d91SCole Faust {
110*4b9c6d91SCole Faust (void)var;
111*4b9c6d91SCole Faust }
112*4b9c6d91SCole Faust
do_fatal_log(int priority,const char * format,...)113*4b9c6d91SCole Faust void do_fatal_log(int priority, const char *format, ...)
114*4b9c6d91SCole Faust {
115*4b9c6d91SCole Faust va_list args, stack_args;
116*4b9c6d91SCole Faust va_start(args, format);
117*4b9c6d91SCole Faust va_copy(stack_args, args);
118*4b9c6d91SCole Faust if (logging_config.logger == LOG_TO_SYSLOG) {
119*4b9c6d91SCole Faust vsyslog(priority, format, args);
120*4b9c6d91SCole Faust } else {
121*4b9c6d91SCole Faust vdprintf(logging_config.fd, format, args);
122*4b9c6d91SCole Faust dprintf(logging_config.fd, "\n");
123*4b9c6d91SCole Faust }
124*4b9c6d91SCole Faust va_end(args);
125*4b9c6d91SCole Faust
126*4b9c6d91SCole Faust /*
127*4b9c6d91SCole Faust * Write another copy of the first few characters of the message into a
128*4b9c6d91SCole Faust * stack-based buffer so that it can appear in minidumps. Choosing a
129*4b9c6d91SCole Faust * small-ish buffer size since breakpad will only pick up the first few
130*4b9c6d91SCole Faust * kilobytes of each stack, so that will prevent this buffer from
131*4b9c6d91SCole Faust * kicking out other stack frames.
132*4b9c6d91SCole Faust */
133*4b9c6d91SCole Faust char log_line[512];
134*4b9c6d91SCole Faust vsnprintf(log_line, sizeof(log_line), format, stack_args);
135*4b9c6d91SCole Faust va_end(stack_args);
136*4b9c6d91SCole Faust alias(log_line);
137*4b9c6d91SCole Faust do_abort();
138*4b9c6d91SCole Faust }
139*4b9c6d91SCole Faust
do_log(int priority,const char * format,...)140*4b9c6d91SCole Faust void do_log(int priority, const char *format, ...)
141*4b9c6d91SCole Faust {
142*4b9c6d91SCole Faust if (logging_config.logger == LOG_TO_SYSLOG) {
143*4b9c6d91SCole Faust va_list args;
144*4b9c6d91SCole Faust va_start(args, format);
145*4b9c6d91SCole Faust vsyslog(priority, format, args);
146*4b9c6d91SCole Faust va_end(args);
147*4b9c6d91SCole Faust return;
148*4b9c6d91SCole Faust }
149*4b9c6d91SCole Faust
150*4b9c6d91SCole Faust if (logging_config.min_priority < priority)
151*4b9c6d91SCole Faust return;
152*4b9c6d91SCole Faust
153*4b9c6d91SCole Faust va_list args;
154*4b9c6d91SCole Faust va_start(args, format);
155*4b9c6d91SCole Faust vdprintf(logging_config.fd, format, args);
156*4b9c6d91SCole Faust va_end(args);
157*4b9c6d91SCole Faust dprintf(logging_config.fd, "\n");
158*4b9c6d91SCole Faust }
159*4b9c6d91SCole Faust
160*4b9c6d91SCole Faust /*
161*4b9c6d91SCole Faust * Returns the syscall nr and optionally populates the index in the pointer
162*4b9c6d91SCole Faust * |ind| if it is non-NULL.
163*4b9c6d91SCole Faust */
lookup_syscall(const char * name,size_t * ind)164*4b9c6d91SCole Faust int lookup_syscall(const char *name, size_t *ind)
165*4b9c6d91SCole Faust {
166*4b9c6d91SCole Faust size_t ind_tmp = 0;
167*4b9c6d91SCole Faust const struct syscall_entry *entry = syscall_table;
168*4b9c6d91SCole Faust for (; entry->name && entry->nr >= 0; ++entry) {
169*4b9c6d91SCole Faust if (streq(entry->name, name)) {
170*4b9c6d91SCole Faust if (ind != NULL)
171*4b9c6d91SCole Faust *ind = ind_tmp;
172*4b9c6d91SCole Faust return entry->nr;
173*4b9c6d91SCole Faust }
174*4b9c6d91SCole Faust ind_tmp++;
175*4b9c6d91SCole Faust }
176*4b9c6d91SCole Faust if (ind != NULL)
177*4b9c6d91SCole Faust *ind = -1;
178*4b9c6d91SCole Faust return -1;
179*4b9c6d91SCole Faust }
180*4b9c6d91SCole Faust
lookup_syscall_name(int nr)181*4b9c6d91SCole Faust const char *lookup_syscall_name(int nr)
182*4b9c6d91SCole Faust {
183*4b9c6d91SCole Faust const struct syscall_entry *entry = syscall_table;
184*4b9c6d91SCole Faust for (; entry->name && entry->nr >= 0; ++entry)
185*4b9c6d91SCole Faust if (entry->nr == nr)
186*4b9c6d91SCole Faust return entry->name;
187*4b9c6d91SCole Faust return NULL;
188*4b9c6d91SCole Faust }
189*4b9c6d91SCole Faust
parse_single_constant(char * constant_str,char ** endptr)190*4b9c6d91SCole Faust long int parse_single_constant(char *constant_str, char **endptr)
191*4b9c6d91SCole Faust {
192*4b9c6d91SCole Faust const struct constant_entry *entry = constant_table;
193*4b9c6d91SCole Faust long int res = 0;
194*4b9c6d91SCole Faust for (; entry->name; ++entry) {
195*4b9c6d91SCole Faust if (streq(entry->name, constant_str)) {
196*4b9c6d91SCole Faust *endptr = constant_str + strlen(constant_str);
197*4b9c6d91SCole Faust return entry->value;
198*4b9c6d91SCole Faust }
199*4b9c6d91SCole Faust }
200*4b9c6d91SCole Faust
201*4b9c6d91SCole Faust errno = 0;
202*4b9c6d91SCole Faust res = strtol(constant_str, endptr, 0);
203*4b9c6d91SCole Faust if (errno == ERANGE) {
204*4b9c6d91SCole Faust if (res == LONG_MAX) {
205*4b9c6d91SCole Faust /* See if the constant fits in an unsigned long int. */
206*4b9c6d91SCole Faust errno = 0;
207*4b9c6d91SCole Faust res = strtoul(constant_str, endptr, 0);
208*4b9c6d91SCole Faust if (errno == ERANGE) {
209*4b9c6d91SCole Faust /*
210*4b9c6d91SCole Faust * On unsigned overflow, use the same convention
211*4b9c6d91SCole Faust * as when strtol(3) finds no digits: set
212*4b9c6d91SCole Faust * |*endptr| to |constant_str| and return 0.
213*4b9c6d91SCole Faust */
214*4b9c6d91SCole Faust warn("unsigned overflow: '%s'", constant_str);
215*4b9c6d91SCole Faust *endptr = constant_str;
216*4b9c6d91SCole Faust return 0;
217*4b9c6d91SCole Faust }
218*4b9c6d91SCole Faust } else if (res == LONG_MIN) {
219*4b9c6d91SCole Faust /*
220*4b9c6d91SCole Faust * Same for signed underflow: set |*endptr| to
221*4b9c6d91SCole Faust * |constant_str| and return 0.
222*4b9c6d91SCole Faust */
223*4b9c6d91SCole Faust warn("signed underflow: '%s'", constant_str);
224*4b9c6d91SCole Faust *endptr = constant_str;
225*4b9c6d91SCole Faust return 0;
226*4b9c6d91SCole Faust }
227*4b9c6d91SCole Faust }
228*4b9c6d91SCole Faust if (**endptr != '\0') {
229*4b9c6d91SCole Faust warn("trailing garbage after constant: '%s'", constant_str);
230*4b9c6d91SCole Faust *endptr = constant_str;
231*4b9c6d91SCole Faust return 0;
232*4b9c6d91SCole Faust }
233*4b9c6d91SCole Faust return res;
234*4b9c6d91SCole Faust }
235*4b9c6d91SCole Faust
tokenize_parenthesized_expression(char ** stringp)236*4b9c6d91SCole Faust static char *tokenize_parenthesized_expression(char **stringp)
237*4b9c6d91SCole Faust {
238*4b9c6d91SCole Faust char *ret = NULL, *found = NULL;
239*4b9c6d91SCole Faust size_t paren_count = 1;
240*4b9c6d91SCole Faust
241*4b9c6d91SCole Faust /* If the string is NULL, there are no parens to be found. */
242*4b9c6d91SCole Faust if (stringp == NULL || *stringp == NULL)
243*4b9c6d91SCole Faust return NULL;
244*4b9c6d91SCole Faust
245*4b9c6d91SCole Faust /* If the string is not on an open paren, the results are undefined. */
246*4b9c6d91SCole Faust if (**stringp != '(')
247*4b9c6d91SCole Faust return NULL;
248*4b9c6d91SCole Faust
249*4b9c6d91SCole Faust for (found = *stringp + 1; *found; ++found) {
250*4b9c6d91SCole Faust switch (*found) {
251*4b9c6d91SCole Faust case '(':
252*4b9c6d91SCole Faust ++paren_count;
253*4b9c6d91SCole Faust break;
254*4b9c6d91SCole Faust case ')':
255*4b9c6d91SCole Faust --paren_count;
256*4b9c6d91SCole Faust if (!paren_count) {
257*4b9c6d91SCole Faust *found = '\0';
258*4b9c6d91SCole Faust ret = *stringp + 1;
259*4b9c6d91SCole Faust *stringp = found + 1;
260*4b9c6d91SCole Faust return ret;
261*4b9c6d91SCole Faust }
262*4b9c6d91SCole Faust break;
263*4b9c6d91SCole Faust }
264*4b9c6d91SCole Faust }
265*4b9c6d91SCole Faust
266*4b9c6d91SCole Faust /* We got to the end without finding the closing paren. */
267*4b9c6d91SCole Faust warn("unclosed parenthesis: '%s'", *stringp);
268*4b9c6d91SCole Faust return NULL;
269*4b9c6d91SCole Faust }
270*4b9c6d91SCole Faust
parse_constant(char * constant_str,char ** endptr)271*4b9c6d91SCole Faust long int parse_constant(char *constant_str, char **endptr)
272*4b9c6d91SCole Faust {
273*4b9c6d91SCole Faust long int value = 0, current_value;
274*4b9c6d91SCole Faust char *group, *lastpos = constant_str;
275*4b9c6d91SCole Faust
276*4b9c6d91SCole Faust /*
277*4b9c6d91SCole Faust * If |endptr| is provided, parsing errors are signaled as |endptr|
278*4b9c6d91SCole Faust * pointing to |constant_str|.
279*4b9c6d91SCole Faust */
280*4b9c6d91SCole Faust if (endptr)
281*4b9c6d91SCole Faust *endptr = constant_str;
282*4b9c6d91SCole Faust
283*4b9c6d91SCole Faust /*
284*4b9c6d91SCole Faust * Try to parse constant expressions. Valid constant expressions are:
285*4b9c6d91SCole Faust *
286*4b9c6d91SCole Faust * - A number that can be parsed with strtol(3).
287*4b9c6d91SCole Faust * - A named constant expression.
288*4b9c6d91SCole Faust * - A parenthesized, valid constant expression.
289*4b9c6d91SCole Faust * - A valid constant expression prefixed with the unary bitwise
290*4b9c6d91SCole Faust * complement operator ~.
291*4b9c6d91SCole Faust * - A series of valid constant expressions separated by pipes. Note
292*4b9c6d91SCole Faust * that since |constant_str| is an atom, there can be no spaces
293*4b9c6d91SCole Faust * between the constant and the pipe.
294*4b9c6d91SCole Faust *
295*4b9c6d91SCole Faust * If there is an error parsing any of the constants, the whole process
296*4b9c6d91SCole Faust * fails.
297*4b9c6d91SCole Faust */
298*4b9c6d91SCole Faust while (constant_str && *constant_str) {
299*4b9c6d91SCole Faust bool negate = false;
300*4b9c6d91SCole Faust if (*constant_str == '~') {
301*4b9c6d91SCole Faust negate = true;
302*4b9c6d91SCole Faust ++constant_str;
303*4b9c6d91SCole Faust }
304*4b9c6d91SCole Faust if (*constant_str == '(') {
305*4b9c6d91SCole Faust group =
306*4b9c6d91SCole Faust tokenize_parenthesized_expression(&constant_str);
307*4b9c6d91SCole Faust if (group == NULL)
308*4b9c6d91SCole Faust return 0;
309*4b9c6d91SCole Faust char *end = group;
310*4b9c6d91SCole Faust /* Recursively parse the parenthesized subexpression. */
311*4b9c6d91SCole Faust current_value = parse_constant(group, &end);
312*4b9c6d91SCole Faust if (end == group)
313*4b9c6d91SCole Faust return 0;
314*4b9c6d91SCole Faust if (constant_str && *constant_str) {
315*4b9c6d91SCole Faust /*
316*4b9c6d91SCole Faust * If this is not the end of the atom, there
317*4b9c6d91SCole Faust * should be another | followed by more stuff.
318*4b9c6d91SCole Faust */
319*4b9c6d91SCole Faust if (*constant_str != '|') {
320*4b9c6d91SCole Faust warn("unterminated constant "
321*4b9c6d91SCole Faust "expression: '%s'",
322*4b9c6d91SCole Faust constant_str);
323*4b9c6d91SCole Faust return 0;
324*4b9c6d91SCole Faust }
325*4b9c6d91SCole Faust ++constant_str;
326*4b9c6d91SCole Faust if (*constant_str == '\0') {
327*4b9c6d91SCole Faust warn("unterminated constant "
328*4b9c6d91SCole Faust "expression: '%s'",
329*4b9c6d91SCole Faust constant_str);
330*4b9c6d91SCole Faust return 0;
331*4b9c6d91SCole Faust }
332*4b9c6d91SCole Faust }
333*4b9c6d91SCole Faust lastpos = end;
334*4b9c6d91SCole Faust } else {
335*4b9c6d91SCole Faust group = tokenize(&constant_str, "|");
336*4b9c6d91SCole Faust char *end = group;
337*4b9c6d91SCole Faust current_value = parse_single_constant(group, &end);
338*4b9c6d91SCole Faust if (end == group)
339*4b9c6d91SCole Faust return 0;
340*4b9c6d91SCole Faust lastpos = end;
341*4b9c6d91SCole Faust }
342*4b9c6d91SCole Faust if (negate)
343*4b9c6d91SCole Faust current_value = ~current_value;
344*4b9c6d91SCole Faust value |= current_value;
345*4b9c6d91SCole Faust }
346*4b9c6d91SCole Faust if (endptr)
347*4b9c6d91SCole Faust *endptr = lastpos;
348*4b9c6d91SCole Faust return value;
349*4b9c6d91SCole Faust }
350*4b9c6d91SCole Faust
351*4b9c6d91SCole Faust /*
352*4b9c6d91SCole Faust * parse_size, specified as a string with a decimal number in bytes,
353*4b9c6d91SCole Faust * possibly with one 1-character suffix like "10K" or "6G".
354*4b9c6d91SCole Faust * Assumes both pointers are non-NULL.
355*4b9c6d91SCole Faust *
356*4b9c6d91SCole Faust * Returns 0 on success, negative errno on failure.
357*4b9c6d91SCole Faust * Only writes to result on success.
358*4b9c6d91SCole Faust */
parse_size(size_t * result,const char * sizespec)359*4b9c6d91SCole Faust int parse_size(size_t *result, const char *sizespec)
360*4b9c6d91SCole Faust {
361*4b9c6d91SCole Faust const char prefixes[] = "KMGTPE";
362*4b9c6d91SCole Faust size_t i, multiplier = 1, nsize, size = 0;
363*4b9c6d91SCole Faust unsigned long long parsed;
364*4b9c6d91SCole Faust const size_t len = strlen(sizespec);
365*4b9c6d91SCole Faust char *end;
366*4b9c6d91SCole Faust
367*4b9c6d91SCole Faust if (len == 0 || sizespec[0] == '-')
368*4b9c6d91SCole Faust return -EINVAL;
369*4b9c6d91SCole Faust
370*4b9c6d91SCole Faust for (i = 0; i < sizeof(prefixes); ++i) {
371*4b9c6d91SCole Faust if (sizespec[len - 1] == prefixes[i]) {
372*4b9c6d91SCole Faust #if __WORDSIZE == 32
373*4b9c6d91SCole Faust if (i >= 3)
374*4b9c6d91SCole Faust return -ERANGE;
375*4b9c6d91SCole Faust #endif
376*4b9c6d91SCole Faust multiplier = 1024;
377*4b9c6d91SCole Faust while (i-- > 0)
378*4b9c6d91SCole Faust multiplier *= 1024;
379*4b9c6d91SCole Faust break;
380*4b9c6d91SCole Faust }
381*4b9c6d91SCole Faust }
382*4b9c6d91SCole Faust
383*4b9c6d91SCole Faust /* We only need size_t but strtoul(3) is too small on IL32P64. */
384*4b9c6d91SCole Faust parsed = strtoull(sizespec, &end, 10);
385*4b9c6d91SCole Faust if (parsed == ULLONG_MAX)
386*4b9c6d91SCole Faust return -errno;
387*4b9c6d91SCole Faust if (parsed >= SIZE_MAX)
388*4b9c6d91SCole Faust return -ERANGE;
389*4b9c6d91SCole Faust if ((multiplier != 1 && end != sizespec + len - 1) ||
390*4b9c6d91SCole Faust (multiplier == 1 && end != sizespec + len))
391*4b9c6d91SCole Faust return -EINVAL;
392*4b9c6d91SCole Faust size = (size_t)parsed;
393*4b9c6d91SCole Faust
394*4b9c6d91SCole Faust nsize = size * multiplier;
395*4b9c6d91SCole Faust if (nsize / multiplier != size)
396*4b9c6d91SCole Faust return -ERANGE;
397*4b9c6d91SCole Faust *result = nsize;
398*4b9c6d91SCole Faust return 0;
399*4b9c6d91SCole Faust }
400*4b9c6d91SCole Faust
strip(char * s)401*4b9c6d91SCole Faust char *strip(char *s)
402*4b9c6d91SCole Faust {
403*4b9c6d91SCole Faust char *end;
404*4b9c6d91SCole Faust while (*s && isblank(*s))
405*4b9c6d91SCole Faust s++;
406*4b9c6d91SCole Faust end = s + strlen(s) - 1;
407*4b9c6d91SCole Faust while (end >= s && *end && (isblank(*end) || *end == '\n'))
408*4b9c6d91SCole Faust end--;
409*4b9c6d91SCole Faust *(end + 1) = '\0';
410*4b9c6d91SCole Faust return s;
411*4b9c6d91SCole Faust }
412*4b9c6d91SCole Faust
tokenize(char ** stringp,const char * delim)413*4b9c6d91SCole Faust char *tokenize(char **stringp, const char *delim)
414*4b9c6d91SCole Faust {
415*4b9c6d91SCole Faust char *ret = NULL;
416*4b9c6d91SCole Faust
417*4b9c6d91SCole Faust /* If the string is NULL, there are no tokens to be found. */
418*4b9c6d91SCole Faust if (stringp == NULL || *stringp == NULL)
419*4b9c6d91SCole Faust return NULL;
420*4b9c6d91SCole Faust
421*4b9c6d91SCole Faust /*
422*4b9c6d91SCole Faust * If the delimiter is NULL or empty,
423*4b9c6d91SCole Faust * the full string makes up the only token.
424*4b9c6d91SCole Faust */
425*4b9c6d91SCole Faust if (delim == NULL || *delim == '\0') {
426*4b9c6d91SCole Faust ret = *stringp;
427*4b9c6d91SCole Faust *stringp = NULL;
428*4b9c6d91SCole Faust return ret;
429*4b9c6d91SCole Faust }
430*4b9c6d91SCole Faust
431*4b9c6d91SCole Faust char *found = strstr(*stringp, delim);
432*4b9c6d91SCole Faust if (!found) {
433*4b9c6d91SCole Faust /*
434*4b9c6d91SCole Faust * The delimiter was not found, so the full string
435*4b9c6d91SCole Faust * makes up the only token, and we're done.
436*4b9c6d91SCole Faust */
437*4b9c6d91SCole Faust ret = *stringp;
438*4b9c6d91SCole Faust *stringp = NULL;
439*4b9c6d91SCole Faust } else {
440*4b9c6d91SCole Faust /* There's a token here, possibly empty. That's OK. */
441*4b9c6d91SCole Faust *found = '\0';
442*4b9c6d91SCole Faust ret = *stringp;
443*4b9c6d91SCole Faust *stringp = found + strlen(delim);
444*4b9c6d91SCole Faust }
445*4b9c6d91SCole Faust
446*4b9c6d91SCole Faust return ret;
447*4b9c6d91SCole Faust }
448*4b9c6d91SCole Faust
path_join(const char * external_path,const char * internal_path)449*4b9c6d91SCole Faust char *path_join(const char *external_path, const char *internal_path)
450*4b9c6d91SCole Faust {
451*4b9c6d91SCole Faust char *path = NULL;
452*4b9c6d91SCole Faust return asprintf(&path, "%s/%s", external_path, internal_path) < 0
453*4b9c6d91SCole Faust ? NULL
454*4b9c6d91SCole Faust : path;
455*4b9c6d91SCole Faust }
456*4b9c6d91SCole Faust
path_is_parent(const char * parent,const char * child)457*4b9c6d91SCole Faust bool path_is_parent(const char *parent, const char *child)
458*4b9c6d91SCole Faust {
459*4b9c6d91SCole Faust /*
460*4b9c6d91SCole Faust * -Make sure |child| starts with |parent|.
461*4b9c6d91SCole Faust * -Make sure that if |child| is longer than |parent|, either:
462*4b9c6d91SCole Faust * --the last character in |parent| is a path separator, or
463*4b9c6d91SCole Faust * --the character immediately following |parent| in |child| is a path
464*4b9c6d91SCole Faust * separator.
465*4b9c6d91SCole Faust */
466*4b9c6d91SCole Faust size_t parent_len = strlen(parent);
467*4b9c6d91SCole Faust return strncmp(parent, child, parent_len) == 0 &&
468*4b9c6d91SCole Faust (strlen(child) > parent_len ? (parent[parent_len - 1] == '/' ||
469*4b9c6d91SCole Faust child[parent_len] == '/')
470*4b9c6d91SCole Faust : false);
471*4b9c6d91SCole Faust }
472*4b9c6d91SCole Faust
consumebytes(size_t length,char ** buf,size_t * buflength)473*4b9c6d91SCole Faust void *consumebytes(size_t length, char **buf, size_t *buflength)
474*4b9c6d91SCole Faust {
475*4b9c6d91SCole Faust char *p = *buf;
476*4b9c6d91SCole Faust if (length > *buflength)
477*4b9c6d91SCole Faust return NULL;
478*4b9c6d91SCole Faust *buf += length;
479*4b9c6d91SCole Faust *buflength -= length;
480*4b9c6d91SCole Faust return p;
481*4b9c6d91SCole Faust }
482*4b9c6d91SCole Faust
consumestr(char ** buf,size_t * buflength)483*4b9c6d91SCole Faust char *consumestr(char **buf, size_t *buflength)
484*4b9c6d91SCole Faust {
485*4b9c6d91SCole Faust size_t len = strnlen(*buf, *buflength);
486*4b9c6d91SCole Faust if (len == *buflength)
487*4b9c6d91SCole Faust /* There's no null-terminator. */
488*4b9c6d91SCole Faust return NULL;
489*4b9c6d91SCole Faust return consumebytes(len + 1, buf, buflength);
490*4b9c6d91SCole Faust }
491*4b9c6d91SCole Faust
init_logging(enum logging_system_t logger,int fd,int min_priority)492*4b9c6d91SCole Faust void init_logging(enum logging_system_t logger, int fd, int min_priority)
493*4b9c6d91SCole Faust {
494*4b9c6d91SCole Faust logging_config.logger = logger;
495*4b9c6d91SCole Faust logging_config.fd = fd;
496*4b9c6d91SCole Faust logging_config.min_priority = min_priority;
497*4b9c6d91SCole Faust }
498*4b9c6d91SCole Faust
minijail_free_env(char ** env)499*4b9c6d91SCole Faust void minijail_free_env(char **env)
500*4b9c6d91SCole Faust {
501*4b9c6d91SCole Faust if (!env)
502*4b9c6d91SCole Faust return;
503*4b9c6d91SCole Faust
504*4b9c6d91SCole Faust for (char **entry = env; *entry; ++entry) {
505*4b9c6d91SCole Faust free(*entry);
506*4b9c6d91SCole Faust }
507*4b9c6d91SCole Faust
508*4b9c6d91SCole Faust free(env);
509*4b9c6d91SCole Faust }
510*4b9c6d91SCole Faust
minijail_copy_env(char * const * env)511*4b9c6d91SCole Faust char **minijail_copy_env(char *const *env)
512*4b9c6d91SCole Faust {
513*4b9c6d91SCole Faust if (!env)
514*4b9c6d91SCole Faust return calloc(1, sizeof(char *));
515*4b9c6d91SCole Faust
516*4b9c6d91SCole Faust int len = 0;
517*4b9c6d91SCole Faust while (env[len])
518*4b9c6d91SCole Faust ++len;
519*4b9c6d91SCole Faust
520*4b9c6d91SCole Faust char **copy = calloc(len + 1, sizeof(char *));
521*4b9c6d91SCole Faust if (!copy)
522*4b9c6d91SCole Faust return NULL;
523*4b9c6d91SCole Faust
524*4b9c6d91SCole Faust for (char **entry = copy; *env; ++env, ++entry) {
525*4b9c6d91SCole Faust *entry = strdup(*env);
526*4b9c6d91SCole Faust if (!*entry) {
527*4b9c6d91SCole Faust minijail_free_env(copy);
528*4b9c6d91SCole Faust return NULL;
529*4b9c6d91SCole Faust }
530*4b9c6d91SCole Faust }
531*4b9c6d91SCole Faust
532*4b9c6d91SCole Faust return copy;
533*4b9c6d91SCole Faust }
534*4b9c6d91SCole Faust
535*4b9c6d91SCole Faust /*
536*4b9c6d91SCole Faust * Utility function used by minijail_setenv, minijail_unsetenv and
537*4b9c6d91SCole Faust * minijail_getenv, returns true if |name| is found, false if not.
538*4b9c6d91SCole Faust * If found, |*i| is |name|'s index. If not, |*i| is the length of |envp|.
539*4b9c6d91SCole Faust */
getenv_index(char ** envp,const char * name,int * i)540*4b9c6d91SCole Faust static bool getenv_index(char **envp, const char *name, int *i) {
541*4b9c6d91SCole Faust if (!envp || !name || !i)
542*4b9c6d91SCole Faust return false;
543*4b9c6d91SCole Faust
544*4b9c6d91SCole Faust size_t name_len = strlen(name);
545*4b9c6d91SCole Faust for (*i = 0; envp[*i]; ++(*i)) {
546*4b9c6d91SCole Faust /*
547*4b9c6d91SCole Faust * If we find a match the size of |name|, we must check
548*4b9c6d91SCole Faust * that the next character is a '=', indicating that
549*4b9c6d91SCole Faust * the full varname of envp[i] is exactly |name| and
550*4b9c6d91SCole Faust * not just happening to start with |name|.
551*4b9c6d91SCole Faust */
552*4b9c6d91SCole Faust if (!strncmp(envp[*i], name, name_len) &&
553*4b9c6d91SCole Faust (envp[*i][name_len] == '=')) {
554*4b9c6d91SCole Faust return true;
555*4b9c6d91SCole Faust }
556*4b9c6d91SCole Faust }
557*4b9c6d91SCole Faust /* No match found, |*i| contains the number of elements in |envp|. */
558*4b9c6d91SCole Faust return false;
559*4b9c6d91SCole Faust }
560*4b9c6d91SCole Faust
minijail_setenv(char *** env,const char * name,const char * value,int overwrite)561*4b9c6d91SCole Faust int minijail_setenv(char ***env, const char *name, const char *value,
562*4b9c6d91SCole Faust int overwrite)
563*4b9c6d91SCole Faust {
564*4b9c6d91SCole Faust if (!env || !*env || !name || !*name || !value)
565*4b9c6d91SCole Faust return EINVAL;
566*4b9c6d91SCole Faust
567*4b9c6d91SCole Faust char **dest = NULL;
568*4b9c6d91SCole Faust int i;
569*4b9c6d91SCole Faust
570*4b9c6d91SCole Faust /* Look in env to check if this var name already exists. */
571*4b9c6d91SCole Faust if (getenv_index(*env, name, &i)) {
572*4b9c6d91SCole Faust if (!overwrite)
573*4b9c6d91SCole Faust return 0;
574*4b9c6d91SCole Faust dest = &(*env)[i];
575*4b9c6d91SCole Faust }
576*4b9c6d91SCole Faust
577*4b9c6d91SCole Faust char *new_entry = NULL;
578*4b9c6d91SCole Faust if (asprintf(&new_entry, "%s=%s", name, value) == -1)
579*4b9c6d91SCole Faust return ENOMEM;
580*4b9c6d91SCole Faust
581*4b9c6d91SCole Faust if (dest) {
582*4b9c6d91SCole Faust free(*dest);
583*4b9c6d91SCole Faust *dest = new_entry;
584*4b9c6d91SCole Faust return 0;
585*4b9c6d91SCole Faust }
586*4b9c6d91SCole Faust
587*4b9c6d91SCole Faust /* getenv_index has set |i| to the length of |env|. */
588*4b9c6d91SCole Faust ++i;
589*4b9c6d91SCole Faust char **new_env = realloc(*env, (i + 1) * sizeof(char *));
590*4b9c6d91SCole Faust if (!new_env) {
591*4b9c6d91SCole Faust free(new_entry);
592*4b9c6d91SCole Faust return ENOMEM;
593*4b9c6d91SCole Faust }
594*4b9c6d91SCole Faust
595*4b9c6d91SCole Faust new_env[i - 1] = new_entry;
596*4b9c6d91SCole Faust new_env[i] = NULL;
597*4b9c6d91SCole Faust *env = new_env;
598*4b9c6d91SCole Faust return 0;
599*4b9c6d91SCole Faust }
600*4b9c6d91SCole Faust
601*4b9c6d91SCole Faust /*
602*4b9c6d91SCole Faust * This is like getline() but supports line wrapping with \.
603*4b9c6d91SCole Faust */
getmultiline(char ** lineptr,size_t * n,FILE * stream)604*4b9c6d91SCole Faust ssize_t getmultiline(char **lineptr, size_t *n, FILE *stream)
605*4b9c6d91SCole Faust {
606*4b9c6d91SCole Faust ssize_t ret = getline(lineptr, n, stream);
607*4b9c6d91SCole Faust if (ret < 0)
608*4b9c6d91SCole Faust return ret;
609*4b9c6d91SCole Faust
610*4b9c6d91SCole Faust char *line = *lineptr;
611*4b9c6d91SCole Faust /* Eat the newline to make processing below easier. */
612*4b9c6d91SCole Faust if (ret > 0 && line[ret - 1] == '\n')
613*4b9c6d91SCole Faust line[--ret] = '\0';
614*4b9c6d91SCole Faust
615*4b9c6d91SCole Faust /* If the line doesn't end in a backslash, we're done. */
616*4b9c6d91SCole Faust if (ret <= 0 || line[ret - 1] != '\\')
617*4b9c6d91SCole Faust return ret;
618*4b9c6d91SCole Faust
619*4b9c6d91SCole Faust /* This line ends in a backslash. Get the nextline. */
620*4b9c6d91SCole Faust line[--ret] = '\0';
621*4b9c6d91SCole Faust size_t next_n = 0;
622*4b9c6d91SCole Faust attribute_cleanup_str char *next_line = NULL;
623*4b9c6d91SCole Faust ssize_t next_ret = getmultiline(&next_line, &next_n, stream);
624*4b9c6d91SCole Faust if (next_ret == -1) {
625*4b9c6d91SCole Faust /* We couldn't fully read the line, so return an error. */
626*4b9c6d91SCole Faust return -1;
627*4b9c6d91SCole Faust }
628*4b9c6d91SCole Faust
629*4b9c6d91SCole Faust /* Merge the lines. */
630*4b9c6d91SCole Faust *n = ret + next_ret + 2;
631*4b9c6d91SCole Faust line = realloc(line, *n);
632*4b9c6d91SCole Faust if (!line)
633*4b9c6d91SCole Faust return -1;
634*4b9c6d91SCole Faust line[ret] = ' ';
635*4b9c6d91SCole Faust memcpy(&line[ret + 1], next_line, next_ret + 1);
636*4b9c6d91SCole Faust *lineptr = line;
637*4b9c6d91SCole Faust return *n - 1;
638*4b9c6d91SCole Faust }
639*4b9c6d91SCole Faust
minijail_getenv(char ** envp,const char * name)640*4b9c6d91SCole Faust char *minijail_getenv(char **envp, const char *name) {
641*4b9c6d91SCole Faust if (!envp || !name)
642*4b9c6d91SCole Faust return NULL;
643*4b9c6d91SCole Faust
644*4b9c6d91SCole Faust int i;
645*4b9c6d91SCole Faust if (!getenv_index(envp, name, &i))
646*4b9c6d91SCole Faust return NULL;
647*4b9c6d91SCole Faust
648*4b9c6d91SCole Faust /* Return a ptr to the value after the '='. */
649*4b9c6d91SCole Faust return envp[i] + strlen(name) + 1;
650*4b9c6d91SCole Faust }
651*4b9c6d91SCole Faust
minijail_unsetenv(char ** envp,const char * name)652*4b9c6d91SCole Faust bool minijail_unsetenv(char **envp, const char *name)
653*4b9c6d91SCole Faust {
654*4b9c6d91SCole Faust if (!envp || !name)
655*4b9c6d91SCole Faust return false;
656*4b9c6d91SCole Faust
657*4b9c6d91SCole Faust int i;
658*4b9c6d91SCole Faust if (!getenv_index(envp, name, &i))
659*4b9c6d91SCole Faust return false;
660*4b9c6d91SCole Faust
661*4b9c6d91SCole Faust /* We found a match, replace it by the last entry of the array. */
662*4b9c6d91SCole Faust int last;
663*4b9c6d91SCole Faust for (last = i; envp[last]; ++last)
664*4b9c6d91SCole Faust continue;
665*4b9c6d91SCole Faust --last;
666*4b9c6d91SCole Faust envp[i] = envp[last];
667*4b9c6d91SCole Faust envp[last] = NULL;
668*4b9c6d91SCole Faust
669*4b9c6d91SCole Faust return true;
670*4b9c6d91SCole Faust }
671