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