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