blob: 51a530051bdadd7f23632155023283f514545b88 [file] [log] [blame]
Elly Jonesdd3e8512012-01-23 15:13:38 -05001/*
2 * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Elly Jonescd7a9042011-07-22 13:56:51 -04003 * Use of this source code is governed by a BSD-style license that can be
Will Drewry32ac9f52011-08-18 21:36:27 -05004 * found in the LICENSE file.
5 */
Elly Jonescd7a9042011-07-22 13:56:51 -04006
7#define _BSD_SOURCE
8#define _GNU_SOURCE
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -07009
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080010#include <asm/unistd.h>
Will Drewry32ac9f52011-08-18 21:36:27 -050011#include <ctype.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040012#include <errno.h>
13#include <grp.h>
14#include <inttypes.h>
Will Drewryfe4a3722011-09-16 14:50:50 -050015#include <limits.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040016#include <linux/capability.h>
17#include <linux/securebits.h>
18#include <pwd.h>
19#include <sched.h>
20#include <signal.h>
Will Drewry2f54b6a2011-09-16 13:45:31 -050021#include <stdarg.h>
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080022#include <stddef.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040023#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <syscall.h>
27#include <sys/capability.h>
28#include <sys/mount.h>
Will Drewryf89aef52011-09-16 16:48:57 -050029#include <sys/param.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040030#include <sys/prctl.h>
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080031#include <sys/user.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040032#include <sys/wait.h>
33#include <syslog.h>
34#include <unistd.h>
35
36#include "libminijail.h"
Will Drewry32ac9f52011-08-18 21:36:27 -050037#include "libsyscalls.h"
Elly Jonescd7a9042011-07-22 13:56:51 -040038#include "libminijail-private.h"
39
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080040#include "syscall_filter.h"
41
Will Drewry32ac9f52011-08-18 21:36:27 -050042/* Until these are reliably available in linux/prctl.h */
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080043#ifndef PR_SET_SECCOMP
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -070044# define PR_SET_SECCOMP 22
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080045#endif
46
47/* For seccomp_filter using BPF. */
48#ifndef PR_SET_NO_NEW_PRIVS
49# define PR_SET_NO_NEW_PRIVS 38
50#endif
51#ifndef SECCOMP_MODE_FILTER
52# define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
Will Drewry32ac9f52011-08-18 21:36:27 -050053#endif
54
Will Drewry32ac9f52011-08-18 21:36:27 -050055#define die(_msg, ...) do { \
Elly Jonese1749eb2011-10-07 13:54:59 -040056 syslog(LOG_ERR, "libminijail: " _msg, ## __VA_ARGS__); \
57 abort(); \
Will Drewry32ac9f52011-08-18 21:36:27 -050058} while (0)
Elly Jonescd7a9042011-07-22 13:56:51 -040059
Will Drewry32ac9f52011-08-18 21:36:27 -050060#define pdie(_msg, ...) \
Elly Jonese1749eb2011-10-07 13:54:59 -040061 die(_msg ": %s", ## __VA_ARGS__, strerror(errno))
Will Drewry32ac9f52011-08-18 21:36:27 -050062
63#define warn(_msg, ...) \
Elly Jonese1749eb2011-10-07 13:54:59 -040064 syslog(LOG_WARNING, "libminijail: " _msg, ## __VA_ARGS__)
Elly Jonescd7a9042011-07-22 13:56:51 -040065
Elly Jones51a5b6c2011-10-12 19:09:26 -040066struct binding {
67 char *src;
68 char *dest;
69 int writeable;
70 struct binding *next;
71};
72
Will Drewryf89aef52011-09-16 16:48:57 -050073struct minijail {
Elly Jonese1749eb2011-10-07 13:54:59 -040074 struct {
75 int uid:1;
76 int gid:1;
77 int caps:1;
78 int vfs:1;
79 int pids:1;
80 int seccomp:1;
81 int readonly:1;
82 int usergroups:1;
83 int ptrace:1;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -070084 int no_new_privs:1;
Elly Jonese1749eb2011-10-07 13:54:59 -040085 int seccomp_filter:1;
Elly Jones51a5b6c2011-10-12 19:09:26 -040086 int chroot:1;
Elly Jonese1749eb2011-10-07 13:54:59 -040087 } flags;
88 uid_t uid;
89 gid_t gid;
90 gid_t usergid;
91 char *user;
92 uint64_t caps;
93 pid_t initpid;
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080094 int filter_len;
Elly Jones51a5b6c2011-10-12 19:09:26 -040095 int binding_count;
96 char *chrootdir;
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080097 struct sock_fprog *filter_prog;
Elly Jones51a5b6c2011-10-12 19:09:26 -040098 struct binding *bindings_head;
99 struct binding *bindings_tail;
Will Drewryf89aef52011-09-16 16:48:57 -0500100};
101
Will Drewry6ac91122011-10-21 16:38:58 -0500102struct minijail API *minijail_new(void)
Elly Jonese1749eb2011-10-07 13:54:59 -0400103{
Elly Jones51a5b6c2011-10-12 19:09:26 -0400104 return calloc(1, sizeof(struct minijail));
Elly Jonescd7a9042011-07-22 13:56:51 -0400105}
106
Will Drewry6ac91122011-10-21 16:38:58 -0500107void API minijail_change_uid(struct minijail *j, uid_t uid)
Elly Jonese1749eb2011-10-07 13:54:59 -0400108{
109 if (uid == 0)
110 die("useless change to uid 0");
111 j->uid = uid;
112 j->flags.uid = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400113}
114
Will Drewry6ac91122011-10-21 16:38:58 -0500115void API minijail_change_gid(struct minijail *j, gid_t gid)
Elly Jonese1749eb2011-10-07 13:54:59 -0400116{
117 if (gid == 0)
118 die("useless change to gid 0");
119 j->gid = gid;
120 j->flags.gid = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400121}
122
Will Drewry6ac91122011-10-21 16:38:58 -0500123int API minijail_change_user(struct minijail *j, const char *user)
Elly Jonese1749eb2011-10-07 13:54:59 -0400124{
125 char *buf = NULL;
126 struct passwd pw;
127 struct passwd *ppw = NULL;
128 ssize_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
129 if (sz == -1)
130 sz = 65536; /* your guess is as good as mine... */
Elly Joneseb300c52011-09-22 14:35:43 -0400131
Elly Jonesdd3e8512012-01-23 15:13:38 -0500132 /*
133 * sysconf(_SC_GETPW_R_SIZE_MAX), under glibc, is documented to return
Elly Jonese1749eb2011-10-07 13:54:59 -0400134 * the maximum needed size of the buffer, so we don't have to search.
135 */
136 buf = malloc(sz);
137 if (!buf)
138 return -ENOMEM;
139 getpwnam_r(user, &pw, buf, sz, &ppw);
Elly Jonesdd3e8512012-01-23 15:13:38 -0500140 /*
141 * We're safe to free the buffer here. The strings inside pw point
142 * inside buf, but we don't use any of them; this leaves the pointers
143 * dangling but it's safe. ppw points at pw if getpwnam_r succeeded.
144 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400145 free(buf);
146 if (!ppw)
147 return -errno;
148 minijail_change_uid(j, ppw->pw_uid);
149 j->user = strdup(user);
150 if (!j->user)
151 return -ENOMEM;
152 j->usergid = ppw->pw_gid;
153 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400154}
155
Will Drewry6ac91122011-10-21 16:38:58 -0500156int API minijail_change_group(struct minijail *j, const char *group)
Elly Jonese1749eb2011-10-07 13:54:59 -0400157{
158 char *buf = NULL;
159 struct group gr;
160 struct group *pgr = NULL;
161 ssize_t sz = sysconf(_SC_GETGR_R_SIZE_MAX);
162 if (sz == -1)
163 sz = 65536; /* and mine is as good as yours, really */
Elly Joneseb300c52011-09-22 14:35:43 -0400164
Elly Jonesdd3e8512012-01-23 15:13:38 -0500165 /*
166 * sysconf(_SC_GETGR_R_SIZE_MAX), under glibc, is documented to return
Elly Jonese1749eb2011-10-07 13:54:59 -0400167 * the maximum needed size of the buffer, so we don't have to search.
168 */
169 buf = malloc(sz);
170 if (!buf)
171 return -ENOMEM;
172 getgrnam_r(group, &gr, buf, sz, &pgr);
Elly Jonesdd3e8512012-01-23 15:13:38 -0500173 /*
174 * We're safe to free the buffer here. The strings inside gr point
175 * inside buf, but we don't use any of them; this leaves the pointers
176 * dangling but it's safe. pgr points at gr if getgrnam_r succeeded.
177 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400178 free(buf);
179 if (!pgr)
180 return -errno;
181 minijail_change_gid(j, pgr->gr_gid);
182 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400183}
184
Will Drewry6ac91122011-10-21 16:38:58 -0500185void API minijail_use_seccomp(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400186{
187 j->flags.seccomp = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400188}
189
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700190void API minijail_no_new_privs(struct minijail *j)
191{
192 j->flags.no_new_privs = 1;
193}
194
Will Drewry6ac91122011-10-21 16:38:58 -0500195void API minijail_use_seccomp_filter(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400196{
197 j->flags.seccomp_filter = 1;
Will Drewry32ac9f52011-08-18 21:36:27 -0500198}
199
Will Drewry6ac91122011-10-21 16:38:58 -0500200void API minijail_use_caps(struct minijail *j, uint64_t capmask)
Elly Jonese1749eb2011-10-07 13:54:59 -0400201{
202 j->caps = capmask;
203 j->flags.caps = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400204}
205
Will Drewry6ac91122011-10-21 16:38:58 -0500206void API minijail_namespace_vfs(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400207{
208 j->flags.vfs = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400209}
210
Will Drewry6ac91122011-10-21 16:38:58 -0500211void API minijail_namespace_pids(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400212{
Elly Jonese58176c2012-01-23 11:46:17 -0500213 j->flags.vfs = 1;
214 j->flags.readonly = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400215 j->flags.pids = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400216}
217
Will Drewry6ac91122011-10-21 16:38:58 -0500218void API minijail_remount_readonly(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400219{
220 j->flags.vfs = 1;
221 j->flags.readonly = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400222}
223
Will Drewry6ac91122011-10-21 16:38:58 -0500224void API minijail_inherit_usergroups(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400225{
226 j->flags.usergroups = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400227}
228
Will Drewry6ac91122011-10-21 16:38:58 -0500229void API minijail_disable_ptrace(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400230{
231 j->flags.ptrace = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400232}
233
Will Drewry6ac91122011-10-21 16:38:58 -0500234int API minijail_enter_chroot(struct minijail *j, const char *dir) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400235 if (j->chrootdir)
236 return -EINVAL;
237 j->chrootdir = strdup(dir);
238 if (!j->chrootdir)
239 return -ENOMEM;
240 j->flags.chroot = 1;
241 return 0;
242}
243
Will Drewry6ac91122011-10-21 16:38:58 -0500244int API minijail_bind(struct minijail *j, const char *src, const char *dest,
245 int writeable) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400246 struct binding *b;
247
248 if (*dest != '/')
249 return -EINVAL;
250 b = calloc(1, sizeof(*b));
251 if (!b)
252 return -ENOMEM;
253 b->dest = strdup(dest);
254 if (!b->dest)
255 goto error;
256 b->src = strdup(src);
257 if (!b->src)
258 goto error;
259 b->writeable = writeable;
260
261 syslog(LOG_INFO, "libminijail: bind %s -> %s", src, dest);
262
Elly Jonesdd3e8512012-01-23 15:13:38 -0500263 /*
264 * Force vfs namespacing so the bind mounts don't leak out into the
Elly Jones51a5b6c2011-10-12 19:09:26 -0400265 * containing vfs namespace.
266 */
267 minijail_namespace_vfs(j);
268
269 if (j->bindings_tail)
270 j->bindings_tail->next = b;
271 else
272 j->bindings_head = b;
273 j->bindings_tail = b;
274 j->binding_count++;
275
276 return 0;
277
278error:
279 free(b->src);
280 free(b->dest);
281 free(b);
282 return -ENOMEM;
283}
284
Will Drewry6ac91122011-10-21 16:38:58 -0500285void API minijail_parse_seccomp_filters(struct minijail *j, const char *path)
Elly Jonese1749eb2011-10-07 13:54:59 -0400286{
287 FILE *file = fopen(path, "r");
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800288 if (!file) {
289 pdie("failed to open seccomp filters file '%s'", path);
Elly Jonese1749eb2011-10-07 13:54:59 -0400290 }
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800291
292 struct sock_fprog *fprog = malloc(sizeof(struct sock_fprog));
293 if (compile_filter(file, fprog)) {
294 die("failed to compile seccomp filters BPF program in '%s'", path);
295 }
296
297 j->filter_len = fprog->len;
298 j->filter_prog = fprog;
299
Elly Jonese1749eb2011-10-07 13:54:59 -0400300 fclose(file);
Will Drewry32ac9f52011-08-18 21:36:27 -0500301}
302
Will Drewryf89aef52011-09-16 16:48:57 -0500303struct marshal_state {
Elly Jonese1749eb2011-10-07 13:54:59 -0400304 size_t available;
305 size_t total;
306 char *buf;
Will Drewryf89aef52011-09-16 16:48:57 -0500307};
308
Will Drewry6ac91122011-10-21 16:38:58 -0500309void marshal_state_init(struct marshal_state *state,
310 char *buf, size_t available)
Elly Jonese1749eb2011-10-07 13:54:59 -0400311{
312 state->available = available;
313 state->buf = buf;
314 state->total = 0;
Will Drewryf89aef52011-09-16 16:48:57 -0500315}
316
Will Drewry6ac91122011-10-21 16:38:58 -0500317void marshal_append(struct marshal_state *state,
318 char *src, size_t length)
Elly Jonese1749eb2011-10-07 13:54:59 -0400319{
320 size_t copy_len = MIN(state->available, length);
Will Drewryf89aef52011-09-16 16:48:57 -0500321
Elly Jonese1749eb2011-10-07 13:54:59 -0400322 /* Up to |available| will be written. */
323 if (copy_len) {
324 memcpy(state->buf, src, copy_len);
325 state->buf += copy_len;
326 state->available -= copy_len;
327 }
328 /* |total| will contain the expected length. */
329 state->total += length;
Will Drewryf89aef52011-09-16 16:48:57 -0500330}
331
Will Drewry6ac91122011-10-21 16:38:58 -0500332void minijail_marshal_helper(struct marshal_state *state,
333 const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400334{
Elly Jones51a5b6c2011-10-12 19:09:26 -0400335 struct binding *b = NULL;
Elly Jonese1749eb2011-10-07 13:54:59 -0400336 marshal_append(state, (char *)j, sizeof(*j));
337 if (j->user)
338 marshal_append(state, j->user, strlen(j->user) + 1);
Elly Jones51a5b6c2011-10-12 19:09:26 -0400339 if (j->chrootdir)
340 marshal_append(state, j->chrootdir, strlen(j->chrootdir) + 1);
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800341 if (j->flags.seccomp_filter && j->filter_prog) {
342 struct sock_fprog *fp = j->filter_prog;
343 marshal_append(state, (char *)fp->filter,
344 fp->len * sizeof(struct sock_filter));
Elly Jonese1749eb2011-10-07 13:54:59 -0400345 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400346 for (b = j->bindings_head; b; b = b->next) {
347 marshal_append(state, b->src, strlen(b->src) + 1);
348 marshal_append(state, b->dest, strlen(b->dest) + 1);
349 marshal_append(state, (char *)&b->writeable, sizeof(b->writeable));
350 }
Will Drewryf89aef52011-09-16 16:48:57 -0500351}
352
Will Drewry6ac91122011-10-21 16:38:58 -0500353size_t API minijail_size(const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400354{
355 struct marshal_state state;
356 marshal_state_init(&state, NULL, 0);
357 minijail_marshal_helper(&state, j);
358 return state.total;
Will Drewry2ddaad02011-09-16 11:36:08 -0500359}
360
Elly Jonese1749eb2011-10-07 13:54:59 -0400361int minijail_marshal(const struct minijail *j, char *buf, size_t available)
362{
363 struct marshal_state state;
364 marshal_state_init(&state, buf, available);
365 minijail_marshal_helper(&state, j);
366 return (state.total > available);
Will Drewry2ddaad02011-09-16 11:36:08 -0500367}
368
Elly Jones51a5b6c2011-10-12 19:09:26 -0400369/* consumebytes: consumes @length bytes from a buffer @buf of length @buflength
370 * @length Number of bytes to consume
371 * @buf Buffer to consume from
372 * @buflength Size of @buf
373 *
374 * Returns a pointer to the base of the bytes, or NULL for errors.
375 */
Will Drewry6ac91122011-10-21 16:38:58 -0500376void *consumebytes(size_t length, char **buf, size_t *buflength) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400377 char *p = *buf;
378 if (length > *buflength)
379 return NULL;
380 *buf += length;
381 *buflength -= length;
382 return p;
383}
384
385/* consumestr: consumes a C string from a buffer @buf of length @length
386 * @buf Buffer to consume
387 * @length Length of buffer
388 *
389 * Returns a pointer to the base of the string, or NULL for errors.
390 */
Will Drewry6ac91122011-10-21 16:38:58 -0500391char *consumestr(char **buf, size_t *buflength) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400392 size_t len = strnlen(*buf, *buflength);
393 if (len == *buflength)
394 /* There's no null-terminator */
395 return NULL;
396 return consumebytes(len + 1, buf, buflength);
397}
398
Elly Jonese1749eb2011-10-07 13:54:59 -0400399int minijail_unmarshal(struct minijail *j, char *serialized, size_t length)
400{
Elly Jones51a5b6c2011-10-12 19:09:26 -0400401 int i;
402 int count;
Will Drewrybee7ba72011-10-21 20:47:01 -0500403 int ret = -EINVAL;
404
Elly Jonese1749eb2011-10-07 13:54:59 -0400405 if (length < sizeof(*j))
Will Drewrybee7ba72011-10-21 20:47:01 -0500406 goto out;
Elly Jonese1749eb2011-10-07 13:54:59 -0400407 memcpy((void *)j, serialized, sizeof(*j));
408 serialized += sizeof(*j);
409 length -= sizeof(*j);
Will Drewryf89aef52011-09-16 16:48:57 -0500410
Will Drewrybee7ba72011-10-21 20:47:01 -0500411 /* Potentially stale pointers not used as signals. */
412 j->bindings_head = NULL;
413 j->bindings_tail = NULL;
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800414 j->filter_prog = NULL;
Will Drewrybee7ba72011-10-21 20:47:01 -0500415
Elly Jonese1749eb2011-10-07 13:54:59 -0400416 if (j->user) { /* stale pointer */
Elly Jones51a5b6c2011-10-12 19:09:26 -0400417 char *user = consumestr(&serialized, &length);
418 if (!user)
Will Drewrybee7ba72011-10-21 20:47:01 -0500419 goto clear_pointers;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400420 j->user = strdup(user);
Will Drewrybee7ba72011-10-21 20:47:01 -0500421 if (!j->user)
422 goto clear_pointers;
Elly Jonese1749eb2011-10-07 13:54:59 -0400423 }
Will Drewryf89aef52011-09-16 16:48:57 -0500424
Elly Jonesa8d1e1b2011-10-21 15:38:00 -0400425 if (j->chrootdir) { /* stale pointer */
426 char *chrootdir = consumestr(&serialized, &length);
427 if (!chrootdir)
Will Drewrybee7ba72011-10-21 20:47:01 -0500428 goto bad_chrootdir;
Elly Jonesa8d1e1b2011-10-21 15:38:00 -0400429 j->chrootdir = strdup(chrootdir);
Will Drewrybee7ba72011-10-21 20:47:01 -0500430 if (!j->chrootdir)
431 goto bad_chrootdir;
Elly Jonesa8d1e1b2011-10-21 15:38:00 -0400432 }
433
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800434 if (j->flags.seccomp_filter && j->filter_len > 0) {
435 size_t ninstrs = j->filter_len;
436 if (ninstrs > (SIZE_MAX / sizeof(struct sock_filter)) ||
437 ninstrs > USHRT_MAX)
438 goto bad_filters;
439
440 size_t program_len = ninstrs * sizeof(struct sock_filter);
441 void *program = consumebytes(program_len, &serialized, &length);
442 if (!program)
443 goto bad_filters;
444
445 j->filter_prog = malloc(sizeof(struct sock_fprog));
446 j->filter_prog->len = ninstrs;
447 j->filter_prog->filter = malloc(program_len);
448 memcpy(j->filter_prog->filter, program, program_len);
Elly Jonese1749eb2011-10-07 13:54:59 -0400449 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400450
451 count = j->binding_count;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400452 j->binding_count = 0;
453 for (i = 0; i < count; ++i) {
454 int *writeable;
455 const char *dest;
456 const char *src = consumestr(&serialized, &length);
457 if (!src)
Will Drewrybee7ba72011-10-21 20:47:01 -0500458 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400459 dest = consumestr(&serialized, &length);
460 if (!dest)
Will Drewrybee7ba72011-10-21 20:47:01 -0500461 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400462 writeable = consumebytes(sizeof(*writeable), &serialized, &length);
463 if (!writeable)
Will Drewrybee7ba72011-10-21 20:47:01 -0500464 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400465 if (minijail_bind(j, src, dest, *writeable))
Will Drewrybee7ba72011-10-21 20:47:01 -0500466 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400467 }
468
Elly Jonese1749eb2011-10-07 13:54:59 -0400469 return 0;
Will Drewrybee7ba72011-10-21 20:47:01 -0500470
471bad_bindings:
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800472 if (j->flags.seccomp_filter && j->filter_len > 0) {
473 free(j->filter_prog->filter);
474 free(j->filter_prog);
475 }
Will Drewrybee7ba72011-10-21 20:47:01 -0500476bad_filters:
477 if (j->chrootdir)
478 free(j->chrootdir);
479bad_chrootdir:
480 if (j->user)
481 free(j->user);
482clear_pointers:
483 j->user = NULL;
484 j->chrootdir = NULL;
485out:
486 return ret;
Will Drewry2ddaad02011-09-16 11:36:08 -0500487}
488
Elly Jonese1749eb2011-10-07 13:54:59 -0400489void minijail_preenter(struct minijail *j)
490{
491 /* Strip out options which are minijail_run() only. */
492 j->flags.vfs = 0;
493 j->flags.readonly = 0;
494 j->flags.pids = 0;
Will Drewryfe4a3722011-09-16 14:50:50 -0500495}
496
Elly Jonese1749eb2011-10-07 13:54:59 -0400497void minijail_preexec(struct minijail *j)
498{
499 int vfs = j->flags.vfs;
500 int readonly = j->flags.readonly;
501 if (j->user)
502 free(j->user);
503 j->user = NULL;
504 memset(&j->flags, 0, sizeof(j->flags));
505 /* Now restore anything we meant to keep. */
506 j->flags.vfs = vfs;
507 j->flags.readonly = readonly;
508 /* Note, pidns will already have been used before this call. */
Will Drewry2ddaad02011-09-16 11:36:08 -0500509}
510
Elly Jones51a5b6c2011-10-12 19:09:26 -0400511/* bind_one: Applies bindings from @b for @j, recursing as needed.
512 * @j Minijail these bindings are for
513 * @b Head of list of bindings
514 *
515 * Returns 0 for success.
516 */
Will Drewry6ac91122011-10-21 16:38:58 -0500517int bind_one(const struct minijail *j, struct binding *b) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400518 int ret = 0;
519 char *dest = NULL;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400520 if (ret)
521 return ret;
522 /* dest has a leading "/" */
523 if (asprintf(&dest, "%s%s", j->chrootdir, b->dest) < 0)
524 return -ENOMEM;
Elly Jonesa1059632011-12-15 15:17:07 -0500525 ret = mount(b->src, dest, NULL, MS_BIND, NULL);
Elly Jones51a5b6c2011-10-12 19:09:26 -0400526 if (ret)
527 pdie("bind: %s -> %s", b->src, dest);
Elly Jonesa1059632011-12-15 15:17:07 -0500528 if (!b->writeable) {
529 ret = mount(b->src, dest, NULL,
530 MS_BIND | MS_REMOUNT | MS_RDONLY, NULL);
531 if (ret)
532 pdie("bind ro: %s -> %s", b->src, dest);
533 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400534 free(dest);
535 if (b->next)
536 return bind_one(j, b->next);
537 return ret;
538}
539
Will Drewry6ac91122011-10-21 16:38:58 -0500540int enter_chroot(const struct minijail *j) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400541 int ret;
542 if (j->bindings_head && (ret = bind_one(j, j->bindings_head)))
543 return ret;
544
545 if (chroot(j->chrootdir))
546 return -errno;
547
548 if (chdir("/"))
549 return -errno;
550
551 return 0;
552}
553
Will Drewry6ac91122011-10-21 16:38:58 -0500554int remount_readonly(void)
Elly Jonese1749eb2011-10-07 13:54:59 -0400555{
556 const char *kProcPath = "/proc";
557 const unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
Elly Jonesdd3e8512012-01-23 15:13:38 -0500558 /*
559 * Right now, we're holding a reference to our parent's old mount of
Elly Jonese1749eb2011-10-07 13:54:59 -0400560 * /proc in our namespace, which means using MS_REMOUNT here would
561 * mutate our parent's mount as well, even though we're in a VFS
562 * namespace (!). Instead, remove their mount from our namespace
563 * and make our own.
564 */
565 if (umount(kProcPath))
566 return -errno;
567 if (mount("", kProcPath, "proc", kSafeFlags | MS_RDONLY, ""))
568 return -errno;
569 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400570}
571
Will Drewry6ac91122011-10-21 16:38:58 -0500572void drop_caps(const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400573{
574 cap_t caps = cap_get_proc();
575 cap_value_t raise_flag[1];
576 unsigned int i;
577 if (!caps)
578 die("can't get process caps");
579 if (cap_clear_flag(caps, CAP_INHERITABLE))
580 die("can't clear inheritable caps");
581 if (cap_clear_flag(caps, CAP_EFFECTIVE))
582 die("can't clear effective caps");
583 if (cap_clear_flag(caps, CAP_PERMITTED))
584 die("can't clear permitted caps");
585 for (i = 0; i < sizeof(j->caps) * 8 && cap_valid((int)i); ++i) {
586 if (i != CAP_SETPCAP && !(j->caps & (1 << i)))
587 continue;
588 raise_flag[0] = i;
589 if (cap_set_flag(caps, CAP_EFFECTIVE, 1, raise_flag, CAP_SET))
590 die("can't add effective cap");
591 if (cap_set_flag(caps, CAP_PERMITTED, 1, raise_flag, CAP_SET))
592 die("can't add permitted cap");
593 if (cap_set_flag(caps, CAP_INHERITABLE, 1, raise_flag, CAP_SET))
594 die("can't add inheritable cap");
595 }
596 if (cap_set_proc(caps))
597 die("can't apply cleaned capset");
598 cap_free(caps);
599 for (i = 0; i < sizeof(j->caps) * 8 && cap_valid((int)i); ++i) {
600 if (j->caps & (1 << i))
601 continue;
602 if (prctl(PR_CAPBSET_DROP, i))
603 pdie("prctl(PR_CAPBSET_DROP)");
604 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400605}
606
Will Drewry6ac91122011-10-21 16:38:58 -0500607void API minijail_enter(const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400608{
609 if (j->flags.pids)
610 die("tried to enter a pid-namespaced jail;"
611 "try minijail_run()?");
Elly Jonescd7a9042011-07-22 13:56:51 -0400612
Elly Jonese1749eb2011-10-07 13:54:59 -0400613 if (j->flags.usergroups && !j->user)
614 die("usergroup inheritance without username");
Elly Jonescd7a9042011-07-22 13:56:51 -0400615
Elly Jonesdd3e8512012-01-23 15:13:38 -0500616 /*
617 * We can't recover from failures if we've dropped privileges partially,
Elly Jonese1749eb2011-10-07 13:54:59 -0400618 * so we don't even try. If any of our operations fail, we abort() the
619 * entire process.
620 */
621 if (j->flags.vfs && unshare(CLONE_NEWNS))
622 pdie("unshare");
Elly Jonescd7a9042011-07-22 13:56:51 -0400623
Elly Jones51a5b6c2011-10-12 19:09:26 -0400624 if (j->flags.chroot && enter_chroot(j))
625 pdie("chroot");
626
Elly Jonese1749eb2011-10-07 13:54:59 -0400627 if (j->flags.readonly && remount_readonly())
628 pdie("remount");
Elly Jonescd7a9042011-07-22 13:56:51 -0400629
Elly Jonese1749eb2011-10-07 13:54:59 -0400630 if (j->flags.caps) {
Elly Jonesdd3e8512012-01-23 15:13:38 -0500631 /*
632 * POSIX capabilities are a bit tricky. If we drop our
Elly Jonese1749eb2011-10-07 13:54:59 -0400633 * capability to change uids, our attempt to use setuid()
634 * below will fail. Hang on to root caps across setuid(), then
635 * lock securebits.
636 */
637 if (prctl(PR_SET_KEEPCAPS, 1))
638 pdie("prctl(PR_SET_KEEPCAPS)");
639 if (prctl
640 (PR_SET_SECUREBITS, SECURE_ALL_BITS | SECURE_ALL_LOCKS))
641 pdie("prctl(PR_SET_SECUREBITS)");
642 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400643
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700644 /*
645 * Set no_new_privs before installing seccomp filter.
646 * TODO(jorgelo): document call to PR_SET_NO_NEW_PRIVS.
647 */
648 if (j->flags.no_new_privs) {
649 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
650 pdie("prctl(PR_SET_NO_NEW_PRIVS)");
651 }
652
653 /*
654 * Install seccomp filter before dropping root and caps.
655 * WARNING: this means that filter policies *must* allow
656 * setgroups()/setresgid()/setresuid() for dropping root and
657 * capget()/capset()/prctl() for dropping caps.
658 */
659 if (j->flags.seccomp_filter) {
660 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, j->filter_prog))
661 pdie("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
662 }
663
Elly Jonese1749eb2011-10-07 13:54:59 -0400664 if (j->flags.usergroups) {
665 if (initgroups(j->user, j->usergid))
666 pdie("initgroups");
667 } else {
668 /* Only attempt to clear supplemental groups if we are changing
669 * users. */
670 if ((j->uid || j->gid) && setgroups(0, NULL))
671 pdie("setgroups");
672 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400673
Elly Jonese1749eb2011-10-07 13:54:59 -0400674 if (j->flags.gid && setresgid(j->gid, j->gid, j->gid))
675 pdie("setresgid");
Elly Jonescd7a9042011-07-22 13:56:51 -0400676
Elly Jonese1749eb2011-10-07 13:54:59 -0400677 if (j->flags.uid && setresuid(j->uid, j->uid, j->uid))
678 pdie("setresuid");
Elly Jonescd7a9042011-07-22 13:56:51 -0400679
Elly Jonese1749eb2011-10-07 13:54:59 -0400680 if (j->flags.caps)
681 drop_caps(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400682
Elly Jonesdd3e8512012-01-23 15:13:38 -0500683 /*
684 * seccomp has to come last since it cuts off all the other
Elly Jonese1749eb2011-10-07 13:54:59 -0400685 * privilege-dropping syscalls :)
686 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400687 if (j->flags.seccomp && prctl(PR_SET_SECCOMP, 1))
688 pdie("prctl(PR_SET_SECCOMP)");
Elly Jonescd7a9042011-07-22 13:56:51 -0400689}
690
Will Drewry6ac91122011-10-21 16:38:58 -0500691/* TODO(wad) will visibility affect this variable? */
Elly Jonescd7a9042011-07-22 13:56:51 -0400692static int init_exitstatus = 0;
693
Will Drewry6ac91122011-10-21 16:38:58 -0500694void init_term(int __attribute__ ((unused)) sig)
Elly Jonese1749eb2011-10-07 13:54:59 -0400695{
696 _exit(init_exitstatus);
Elly Jonescd7a9042011-07-22 13:56:51 -0400697}
698
Will Drewry6ac91122011-10-21 16:38:58 -0500699int init(pid_t rootpid)
Elly Jonese1749eb2011-10-07 13:54:59 -0400700{
701 pid_t pid;
702 int status;
703 /* so that we exit with the right status */
704 signal(SIGTERM, init_term);
705 /* TODO(wad) self jail with seccomp_filters here. */
706 while ((pid = wait(&status)) > 0) {
Elly Jonesdd3e8512012-01-23 15:13:38 -0500707 /*
708 * This loop will only end when either there are no processes
Elly Jonese1749eb2011-10-07 13:54:59 -0400709 * left inside our pid namespace or we get a signal.
710 */
711 if (pid == rootpid)
712 init_exitstatus = status;
713 }
714 if (!WIFEXITED(init_exitstatus))
715 _exit(MINIJAIL_ERR_INIT);
716 _exit(WEXITSTATUS(init_exitstatus));
Elly Jonescd7a9042011-07-22 13:56:51 -0400717}
718
Will Drewry6ac91122011-10-21 16:38:58 -0500719int API minijail_from_fd(int fd, struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400720{
721 size_t sz = 0;
722 size_t bytes = read(fd, &sz, sizeof(sz));
723 char *buf;
724 int r;
725 if (sizeof(sz) != bytes)
726 return -EINVAL;
727 if (sz > USHRT_MAX) /* Arbitrary sanity check */
728 return -E2BIG;
729 buf = malloc(sz);
730 if (!buf)
731 return -ENOMEM;
732 bytes = read(fd, buf, sz);
733 if (bytes != sz) {
734 free(buf);
735 return -EINVAL;
736 }
737 r = minijail_unmarshal(j, buf, sz);
738 free(buf);
739 return r;
Will Drewry2f54b6a2011-09-16 13:45:31 -0500740}
741
Will Drewry6ac91122011-10-21 16:38:58 -0500742int API minijail_to_fd(struct minijail *j, int fd)
Elly Jonese1749eb2011-10-07 13:54:59 -0400743{
744 char *buf;
745 size_t sz = minijail_size(j);
746 ssize_t written;
747 int r;
Elly Jonescd7a9042011-07-22 13:56:51 -0400748
Elly Jonese1749eb2011-10-07 13:54:59 -0400749 if (!sz)
750 return -EINVAL;
751 buf = malloc(sz);
752 r = minijail_marshal(j, buf, sz);
753 if (r) {
754 free(buf);
755 return r;
756 }
757 /* Sends [size][minijail]. */
758 written = write(fd, &sz, sizeof(sz));
759 if (written != sizeof(sz)) {
760 free(buf);
761 return -EFAULT;
762 }
763 written = write(fd, buf, sz);
764 if (written < 0 || (size_t) written != sz) {
765 free(buf);
766 return -EFAULT;
767 }
768 free(buf);
769 return 0;
Will Drewry2f54b6a2011-09-16 13:45:31 -0500770}
Elly Jonescd7a9042011-07-22 13:56:51 -0400771
Will Drewry6ac91122011-10-21 16:38:58 -0500772int setup_preload(void)
Elly Jonese1749eb2011-10-07 13:54:59 -0400773{
774 char *oldenv = getenv(kLdPreloadEnvVar) ? : "";
775 char *newenv = malloc(strlen(oldenv) + 2 + strlen(PRELOADPATH));
776 if (!newenv)
777 return -ENOMEM;
Elly Jonescd7a9042011-07-22 13:56:51 -0400778
Elly Jonese1749eb2011-10-07 13:54:59 -0400779 /* Only insert a separating space if we have something to separate... */
780 sprintf(newenv, "%s%s%s", oldenv, strlen(oldenv) ? " " : "",
781 PRELOADPATH);
Elly Jonescd7a9042011-07-22 13:56:51 -0400782
Elly Jonese1749eb2011-10-07 13:54:59 -0400783 /* setenv() makes a copy of the string we give it */
784 setenv(kLdPreloadEnvVar, newenv, 1);
785 free(newenv);
786 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400787}
788
Will Drewry6ac91122011-10-21 16:38:58 -0500789int setup_pipe(int fds[2])
Elly Jonese1749eb2011-10-07 13:54:59 -0400790{
791 int r = pipe(fds);
792 char fd_buf[11];
793 if (r)
794 return r;
795 r = snprintf(fd_buf, sizeof(fd_buf), "%d", fds[0]);
796 if (r <= 0)
797 return -EINVAL;
798 setenv(kFdEnvVar, fd_buf, 1);
799 return 0;
Will Drewryf89aef52011-09-16 16:48:57 -0500800}
801
Will Drewry6ac91122011-10-21 16:38:58 -0500802int API minijail_run(struct minijail *j, const char *filename,
803 char *const argv[])
Elly Jonese1749eb2011-10-07 13:54:59 -0400804{
Jorge Lucangeli Obes9807d032012-04-17 13:36:00 -0700805 return minijail_run_pid(j, filename, argv, NULL);
806}
807
808int API minijail_run_pid(struct minijail *j, const char *filename,
809 char *const argv[], pid_t *pchild_pid)
810{
Elly Jonese1749eb2011-10-07 13:54:59 -0400811 char *oldenv, *oldenv_copy = NULL;
812 pid_t child_pid;
813 int pipe_fds[2];
814 int ret;
Elly Jonesa05d7bb2012-06-14 14:09:27 -0400815 /* We need to remember this across the minijail_preexec() call. */
816 int pid_namespace = j->flags.pids;
Ben Chan541c7e52011-08-26 14:55:53 -0700817
Elly Jonese1749eb2011-10-07 13:54:59 -0400818 oldenv = getenv(kLdPreloadEnvVar);
819 if (oldenv) {
820 oldenv_copy = strdup(oldenv);
821 if (!oldenv_copy)
822 return -ENOMEM;
823 }
Will Drewryf89aef52011-09-16 16:48:57 -0500824
Elly Jonese1749eb2011-10-07 13:54:59 -0400825 if (setup_preload())
826 return -EFAULT;
Will Drewry2f54b6a2011-09-16 13:45:31 -0500827
Elly Jonesdd3e8512012-01-23 15:13:38 -0500828 /*
829 * Before we fork(2) and execve(2) the child process, we need to open
Elly Jonese1749eb2011-10-07 13:54:59 -0400830 * a pipe(2) to send the minijail configuration over.
831 */
832 if (setup_pipe(pipe_fds))
833 return -EFAULT;
Elly Jonescd7a9042011-07-22 13:56:51 -0400834
Elly Jones761b7412012-06-13 15:49:52 -0400835 /* Use sys_clone() if and only if we're creating a pid namespace.
836 *
837 * tl;dr: WARNING: do not mix pid namespaces and multithreading.
838 *
839 * In multithreaded programs, there are a bunch of locks inside libc,
840 * some of which may be held by other threads at the time that we call
841 * minijail_run_pid(). If we call fork(), glibc does its level best to
842 * ensure that we hold all of these locks before it calls clone()
843 * internally and drop them after clone() returns, but when we call
844 * sys_clone(2) directly, all that gets bypassed and we end up with a
845 * child address space where some of libc's important locks are held by
846 * other threads (which did not get cloned, and hence will never release
847 * those locks). This is okay so long as we call exec() immediately
848 * after, but a bunch of seemingly-innocent libc functions like setenv()
849 * take locks.
850 *
851 * Hence, only call sys_clone() if we need to, in order to get at pid
852 * namespacing. If we follow this path, the child's address space might
853 * have broken locks; you may only call functions that do not acquire
854 * any locks.
855 *
856 * Unfortunately, fork() acquires every lock it can get its hands on, as
857 * previously detailed, so this function is highly likely to deadlock
858 * later on (see "deadlock here") if we're multithreaded.
859 *
860 * We might hack around this by having the clone()d child (init of the
861 * pid namespace) return directly, rather than leaving the clone()d
862 * process hanging around to be init for the new namespace (and having
863 * its fork()ed child return in turn), but that process would be crippled
864 * with its libc locks potentially broken. We might try fork()ing in the
865 * parent before we clone() to ensure that we own all the locks, but
866 * then we have to have the forked child hanging around consuming
867 * resources (and possibly having file descriptors / shared memory
868 * regions / etc attached). We'd need to keep the child around to avoid
869 * having its children get reparented to init.
870 *
871 * TODO(ellyjones): figure out if the "forked child hanging around"
872 * problem is fixable or not. It would be nice if we worked in this
873 * case.
874 */
Elly Jonesa05d7bb2012-06-14 14:09:27 -0400875 if (pid_namespace)
Elly Jones761b7412012-06-13 15:49:52 -0400876 child_pid = syscall(SYS_clone, CLONE_NEWPID | SIGCHLD, NULL);
877 else
878 child_pid = fork();
879
Elly Jonese1749eb2011-10-07 13:54:59 -0400880 if (child_pid < 0) {
881 free(oldenv_copy);
882 return child_pid;
883 }
Will Drewryf89aef52011-09-16 16:48:57 -0500884
Elly Jonese1749eb2011-10-07 13:54:59 -0400885 if (child_pid) {
886 /* Restore parent's LD_PRELOAD. */
887 if (oldenv_copy) {
888 setenv(kLdPreloadEnvVar, oldenv_copy, 1);
889 free(oldenv_copy);
890 } else {
891 unsetenv(kLdPreloadEnvVar);
892 }
893 unsetenv(kFdEnvVar);
894 j->initpid = child_pid;
895 close(pipe_fds[0]); /* read endpoint */
896 ret = minijail_to_fd(j, pipe_fds[1]);
897 close(pipe_fds[1]); /* write endpoint */
898 if (ret) {
899 kill(j->initpid, SIGKILL);
900 die("failed to send marshalled minijail");
901 }
Jorge Lucangeli Obes9807d032012-04-17 13:36:00 -0700902 if (pchild_pid)
903 *pchild_pid = child_pid;
Elly Jonese1749eb2011-10-07 13:54:59 -0400904 return 0;
905 }
906 free(oldenv_copy);
Ben Chan541c7e52011-08-26 14:55:53 -0700907
Elly Jonese1749eb2011-10-07 13:54:59 -0400908 /* Drop everything that cannot be inherited across execve. */
909 minijail_preexec(j);
910 /* Jail this process and its descendants... */
911 minijail_enter(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400912
Elly Jonesa05d7bb2012-06-14 14:09:27 -0400913 if (pid_namespace) {
Elly Jonesdd3e8512012-01-23 15:13:38 -0500914 /*
915 * pid namespace: this process will become init inside the new
Elly Jonese1749eb2011-10-07 13:54:59 -0400916 * namespace, so fork off a child to actually run the program
917 * (we don't want all programs we might exec to have to know
918 * how to be init).
Elly Jones761b7412012-06-13 15:49:52 -0400919 *
920 * If we're multithreaded, we'll probably deadlock here. See
921 * WARNING above.
Elly Jonese1749eb2011-10-07 13:54:59 -0400922 */
923 child_pid = fork();
924 if (child_pid < 0)
925 _exit(child_pid);
926 else if (child_pid > 0)
927 init(child_pid); /* never returns */
928 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400929
Elly Jonesdd3e8512012-01-23 15:13:38 -0500930 /*
931 * If we aren't pid-namespaced:
Elly Jonese1749eb2011-10-07 13:54:59 -0400932 * calling process
933 * -> execve()-ing process
934 * If we are:
935 * calling process
936 * -> init()-ing process
937 * -> execve()-ing process
938 */
939 _exit(execve(filename, argv, environ));
Elly Jonescd7a9042011-07-22 13:56:51 -0400940}
941
Will Drewry6ac91122011-10-21 16:38:58 -0500942int API minijail_kill(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400943{
944 int st;
945 if (kill(j->initpid, SIGTERM))
946 return -errno;
947 if (waitpid(j->initpid, &st, 0) < 0)
948 return -errno;
949 return st;
Elly Jonescd7a9042011-07-22 13:56:51 -0400950}
951
Will Drewry6ac91122011-10-21 16:38:58 -0500952int API minijail_wait(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400953{
954 int st;
955 if (waitpid(j->initpid, &st, 0) < 0)
956 return -errno;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700957 if (!WIFEXITED(st)) {
958 if (WIFSIGNALED(st))
959 warn("child process received signal %d", WTERMSIG(st));
Elly Jonese1749eb2011-10-07 13:54:59 -0400960 return MINIJAIL_ERR_JAIL;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700961 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400962 return WEXITSTATUS(st);
Elly Jonescd7a9042011-07-22 13:56:51 -0400963}
964
Will Drewry6ac91122011-10-21 16:38:58 -0500965void API minijail_destroy(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400966{
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800967 if (j->flags.seccomp_filter && j->filter_prog) {
968 free(j->filter_prog->filter);
969 free(j->filter_prog);
Elly Jonese1749eb2011-10-07 13:54:59 -0400970 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400971 while (j->bindings_head) {
972 struct binding *b = j->bindings_head;
973 j->bindings_head = j->bindings_head->next;
974 free(b->dest);
975 free(b->src);
976 free(b);
977 }
978 j->bindings_tail = NULL;
Elly Jonese1749eb2011-10-07 13:54:59 -0400979 if (j->user)
980 free(j->user);
Will Drewrybee7ba72011-10-21 20:47:01 -0500981 if (j->chrootdir)
982 free(j->chrootdir);
Elly Jonese1749eb2011-10-07 13:54:59 -0400983 free(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400984}