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