]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/namespace.c
build-sys: add missing makefile symlink
[thirdparty/systemd.git] / src / core / namespace.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
15ae422b
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
15ae422b
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
15ae422b 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
15ae422b
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
07630cea 23#include <sched.h>
15ae422b 24#include <stdio.h>
07630cea
LP
25#include <string.h>
26#include <sys/mount.h>
15ae422b 27#include <sys/stat.h>
07630cea 28#include <unistd.h>
25e870b5 29#include <linux/fs.h>
15ae422b 30
7f112f50 31#include "dev-setup.h"
3ffd4af2 32#include "fd-util.h"
07630cea
LP
33#include "loopback-setup.h"
34#include "missing.h"
35#include "mkdir.h"
3ffd4af2 36#include "namespace.h"
07630cea 37#include "path-util.h"
d7b8eec7 38#include "selinux-util.h"
07630cea
LP
39#include "string-util.h"
40#include "strv.h"
41#include "util.h"
15ae422b 42
c17ec25e 43typedef enum MountMode {
15ae422b
LP
44 /* This is ordered by priority! */
45 INACCESSIBLE,
46 READONLY,
ac0930c8
LP
47 PRIVATE_TMP,
48 PRIVATE_VAR_TMP,
7f112f50 49 PRIVATE_DEV,
a610cc4f 50 PRIVATE_BUS_ENDPOINT,
15ae422b 51 READWRITE
c17ec25e 52} MountMode;
15ae422b 53
c17ec25e 54typedef struct BindMount {
15ae422b 55 const char *path;
c17ec25e 56 MountMode mode;
ac0930c8 57 bool done;
ea92ae33 58 bool ignore;
c17ec25e 59} BindMount;
15ae422b 60
c17ec25e 61static int append_mounts(BindMount **p, char **strv, MountMode mode) {
15ae422b
LP
62 char **i;
63
613b411c
LP
64 assert(p);
65
15ae422b
LP
66 STRV_FOREACH(i, strv) {
67
ea92ae33 68 (*p)->ignore = false;
002b2268 69 (*p)->done = false;
ea92ae33 70
94828d2d 71 if ((mode == INACCESSIBLE || mode == READONLY || mode == READWRITE) && (*i)[0] == '-') {
ea92ae33
MW
72 (*p)->ignore = true;
73 (*i)++;
74 }
75
15ae422b
LP
76 if (!path_is_absolute(*i))
77 return -EINVAL;
78
79 (*p)->path = *i;
80 (*p)->mode = mode;
81 (*p)++;
82 }
83
84 return 0;
85}
86
c17ec25e
MS
87static int mount_path_compare(const void *a, const void *b) {
88 const BindMount *p = a, *q = b;
a0827e2b 89 int d;
15ae422b 90
a0827e2b 91 d = path_compare(p->path, q->path);
15ae422b 92
5a8af538 93 if (d == 0) {
15ae422b
LP
94 /* If the paths are equal, check the mode */
95 if (p->mode < q->mode)
96 return -1;
97
98 if (p->mode > q->mode)
99 return 1;
100
101 return 0;
102 }
103
104 /* If the paths are not equal, then order prefixes first */
a0827e2b 105 return d;
15ae422b
LP
106}
107
c17ec25e
MS
108static void drop_duplicates(BindMount *m, unsigned *n) {
109 BindMount *f, *t, *previous;
15ae422b 110
c17ec25e 111 assert(m);
15ae422b 112 assert(n);
15ae422b 113
c17ec25e 114 for (f = m, t = m, previous = NULL; f < m+*n; f++) {
15ae422b 115
ac0930c8 116 /* The first one wins */
15ae422b
LP
117 if (previous && path_equal(f->path, previous->path))
118 continue;
119
e2d7c1a0 120 *t = *f;
15ae422b 121
15ae422b
LP
122 previous = t;
123
124 t++;
125 }
126
c17ec25e 127 *n = t - m;
15ae422b
LP
128}
129
7f112f50
LP
130static int mount_dev(BindMount *m) {
131 static const char devnodes[] =
132 "/dev/null\0"
133 "/dev/zero\0"
134 "/dev/full\0"
135 "/dev/random\0"
136 "/dev/urandom\0"
137 "/dev/tty\0";
138
2b85f4e1 139 char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
63cc4c31 140 const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
7f112f50
LP
141 _cleanup_umask_ mode_t u;
142 int r;
143
144 assert(m);
145
146 u = umask(0000);
147
2b85f4e1
LP
148 if (!mkdtemp(temporary_mount))
149 return -errno;
150
63c372cb 151 dev = strjoina(temporary_mount, "/dev");
dc751688 152 (void) mkdir(dev, 0755);
2b85f4e1
LP
153 if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
154 r = -errno;
155 goto fail;
156 }
157
63c372cb 158 devpts = strjoina(temporary_mount, "/dev/pts");
dc751688 159 (void) mkdir(devpts, 0755);
2b85f4e1
LP
160 if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
161 r = -errno;
162 goto fail;
163 }
164
63c372cb 165 devptmx = strjoina(temporary_mount, "/dev/ptmx");
3164e3cb
ZJS
166 if (symlink("pts/ptmx", devptmx) < 0) {
167 r = -errno;
168 goto fail;
169 }
e06b6479 170
63c372cb 171 devshm = strjoina(temporary_mount, "/dev/shm");
dc751688 172 (void) mkdir(devshm, 01777);
2b85f4e1
LP
173 r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
174 if (r < 0) {
175 r = -errno;
176 goto fail;
177 }
178
63c372cb 179 devmqueue = strjoina(temporary_mount, "/dev/mqueue");
dc751688 180 (void) mkdir(devmqueue, 0755);
3164e3cb 181 (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
2b85f4e1 182
63c372cb 183 devhugepages = strjoina(temporary_mount, "/dev/hugepages");
dc751688 184 (void) mkdir(devhugepages, 0755);
3164e3cb 185 (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
2b85f4e1 186
63c372cb 187 devlog = strjoina(temporary_mount, "/dev/log");
3164e3cb 188 (void) symlink("/run/systemd/journal/dev-log", devlog);
82d25240 189
7f112f50 190 NULSTR_FOREACH(d, devnodes) {
2b85f4e1
LP
191 _cleanup_free_ char *dn = NULL;
192 struct stat st;
193
194 r = stat(d, &st);
7f112f50 195 if (r < 0) {
2b85f4e1
LP
196
197 if (errno == ENOENT)
198 continue;
199
200 r = -errno;
201 goto fail;
7f112f50
LP
202 }
203
2b85f4e1
LP
204 if (!S_ISBLK(st.st_mode) &&
205 !S_ISCHR(st.st_mode)) {
206 r = -EINVAL;
207 goto fail;
208 }
209
210 if (st.st_rdev == 0)
211 continue;
212
213 dn = strappend(temporary_mount, d);
214 if (!dn) {
215 r = -ENOMEM;
216 goto fail;
217 }
218
ecabcf8b 219 mac_selinux_create_file_prepare(d, st.st_mode);
2b85f4e1 220 r = mknod(dn, st.st_mode, st.st_rdev);
ecabcf8b 221 mac_selinux_create_file_clear();
dd078a1e 222
2b85f4e1
LP
223 if (r < 0) {
224 r = -errno;
225 goto fail;
226 }
7f112f50
LP
227 }
228
03cfe0d5 229 dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
7f112f50 230
ee818b89
AC
231 /* Create the /dev directory if missing. It is more likely to be
232 * missing when the service is started with RootDirectory. This is
233 * consistent with mount units creating the mount points when missing.
234 */
235 (void) mkdir_p_label(m->path, 0755);
236
237 if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
2b85f4e1
LP
238 r = -errno;
239 goto fail;
240 }
7f112f50 241
2b85f4e1
LP
242 rmdir(dev);
243 rmdir(temporary_mount);
7f112f50 244
2b85f4e1 245 return 0;
7f112f50 246
2b85f4e1
LP
247fail:
248 if (devpts)
249 umount(devpts);
7f112f50 250
2b85f4e1
LP
251 if (devshm)
252 umount(devshm);
7f112f50 253
2b85f4e1
LP
254 if (devhugepages)
255 umount(devhugepages);
7f112f50 256
2b85f4e1
LP
257 if (devmqueue)
258 umount(devmqueue);
7f112f50 259
d267c5aa
ZJS
260 umount(dev);
261 rmdir(dev);
2b85f4e1 262 rmdir(temporary_mount);
7f112f50 263
2b85f4e1 264 return r;
7f112f50
LP
265}
266
a610cc4f
DM
267static int mount_kdbus(BindMount *m) {
268
269 char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX";
270 _cleanup_free_ char *basepath = NULL;
271 _cleanup_umask_ mode_t u;
120d578e 272 char *busnode = NULL, *root;
a610cc4f
DM
273 struct stat st;
274 int r;
275
276 assert(m);
277
278 u = umask(0000);
279
4a62c710
MS
280 if (!mkdtemp(temporary_mount))
281 return log_error_errno(errno, "Failed create temp dir: %m");
a610cc4f 282
63c372cb 283 root = strjoina(temporary_mount, "/kdbus");
dc751688 284 (void) mkdir(root, 0755);
a610cc4f
DM
285 if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
286 r = -errno;
287 goto fail;
288 }
289
290 /* create a new /dev/null dev node copy so we have some fodder to
291 * bind-mount the custom endpoint over. */
292 if (stat("/dev/null", &st) < 0) {
76ef789d 293 r = log_error_errno(errno, "Failed to stat /dev/null: %m");
a610cc4f
DM
294 goto fail;
295 }
296
63c372cb 297 busnode = strjoina(root, "/bus");
a610cc4f 298 if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
94c156cd
LP
299 r = log_error_errno(errno, "mknod() for %s failed: %m",
300 busnode);
a610cc4f
DM
301 goto fail;
302 }
303
4543768d 304 r = mount(m->path, busnode, NULL, MS_BIND, NULL);
a610cc4f 305 if (r < 0) {
94c156cd
LP
306 r = log_error_errno(errno, "bind mount of %s failed: %m",
307 m->path);
a610cc4f
DM
308 goto fail;
309 }
310
311 basepath = dirname_malloc(m->path);
312 if (!basepath) {
313 r = -ENOMEM;
314 goto fail;
315 }
316
317 if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
94c156cd
LP
318 r = log_error_errno(errno, "bind mount of %s failed: %m",
319 basepath);
a610cc4f
DM
320 goto fail;
321 }
322
323 rmdir(temporary_mount);
324 return 0;
325
326fail:
327 if (busnode) {
328 umount(busnode);
329 unlink(busnode);
330 }
331
1775f1eb
ZJS
332 umount(root);
333 rmdir(root);
a610cc4f
DM
334 rmdir(temporary_mount);
335
336 return r;
337}
338
ac0930c8 339static int apply_mount(
c17ec25e 340 BindMount *m,
ac0930c8 341 const char *tmp_dir,
c17ec25e 342 const char *var_tmp_dir) {
ac0930c8 343
15ae422b 344 const char *what;
15ae422b 345 int r;
15ae422b 346
c17ec25e 347 assert(m);
15ae422b 348
c17ec25e 349 switch (m->mode) {
15ae422b
LP
350
351 case INACCESSIBLE:
6d313367
LP
352
353 /* First, get rid of everything that is below if there
354 * is anything... Then, overmount it with an
355 * inaccessible directory. */
356 umount_recursive(m->path, 0);
357
c17ec25e 358 what = "/run/systemd/inaccessible";
15ae422b
LP
359 break;
360
361 case READONLY:
15ae422b 362 case READWRITE:
d6797c92
LP
363 /* Nothing to mount here, we just later toggle the
364 * MS_RDONLY bit for the mount point */
365 return 0;
15ae422b 366
ac0930c8
LP
367 case PRIVATE_TMP:
368 what = tmp_dir;
369 break;
370
371 case PRIVATE_VAR_TMP:
372 what = var_tmp_dir;
15ae422b 373 break;
e364ad06 374
d6797c92
LP
375 case PRIVATE_DEV:
376 return mount_dev(m);
377
a610cc4f
DM
378 case PRIVATE_BUS_ENDPOINT:
379 return mount_kdbus(m);
380
e364ad06
LP
381 default:
382 assert_not_reached("Unknown mode");
15ae422b
LP
383 }
384
ac0930c8 385 assert(what);
15ae422b 386
c17ec25e 387 r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL);
ac0930c8 388 if (r >= 0)
c17ec25e 389 log_debug("Successfully mounted %s to %s", what, m->path);
ea92ae33 390 else if (m->ignore && errno == ENOENT)
d6797c92 391 return 0;
15ae422b 392
ac0930c8
LP
393 return r;
394}
15ae422b 395
c17ec25e 396static int make_read_only(BindMount *m) {
ac0930c8 397 int r;
15ae422b 398
c17ec25e 399 assert(m);
ac0930c8 400
d6797c92
LP
401 if (IN_SET(m->mode, INACCESSIBLE, READONLY))
402 r = bind_remount_recursive(m->path, true);
664064d6 403 else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV))
d6797c92
LP
404 r = bind_remount_recursive(m->path, false);
405 else
406 r = 0;
ac0930c8 407
d6797c92
LP
408 if (m->ignore && r == -ENOENT)
409 return 0;
ac0930c8 410
d6797c92 411 return r;
15ae422b
LP
412}
413
613b411c 414int setup_namespace(
ee818b89 415 const char* root_directory,
613b411c
LP
416 char** read_write_dirs,
417 char** read_only_dirs,
418 char** inaccessible_dirs,
a004cb4c
LP
419 const char* tmp_dir,
420 const char* var_tmp_dir,
421 const char* bus_endpoint_path,
7f112f50 422 bool private_dev,
1b8689f9
LP
423 ProtectHome protect_home,
424 ProtectSystem protect_system,
e6547662 425 unsigned long mount_flags) {
15ae422b 426
7ff7394d 427 BindMount *m, *mounts = NULL;
613b411c 428 unsigned n;
c17ec25e 429 int r = 0;
15ae422b 430
613b411c 431 if (mount_flags == 0)
c17ec25e 432 mount_flags = MS_SHARED;
ac0930c8 433
d5a3f0ea
ZJS
434 if (unshare(CLONE_NEWNS) < 0)
435 return -errno;
15ae422b 436
a610cc4f 437 n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path +
613b411c
LP
438 strv_length(read_write_dirs) +
439 strv_length(read_only_dirs) +
7f112f50 440 strv_length(inaccessible_dirs) +
417116f2 441 private_dev +
c8835999 442 (protect_home != PROTECT_HOME_NO ? 3 : 0) +
051be1f7 443 (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) +
1b8689f9 444 (protect_system == PROTECT_SYSTEM_FULL ? 1 : 0);
613b411c
LP
445
446 if (n > 0) {
002b2268 447 m = mounts = (BindMount *) alloca0(n * sizeof(BindMount));
613b411c
LP
448 r = append_mounts(&m, read_write_dirs, READWRITE);
449 if (r < 0)
450 return r;
451
452 r = append_mounts(&m, read_only_dirs, READONLY);
453 if (r < 0)
454 return r;
455
456 r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE);
457 if (r < 0)
7ff7394d
ZJS
458 return r;
459
613b411c 460 if (tmp_dir) {
ee818b89 461 m->path = prefix_roota(root_directory, "/tmp");
7ff7394d
ZJS
462 m->mode = PRIVATE_TMP;
463 m++;
613b411c 464 }
7ff7394d 465
613b411c 466 if (var_tmp_dir) {
ee818b89 467 m->path = prefix_roota(root_directory, "/var/tmp");
7ff7394d
ZJS
468 m->mode = PRIVATE_VAR_TMP;
469 m++;
470 }
ac0930c8 471
7f112f50 472 if (private_dev) {
ee818b89 473 m->path = prefix_roota(root_directory, "/dev");
7f112f50
LP
474 m->mode = PRIVATE_DEV;
475 m++;
476 }
477
a610cc4f 478 if (bus_endpoint_path) {
ee818b89 479 m->path = prefix_roota(root_directory, bus_endpoint_path);
a610cc4f
DM
480 m->mode = PRIVATE_BUS_ENDPOINT;
481 m++;
482 }
483
1b8689f9 484 if (protect_home != PROTECT_HOME_NO) {
ee818b89
AC
485 const char *home_dir, *run_user_dir, *root_dir;
486
487 home_dir = prefix_roota(root_directory, "/home");
488 home_dir = strjoina("-", home_dir);
489 run_user_dir = prefix_roota(root_directory, "/run/user");
490 run_user_dir = strjoina("-", run_user_dir);
491 root_dir = prefix_roota(root_directory, "/root");
492 root_dir = strjoina("-", root_dir);
493
494 r = append_mounts(&m, STRV_MAKE(home_dir, run_user_dir, root_dir),
495 protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
417116f2
LP
496 if (r < 0)
497 return r;
498 }
499
1b8689f9 500 if (protect_system != PROTECT_SYSTEM_NO) {
ee818b89
AC
501 const char *usr_dir, *boot_dir, *etc_dir;
502
d38e01dc 503 usr_dir = prefix_roota(root_directory, "/usr");
ee818b89
AC
504 boot_dir = prefix_roota(root_directory, "/boot");
505 boot_dir = strjoina("-", boot_dir);
506 etc_dir = prefix_roota(root_directory, "/etc");
507
508 r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL
509 ? STRV_MAKE(usr_dir, boot_dir, etc_dir)
510 : STRV_MAKE(usr_dir, boot_dir), READONLY);
417116f2
LP
511 if (r < 0)
512 return r;
513 }
514
7ff7394d 515 assert(mounts + n == m);
ac0930c8 516
7ff7394d
ZJS
517 qsort(mounts, n, sizeof(BindMount), mount_path_compare);
518 drop_duplicates(mounts, &n);
15ae422b
LP
519 }
520
ee818b89 521 if (n > 0 || root_directory) {
c2c13f2d
LP
522 /* Remount / as SLAVE so that nothing now mounted in the namespace
523 shows up in the parent */
524 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
525 return -errno;
ee818b89
AC
526 }
527
528 if (root_directory) {
529 /* Turn directory into bind mount */
530 if (mount(root_directory, root_directory, NULL, MS_BIND|MS_REC, NULL) < 0)
531 return -errno;
532 }
c2c13f2d 533
ee818b89 534 if (n > 0) {
c2c13f2d
LP
535 for (m = mounts; m < mounts + n; ++m) {
536 r = apply_mount(m, tmp_dir, var_tmp_dir);
537 if (r < 0)
538 goto fail;
539 }
15ae422b 540
c2c13f2d
LP
541 for (m = mounts; m < mounts + n; ++m) {
542 r = make_read_only(m);
543 if (r < 0)
544 goto fail;
545 }
15ae422b
LP
546 }
547
ee818b89
AC
548 if (root_directory) {
549 /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
550 r = mount_move_root(root_directory);
551
552 /* at this point, we cannot rollback */
553 if (r < 0)
554 return r;
555 }
556
c2c13f2d
LP
557 /* Remount / as the desired mode. Not that this will not
558 * reestablish propagation from our side to the host, since
559 * what's disconnected is disconnected. */
1f6b4113 560 if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0)
ee818b89
AC
561 /* at this point, we cannot rollback */
562 return -errno;
15ae422b 563
15ae422b
LP
564 return 0;
565
613b411c 566fail:
c2c13f2d
LP
567 if (n > 0) {
568 for (m = mounts; m < mounts + n; ++m)
569 if (m->done)
42b1b990 570 (void) umount2(m->path, MNT_DETACH);
c2c13f2d 571 }
613b411c
LP
572
573 return r;
574}
575
576static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
577 _cleanup_free_ char *x = NULL;
6b46ea73
LP
578 char bid[SD_ID128_STRING_MAX];
579 sd_id128_t boot_id;
580 int r;
613b411c
LP
581
582 assert(id);
583 assert(prefix);
584 assert(path);
585
6b46ea73
LP
586 /* We include the boot id in the directory so that after a
587 * reboot we can easily identify obsolete directories. */
588
589 r = sd_id128_get_boot(&boot_id);
590 if (r < 0)
591 return r;
592
593 x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX", NULL);
613b411c
LP
594 if (!x)
595 return -ENOMEM;
596
597 RUN_WITH_UMASK(0077)
598 if (!mkdtemp(x))
599 return -errno;
600
601 RUN_WITH_UMASK(0000) {
602 char *y;
603
63c372cb 604 y = strjoina(x, "/tmp");
613b411c
LP
605
606 if (mkdir(y, 0777 | S_ISVTX) < 0)
607 return -errno;
c17ec25e 608 }
15ae422b 609
613b411c
LP
610 *path = x;
611 x = NULL;
612
613 return 0;
614}
615
616int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
617 char *a, *b;
618 int r;
619
620 assert(id);
621 assert(tmp_dir);
622 assert(var_tmp_dir);
623
624 r = setup_one_tmp_dir(id, "/tmp", &a);
625 if (r < 0)
626 return r;
627
628 r = setup_one_tmp_dir(id, "/var/tmp", &b);
629 if (r < 0) {
630 char *t;
631
63c372cb 632 t = strjoina(a, "/tmp");
613b411c
LP
633 rmdir(t);
634 rmdir(a);
635
636 free(a);
637 return r;
638 }
639
640 *tmp_dir = a;
641 *var_tmp_dir = b;
642
643 return 0;
644}
645
646int setup_netns(int netns_storage_socket[2]) {
647 _cleanup_close_ int netns = -1;
3ee897d6 648 int r, q;
613b411c
LP
649
650 assert(netns_storage_socket);
651 assert(netns_storage_socket[0] >= 0);
652 assert(netns_storage_socket[1] >= 0);
653
654 /* We use the passed socketpair as a storage buffer for our
76cd584b
LP
655 * namespace reference fd. Whatever process runs this first
656 * shall create a new namespace, all others should just join
657 * it. To serialize that we use a file lock on the socket
658 * pair.
613b411c
LP
659 *
660 * It's a bit crazy, but hey, works great! */
661
662 if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
663 return -errno;
664
3ee897d6
LP
665 netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
666 if (netns == -EAGAIN) {
613b411c
LP
667 /* Nothing stored yet, so let's create a new namespace */
668
669 if (unshare(CLONE_NEWNET) < 0) {
670 r = -errno;
671 goto fail;
672 }
673
674 loopback_setup();
675
676 netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
677 if (netns < 0) {
678 r = -errno;
679 goto fail;
680 }
681
682 r = 1;
613b411c 683
3ee897d6
LP
684 } else if (netns < 0) {
685 r = netns;
686 goto fail;
613b411c 687
3ee897d6
LP
688 } else {
689 /* Yay, found something, so let's join the namespace */
613b411c
LP
690 if (setns(netns, CLONE_NEWNET) < 0) {
691 r = -errno;
692 goto fail;
693 }
694
695 r = 0;
696 }
697
3ee897d6
LP
698 q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
699 if (q < 0) {
700 r = q;
613b411c
LP
701 goto fail;
702 }
703
704fail:
705 lockf(netns_storage_socket[0], F_ULOCK, 0);
15ae422b
LP
706 return r;
707}
417116f2 708
1b8689f9
LP
709static const char *const protect_home_table[_PROTECT_HOME_MAX] = {
710 [PROTECT_HOME_NO] = "no",
711 [PROTECT_HOME_YES] = "yes",
712 [PROTECT_HOME_READ_ONLY] = "read-only",
417116f2
LP
713};
714
1b8689f9
LP
715DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
716
717static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = {
718 [PROTECT_SYSTEM_NO] = "no",
719 [PROTECT_SYSTEM_YES] = "yes",
720 [PROTECT_SYSTEM_FULL] = "full",
721};
722
723DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem);