blob: 4da1f660cf81b90644950b4683c06e21fad118b2 [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>
Elly Jonescd7a9042011-07-22 13:56:51 -040033#include <unistd.h>
34
35#include "libminijail.h"
36#include "libminijail-private.h"
37
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070038#include "signal.h"
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080039#include "syscall_filter.h"
Jorge Lucangeli Obesa6b034d2012-08-07 15:29:20 -070040#include "util.h"
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080041
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
Elly Jones51a5b6c2011-10-12 19:09:26 -040055struct binding {
56 char *src;
57 char *dest;
58 int writeable;
59 struct binding *next;
60};
61
Will Drewryf89aef52011-09-16 16:48:57 -050062struct minijail {
Elly Jonese1749eb2011-10-07 13:54:59 -040063 struct {
64 int uid:1;
65 int gid:1;
66 int caps:1;
67 int vfs:1;
68 int pids:1;
69 int seccomp:1;
70 int readonly:1;
71 int usergroups:1;
72 int ptrace:1;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -070073 int no_new_privs:1;
Elly Jonese1749eb2011-10-07 13:54:59 -040074 int seccomp_filter:1;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070075 int log_seccomp_filter:1;
Elly Jones51a5b6c2011-10-12 19:09:26 -040076 int chroot:1;
Elly Jonese1749eb2011-10-07 13:54:59 -040077 } flags;
78 uid_t uid;
79 gid_t gid;
80 gid_t usergid;
81 char *user;
82 uint64_t caps;
83 pid_t initpid;
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080084 int filter_len;
Elly Jones51a5b6c2011-10-12 19:09:26 -040085 int binding_count;
86 char *chrootdir;
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -080087 struct sock_fprog *filter_prog;
Elly Jones51a5b6c2011-10-12 19:09:26 -040088 struct binding *bindings_head;
89 struct binding *bindings_tail;
Will Drewryf89aef52011-09-16 16:48:57 -050090};
91
Will Drewry6ac91122011-10-21 16:38:58 -050092struct minijail API *minijail_new(void)
Elly Jonese1749eb2011-10-07 13:54:59 -040093{
Elly Jones51a5b6c2011-10-12 19:09:26 -040094 return calloc(1, sizeof(struct minijail));
Elly Jonescd7a9042011-07-22 13:56:51 -040095}
96
Will Drewry6ac91122011-10-21 16:38:58 -050097void API minijail_change_uid(struct minijail *j, uid_t uid)
Elly Jonese1749eb2011-10-07 13:54:59 -040098{
99 if (uid == 0)
100 die("useless change to uid 0");
101 j->uid = uid;
102 j->flags.uid = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400103}
104
Will Drewry6ac91122011-10-21 16:38:58 -0500105void API minijail_change_gid(struct minijail *j, gid_t gid)
Elly Jonese1749eb2011-10-07 13:54:59 -0400106{
107 if (gid == 0)
108 die("useless change to gid 0");
109 j->gid = gid;
110 j->flags.gid = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400111}
112
Will Drewry6ac91122011-10-21 16:38:58 -0500113int API minijail_change_user(struct minijail *j, const char *user)
Elly Jonese1749eb2011-10-07 13:54:59 -0400114{
115 char *buf = NULL;
116 struct passwd pw;
117 struct passwd *ppw = NULL;
118 ssize_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
119 if (sz == -1)
120 sz = 65536; /* your guess is as good as mine... */
Elly Joneseb300c52011-09-22 14:35:43 -0400121
Elly Jonesdd3e8512012-01-23 15:13:38 -0500122 /*
123 * sysconf(_SC_GETPW_R_SIZE_MAX), under glibc, is documented to return
Elly Jonese1749eb2011-10-07 13:54:59 -0400124 * the maximum needed size of the buffer, so we don't have to search.
125 */
126 buf = malloc(sz);
127 if (!buf)
128 return -ENOMEM;
129 getpwnam_r(user, &pw, buf, sz, &ppw);
Elly Jonesdd3e8512012-01-23 15:13:38 -0500130 /*
131 * We're safe to free the buffer here. The strings inside pw point
132 * inside buf, but we don't use any of them; this leaves the pointers
133 * dangling but it's safe. ppw points at pw if getpwnam_r succeeded.
134 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400135 free(buf);
136 if (!ppw)
137 return -errno;
138 minijail_change_uid(j, ppw->pw_uid);
139 j->user = strdup(user);
140 if (!j->user)
141 return -ENOMEM;
142 j->usergid = ppw->pw_gid;
143 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400144}
145
Will Drewry6ac91122011-10-21 16:38:58 -0500146int API minijail_change_group(struct minijail *j, const char *group)
Elly Jonese1749eb2011-10-07 13:54:59 -0400147{
148 char *buf = NULL;
149 struct group gr;
150 struct group *pgr = NULL;
151 ssize_t sz = sysconf(_SC_GETGR_R_SIZE_MAX);
152 if (sz == -1)
153 sz = 65536; /* and mine is as good as yours, really */
Elly Joneseb300c52011-09-22 14:35:43 -0400154
Elly Jonesdd3e8512012-01-23 15:13:38 -0500155 /*
156 * sysconf(_SC_GETGR_R_SIZE_MAX), under glibc, is documented to return
Elly Jonese1749eb2011-10-07 13:54:59 -0400157 * the maximum needed size of the buffer, so we don't have to search.
158 */
159 buf = malloc(sz);
160 if (!buf)
161 return -ENOMEM;
162 getgrnam_r(group, &gr, buf, sz, &pgr);
Elly Jonesdd3e8512012-01-23 15:13:38 -0500163 /*
164 * We're safe to free the buffer here. The strings inside gr point
165 * inside buf, but we don't use any of them; this leaves the pointers
166 * dangling but it's safe. pgr points at gr if getgrnam_r succeeded.
167 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400168 free(buf);
169 if (!pgr)
170 return -errno;
171 minijail_change_gid(j, pgr->gr_gid);
172 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400173}
174
Will Drewry6ac91122011-10-21 16:38:58 -0500175void API minijail_use_seccomp(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400176{
177 j->flags.seccomp = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400178}
179
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700180void API minijail_no_new_privs(struct minijail *j)
181{
182 j->flags.no_new_privs = 1;
183}
184
Will Drewry6ac91122011-10-21 16:38:58 -0500185void API minijail_use_seccomp_filter(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400186{
187 j->flags.seccomp_filter = 1;
Will Drewry32ac9f52011-08-18 21:36:27 -0500188}
189
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700190void API minijail_log_seccomp_filter_failures(struct minijail *j)
191{
192 j->flags.log_seccomp_filter = 1;
193}
194
Will Drewry6ac91122011-10-21 16:38:58 -0500195void API minijail_use_caps(struct minijail *j, uint64_t capmask)
Elly Jonese1749eb2011-10-07 13:54:59 -0400196{
197 j->caps = capmask;
198 j->flags.caps = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400199}
200
Will Drewry6ac91122011-10-21 16:38:58 -0500201void API minijail_namespace_vfs(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400202{
203 j->flags.vfs = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400204}
205
Will Drewry6ac91122011-10-21 16:38:58 -0500206void API minijail_namespace_pids(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400207{
Elly Jonese58176c2012-01-23 11:46:17 -0500208 j->flags.vfs = 1;
209 j->flags.readonly = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400210 j->flags.pids = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400211}
212
Will Drewry6ac91122011-10-21 16:38:58 -0500213void API minijail_remount_readonly(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400214{
215 j->flags.vfs = 1;
216 j->flags.readonly = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400217}
218
Will Drewry6ac91122011-10-21 16:38:58 -0500219void API minijail_inherit_usergroups(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400220{
221 j->flags.usergroups = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400222}
223
Will Drewry6ac91122011-10-21 16:38:58 -0500224void API minijail_disable_ptrace(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400225{
226 j->flags.ptrace = 1;
Elly Jonescd7a9042011-07-22 13:56:51 -0400227}
228
Will Drewry6ac91122011-10-21 16:38:58 -0500229int API minijail_enter_chroot(struct minijail *j, const char *dir) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400230 if (j->chrootdir)
231 return -EINVAL;
232 j->chrootdir = strdup(dir);
233 if (!j->chrootdir)
234 return -ENOMEM;
235 j->flags.chroot = 1;
236 return 0;
237}
238
Will Drewry6ac91122011-10-21 16:38:58 -0500239int API minijail_bind(struct minijail *j, const char *src, const char *dest,
240 int writeable) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400241 struct binding *b;
242
243 if (*dest != '/')
244 return -EINVAL;
245 b = calloc(1, sizeof(*b));
246 if (!b)
247 return -ENOMEM;
248 b->dest = strdup(dest);
249 if (!b->dest)
250 goto error;
251 b->src = strdup(src);
252 if (!b->src)
253 goto error;
254 b->writeable = writeable;
255
Jorge Lucangeli Obes224e4272012-08-02 14:31:39 -0700256 info("bind %s -> %s", src, dest);
Elly Jones51a5b6c2011-10-12 19:09:26 -0400257
Elly Jonesdd3e8512012-01-23 15:13:38 -0500258 /*
259 * Force vfs namespacing so the bind mounts don't leak out into the
Elly Jones51a5b6c2011-10-12 19:09:26 -0400260 * containing vfs namespace.
261 */
262 minijail_namespace_vfs(j);
263
264 if (j->bindings_tail)
265 j->bindings_tail->next = b;
266 else
267 j->bindings_head = b;
268 j->bindings_tail = b;
269 j->binding_count++;
270
271 return 0;
272
273error:
274 free(b->src);
275 free(b->dest);
276 free(b);
277 return -ENOMEM;
278}
279
Will Drewry6ac91122011-10-21 16:38:58 -0500280void API minijail_parse_seccomp_filters(struct minijail *j, const char *path)
Elly Jonese1749eb2011-10-07 13:54:59 -0400281{
282 FILE *file = fopen(path, "r");
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800283 if (!file) {
Jorge Lucangeli Obes224e4272012-08-02 14:31:39 -0700284 pdie("failed to open seccomp filter file '%s'", path);
Elly Jonese1749eb2011-10-07 13:54:59 -0400285 }
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800286
287 struct sock_fprog *fprog = malloc(sizeof(struct sock_fprog));
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700288 if (compile_filter(file, fprog, j->flags.log_seccomp_filter)) {
289 die("failed to compile seccomp filter BPF program in '%s'",
290 path);
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800291 }
292
293 j->filter_len = fprog->len;
294 j->filter_prog = fprog;
295
Elly Jonese1749eb2011-10-07 13:54:59 -0400296 fclose(file);
Will Drewry32ac9f52011-08-18 21:36:27 -0500297}
298
Will Drewryf89aef52011-09-16 16:48:57 -0500299struct marshal_state {
Elly Jonese1749eb2011-10-07 13:54:59 -0400300 size_t available;
301 size_t total;
302 char *buf;
Will Drewryf89aef52011-09-16 16:48:57 -0500303};
304
Will Drewry6ac91122011-10-21 16:38:58 -0500305void marshal_state_init(struct marshal_state *state,
306 char *buf, size_t available)
Elly Jonese1749eb2011-10-07 13:54:59 -0400307{
308 state->available = available;
309 state->buf = buf;
310 state->total = 0;
Will Drewryf89aef52011-09-16 16:48:57 -0500311}
312
Will Drewry6ac91122011-10-21 16:38:58 -0500313void marshal_append(struct marshal_state *state,
314 char *src, size_t length)
Elly Jonese1749eb2011-10-07 13:54:59 -0400315{
316 size_t copy_len = MIN(state->available, length);
Will Drewryf89aef52011-09-16 16:48:57 -0500317
Elly Jonese1749eb2011-10-07 13:54:59 -0400318 /* Up to |available| will be written. */
319 if (copy_len) {
320 memcpy(state->buf, src, copy_len);
321 state->buf += copy_len;
322 state->available -= copy_len;
323 }
324 /* |total| will contain the expected length. */
325 state->total += length;
Will Drewryf89aef52011-09-16 16:48:57 -0500326}
327
Will Drewry6ac91122011-10-21 16:38:58 -0500328void minijail_marshal_helper(struct marshal_state *state,
329 const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400330{
Elly Jones51a5b6c2011-10-12 19:09:26 -0400331 struct binding *b = NULL;
Elly Jonese1749eb2011-10-07 13:54:59 -0400332 marshal_append(state, (char *)j, sizeof(*j));
333 if (j->user)
334 marshal_append(state, j->user, strlen(j->user) + 1);
Elly Jones51a5b6c2011-10-12 19:09:26 -0400335 if (j->chrootdir)
336 marshal_append(state, j->chrootdir, strlen(j->chrootdir) + 1);
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800337 if (j->flags.seccomp_filter && j->filter_prog) {
338 struct sock_fprog *fp = j->filter_prog;
339 marshal_append(state, (char *)fp->filter,
340 fp->len * sizeof(struct sock_filter));
Elly Jonese1749eb2011-10-07 13:54:59 -0400341 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400342 for (b = j->bindings_head; b; b = b->next) {
343 marshal_append(state, b->src, strlen(b->src) + 1);
344 marshal_append(state, b->dest, strlen(b->dest) + 1);
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700345 marshal_append(state, (char *)&b->writeable,
346 sizeof(b->writeable));
Elly Jones51a5b6c2011-10-12 19:09:26 -0400347 }
Will Drewryf89aef52011-09-16 16:48:57 -0500348}
349
Will Drewry6ac91122011-10-21 16:38:58 -0500350size_t API minijail_size(const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400351{
352 struct marshal_state state;
353 marshal_state_init(&state, NULL, 0);
354 minijail_marshal_helper(&state, j);
355 return state.total;
Will Drewry2ddaad02011-09-16 11:36:08 -0500356}
357
Elly Jonese1749eb2011-10-07 13:54:59 -0400358int minijail_marshal(const struct minijail *j, char *buf, size_t available)
359{
360 struct marshal_state state;
361 marshal_state_init(&state, buf, available);
362 minijail_marshal_helper(&state, j);
363 return (state.total > available);
Will Drewry2ddaad02011-09-16 11:36:08 -0500364}
365
Elly Jones51a5b6c2011-10-12 19:09:26 -0400366/* consumebytes: consumes @length bytes from a buffer @buf of length @buflength
367 * @length Number of bytes to consume
368 * @buf Buffer to consume from
369 * @buflength Size of @buf
370 *
371 * Returns a pointer to the base of the bytes, or NULL for errors.
372 */
Will Drewry6ac91122011-10-21 16:38:58 -0500373void *consumebytes(size_t length, char **buf, size_t *buflength) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400374 char *p = *buf;
375 if (length > *buflength)
376 return NULL;
377 *buf += length;
378 *buflength -= length;
379 return p;
380}
381
382/* consumestr: consumes a C string from a buffer @buf of length @length
383 * @buf Buffer to consume
384 * @length Length of buffer
385 *
386 * Returns a pointer to the base of the string, or NULL for errors.
387 */
Will Drewry6ac91122011-10-21 16:38:58 -0500388char *consumestr(char **buf, size_t *buflength) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400389 size_t len = strnlen(*buf, *buflength);
390 if (len == *buflength)
391 /* There's no null-terminator */
392 return NULL;
393 return consumebytes(len + 1, buf, buflength);
394}
395
Elly Jonese1749eb2011-10-07 13:54:59 -0400396int minijail_unmarshal(struct minijail *j, char *serialized, size_t length)
397{
Elly Jones51a5b6c2011-10-12 19:09:26 -0400398 int i;
399 int count;
Will Drewrybee7ba72011-10-21 20:47:01 -0500400 int ret = -EINVAL;
401
Elly Jonese1749eb2011-10-07 13:54:59 -0400402 if (length < sizeof(*j))
Will Drewrybee7ba72011-10-21 20:47:01 -0500403 goto out;
Elly Jonese1749eb2011-10-07 13:54:59 -0400404 memcpy((void *)j, serialized, sizeof(*j));
405 serialized += sizeof(*j);
406 length -= sizeof(*j);
Will Drewryf89aef52011-09-16 16:48:57 -0500407
Will Drewrybee7ba72011-10-21 20:47:01 -0500408 /* Potentially stale pointers not used as signals. */
409 j->bindings_head = NULL;
410 j->bindings_tail = NULL;
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800411 j->filter_prog = NULL;
Will Drewrybee7ba72011-10-21 20:47:01 -0500412
Elly Jonese1749eb2011-10-07 13:54:59 -0400413 if (j->user) { /* stale pointer */
Elly Jones51a5b6c2011-10-12 19:09:26 -0400414 char *user = consumestr(&serialized, &length);
415 if (!user)
Will Drewrybee7ba72011-10-21 20:47:01 -0500416 goto clear_pointers;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400417 j->user = strdup(user);
Will Drewrybee7ba72011-10-21 20:47:01 -0500418 if (!j->user)
419 goto clear_pointers;
Elly Jonese1749eb2011-10-07 13:54:59 -0400420 }
Will Drewryf89aef52011-09-16 16:48:57 -0500421
Elly Jonesa8d1e1b2011-10-21 15:38:00 -0400422 if (j->chrootdir) { /* stale pointer */
423 char *chrootdir = consumestr(&serialized, &length);
424 if (!chrootdir)
Will Drewrybee7ba72011-10-21 20:47:01 -0500425 goto bad_chrootdir;
Elly Jonesa8d1e1b2011-10-21 15:38:00 -0400426 j->chrootdir = strdup(chrootdir);
Will Drewrybee7ba72011-10-21 20:47:01 -0500427 if (!j->chrootdir)
428 goto bad_chrootdir;
Elly Jonesa8d1e1b2011-10-21 15:38:00 -0400429 }
430
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800431 if (j->flags.seccomp_filter && j->filter_len > 0) {
432 size_t ninstrs = j->filter_len;
433 if (ninstrs > (SIZE_MAX / sizeof(struct sock_filter)) ||
434 ninstrs > USHRT_MAX)
435 goto bad_filters;
436
437 size_t program_len = ninstrs * sizeof(struct sock_filter);
438 void *program = consumebytes(program_len, &serialized, &length);
439 if (!program)
440 goto bad_filters;
441
442 j->filter_prog = malloc(sizeof(struct sock_fprog));
443 j->filter_prog->len = ninstrs;
444 j->filter_prog->filter = malloc(program_len);
445 memcpy(j->filter_prog->filter, program, program_len);
Elly Jonese1749eb2011-10-07 13:54:59 -0400446 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400447
448 count = j->binding_count;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400449 j->binding_count = 0;
450 for (i = 0; i < count; ++i) {
451 int *writeable;
452 const char *dest;
453 const char *src = consumestr(&serialized, &length);
454 if (!src)
Will Drewrybee7ba72011-10-21 20:47:01 -0500455 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400456 dest = consumestr(&serialized, &length);
457 if (!dest)
Will Drewrybee7ba72011-10-21 20:47:01 -0500458 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400459 writeable = consumebytes(sizeof(*writeable), &serialized, &length);
460 if (!writeable)
Will Drewrybee7ba72011-10-21 20:47:01 -0500461 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400462 if (minijail_bind(j, src, dest, *writeable))
Will Drewrybee7ba72011-10-21 20:47:01 -0500463 goto bad_bindings;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400464 }
465
Elly Jonese1749eb2011-10-07 13:54:59 -0400466 return 0;
Will Drewrybee7ba72011-10-21 20:47:01 -0500467
468bad_bindings:
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800469 if (j->flags.seccomp_filter && j->filter_len > 0) {
470 free(j->filter_prog->filter);
471 free(j->filter_prog);
472 }
Will Drewrybee7ba72011-10-21 20:47:01 -0500473bad_filters:
474 if (j->chrootdir)
475 free(j->chrootdir);
476bad_chrootdir:
477 if (j->user)
478 free(j->user);
479clear_pointers:
480 j->user = NULL;
481 j->chrootdir = NULL;
482out:
483 return ret;
Will Drewry2ddaad02011-09-16 11:36:08 -0500484}
485
Elly Jonese1749eb2011-10-07 13:54:59 -0400486void minijail_preenter(struct minijail *j)
487{
488 /* Strip out options which are minijail_run() only. */
489 j->flags.vfs = 0;
490 j->flags.readonly = 0;
491 j->flags.pids = 0;
Will Drewryfe4a3722011-09-16 14:50:50 -0500492}
493
Elly Jonese1749eb2011-10-07 13:54:59 -0400494void minijail_preexec(struct minijail *j)
495{
496 int vfs = j->flags.vfs;
497 int readonly = j->flags.readonly;
498 if (j->user)
499 free(j->user);
500 j->user = NULL;
501 memset(&j->flags, 0, sizeof(j->flags));
502 /* Now restore anything we meant to keep. */
503 j->flags.vfs = vfs;
504 j->flags.readonly = readonly;
505 /* Note, pidns will already have been used before this call. */
Will Drewry2ddaad02011-09-16 11:36:08 -0500506}
507
Elly Jones51a5b6c2011-10-12 19:09:26 -0400508/* bind_one: Applies bindings from @b for @j, recursing as needed.
509 * @j Minijail these bindings are for
510 * @b Head of list of bindings
511 *
512 * Returns 0 for success.
513 */
Will Drewry6ac91122011-10-21 16:38:58 -0500514int bind_one(const struct minijail *j, struct binding *b) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400515 int ret = 0;
516 char *dest = NULL;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400517 if (ret)
518 return ret;
519 /* dest has a leading "/" */
520 if (asprintf(&dest, "%s%s", j->chrootdir, b->dest) < 0)
521 return -ENOMEM;
Elly Jonesa1059632011-12-15 15:17:07 -0500522 ret = mount(b->src, dest, NULL, MS_BIND, NULL);
Elly Jones51a5b6c2011-10-12 19:09:26 -0400523 if (ret)
524 pdie("bind: %s -> %s", b->src, dest);
Elly Jonesa1059632011-12-15 15:17:07 -0500525 if (!b->writeable) {
526 ret = mount(b->src, dest, NULL,
527 MS_BIND | MS_REMOUNT | MS_RDONLY, NULL);
528 if (ret)
529 pdie("bind ro: %s -> %s", b->src, dest);
530 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400531 free(dest);
532 if (b->next)
533 return bind_one(j, b->next);
534 return ret;
535}
536
Will Drewry6ac91122011-10-21 16:38:58 -0500537int enter_chroot(const struct minijail *j) {
Elly Jones51a5b6c2011-10-12 19:09:26 -0400538 int ret;
539 if (j->bindings_head && (ret = bind_one(j, j->bindings_head)))
540 return ret;
541
542 if (chroot(j->chrootdir))
543 return -errno;
544
545 if (chdir("/"))
546 return -errno;
547
548 return 0;
549}
550
Will Drewry6ac91122011-10-21 16:38:58 -0500551int remount_readonly(void)
Elly Jonese1749eb2011-10-07 13:54:59 -0400552{
553 const char *kProcPath = "/proc";
554 const unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
Elly Jonesdd3e8512012-01-23 15:13:38 -0500555 /*
556 * Right now, we're holding a reference to our parent's old mount of
Elly Jonese1749eb2011-10-07 13:54:59 -0400557 * /proc in our namespace, which means using MS_REMOUNT here would
558 * mutate our parent's mount as well, even though we're in a VFS
559 * namespace (!). Instead, remove their mount from our namespace
560 * and make our own.
561 */
562 if (umount(kProcPath))
563 return -errno;
564 if (mount("", kProcPath, "proc", kSafeFlags | MS_RDONLY, ""))
565 return -errno;
566 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400567}
568
Will Drewry6ac91122011-10-21 16:38:58 -0500569void drop_caps(const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400570{
571 cap_t caps = cap_get_proc();
572 cap_value_t raise_flag[1];
573 unsigned int i;
574 if (!caps)
575 die("can't get process caps");
576 if (cap_clear_flag(caps, CAP_INHERITABLE))
577 die("can't clear inheritable caps");
578 if (cap_clear_flag(caps, CAP_EFFECTIVE))
579 die("can't clear effective caps");
580 if (cap_clear_flag(caps, CAP_PERMITTED))
581 die("can't clear permitted caps");
582 for (i = 0; i < sizeof(j->caps) * 8 && cap_valid((int)i); ++i) {
583 if (i != CAP_SETPCAP && !(j->caps & (1 << i)))
584 continue;
585 raise_flag[0] = i;
586 if (cap_set_flag(caps, CAP_EFFECTIVE, 1, raise_flag, CAP_SET))
587 die("can't add effective cap");
588 if (cap_set_flag(caps, CAP_PERMITTED, 1, raise_flag, CAP_SET))
589 die("can't add permitted cap");
590 if (cap_set_flag(caps, CAP_INHERITABLE, 1, raise_flag, CAP_SET))
591 die("can't add inheritable cap");
592 }
593 if (cap_set_proc(caps))
594 die("can't apply cleaned capset");
595 cap_free(caps);
596 for (i = 0; i < sizeof(j->caps) * 8 && cap_valid((int)i); ++i) {
597 if (j->caps & (1 << i))
598 continue;
599 if (prctl(PR_CAPBSET_DROP, i))
600 pdie("prctl(PR_CAPBSET_DROP)");
601 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400602}
603
Will Drewry6ac91122011-10-21 16:38:58 -0500604void API minijail_enter(const struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400605{
606 if (j->flags.pids)
607 die("tried to enter a pid-namespaced jail;"
608 "try minijail_run()?");
Elly Jonescd7a9042011-07-22 13:56:51 -0400609
Elly Jonese1749eb2011-10-07 13:54:59 -0400610 if (j->flags.usergroups && !j->user)
611 die("usergroup inheritance without username");
Elly Jonescd7a9042011-07-22 13:56:51 -0400612
Elly Jonesdd3e8512012-01-23 15:13:38 -0500613 /*
614 * We can't recover from failures if we've dropped privileges partially,
Elly Jonese1749eb2011-10-07 13:54:59 -0400615 * so we don't even try. If any of our operations fail, we abort() the
616 * entire process.
617 */
618 if (j->flags.vfs && unshare(CLONE_NEWNS))
619 pdie("unshare");
Elly Jonescd7a9042011-07-22 13:56:51 -0400620
Elly Jones51a5b6c2011-10-12 19:09:26 -0400621 if (j->flags.chroot && enter_chroot(j))
622 pdie("chroot");
623
Elly Jonese1749eb2011-10-07 13:54:59 -0400624 if (j->flags.readonly && remount_readonly())
625 pdie("remount");
Elly Jonescd7a9042011-07-22 13:56:51 -0400626
Elly Jonese1749eb2011-10-07 13:54:59 -0400627 if (j->flags.caps) {
Elly Jonesdd3e8512012-01-23 15:13:38 -0500628 /*
629 * POSIX capabilities are a bit tricky. If we drop our
Elly Jonese1749eb2011-10-07 13:54:59 -0400630 * capability to change uids, our attempt to use setuid()
631 * below will fail. Hang on to root caps across setuid(), then
632 * lock securebits.
633 */
634 if (prctl(PR_SET_KEEPCAPS, 1))
635 pdie("prctl(PR_SET_KEEPCAPS)");
636 if (prctl
637 (PR_SET_SECUREBITS, SECURE_ALL_BITS | SECURE_ALL_LOCKS))
638 pdie("prctl(PR_SET_SECUREBITS)");
639 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400640
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700641 /*
Elly Jones1c888ae2012-07-31 12:23:47 -0400642 * Set no_new_privs before installing seccomp filter. See
643 * </kernel/seccomp.c> and </kernel/sys.c> in the kernel source tree for
644 * an explanation of the parameters.
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700645 */
646 if (j->flags.no_new_privs) {
647 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
648 pdie("prctl(PR_SET_NO_NEW_PRIVS)");
649 }
650
651 /*
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700652 * If we're logging seccomp filter failures,
653 * install the SIGSYS handler first.
654 */
655 if (j->flags.seccomp_filter && j->flags.log_seccomp_filter) {
656 if (install_sigsys_handler())
657 pdie("install SIGSYS handler");
658 warn("logging seccomp filter failures");
659 }
660
661 /*
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700662 * Install seccomp filter before dropping root and caps.
663 * WARNING: this means that filter policies *must* allow
664 * setgroups()/setresgid()/setresuid() for dropping root and
665 * capget()/capset()/prctl() for dropping caps.
666 */
667 if (j->flags.seccomp_filter) {
668 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, j->filter_prog))
669 pdie("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
670 }
671
Elly Jonese1749eb2011-10-07 13:54:59 -0400672 if (j->flags.usergroups) {
673 if (initgroups(j->user, j->usergid))
674 pdie("initgroups");
675 } else {
676 /* Only attempt to clear supplemental groups if we are changing
677 * users. */
678 if ((j->uid || j->gid) && setgroups(0, NULL))
679 pdie("setgroups");
680 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400681
Elly Jonese1749eb2011-10-07 13:54:59 -0400682 if (j->flags.gid && setresgid(j->gid, j->gid, j->gid))
683 pdie("setresgid");
Elly Jonescd7a9042011-07-22 13:56:51 -0400684
Elly Jonese1749eb2011-10-07 13:54:59 -0400685 if (j->flags.uid && setresuid(j->uid, j->uid, j->uid))
686 pdie("setresuid");
Elly Jonescd7a9042011-07-22 13:56:51 -0400687
Elly Jonese1749eb2011-10-07 13:54:59 -0400688 if (j->flags.caps)
689 drop_caps(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400690
Elly Jonesdd3e8512012-01-23 15:13:38 -0500691 /*
692 * seccomp has to come last since it cuts off all the other
Elly Jonese1749eb2011-10-07 13:54:59 -0400693 * privilege-dropping syscalls :)
694 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400695 if (j->flags.seccomp && prctl(PR_SET_SECCOMP, 1))
696 pdie("prctl(PR_SET_SECCOMP)");
Elly Jonescd7a9042011-07-22 13:56:51 -0400697}
698
Will Drewry6ac91122011-10-21 16:38:58 -0500699/* TODO(wad) will visibility affect this variable? */
Elly Jonescd7a9042011-07-22 13:56:51 -0400700static int init_exitstatus = 0;
701
Will Drewry6ac91122011-10-21 16:38:58 -0500702void init_term(int __attribute__ ((unused)) sig)
Elly Jonese1749eb2011-10-07 13:54:59 -0400703{
704 _exit(init_exitstatus);
Elly Jonescd7a9042011-07-22 13:56:51 -0400705}
706
Will Drewry6ac91122011-10-21 16:38:58 -0500707int init(pid_t rootpid)
Elly Jonese1749eb2011-10-07 13:54:59 -0400708{
709 pid_t pid;
710 int status;
711 /* so that we exit with the right status */
712 signal(SIGTERM, init_term);
713 /* TODO(wad) self jail with seccomp_filters here. */
714 while ((pid = wait(&status)) > 0) {
Elly Jonesdd3e8512012-01-23 15:13:38 -0500715 /*
716 * This loop will only end when either there are no processes
Elly Jonese1749eb2011-10-07 13:54:59 -0400717 * left inside our pid namespace or we get a signal.
718 */
719 if (pid == rootpid)
720 init_exitstatus = status;
721 }
722 if (!WIFEXITED(init_exitstatus))
723 _exit(MINIJAIL_ERR_INIT);
724 _exit(WEXITSTATUS(init_exitstatus));
Elly Jonescd7a9042011-07-22 13:56:51 -0400725}
726
Will Drewry6ac91122011-10-21 16:38:58 -0500727int API minijail_from_fd(int fd, struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400728{
729 size_t sz = 0;
730 size_t bytes = read(fd, &sz, sizeof(sz));
731 char *buf;
732 int r;
733 if (sizeof(sz) != bytes)
734 return -EINVAL;
735 if (sz > USHRT_MAX) /* Arbitrary sanity check */
736 return -E2BIG;
737 buf = malloc(sz);
738 if (!buf)
739 return -ENOMEM;
740 bytes = read(fd, buf, sz);
741 if (bytes != sz) {
742 free(buf);
743 return -EINVAL;
744 }
745 r = minijail_unmarshal(j, buf, sz);
746 free(buf);
747 return r;
Will Drewry2f54b6a2011-09-16 13:45:31 -0500748}
749
Will Drewry6ac91122011-10-21 16:38:58 -0500750int API minijail_to_fd(struct minijail *j, int fd)
Elly Jonese1749eb2011-10-07 13:54:59 -0400751{
752 char *buf;
753 size_t sz = minijail_size(j);
754 ssize_t written;
755 int r;
Elly Jonescd7a9042011-07-22 13:56:51 -0400756
Elly Jonese1749eb2011-10-07 13:54:59 -0400757 if (!sz)
758 return -EINVAL;
759 buf = malloc(sz);
760 r = minijail_marshal(j, buf, sz);
761 if (r) {
762 free(buf);
763 return r;
764 }
765 /* Sends [size][minijail]. */
766 written = write(fd, &sz, sizeof(sz));
767 if (written != sizeof(sz)) {
768 free(buf);
769 return -EFAULT;
770 }
771 written = write(fd, buf, sz);
772 if (written < 0 || (size_t) written != sz) {
773 free(buf);
774 return -EFAULT;
775 }
776 free(buf);
777 return 0;
Will Drewry2f54b6a2011-09-16 13:45:31 -0500778}
Elly Jonescd7a9042011-07-22 13:56:51 -0400779
Will Drewry6ac91122011-10-21 16:38:58 -0500780int setup_preload(void)
Elly Jonese1749eb2011-10-07 13:54:59 -0400781{
782 char *oldenv = getenv(kLdPreloadEnvVar) ? : "";
783 char *newenv = malloc(strlen(oldenv) + 2 + strlen(PRELOADPATH));
784 if (!newenv)
785 return -ENOMEM;
Elly Jonescd7a9042011-07-22 13:56:51 -0400786
Elly Jonese1749eb2011-10-07 13:54:59 -0400787 /* Only insert a separating space if we have something to separate... */
788 sprintf(newenv, "%s%s%s", oldenv, strlen(oldenv) ? " " : "",
789 PRELOADPATH);
Elly Jonescd7a9042011-07-22 13:56:51 -0400790
Elly Jonese1749eb2011-10-07 13:54:59 -0400791 /* setenv() makes a copy of the string we give it */
792 setenv(kLdPreloadEnvVar, newenv, 1);
793 free(newenv);
794 return 0;
Elly Jonescd7a9042011-07-22 13:56:51 -0400795}
796
Will Drewry6ac91122011-10-21 16:38:58 -0500797int setup_pipe(int fds[2])
Elly Jonese1749eb2011-10-07 13:54:59 -0400798{
799 int r = pipe(fds);
800 char fd_buf[11];
801 if (r)
802 return r;
803 r = snprintf(fd_buf, sizeof(fd_buf), "%d", fds[0]);
804 if (r <= 0)
805 return -EINVAL;
806 setenv(kFdEnvVar, fd_buf, 1);
807 return 0;
Will Drewryf89aef52011-09-16 16:48:57 -0500808}
809
Will Drewry6ac91122011-10-21 16:38:58 -0500810int API minijail_run(struct minijail *j, const char *filename,
811 char *const argv[])
Elly Jonese1749eb2011-10-07 13:54:59 -0400812{
Jorge Lucangeli Obes9807d032012-04-17 13:36:00 -0700813 return minijail_run_pid(j, filename, argv, NULL);
814}
815
816int API minijail_run_pid(struct minijail *j, const char *filename,
817 char *const argv[], pid_t *pchild_pid)
818{
Elly Jonese1749eb2011-10-07 13:54:59 -0400819 char *oldenv, *oldenv_copy = NULL;
820 pid_t child_pid;
821 int pipe_fds[2];
822 int ret;
Elly Jonesa05d7bb2012-06-14 14:09:27 -0400823 /* We need to remember this across the minijail_preexec() call. */
824 int pid_namespace = j->flags.pids;
Ben Chan541c7e52011-08-26 14:55:53 -0700825
Elly Jonese1749eb2011-10-07 13:54:59 -0400826 oldenv = getenv(kLdPreloadEnvVar);
827 if (oldenv) {
828 oldenv_copy = strdup(oldenv);
829 if (!oldenv_copy)
830 return -ENOMEM;
831 }
Will Drewryf89aef52011-09-16 16:48:57 -0500832
Elly Jonese1749eb2011-10-07 13:54:59 -0400833 if (setup_preload())
834 return -EFAULT;
Will Drewry2f54b6a2011-09-16 13:45:31 -0500835
Elly Jonesdd3e8512012-01-23 15:13:38 -0500836 /*
837 * Before we fork(2) and execve(2) the child process, we need to open
Elly Jonese1749eb2011-10-07 13:54:59 -0400838 * a pipe(2) to send the minijail configuration over.
839 */
840 if (setup_pipe(pipe_fds))
841 return -EFAULT;
Elly Jonescd7a9042011-07-22 13:56:51 -0400842
Elly Jones761b7412012-06-13 15:49:52 -0400843 /* Use sys_clone() if and only if we're creating a pid namespace.
844 *
845 * tl;dr: WARNING: do not mix pid namespaces and multithreading.
846 *
847 * In multithreaded programs, there are a bunch of locks inside libc,
848 * some of which may be held by other threads at the time that we call
849 * minijail_run_pid(). If we call fork(), glibc does its level best to
850 * ensure that we hold all of these locks before it calls clone()
851 * internally and drop them after clone() returns, but when we call
852 * sys_clone(2) directly, all that gets bypassed and we end up with a
853 * child address space where some of libc's important locks are held by
854 * other threads (which did not get cloned, and hence will never release
855 * those locks). This is okay so long as we call exec() immediately
856 * after, but a bunch of seemingly-innocent libc functions like setenv()
857 * take locks.
858 *
859 * Hence, only call sys_clone() if we need to, in order to get at pid
860 * namespacing. If we follow this path, the child's address space might
861 * have broken locks; you may only call functions that do not acquire
862 * any locks.
863 *
864 * Unfortunately, fork() acquires every lock it can get its hands on, as
865 * previously detailed, so this function is highly likely to deadlock
866 * later on (see "deadlock here") if we're multithreaded.
867 *
868 * We might hack around this by having the clone()d child (init of the
869 * pid namespace) return directly, rather than leaving the clone()d
870 * process hanging around to be init for the new namespace (and having
871 * its fork()ed child return in turn), but that process would be crippled
872 * with its libc locks potentially broken. We might try fork()ing in the
873 * parent before we clone() to ensure that we own all the locks, but
874 * then we have to have the forked child hanging around consuming
875 * resources (and possibly having file descriptors / shared memory
876 * regions / etc attached). We'd need to keep the child around to avoid
877 * having its children get reparented to init.
878 *
879 * TODO(ellyjones): figure out if the "forked child hanging around"
880 * problem is fixable or not. It would be nice if we worked in this
881 * case.
882 */
Elly Jonesa05d7bb2012-06-14 14:09:27 -0400883 if (pid_namespace)
Elly Jones761b7412012-06-13 15:49:52 -0400884 child_pid = syscall(SYS_clone, CLONE_NEWPID | SIGCHLD, NULL);
885 else
886 child_pid = fork();
887
Elly Jonese1749eb2011-10-07 13:54:59 -0400888 if (child_pid < 0) {
889 free(oldenv_copy);
890 return child_pid;
891 }
Will Drewryf89aef52011-09-16 16:48:57 -0500892
Elly Jonese1749eb2011-10-07 13:54:59 -0400893 if (child_pid) {
894 /* Restore parent's LD_PRELOAD. */
895 if (oldenv_copy) {
896 setenv(kLdPreloadEnvVar, oldenv_copy, 1);
897 free(oldenv_copy);
898 } else {
899 unsetenv(kLdPreloadEnvVar);
900 }
901 unsetenv(kFdEnvVar);
902 j->initpid = child_pid;
903 close(pipe_fds[0]); /* read endpoint */
904 ret = minijail_to_fd(j, pipe_fds[1]);
905 close(pipe_fds[1]); /* write endpoint */
906 if (ret) {
907 kill(j->initpid, SIGKILL);
908 die("failed to send marshalled minijail");
909 }
Jorge Lucangeli Obes9807d032012-04-17 13:36:00 -0700910 if (pchild_pid)
911 *pchild_pid = child_pid;
Elly Jonese1749eb2011-10-07 13:54:59 -0400912 return 0;
913 }
914 free(oldenv_copy);
Ben Chan541c7e52011-08-26 14:55:53 -0700915
Elly Jonese1749eb2011-10-07 13:54:59 -0400916 /* Drop everything that cannot be inherited across execve. */
917 minijail_preexec(j);
918 /* Jail this process and its descendants... */
919 minijail_enter(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400920
Elly Jonesa05d7bb2012-06-14 14:09:27 -0400921 if (pid_namespace) {
Elly Jonesdd3e8512012-01-23 15:13:38 -0500922 /*
923 * pid namespace: this process will become init inside the new
Elly Jonese1749eb2011-10-07 13:54:59 -0400924 * namespace, so fork off a child to actually run the program
925 * (we don't want all programs we might exec to have to know
926 * how to be init).
Elly Jones761b7412012-06-13 15:49:52 -0400927 *
928 * If we're multithreaded, we'll probably deadlock here. See
929 * WARNING above.
Elly Jonese1749eb2011-10-07 13:54:59 -0400930 */
931 child_pid = fork();
932 if (child_pid < 0)
933 _exit(child_pid);
934 else if (child_pid > 0)
935 init(child_pid); /* never returns */
936 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400937
Elly Jonesdd3e8512012-01-23 15:13:38 -0500938 /*
939 * If we aren't pid-namespaced:
Elly Jonese1749eb2011-10-07 13:54:59 -0400940 * calling process
941 * -> execve()-ing process
942 * If we are:
943 * calling process
944 * -> init()-ing process
945 * -> execve()-ing process
946 */
947 _exit(execve(filename, argv, environ));
Elly Jonescd7a9042011-07-22 13:56:51 -0400948}
949
Will Drewry6ac91122011-10-21 16:38:58 -0500950int API minijail_kill(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400951{
952 int st;
953 if (kill(j->initpid, SIGTERM))
954 return -errno;
955 if (waitpid(j->initpid, &st, 0) < 0)
956 return -errno;
957 return st;
Elly Jonescd7a9042011-07-22 13:56:51 -0400958}
959
Will Drewry6ac91122011-10-21 16:38:58 -0500960int API minijail_wait(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400961{
962 int st;
963 if (waitpid(j->initpid, &st, 0) < 0)
964 return -errno;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700965 if (!WIFEXITED(st)) {
966 if (WIFSIGNALED(st))
967 warn("child process received signal %d", WTERMSIG(st));
Elly Jonese1749eb2011-10-07 13:54:59 -0400968 return MINIJAIL_ERR_JAIL;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700969 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400970 return WEXITSTATUS(st);
Elly Jonescd7a9042011-07-22 13:56:51 -0400971}
972
Will Drewry6ac91122011-10-21 16:38:58 -0500973void API minijail_destroy(struct minijail *j)
Elly Jonese1749eb2011-10-07 13:54:59 -0400974{
Jorge Lucangeli Obes524c0402012-01-17 11:30:23 -0800975 if (j->flags.seccomp_filter && j->filter_prog) {
976 free(j->filter_prog->filter);
977 free(j->filter_prog);
Elly Jonese1749eb2011-10-07 13:54:59 -0400978 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400979 while (j->bindings_head) {
980 struct binding *b = j->bindings_head;
981 j->bindings_head = j->bindings_head->next;
982 free(b->dest);
983 free(b->src);
984 free(b);
985 }
986 j->bindings_tail = NULL;
Elly Jonese1749eb2011-10-07 13:54:59 -0400987 if (j->user)
988 free(j->user);
Will Drewrybee7ba72011-10-21 20:47:01 -0500989 if (j->chrootdir)
990 free(j->chrootdir);
Elly Jonese1749eb2011-10-07 13:54:59 -0400991 free(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400992}