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