chiark / gitweb /
Use space after a silencing (void)
[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 <sched.h>
29 #include <linux/fs.h>
30
31 #include "strv.h"
32 #include "util.h"
33 #include "path-util.h"
34 #include "missing.h"
35 #include "loopback-setup.h"
36 #include "dev-setup.h"
37 #include "selinux-util.h"
38 #include "namespace.h"
39
40 typedef enum MountMode {
41         /* This is ordered by priority! */
42         INACCESSIBLE,
43         READONLY,
44         PRIVATE_TMP,
45         PRIVATE_VAR_TMP,
46         PRIVATE_DEV,
47         PRIVATE_BUS_ENDPOINT,
48         READWRITE
49 } MountMode;
50
51 typedef struct BindMount {
52         const char *path;
53         MountMode mode;
54         bool done;
55         bool ignore;
56 } BindMount;
57
58 static int append_mounts(BindMount **p, char **strv, MountMode mode) {
59         char **i;
60
61         assert(p);
62
63         STRV_FOREACH(i, strv) {
64
65                 (*p)->ignore = false;
66                 (*p)->done = false;
67
68                 if ((mode == INACCESSIBLE || mode == READONLY || mode == READWRITE) && (*i)[0] == '-') {
69                         (*p)->ignore = true;
70                         (*i)++;
71                 }
72
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
84 static int mount_path_compare(const void *a, const void *b) {
85         const BindMount *p = a, *q = b;
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
109 static void drop_duplicates(BindMount *m, unsigned *n) {
110         BindMount *f, *t, *previous;
111
112         assert(m);
113         assert(n);
114
115         for (f = m, t = m, previous = NULL; f < m+*n; f++) {
116
117                 /* The first one wins */
118                 if (previous && path_equal(f->path, previous->path))
119                         continue;
120
121                 *t = *f;
122
123                 previous = t;
124
125                 t++;
126         }
127
128         *n = t - m;
129 }
130
131 static 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
140         char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
141         const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
142         _cleanup_umask_ mode_t u;
143         int r;
144
145         assert(m);
146
147         u = umask(0000);
148
149         if (!mkdtemp(temporary_mount))
150                 return -errno;
151
152         dev = strjoina(temporary_mount, "/dev");
153         (void) mkdir(dev, 0755);
154         if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
155                 r = -errno;
156                 goto fail;
157         }
158
159         devpts = strjoina(temporary_mount, "/dev/pts");
160         (void) mkdir(devpts, 0755);
161         if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
162                 r = -errno;
163                 goto fail;
164         }
165
166         devptmx = strjoina(temporary_mount, "/dev/ptmx");
167         symlink("pts/ptmx", devptmx);
168
169         devshm = strjoina(temporary_mount, "/dev/shm");
170         (void) mkdir(devshm, 01777);
171         r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
172         if (r < 0) {
173                 r = -errno;
174                 goto fail;
175         }
176
177         devmqueue = strjoina(temporary_mount, "/dev/mqueue");
178         (void) mkdir(devmqueue, 0755);
179         mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
180
181         devhugepages = strjoina(temporary_mount, "/dev/hugepages");
182         (void) mkdir(devhugepages, 0755);
183         mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
184
185         devlog = strjoina(temporary_mount, "/dev/log");
186         symlink("/run/systemd/journal/dev-log", devlog);
187
188         NULSTR_FOREACH(d, devnodes) {
189                 _cleanup_free_ char *dn = NULL;
190                 struct stat st;
191
192                 r = stat(d, &st);
193                 if (r < 0) {
194
195                         if (errno == ENOENT)
196                                 continue;
197
198                         r = -errno;
199                         goto fail;
200                 }
201
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
217                 mac_selinux_create_file_prepare(d, st.st_mode);
218                 r = mknod(dn, st.st_mode, st.st_rdev);
219                 mac_selinux_create_file_clear();
220
221                 if (r < 0) {
222                         r = -errno;
223                         goto fail;
224                 }
225         }
226
227         dev_setup(temporary_mount);
228
229         if (mount(dev, "/dev/", NULL, MS_MOVE, NULL) < 0) {
230                 r = -errno;
231                 goto fail;
232         }
233
234         rmdir(dev);
235         rmdir(temporary_mount);
236
237         return 0;
238
239 fail:
240         if (devpts)
241                 umount(devpts);
242
243         if (devshm)
244                 umount(devshm);
245
246         if (devhugepages)
247                 umount(devhugepages);
248
249         if (devmqueue)
250                 umount(devmqueue);
251
252         umount(dev);
253         rmdir(dev);
254         rmdir(temporary_mount);
255
256         return r;
257 }
258
259 static 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;
264         char *busnode = NULL, *root;
265         struct stat st;
266         int r;
267
268         assert(m);
269
270         u = umask(0000);
271
272         if (!mkdtemp(temporary_mount))
273                 return log_error_errno(errno, "Failed create temp dir: %m");
274
275         root = strjoina(temporary_mount, "/kdbus");
276         (void) mkdir(root, 0755);
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) {
285                 log_error_errno(errno, "Failed to stat /dev/null: %m");
286                 r = -errno;
287                 goto fail;
288         }
289
290         busnode = strjoina(root, "/bus");
291         if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
292                 log_error_errno(errno, "mknod() for %s failed: %m", busnode);
293                 r = -errno;
294                 goto fail;
295         }
296
297         r = mount(m->path, busnode, "bind", MS_BIND, NULL);
298         if (r < 0) {
299                 log_error_errno(errno, "bind mount of %s failed: %m", m->path);
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) {
311                 log_error_errno(errno, "bind mount of %s failed: %m", basepath);
312                 r = -errno;
313                 goto fail;
314         }
315
316         rmdir(temporary_mount);
317         return 0;
318
319 fail:
320         if (busnode) {
321                 umount(busnode);
322                 unlink(busnode);
323         }
324
325         umount(root);
326         rmdir(root);
327         rmdir(temporary_mount);
328
329         return r;
330 }
331
332 static int apply_mount(
333                 BindMount *m,
334                 const char *tmp_dir,
335                 const char *var_tmp_dir) {
336
337         const char *what;
338         int r;
339
340         assert(m);
341
342         switch (m->mode) {
343
344         case INACCESSIBLE:
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
351                 what = "/run/systemd/inaccessible";
352                 break;
353
354         case READONLY:
355         case READWRITE:
356                 /* Nothing to mount here, we just later toggle the
357                  * MS_RDONLY bit for the mount point */
358                 return 0;
359
360         case PRIVATE_TMP:
361                 what = tmp_dir;
362                 break;
363
364         case PRIVATE_VAR_TMP:
365                 what = var_tmp_dir;
366                 break;
367
368         case PRIVATE_DEV:
369                 return mount_dev(m);
370
371         case PRIVATE_BUS_ENDPOINT:
372                 return mount_kdbus(m);
373
374         default:
375                 assert_not_reached("Unknown mode");
376         }
377
378         assert(what);
379
380         r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL);
381         if (r >= 0)
382                 log_debug("Successfully mounted %s to %s", what, m->path);
383         else if (m->ignore && errno == ENOENT)
384                 return 0;
385
386         return r;
387 }
388
389 static int make_read_only(BindMount *m) {
390         int r;
391
392         assert(m);
393
394         if (IN_SET(m->mode, INACCESSIBLE, READONLY))
395                 r = bind_remount_recursive(m->path, true);
396         else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV))
397                 r = bind_remount_recursive(m->path, false);
398         else
399                 r = 0;
400
401         if (m->ignore && r == -ENOENT)
402                 return 0;
403
404         return r;
405 }
406
407 int setup_namespace(
408                 char** read_write_dirs,
409                 char** read_only_dirs,
410                 char** inaccessible_dirs,
411                 const char* tmp_dir,
412                 const char* var_tmp_dir,
413                 const char* bus_endpoint_path,
414                 bool private_dev,
415                 ProtectHome protect_home,
416                 ProtectSystem protect_system,
417                 unsigned long mount_flags) {
418
419         BindMount *m, *mounts = NULL;
420         unsigned n;
421         int r = 0;
422
423         if (mount_flags == 0)
424                 mount_flags = MS_SHARED;
425
426         if (unshare(CLONE_NEWNS) < 0)
427                 return -errno;
428
429         n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path +
430                 strv_length(read_write_dirs) +
431                 strv_length(read_only_dirs) +
432                 strv_length(inaccessible_dirs) +
433                 private_dev +
434                 (protect_home != PROTECT_HOME_NO ? 3 : 0) +
435                 (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) +
436                 (protect_system == PROTECT_SYSTEM_FULL ? 1 : 0);
437
438         if (n > 0) {
439                 m = mounts = (BindMount *) alloca0(n * sizeof(BindMount));
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)
450                         return r;
451
452                 if (tmp_dir) {
453                         m->path = "/tmp";
454                         m->mode = PRIVATE_TMP;
455                         m++;
456                 }
457
458                 if (var_tmp_dir) {
459                         m->path = "/var/tmp";
460                         m->mode = PRIVATE_VAR_TMP;
461                         m++;
462                 }
463
464                 if (private_dev) {
465                         m->path = "/dev";
466                         m->mode = PRIVATE_DEV;
467                         m++;
468                 }
469
470                 if (bus_endpoint_path) {
471                         m->path = bus_endpoint_path;
472                         m->mode = PRIVATE_BUS_ENDPOINT;
473                         m++;
474                 }
475
476                 if (protect_home != PROTECT_HOME_NO) {
477                         r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
478                         if (r < 0)
479                                 return r;
480                 }
481
482                 if (protect_system != PROTECT_SYSTEM_NO) {
483                         r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ? STRV_MAKE("/usr", "-/boot", "/etc") : STRV_MAKE("/usr", "-/boot"), READONLY);
484                         if (r < 0)
485                                 return r;
486                 }
487
488                 assert(mounts + n == m);
489
490                 qsort(mounts, n, sizeof(BindMount), mount_path_compare);
491                 drop_duplicates(mounts, &n);
492         }
493
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                 }
505
506                 for (m = mounts; m < mounts + n; ++m) {
507                         r = make_read_only(m);
508                         if (r < 0)
509                                 goto fail;
510                 }
511         }
512
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. */
516         if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
517                 r = -errno;
518                 goto fail;
519         }
520
521         return 0;
522
523 fail:
524         if (n > 0) {
525                 for (m = mounts; m < mounts + n; ++m)
526                         if (m->done)
527                                 umount2(m->path, MNT_DETACH);
528         }
529
530         return r;
531 }
532
533 static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
534         _cleanup_free_ char *x = NULL;
535         char bid[SD_ID128_STRING_MAX];
536         sd_id128_t boot_id;
537         int r;
538
539         assert(id);
540         assert(prefix);
541         assert(path);
542
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);
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
561                 y = strjoina(x, "/tmp");
562
563                 if (mkdir(y, 0777 | S_ISVTX) < 0)
564                         return -errno;
565         }
566
567         *path = x;
568         x = NULL;
569
570         return 0;
571 }
572
573 int 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
589                 t = strjoina(a, "/tmp");
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
603 int 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
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.
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
683 fail:
684         lockf(netns_storage_socket[0], F_ULOCK, 0);
685
686         return r;
687 }
688
689 static 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",
693 };
694
695 DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
696
697 static 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
703 DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem);