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