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