xref: /aosp_15_r20/external/minijail/util.c (revision 4b9c6d91573e8b3a96609339b46361b5476dd0f9)
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