]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/namespace.c
man: also mention /run/log/journal in systemd-jouranld.service(8)
[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>
28#include <sys/types.h>
29#include <sched.h>
30#include <sys/syscall.h>
31#include <limits.h>
25e870b5 32#include <linux/fs.h>
15ae422b
LP
33
34#include "strv.h"
35#include "util.h"
9eb977db 36#include "path-util.h"
15ae422b
LP
37#include "namespace.h"
38#include "missing.h"
c17ec25e 39#include "execute.h"
15ae422b 40
c17ec25e 41typedef enum MountMode {
15ae422b
LP
42 /* This is ordered by priority! */
43 INACCESSIBLE,
44 READONLY,
ac0930c8
LP
45 PRIVATE_TMP,
46 PRIVATE_VAR_TMP,
15ae422b 47 READWRITE
c17ec25e 48} MountMode;
15ae422b 49
c17ec25e 50typedef struct BindMount {
15ae422b 51 const char *path;
c17ec25e 52 MountMode mode;
ac0930c8 53 bool done;
c17ec25e 54} BindMount;
15ae422b 55
c17ec25e 56static int append_mounts(BindMount **p, char **strv, MountMode mode) {
15ae422b
LP
57 char **i;
58
59 STRV_FOREACH(i, strv) {
60
61 if (!path_is_absolute(*i))
62 return -EINVAL;
63
64 (*p)->path = *i;
65 (*p)->mode = mode;
66 (*p)++;
67 }
68
69 return 0;
70}
71
c17ec25e
MS
72static int mount_path_compare(const void *a, const void *b) {
73 const BindMount *p = a, *q = b;
15ae422b
LP
74
75 if (path_equal(p->path, q->path)) {
76
77 /* If the paths are equal, check the mode */
78 if (p->mode < q->mode)
79 return -1;
80
81 if (p->mode > q->mode)
82 return 1;
83
84 return 0;
85 }
86
87 /* If the paths are not equal, then order prefixes first */
88 if (path_startswith(p->path, q->path))
89 return 1;
90
91 if (path_startswith(q->path, p->path))
92 return -1;
93
94 return 0;
95}
96
c17ec25e
MS
97static void drop_duplicates(BindMount *m, unsigned *n) {
98 BindMount *f, *t, *previous;
15ae422b 99
c17ec25e 100 assert(m);
15ae422b 101 assert(n);
15ae422b 102
c17ec25e 103 for (f = m, t = m, previous = NULL; f < m+*n; f++) {
15ae422b 104
ac0930c8 105 /* The first one wins */
15ae422b
LP
106 if (previous && path_equal(f->path, previous->path))
107 continue;
108
109 t->path = f->path;
110 t->mode = f->mode;
111
15ae422b
LP
112 previous = t;
113
114 t++;
115 }
116
c17ec25e 117 *n = t - m;
15ae422b
LP
118}
119
ac0930c8 120static int apply_mount(
c17ec25e 121 BindMount *m,
ac0930c8 122 const char *tmp_dir,
c17ec25e 123 const char *var_tmp_dir) {
ac0930c8 124
15ae422b 125 const char *what;
15ae422b 126 int r;
15ae422b 127
c17ec25e 128 assert(m);
15ae422b 129
c17ec25e 130 switch (m->mode) {
15ae422b
LP
131
132 case INACCESSIBLE:
c17ec25e 133 what = "/run/systemd/inaccessible";
15ae422b
LP
134 break;
135
136 case READONLY:
15ae422b 137 case READWRITE:
c17ec25e 138 what = m->path;
15ae422b
LP
139 break;
140
ac0930c8
LP
141 case PRIVATE_TMP:
142 what = tmp_dir;
143 break;
144
145 case PRIVATE_VAR_TMP:
146 what = var_tmp_dir;
15ae422b 147 break;
e364ad06
LP
148
149 default:
150 assert_not_reached("Unknown mode");
15ae422b
LP
151 }
152
ac0930c8 153 assert(what);
15ae422b 154
c17ec25e 155 r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL);
ac0930c8 156 if (r >= 0)
c17ec25e 157 log_debug("Successfully mounted %s to %s", what, m->path);
15ae422b 158
ac0930c8
LP
159 return r;
160}
15ae422b 161
c17ec25e 162static int make_read_only(BindMount *m) {
ac0930c8 163 int r;
15ae422b 164
c17ec25e 165 assert(m);
ac0930c8 166
c17ec25e 167 if (m->mode != INACCESSIBLE && m->mode != READONLY)
ac0930c8
LP
168 return 0;
169
c17ec25e 170 r = mount(NULL, m->path, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL);
ac0930c8
LP
171 if (r < 0)
172 return -errno;
173
174 return 0;
15ae422b
LP
175}
176
c17ec25e
MS
177int setup_tmpdirs(char **tmp_dir,
178 char **var_tmp_dir) {
179 int r = 0;
180 char tmp_dir_template[] = "/tmp/systemd-private-XXXXXX",
181 var_tmp_dir_template[] = "/var/tmp/systemd-private-XXXXXX";
15ae422b 182
c17ec25e
MS
183 assert(tmp_dir);
184 assert(var_tmp_dir);
15ae422b 185
d34cd374 186 r = create_tmp_dir(tmp_dir_template, tmp_dir);
c17ec25e 187 if (r < 0)
d34cd374 188 return r;
15ae422b 189
d34cd374
ZJS
190 r = create_tmp_dir(var_tmp_dir_template, var_tmp_dir);
191 if (r == 0)
192 return 0;
15ae422b 193
d34cd374 194 /* failure */
c17ec25e 195 rmdir(*tmp_dir);
d34cd374 196 rmdir(tmp_dir_template);
c17ec25e
MS
197 free(*tmp_dir);
198 *tmp_dir = NULL;
15ae422b 199
c17ec25e
MS
200 return r;
201}
15ae422b 202
c17ec25e
MS
203int setup_namespace(char** read_write_dirs,
204 char** read_only_dirs,
205 char** inaccessible_dirs,
206 char* tmp_dir,
207 char* var_tmp_dir,
208 bool private_tmp,
209 unsigned mount_flags) {
15ae422b 210
c17ec25e
MS
211 unsigned n = strv_length(read_write_dirs) +
212 strv_length(read_only_dirs) +
213 strv_length(inaccessible_dirs) +
214 (private_tmp ? 2 : 0);
215 BindMount *m, *mounts;
216 int r = 0;
15ae422b 217
c17ec25e
MS
218 if (!mount_flags)
219 mount_flags = MS_SHARED;
ac0930c8 220
d5a3f0ea
ZJS
221 if (unshare(CLONE_NEWNS) < 0)
222 return -errno;
15ae422b 223
c17ec25e
MS
224 m = mounts = (BindMount *) alloca(n * sizeof(BindMount));
225 if ((r = append_mounts(&m, read_write_dirs, READWRITE)) < 0 ||
226 (r = append_mounts(&m, read_only_dirs, READONLY)) < 0 ||
227 (r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE)) < 0)
d5a3f0ea 228 return r;
ac0930c8 229
c17ec25e
MS
230 if (private_tmp) {
231 m->path = "/tmp";
232 m->mode = PRIVATE_TMP;
233 m++;
ac0930c8 234
c17ec25e
MS
235 m->path = "/var/tmp";
236 m->mode = PRIVATE_VAR_TMP;
237 m++;
15ae422b
LP
238 }
239
c17ec25e
MS
240 assert(mounts + n == m);
241
242 qsort(mounts, n, sizeof(BindMount), mount_path_compare);
243 drop_duplicates(mounts, &n);
15ae422b 244
ac0930c8 245 /* Remount / as SLAVE so that nothing now mounted in the namespace
dc4b0200 246 shows up in the parent */
d5a3f0ea
ZJS
247 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
248 return -errno;
15ae422b 249
c17ec25e
MS
250 for (m = mounts; m < mounts + n; ++m) {
251 r = apply_mount(m, tmp_dir, var_tmp_dir);
c1d70f7c 252 if (r < 0)
15ae422b 253 goto undo_mounts;
c1d70f7c 254 }
15ae422b 255
c17ec25e
MS
256 for (m = mounts; m < mounts + n; ++m) {
257 r = make_read_only(m);
ac0930c8
LP
258 if (r < 0)
259 goto undo_mounts;
15ae422b
LP
260 }
261
ac0930c8 262 /* Remount / as the desired mode */
c17ec25e 263 if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
15ae422b
LP
264 r = -errno;
265 goto undo_mounts;
266 }
267
15ae422b
LP
268 return 0;
269
270undo_mounts:
c17ec25e
MS
271 for (m = mounts; m < mounts + n; ++m) {
272 if (m->done)
273 umount2(m->path, MNT_DETACH);
274 }
15ae422b 275
15ae422b
LP
276 return r;
277}