Branch data Line data Source code
1 : : #include <stdio.h>
2 : : #include <unistd.h>
3 : : #include <fcntl.h>
4 : : #include <sys/mman.h>
5 : : #include <sys/types.h>
6 : : #include <dirent.h>
7 : : #include <errno.h>
8 : : #include <sys/stat.h>
9 : : #include <string.h>
10 : : #include <stdlib.h>
11 : : #include <sys/mount.h>
12 : : #include <sys/types.h>
13 : : #include <sys/wait.h>
14 : :
15 : : #include "cr_options.h"
16 : : #include "asm/types.h"
17 : : #include "util.h"
18 : : #include "util-pie.h"
19 : : #include "log.h"
20 : : #include "plugin.h"
21 : : #include "mount.h"
22 : : #include "pstree.h"
23 : : #include "proc_parse.h"
24 : : #include "image.h"
25 : : #include "namespaces.h"
26 : : #include "protobuf.h"
27 : : #include "kerndat.h"
28 : : #include "fs-magic.h"
29 : :
30 : : #include "protobuf/mnt.pb-c.h"
31 : :
32 : : /*
33 : : * Single linked list of mount points get from proc/images
34 : : */
35 : : struct mount_info *mntinfo;
36 : :
37 : : static int open_mountpoint(struct mount_info *pm);
38 : :
39 : : static struct mount_info *mnt_build_tree(struct mount_info *list);
40 : : static int validate_mounts(struct mount_info *info, bool call_plugins);
41 : :
42 : : /* Asolute paths are used on dump and relative paths are used on restore */
43 : : static inline int is_root(char *p)
44 : : {
45 [ + - ][ + - ]: 3774 : return (!strcmp(p, "/"));
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
46 : : }
47 : :
48 : : /* True for the root mount (the topmost one) */
49 : : static inline int is_root_mount(struct mount_info *mi)
50 : : {
51 : : return is_root(mi->mountpoint + 1);
52 : : }
53 : :
54 : : /*
55 : : * True if the mountpoint target is root on its FS.
56 : : *
57 : : * This is used to determine whether we need to postpone
58 : : * mounting. E.g. one can bind mount some subdir from a
59 : : * disk, and in this case we'll have to get the root disk
60 : : * mount first, then bind-mount it. See do_mount_one().
61 : : */
62 : : static inline int fsroot_mounted(struct mount_info *mi)
63 : : {
64 : : return is_root(mi->root);
65 : : }
66 : :
67 : : static int __open_mountpoint(struct mount_info *pm, int mnt_fd);
68 : 52 : int open_mount(unsigned int s_dev)
69 : : {
70 : : struct mount_info *i;
71 : :
72 [ + - ]: 800 : for (i = mntinfo; i != NULL; i = i->next)
73 [ + + ]: 800 : if (s_dev == i->s_dev)
74 : 52 : return __open_mountpoint(i, -1);
75 : :
76 : : return -ENOENT;
77 : : }
78 : :
79 : : static struct mount_info *__lookup_mnt_id(struct mount_info *list, int id)
80 : : {
81 : : struct mount_info *m;
82 : :
83 [ # # ][ # # ]: 1916902 : for (m = list; m != NULL; m = m->next)
[ + + ][ + - ]
84 [ # # ][ # # ]: 1913798 : if (m->mnt_id == id)
[ + + ][ + + ]
85 : : return m;
86 : :
87 : : return NULL;
88 : : }
89 : :
90 : 4 : struct mount_info *lookup_mnt_id(unsigned int id)
91 : : {
92 : 4 : return __lookup_mnt_id(mntinfo, id);
93 : : }
94 : :
95 : 50 : struct mount_info *lookup_mnt_sdev(unsigned int s_dev)
96 : : {
97 : : struct mount_info *m;
98 : :
99 [ + - ]: 748 : for (m = mntinfo; m != NULL; m = m->next)
100 [ + + ]: 748 : if (m->s_dev == s_dev)
101 : : return m;
102 : :
103 : : return NULL;
104 : : }
105 : :
106 : 308 : static struct mount_info *mount_resolve_path(struct mount_info *mntinfo_tree, const char *path)
107 : : {
108 : 308 : size_t pathlen = strlen(path);
109 : : struct mount_info *m = mntinfo_tree, *c;
110 : :
111 : : while (1) {
112 [ + + ]: 1180 : list_for_each_entry(c, &m->children, siblings) {
113 : : size_t n;
114 : :
115 : 872 : n = strlen(c->mountpoint + 1);
116 [ + + ]: 872 : if (n > pathlen)
117 : 246 : continue;
118 : :
119 [ + + ]: 626 : if (strncmp(c->mountpoint + 1, path, min(n, pathlen)))
120 : 408 : continue;
121 [ + + ][ - + ]: 218 : if (n < pathlen && path[n] != '/')
122 : 0 : continue;
123 : :
124 : : m = c;
125 : : break;
126 : : }
127 [ + + ]: 526 : if (&c->siblings == &m->children)
128 : : break;
129 : : }
130 : :
131 : 308 : pr_debug("Path `%s' resolved to `%s' mountpoint\n", path, m->mountpoint);
132 : 308 : return m;
133 : : }
134 : :
135 : 306 : dev_t phys_stat_resolve_dev(struct mount_info *tree,
136 : : dev_t st_dev, const char *path)
137 : : {
138 : : struct mount_info *m;
139 : :
140 : 306 : m = mount_resolve_path(tree, path);
141 : : /*
142 : : * BTRFS returns subvolume dev-id instead of
143 : : * superblock dev-id, in such case return device
144 : : * obtained from mountinfo (ie subvolume0).
145 : : */
146 : 612 : return strcmp(m->fstype->name, "btrfs") ?
147 [ + - ]: 306 : MKKDEV(MAJOR(st_dev), MINOR(st_dev)) : m->s_dev;
148 : : }
149 : :
150 : 18825 : bool phys_stat_dev_match(struct mount_info *tree, dev_t st_dev,
151 : : dev_t phys_dev, const char *path)
152 : : {
153 [ - + ]: 18825 : if (st_dev == kdev_to_odev(phys_dev))
154 : : return true;
155 : :
156 : 0 : return phys_dev == phys_stat_resolve_dev(tree, st_dev, path);
157 : : }
158 : :
159 : : /*
160 : : * Comparer two mounts. Return true if only mount points are differ.
161 : : * Don't care about root and mountpoints, if bind is true.
162 : : */
163 : 1063186 : static bool mounts_equal(struct mount_info* mi, struct mount_info *c, bool bind)
164 : : {
165 [ + + ][ + - ]: 1063186 : if (mi->s_dev != c->s_dev ||
166 [ + - ]: 344 : c->fstype != mi->fstype ||
167 [ + - ]: 344 : strcmp(c->source, mi->source) ||
168 : 344 : strcmp(c->options, mi->options))
169 : : return false;
170 : :
171 [ - + ]: 344 : if (bind)
172 : : return true;
173 : :
174 [ # # ]: 0 : if (strcmp(c->root, mi->root))
175 : : return false;
176 [ # # ]: 0 : if (strcmp(basename(c->mountpoint), basename(mi->mountpoint)))
177 : : return false;
178 : 0 : return true;
179 : : }
180 : :
181 : 3104 : static struct mount_info *mnt_build_ids_tree(struct mount_info *list)
182 : : {
183 : 3104 : struct mount_info *m, *root = NULL;
184 : :
185 : : /*
186 : : * Just resolve the mnt_id:parent_mnt_id relations
187 : : */
188 : :
189 : 3104 : pr_debug("\tBuilding plain mount tree\n");
190 [ + + ]: 76116 : for (m = list; m != NULL; m = m->next) {
191 : : struct mount_info *p;
192 : :
193 : 73012 : pr_debug("\t\tWorking on %d->%d\n", m->mnt_id, m->parent_mnt_id);
194 : 73012 : p = __lookup_mnt_id(list, m->parent_mnt_id);
195 [ + + ]: 73012 : if (!p) {
196 : : /* This should be / */
197 [ + - ][ + - ]: 6208 : if (root == NULL && is_root_mount(m)) {
198 : : root = m;
199 : 3104 : continue;
200 : : }
201 : :
202 [ # # ]: 0 : pr_err("Mountpoint %d w/o parent %d found @%s (root %s)\n",
203 : : m->mnt_id, m->parent_mnt_id, m->mountpoint,
204 : : root ? "found" : "not found");
205 [ # # ][ # # ]: 0 : if (root && m->is_ns_root) {
206 [ # # ][ # # ]: 0 : if (!mounts_equal(root, m, true) ||
207 : 0 : strcmp(root->root, m->root)) {
208 : 0 : pr_err("Nested mount namespaces with different roots are not supported yet");
209 : 0 : return NULL;
210 : : }
211 : :
212 : : /*
213 : : * A root of a sub mount namespace is
214 : : * mounted in a temporary directory in the
215 : : * root mount namespace, so its parent is
216 : : * the main root.
217 : : */
218 : : p = root;
219 : : } else
220 : : return NULL;
221 : : }
222 : :
223 : 69908 : m->parent = p;
224 : 69908 : list_add_tail(&m->siblings, &p->children);
225 : : }
226 : :
227 [ - + ]: 3104 : if (!root) {
228 : 0 : pr_err("No root found for tree\n");
229 : 0 : return NULL;
230 : : }
231 : :
232 : : return root;
233 : : }
234 : :
235 : : static int mnt_depth(struct mount_info *m)
236 : : {
237 : : int depth = 0;
238 : : char *c;
239 : :
240 [ + + ][ + + ]: 2312560 : for (c = m->mountpoint; *c != '\0'; c++)
241 [ + + ][ + + ]: 2186816 : if (*c == '/')
242 : 371936 : depth++;
243 : :
244 : : return depth;
245 : : }
246 : :
247 : 73012 : static void mnt_resort_siblings(struct mount_info *tree)
248 : : {
249 : 125744 : struct mount_info *m, *p;
250 : 73012 : LIST_HEAD(list);
251 : :
252 : : /*
253 : : * Put siblings of each node in an order they can be (u)mounted
254 : : * I.e. if we have mounts on foo/bar/, foo/bar/foobar/ and foo/
255 : : * we should put them in the foo/bar/foobar/, foo/bar/, foo/ order.
256 : : * Otherwise we will not be able to (u)mount them in a sequence.
257 : : *
258 : : * Funny, but all we need for this is to sort them in the descending
259 : : * order of the amount of /-s in a path =)
260 : : *
261 : : * Use stupid insertion sort here, we're not expecting mount trees
262 : : * to contain hundreds (or more) elements.
263 : : */
264 : :
265 : 73012 : pr_info("\tResorting siblings on %d\n", tree->mnt_id);
266 [ + + ]: 142920 : while (!list_empty(&tree->children)) {
267 : : int depth;
268 : :
269 : 69908 : m = list_first_entry(&tree->children, struct mount_info, siblings);
270 : : list_del(&m->siblings);
271 : :
272 : : depth = mnt_depth(m);
273 [ + + ]: 77566 : list_for_each_entry(p, &list, siblings)
274 [ + + ]: 55836 : if (mnt_depth(p) <= depth)
275 : : break;
276 : :
277 : 69908 : list_add(&m->siblings, &p->siblings);
278 : 69908 : mnt_resort_siblings(m);
279 : : }
280 : :
281 : : list_splice(&list, &tree->children);
282 : 73012 : }
283 : :
284 : 73012 : static void mnt_tree_show(struct mount_info *tree, int off)
285 : : {
286 : : struct mount_info *m;
287 : :
288 : 73012 : pr_info("%*s[%s](%d->%d)\n", off, "",
289 : : tree->mountpoint, tree->mnt_id, tree->parent_mnt_id);
290 : :
291 [ + + ]: 142920 : list_for_each_entry(m, &tree->children, siblings)
292 : 69908 : mnt_tree_show(m, off + 1);
293 : :
294 : 73012 : pr_info("%*s<--\n", off, "");
295 : 73012 : }
296 : :
297 : 212 : static int validate_mounts(struct mount_info *info, bool call_plugins)
298 : : {
299 : 436 : struct mount_info *m, *t;
300 : :
301 [ + + ]: 858 : for (m = info; m; m = m->next) {
302 [ + + ][ - + ]: 646 : if (m->parent && m->parent->shared_id) {
303 : : struct mount_info *ct;
304 [ # # ]: 0 : if (list_empty(&m->parent->mnt_share))
305 : 0 : continue;
306 : : t = list_first_entry(&m->parent->mnt_share, struct mount_info, mnt_share);
307 : :
308 [ # # ]: 0 : list_for_each_entry(ct, &t->children, siblings) {
309 [ # # ]: 0 : if (mounts_equal(m, ct, false))
310 : : break;
311 : : }
312 [ # # ]: 0 : if (&ct->siblings == &t->children) {
313 : 0 : pr_err("Two shared mounts %d, %d have different sets of children\n",
314 : : m->parent->mnt_id, t->mnt_id);
315 : 0 : pr_err("%d:%s doesn't have a proper point for %d:%s\n",
316 : : t->mnt_id, t->mountpoint,
317 : : m->mnt_id, m->mountpoint);
318 : 0 : return -1;
319 : : }
320 : : }
321 : :
322 [ + + ][ + + ]: 1080 : if (m->parent && !fsroot_mounted(m)) {
323 [ + - ]: 2 : list_for_each_entry(t, &m->mnt_bind, mnt_bind) {
324 [ + - ][ - + ]: 2 : if (fsroot_mounted(t) || t->parent == NULL)
325 : : break;
326 : : }
327 [ - + ]: 2 : if (&t->mnt_bind == &m->mnt_bind) {
328 : : int ret;
329 : :
330 [ # # ]: 0 : if (call_plugins) {
331 : 0 : ret = cr_plugin_dump_ext_mount(m->mountpoint + 1, m->mnt_id);
332 [ # # ]: 0 : if (ret == 0)
333 : 0 : m->need_plugin = true;
334 [ # # ]: 0 : } else if (m->need_plugin)
335 : : /* plugin should take care of this one */
336 : : ret = 0;
337 : : else
338 : : ret = -ENOTSUP;
339 [ # # ]: 0 : if (ret < 0) {
340 [ # # ]: 0 : if (ret == -ENOTSUP)
341 : 0 : pr_err("%d:%s doesn't have a proper root mount\n",
342 : : m->mnt_id, m->mountpoint);
343 : : return -1;
344 : : }
345 : : }
346 : : }
347 : :
348 [ + + ]: 646 : if (m->parent == NULL)
349 : 212 : continue;
350 : :
351 [ + + ]: 1316 : list_for_each_entry(t, &m->parent->children, siblings) {
352 : : int tlen, mlen;
353 : :
354 [ + + ]: 882 : if (m == t)
355 : 434 : continue;
356 : :
357 : 448 : tlen = strlen(t->mountpoint);
358 : 448 : mlen = strlen(m->mountpoint);
359 [ + + ]: 448 : if (mlen < tlen)
360 : 224 : continue;
361 [ + - ]: 224 : if (strncmp(t->mountpoint, m->mountpoint, tlen))
362 : 224 : continue;
363 [ # # ][ # # ]: 0 : if (mlen > tlen && m->mountpoint[tlen] != '/')
364 : 0 : continue;
365 : 0 : pr_err("%d:%s is overmounted\n", m->mnt_id, m->mountpoint);
366 : 0 : return -1;
367 : : }
368 : : }
369 : :
370 : : return 0;
371 : : }
372 : :
373 : 3104 : static int collect_shared(struct mount_info *info)
374 : : {
375 : : struct mount_info *m, *t;
376 : :
377 : : /*
378 : : * If we have a shared mounts, both master
379 : : * slave targets are to be present in mount
380 : : * list, otherwise we can't be sure if we can
381 : : * recreate the scheme later on restore.
382 : : */
383 [ + + ]: 76116 : for (m = info; m; m = m->next) {
384 : : bool need_share, need_master;
385 : :
386 [ - + ][ # # ]: 73012 : need_share = m->shared_id && list_empty(&m->mnt_share);
387 : 73012 : need_master = m->master_id;
388 : :
389 [ + - ][ - + ]: 73012 : for (t = info; t && (need_share || need_master); t = t->next) {
390 [ # # ]: 0 : if (t == m)
391 : 0 : continue;
392 [ # # ][ # # ]: 0 : if (need_master && t->shared_id == m->master_id) {
393 : 0 : pr_debug("The mount %d is slave for %d\n", m->mnt_id, t->mnt_id);
394 : 0 : list_add(&m->mnt_slave, &t->mnt_slave_list);
395 : 0 : m->mnt_master = t;
396 : : need_master = false;
397 : : }
398 : :
399 : : /* Collect all mounts from this group */
400 [ # # ][ # # ]: 0 : if (need_share && t->shared_id == m->shared_id) {
401 : 0 : pr_debug("Mount %d is shared with %d group %d\n",
402 : : m->mnt_id, t->mnt_id, m->shared_id);
403 : 0 : list_add(&t->mnt_share, &m->mnt_share);
404 : : }
405 : : }
406 : :
407 [ - + ][ # # ]: 73012 : if (need_master && m->parent) {
408 : 0 : pr_err("Mount %d (master_id: %d shared_id: %d) "
409 : : "has unreachable sharing\n", m->mnt_id,
410 : : m->master_id, m->shared_id);
411 : 0 : return -1;
412 : : }
413 : :
414 : : /* Search bind-mounts */
415 [ + + ]: 73012 : if (list_empty(&m->mnt_bind)) {
416 : : /*
417 : : * A first mounted point will be set up as a source point
418 : : * for others. Look at propagate_mount()
419 : : */
420 [ + + ]: 1135854 : for (t = m->next; t; t = t->next) {
421 [ + + ]: 1063186 : if (mounts_equal(m, t, true))
422 : 344 : list_add(&t->mnt_bind, &m->mnt_bind);
423 : : }
424 : : }
425 : : }
426 : :
427 : : return 0;
428 : : }
429 : :
430 : 3104 : static struct mount_info *mnt_build_tree(struct mount_info *list)
431 : : {
432 : : struct mount_info *tree;
433 : :
434 : : /*
435 : : * Organize them in a sequence in which they can be mounted/umounted.
436 : : */
437 : :
438 : 3104 : pr_info("Building mountpoints tree\n");
439 : 3104 : tree = mnt_build_ids_tree(list);
440 [ + - ]: 3104 : if (!tree)
441 : : return NULL;
442 : :
443 : 3104 : mnt_resort_siblings(tree);
444 [ + - ]: 3104 : if (collect_shared(list))
445 : : return NULL;
446 : 3104 : pr_info("Done:\n");
447 : 3104 : mnt_tree_show(tree, 0);
448 : 3104 : return tree;
449 : : }
450 : :
451 : : /*
452 : : * mnt_fd is a file descriptor on the mountpoint, which is closed in an error case.
453 : : * If mnt_fd is -1, the mountpoint will be opened by this function.
454 : : */
455 : 266 : static int __open_mountpoint(struct mount_info *pm, int mnt_fd)
456 : : {
457 : : dev_t dev;
458 : : struct stat st;
459 : : int ret;
460 : :
461 [ + + ]: 266 : if (mnt_fd == -1) {
462 : : int mntns_root;
463 : :
464 : 264 : mntns_root = mntns_collect_root(pm->nsid->pid);
465 [ + - ]: 264 : if (mntns_root < 0)
466 : : return -1;
467 : :
468 : 264 : mnt_fd = openat(mntns_root, pm->mountpoint, O_RDONLY);
469 [ - + ]: 264 : if (mnt_fd < 0) {
470 : 0 : pr_perror("Can't open %s", pm->mountpoint);
471 : 0 : return -1;
472 : : }
473 : : }
474 : :
475 : : ret = fstat(mnt_fd, &st);
476 [ - + ]: 266 : if (ret < 0) {
477 : 0 : pr_perror("fstat(%s) failed", pm->mountpoint);
478 : 0 : goto err;
479 : : }
480 : :
481 : 266 : dev = phys_stat_resolve_dev(pm->nsid->mnt.mntinfo_tree, st.st_dev, pm->mountpoint + 1);
482 [ - + ]: 266 : if (dev != pm->s_dev) {
483 : 0 : pr_err("The file system %#x (%#x) %s %s is inaccessible\n",
484 : : pm->s_dev, (int)dev, pm->fstype->name, pm->mountpoint);
485 : 0 : goto err;
486 : : }
487 : :
488 : : return mnt_fd;
489 : : err:
490 : 0 : close(mnt_fd);
491 : 0 : return -1;
492 : : }
493 : :
494 : 214 : static int open_mountpoint(struct mount_info *pm)
495 : : {
496 : 214 : int fd = -1, ns_old = -1;
497 : 214 : char mnt_path[] = "/tmp/cr-tmpfs.XXXXXX";
498 : :
499 : : /*
500 : : * If a mount doesn't have children, we can open a mount point,
501 : : * otherwise we need to create a "private" copy.
502 : : */
503 [ + + ]: 214 : if (list_empty(&pm->children))
504 : 212 : return __open_mountpoint(pm, -1);
505 : :
506 : 2 : pr_info("Something is mounted on top of %s\n", pm->mountpoint);
507 : :
508 : : /*
509 : : * To create a "private" copy, the target mount is bind-mounted
510 : : * in a temporary place w/o MS_REC (non-recursively).
511 : : * A mount point can't be bind-mounted in criu's namespace, it will be
512 : : * mounted in a target namespace. The sequence of actions is
513 : : * mkdtemp, setns(tgt), mount, open, detach, setns(old).
514 : : */
515 : :
516 [ + - ]: 2 : if (switch_ns(root_item->pid.real, &mnt_ns_desc, &ns_old) < 0)
517 : : return -1;
518 : :
519 [ - + ]: 2 : if (mkdtemp(mnt_path) == NULL) {
520 : 0 : pr_perror("Can't create a temporary directory");
521 : 0 : goto out;
522 : : }
523 : :
524 [ - + ]: 2 : if (mount(pm->mountpoint, mnt_path, NULL, MS_BIND, NULL)) {
525 : 0 : pr_perror("Can't bind-mount %d:%s to %s",
526 : : pm->mnt_id, pm->mountpoint, mnt_path);
527 : 0 : rmdir(mnt_path);
528 : 0 : goto out;
529 : : }
530 : :
531 : 2 : fd = open_detach_mount(mnt_path);
532 [ + - ]: 2 : if (fd < 0)
533 : : goto out;
534 : :
535 [ - + ]: 2 : if (restore_ns(ns_old, &mnt_ns_desc)) {
536 : 0 : ns_old = -1;
537 : 0 : goto out;
538 : : }
539 : :
540 : 2 : return __open_mountpoint(pm, fd);;
541 : : out:
542 [ # # ]: 0 : if (ns_old >= 0)
543 : 0 : restore_ns(ns_old, &mnt_ns_desc);
544 : 0 : close_safe(&fd);
545 : 0 : return -1;
546 : : }
547 : :
548 : : /* Is it mounted w or w/o the newinstance option */
549 : 210 : static int devpts_dump(struct mount_info *pm)
550 : : {
551 : : static const char newinstance[] = ",newinstance";
552 : : struct stat *host_st;
553 : : struct stat st;
554 : : int fdir;
555 : : char *buf;
556 : : int len;
557 : :
558 : 210 : host_st = kerndat_get_devpts_stat();
559 [ + - ]: 210 : if (host_st == NULL)
560 : : return -1;
561 : :
562 : 210 : fdir = open_mountpoint(pm);
563 [ + - ]: 210 : if (fdir < 0)
564 : : return -1;
565 : :
566 [ - + ]: 210 : if (fstat(fdir, &st)) {
567 : 0 : pr_perror("Unable to statfs %d:%s",
568 : : pm->mnt_id, pm->mountpoint);
569 : 0 : close(fdir);
570 : 0 : return -1;
571 : : }
572 : 210 : close(fdir);
573 : :
574 [ + - ]: 210 : if (host_st->st_dev == st.st_dev)
575 : : return 0;
576 : :
577 : 210 : len = strlen(pm->options);
578 [ - + ]: 210 : buf = xrealloc(pm->options, len + sizeof(newinstance));
579 [ + - ]: 210 : if (buf == NULL)
580 : : return -1;
581 : : memcpy(buf, newinstance, sizeof(newinstance));
582 : :
583 : 210 : pm->options = buf;
584 : :
585 : 210 : return 0;
586 : : }
587 : :
588 : 4 : static int tmpfs_dump(struct mount_info *pm)
589 : : {
590 : : int ret = -1;
591 : : char tmpfs_path[PSFDS];
592 : 4 : int fd = -1, fd_img = -1;
593 : :
594 : 4 : fd = open_mountpoint(pm);
595 [ + - ]: 4 : if (fd < 0)
596 : : return -1;
597 : :
598 [ - + ]: 4 : if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC) == -1) {
599 : 0 : pr_perror("Can not drop FD_CLOEXEC");
600 : 0 : goto out;
601 : : }
602 : :
603 : 4 : fd_img = open_image(CR_FD_TMPFS_IMG, O_DUMP, pm->mnt_id);
604 [ + - ]: 4 : if (fd_img < 0)
605 : : goto out;
606 : :
607 : 4 : sprintf(tmpfs_path, "/proc/self/fd/%d", fd);
608 : :
609 : 4 : ret = cr_system(-1, fd_img, -1, "tar", (char *[])
610 : 4 : { "tar", "--create",
611 : : "--gzip",
612 : : "--one-file-system",
613 : : "--check-links",
614 : : "--preserve-permissions",
615 : : "--sparse",
616 : : "--numeric-owner",
617 : : "--directory", tmpfs_path, ".", NULL });
618 : :
619 [ - + ]: 4 : if (ret)
620 : 0 : pr_err("Can't dump tmpfs content\n");
621 : :
622 : : out:
623 : 4 : close_safe(&fd_img);
624 : 4 : close_safe(&fd);
625 : 4 : return ret;
626 : : }
627 : :
628 : 4 : static int tmpfs_restore(struct mount_info *pm)
629 : : {
630 : : int ret;
631 : : int fd_img;
632 : :
633 : 4 : fd_img = open_image(CR_FD_TMPFS_IMG, O_RSTR, pm->mnt_id);
634 [ + - ]: 4 : if (fd_img < 0)
635 : : return -1;
636 : :
637 : 4 : ret = cr_system(fd_img, -1, -1, "tar",
638 : 8 : (char *[]) {"tar", "--extract", "--gzip",
639 : 4 : "--directory", pm->mountpoint, NULL});
640 : 2 : close(fd_img);
641 : :
642 [ - + ]: 2 : if (ret) {
643 : 0 : pr_err("Can't restore tmpfs content\n");
644 : 0 : return -1;
645 : : }
646 : :
647 : : return 0;
648 : : }
649 : :
650 : 0 : static int binfmt_misc_dump(struct mount_info *pm)
651 : : {
652 : : int fd, ret = -1;
653 : : struct dirent *de;
654 : : DIR *fdir = NULL;
655 : :
656 : 0 : fd = open_mountpoint(pm);
657 [ # # ]: 0 : if (fd < 0)
658 : : return -1;
659 : :
660 : 0 : fdir = fdopendir(fd);
661 [ # # ]: 0 : if (fdir == NULL) {
662 : 0 : close(fd);
663 : 0 : return -1;
664 : : }
665 : :
666 [ # # ]: 0 : while ((de = readdir(fdir))) {
667 [ # # ]: 0 : if (dir_dots(de))
668 : 0 : continue;
669 [ # # ]: 0 : if (!strcmp(de->d_name, "register"))
670 : 0 : continue;
671 [ # # ]: 0 : if (!strcmp(de->d_name, "status"))
672 : 0 : continue;
673 : :
674 : 0 : pr_err("binfmt_misc isn't empty: %s\n", de->d_name);
675 : 0 : goto out;
676 : : }
677 : :
678 : : ret = 0;
679 : : out:
680 : 0 : closedir(fdir);
681 : 0 : return ret;
682 : : }
683 : :
684 : : static struct fstype fstypes[] = {
685 : : {
686 : : .name = "unsupported",
687 : : .code = FSTYPE__UNSUPPORTED,
688 : : }, {
689 : : .name = "proc",
690 : : .code = FSTYPE__PROC,
691 : : }, {
692 : : .name = "sysfs",
693 : : .code = FSTYPE__SYSFS,
694 : : }, {
695 : : .name = "devtmpfs",
696 : : .code = FSTYPE__DEVTMPFS,
697 : : }, {
698 : : .name = "binfmt_misc",
699 : : .code = FSTYPE__BINFMT_MISC,
700 : : .dump = binfmt_misc_dump,
701 : : }, {
702 : : .name = "tmpfs",
703 : : .code = FSTYPE__TMPFS,
704 : : .dump = tmpfs_dump,
705 : : .restore = tmpfs_restore,
706 : : }, {
707 : : .name = "devpts",
708 : : .dump = devpts_dump,
709 : : .code = FSTYPE__DEVPTS,
710 : : }, {
711 : : .name = "simfs",
712 : : .code = FSTYPE__SIMFS,
713 : : }, {
714 : : .name = "btrfs",
715 : : .code = FSTYPE__UNSUPPORTED,
716 : : }
717 : : };
718 : :
719 : 73002 : struct fstype *find_fstype_by_name(char *fst)
720 : : {
721 : : int i;
722 : :
723 : : /*
724 : : * This fn is required for two things.
725 : : * 1st -- to check supported filesystems (as just mounting
726 : : * anything is wrong, almost every fs has its own features)
727 : : * 2nd -- save some space in the image (since we scan all
728 : : * names anyway)
729 : : */
730 : :
731 [ + + ]: 612140 : for (i = 0; i < ARRAY_SIZE(fstypes); i++)
732 [ + + ]: 563454 : if (!strcmp(fstypes[i].name, fst))
733 : 24316 : return fstypes + i;
734 : :
735 : : return &fstypes[0];
736 : : }
737 : :
738 : : static struct fstype *decode_fstype(u32 fst)
739 : : {
740 : : int i;
741 : :
742 [ + + ]: 10 : if (fst == FSTYPE__UNSUPPORTED)
743 : : goto uns;
744 : :
745 [ + - ]: 42 : for (i = 0; i < ARRAY_SIZE(fstypes); i++)
746 [ + + ]: 42 : if (fstypes[i].code == fst)
747 : 8 : return fstypes + i;
748 : : uns:
749 : : return &fstypes[0];
750 : : }
751 : :
752 : 636 : static int dump_one_mountpoint(struct mount_info *pm, int fd)
753 : : {
754 : 636 : MntEntry me = MNT_ENTRY__INIT;
755 : :
756 : 636 : pr_info("\t%d: %x:%s @ %s\n", pm->mnt_id, pm->s_dev,
757 : : pm->root, pm->mountpoint);
758 : :
759 : 636 : me.fstype = pm->fstype->code;
760 [ + + ][ + + ]: 848 : if ((me.fstype == FSTYPE__UNSUPPORTED) && !is_root_mount(pm)) {
761 : : struct mount_info *t;
762 : :
763 : : /* Is it a bind-mount of the root mount */
764 [ + - ]: 2 : list_for_each_entry(t, &pm->mnt_bind, mnt_bind)
765 [ - + ]: 2 : if (t->parent == NULL)
766 : : break;
767 : :
768 [ + - ][ - + ]: 2 : if (&t->mnt_bind == &pm->mnt_bind ||
769 : 2 : strlen(t->source) > strlen(pm->source)) {
770 : 0 : pr_err("FS mnt %s dev %#x root %s unsupported\n",
771 : : pm->mountpoint, pm->s_dev, pm->root);
772 : 0 : return -1;
773 : : }
774 : : }
775 : :
776 [ + - ][ + + ]: 636 : if (!pm->need_plugin && pm->fstype->dump && pm->fstype->dump(pm))
[ + - ]
777 : : return -1;
778 : :
779 : 636 : me.mnt_id = pm->mnt_id;
780 : 636 : me.root_dev = pm->s_dev;
781 : 636 : me.parent_mnt_id = pm->parent_mnt_id;
782 : 636 : me.flags = pm->flags;
783 : 636 : me.root = pm->root;
784 : 636 : me.mountpoint = pm->mountpoint + 1;
785 : 636 : me.source = pm->source;
786 : 636 : me.options = pm->options;
787 : 636 : me.shared_id = pm->shared_id;
788 : 636 : me.has_shared_id = true;
789 : 636 : me.master_id = pm->master_id;
790 : 636 : me.has_master_id = true;
791 [ - + ]: 636 : if (pm->need_plugin) {
792 : 0 : me.has_with_plugin = true;
793 : 0 : me.with_plugin = true;
794 : : }
795 : :
796 [ + - ]: 636 : if (pb_write_one(fd, &me, PB_MNT))
797 : : return -1;
798 : :
799 : 636 : return 0;
800 : : }
801 : :
802 : 3102 : struct mount_info *collect_mntinfo(struct ns_id *ns)
803 : : {
804 : : struct mount_info *pm, *p;
805 : :
806 [ + - ]: 3102 : if (mntns_collect_root(ns->pid) < 0)
807 : : return NULL;
808 : :
809 : 3102 : pm = parse_mountinfo(ns->pid, ns);
810 [ - + ]: 3102 : if (!pm) {
811 : 0 : pr_err("Can't parse %d's mountinfo\n", ns->pid);
812 : 0 : return NULL;
813 : : }
814 : :
815 : 3102 : ns->mnt.mntinfo_tree = mnt_build_tree(pm);
816 [ - + ]: 3102 : if (ns->mnt.mntinfo_tree == NULL)
817 : : goto err;
818 : :
819 : : return pm;
820 : : err:
821 [ # # ]: 0 : while (pm) {
822 : : p = pm;
823 : 0 : pm = pm->next;
824 [ # # ]: 0 : xfree(p);
825 : : }
826 : :
827 : 0 : ns->mnt.mntinfo_tree = NULL;
828 : :
829 : 0 : return NULL;
830 : : }
831 : :
832 : 210 : int dump_mnt_ns(struct ns_id *ns)
833 : : {
834 : : struct mount_info *pm, *pms;
835 : : int img_fd = -1, ret = -1;
836 : 210 : int ns_id = ns->id;
837 : :
838 : 210 : pms = collect_mntinfo(ns);
839 [ + - ]: 210 : if (pms == NULL)
840 : : goto err;
841 : :
842 [ + - ]: 210 : if (validate_mounts(pms, true))
843 : : goto err;
844 : :
845 : 210 : pr_info("Dumping mountpoints\n");
846 : :
847 : 210 : img_fd = open_image(CR_FD_MNTS, O_DUMP, ns_id);
848 [ + - ]: 210 : if (img_fd < 0)
849 : : goto err;
850 : :
851 [ + + ]: 846 : for (pm = pms; pm; pm = pm->next)
852 [ + - ]: 636 : if (dump_one_mountpoint(pm, img_fd))
853 : : goto err;
854 : :
855 [ + - ]: 210 : if (mntinfo == NULL)
856 : 210 : mntinfo = pms;
857 : : else {
858 [ # # ]: 0 : for (pm = mntinfo; pm->next != NULL; pm = pm->next);
859 : :
860 : 0 : pm->next = pms;
861 : : }
862 : : ret = 0;
863 : : err:
864 : 210 : close(img_fd);
865 : 210 : return ret;
866 : : }
867 : :
868 : : /*
869 : : * _fn_f - pre-order traversal function
870 : : * _fn_f - post-order traversal function
871 : : * _plist - a postpone list. _el is added to this list, if _fn_f returns
872 : : * a positive value, and all lower elements are not enumirated.
873 : : */
874 : : #define MNT_TREE_WALK(_r, _el, _fn_f, _fn_r, _plist, _prgs) do { \
875 : : struct mount_info *_mi = _r; \
876 : : \
877 : : while (1) { \
878 : : int ret; \
879 : : \
880 : : list_del_init(&_mi->postpone); \
881 : : \
882 : : ret = _fn_f(_mi); \
883 : : if (ret < 0) \
884 : : return -1; \
885 : : else if (ret > 0) { \
886 : : list_add_tail(&_mi->postpone, _plist); \
887 : : goto up; \
888 : : } \
889 : : \
890 : : _prgs++; \
891 : : \
892 : : if (!list_empty(&_mi->children)) { \
893 : : _mi = list_entry(_mi->children._el, \
894 : : struct mount_info, siblings); \
895 : : continue; \
896 : : } \
897 : : up: \
898 : : if (_fn_r(_mi)) \
899 : : return -1; \
900 : : if (_mi == _r) \
901 : : break; \
902 : : if (_mi->siblings._el == &_mi->parent->children) { \
903 : : _mi = _mi->parent; \
904 : : goto up; \
905 : : } \
906 : : _mi = list_entry(_mi->siblings._el, \
907 : : struct mount_info, siblings); \
908 : : } \
909 : : } while (0)
910 : :
911 : : #define MNT_WALK_NONE 0 &&
912 : :
913 : :
914 : 2 : static int mnt_tree_for_each(struct mount_info *start,
915 : : int (*fn)(struct mount_info *))
916 : : {
917 : : struct mount_info *tmp;
918 : 2 : LIST_HEAD(postpone);
919 : 2 : LIST_HEAD(postpone2);
920 : : int progress;
921 : :
922 : 2 : pr_debug("Start with %d:%s\n", start->mnt_id, start->mountpoint);
923 : 2 : list_add(&start->postpone, &postpone);
924 : :
925 : : again:
926 : : progress = 0;
927 : :
928 [ + - ]: 8 : list_for_each_entry_safe(start, tmp, &postpone, postpone)
929 [ + - ][ - + ]: 8 : MNT_TREE_WALK(start, next, fn, MNT_WALK_NONE, &postpone2, progress);
[ + + ][ + - ]
[ - + ]
930 : :
931 [ # # ]: 0 : if (!progress) {
932 : : struct mount_info *m;
933 : :
934 : 0 : pr_err("A few mount points can't be mounted");
935 [ # # ]: 0 : list_for_each_entry(m, &postpone2, postpone) {
936 : 0 : pr_err("%d:%d %s %s %s\n", m->mnt_id,
937 : : m->parent_mnt_id, m->root,
938 : : m->mountpoint, m->source);
939 : : }
940 : : return -1;
941 : : }
942 : :
943 : : list_splice_init(&postpone2, &postpone);
944 : :
945 [ # # ]: 0 : if (!list_empty(&postpone))
946 : : goto again;
947 : :
948 : : return 0;
949 : :
950 : : }
951 : :
952 : 0 : static int mnt_tree_for_each_reverse(struct mount_info *m,
953 : : int (*fn)(struct mount_info *))
954 : : {
955 : : int progress = 0;
956 : :
957 [ # # ][ # # ]: 0 : MNT_TREE_WALK(m, prev, MNT_WALK_NONE, fn, (struct list_head *) NULL, progress);
[ # # ][ # # ]
958 : :
959 : : return 0;
960 : : }
961 : :
962 : 6 : static char *resolve_source(struct mount_info *mi)
963 : : {
964 [ + - ]: 6 : if (kdev_major(mi->s_dev) == 0)
965 : : /*
966 : : * Anonymous block device. Kernel creates them for
967 : : * diskless mounts.
968 : : */
969 : 6 : return mi->source;
970 : :
971 : 0 : pr_err("No device for %s mount\n", mi->mountpoint);
972 : 0 : return NULL;
973 : : }
974 : :
975 : 16 : static int restore_shared_options(struct mount_info *mi, bool private, bool shared, bool slave)
976 : : {
977 : 8 : pr_debug("%d:%s private %d shared %d slave %d\n",
978 : : mi->mnt_id, mi->mountpoint, private, shared, slave);
979 : :
980 [ + + ][ - + ]: 8 : if (private && mount(NULL, mi->mountpoint, NULL, MS_PRIVATE, NULL)) {
981 : 0 : pr_perror("Unable to make %s private", mi->mountpoint);
982 : : return -1;
983 : : }
984 [ - + ][ # # ]: 8 : if (slave && mount(NULL, mi->mountpoint, NULL, MS_SLAVE, NULL)) {
985 : 0 : pr_perror("Unable to make %s slave", mi->mountpoint);
986 : : return -1;
987 : : }
988 [ - + ][ # # ]: 8 : if (shared && mount(NULL, mi->mountpoint, NULL, MS_SHARED, NULL)) {
989 : 0 : pr_perror("Unable to make %s shared", mi->mountpoint);
990 : : return -1;
991 : : }
992 : :
993 : : return 0;
994 : : }
995 : :
996 : : /*
997 : : * Umount points, which are propagated in slave parents, because
998 : : * we can't be sure, that they were inherited in a real life.
999 : : */
1000 : 8 : static int umount_from_slaves(struct mount_info *mi)
1001 : : {
1002 : : struct mount_info *t;
1003 : : char mpath[PATH_MAX];
1004 : :
1005 [ - + ]: 4 : list_for_each_entry(t, &mi->parent->mnt_slave_list, mnt_slave) {
1006 [ # # ]: 0 : if (!t->mounted)
1007 : 0 : continue;
1008 : :
1009 : 0 : snprintf(mpath, sizeof(mpath), "%s/%s",
1010 : 0 : t->mountpoint, basename(mi->mountpoint));
1011 : 0 : pr_debug("\t\tUmount %s\n", mpath);
1012 [ # # ]: 0 : if (umount(mpath) == -1) {
1013 : 0 : pr_perror("Can't umount %s", mpath);
1014 : : return -1;
1015 : : }
1016 : : }
1017 : :
1018 : : return 0;
1019 : : }
1020 : :
1021 : : /*
1022 : : * If something is mounted in one shared point, it will be spread in
1023 : : * all other points from this shared group.
1024 : : *
1025 : : * Look at Documentation/filesystems/sharedsubtree.txt for more details
1026 : : */
1027 : 6 : static int propagate_siblings(struct mount_info *mi)
1028 : : {
1029 : : struct mount_info *t;
1030 : :
1031 : : /*
1032 : : * Find all mounts, which must be bind-mounted from this one
1033 : : * to inherite shared group or master id
1034 : : */
1035 [ - + ]: 6 : list_for_each_entry(t, &mi->mnt_share, mnt_share) {
1036 : 0 : pr_debug("\t\tBind %s\n", t->mountpoint);
1037 : 0 : t->bind = mi;
1038 : : }
1039 : :
1040 [ - + ]: 6 : list_for_each_entry(t, &mi->mnt_slave_list, mnt_slave) {
1041 : 0 : pr_debug("\t\tBind %s\n", t->mountpoint);
1042 : 0 : t->bind = mi;
1043 : : }
1044 : :
1045 : 6 : return 0;
1046 : : }
1047 : :
1048 : 6 : static int propagate_mount(struct mount_info *mi)
1049 : : {
1050 : : struct mount_info *t;
1051 : :
1052 : 6 : propagate_siblings(mi);
1053 : :
1054 [ + + ]: 6 : if (!mi->parent)
1055 : : goto skip_parent;
1056 : :
1057 : 4 : umount_from_slaves(mi);
1058 : :
1059 : : /* Propagate this mount to everyone from a parent group */
1060 : :
1061 [ - + ]: 4 : list_for_each_entry(t, &mi->parent->mnt_share, mnt_share) {
1062 : : struct mount_info *c;
1063 : :
1064 [ # # ]: 0 : list_for_each_entry(c, &t->children, siblings) {
1065 [ # # ]: 0 : if (mounts_equal(mi, c, false)) {
1066 : 0 : pr_debug("\t\tPropogate %s\n", c->mountpoint);
1067 : 0 : c->mounted = true;
1068 : 0 : propagate_siblings(c);
1069 : 0 : umount_from_slaves(c);
1070 : : }
1071 : : }
1072 : : }
1073 : :
1074 : : skip_parent:
1075 : : /*
1076 : : * FIXME Currently non-root mounts can be restored
1077 : : * only if a proper root mount exists
1078 : : */
1079 [ + + ][ + - ]: 6 : if (fsroot_mounted(mi) || mi->parent == NULL)
1080 [ - + ]: 6 : list_for_each_entry(t, &mi->mnt_bind, mnt_bind) {
1081 [ # # ]: 0 : if (t->bind)
1082 : 0 : continue;
1083 [ # # ]: 0 : if (t->master_id)
1084 : 0 : continue;
1085 : 0 : t->bind = mi;
1086 : : }
1087 : :
1088 : 6 : return 0;
1089 : : }
1090 : :
1091 : 6 : static int do_new_mount(struct mount_info *mi)
1092 : : {
1093 : : char *src;
1094 : 6 : struct fstype *tp = mi->fstype;
1095 : : struct mount_info *t;
1096 : :
1097 : 6 : src = resolve_source(mi);
1098 [ + - ]: 6 : if (!src)
1099 : : return -1;
1100 : :
1101 : : /*
1102 : : * Wait while all parent are not mounted
1103 : : *
1104 : : * FIXME a child is shared only between parents,
1105 : : * who was present in a moment of birth
1106 : : */
1107 [ - + ]: 6 : if (mi->parent->flags & MS_SHARED) {
1108 [ # # ]: 0 : list_for_each_entry(t, &mi->parent->mnt_share, mnt_share) {
1109 [ # # ]: 0 : if (!t->mounted) {
1110 : 0 : pr_debug("\t\tPostpone %s due to %s\n",
1111 : : mi->mountpoint, t->mountpoint);
1112 : 0 : return 1;
1113 : : }
1114 : : }
1115 : : }
1116 : :
1117 [ - + ]: 6 : if (mount(src, mi->mountpoint, tp->name,
1118 : 6 : mi->flags & (~MS_SHARED), mi->options) < 0) {
1119 : 0 : pr_perror("Can't mount at %s", mi->mountpoint);
1120 : 0 : return -1;
1121 : : }
1122 : :
1123 [ + - ]: 6 : if (restore_shared_options(mi, 0, mi->shared_id, 0))
1124 : : return -1;
1125 : :
1126 : 6 : mi->mounted = true;
1127 : :
1128 [ + + ][ + - ]: 6 : if (tp->restore && tp->restore(mi))
1129 : : return -1;
1130 : :
1131 : : return 0;
1132 : : }
1133 : :
1134 : 0 : static int restore_ext_mount(struct mount_info *mi)
1135 : : {
1136 : : int ret;
1137 : :
1138 : 0 : pr_debug("Restoring external bind mount %s\n", mi->mountpoint);
1139 : 0 : ret = cr_plugin_restore_ext_mount(mi->mnt_id, mi->mountpoint, "/", NULL);
1140 [ # # ]: 0 : if (ret)
1141 : 0 : pr_perror("Can't restore ext mount (%d)\n", ret);
1142 : 0 : return ret;
1143 : : }
1144 : :
1145 : 0 : static int do_bind_mount(struct mount_info *mi)
1146 : : {
1147 [ # # ][ # # ]: 0 : bool shared = mi->shared_id && mi->shared_id == mi->bind->shared_id;
1148 : :
1149 [ # # ]: 0 : if (!mi->need_plugin) {
1150 : : char rpath[PATH_MAX];
1151 : : int tok = 0;
1152 : :
1153 : : /*
1154 : : * Cut common part of root.
1155 : : * For non-root binds the source is always "/" (checked)
1156 : : * so this will result in this slash removal only.
1157 : : */
1158 [ # # ]: 0 : while (mi->root[tok] == mi->bind->root[tok]) {
1159 : 0 : tok++;
1160 [ # # ]: 0 : if (mi->bind->root[tok] == '\0')
1161 : : break;
1162 [ # # ]: 0 : BUG_ON(mi->root[tok] == '\0');
1163 : : }
1164 : :
1165 : 0 : snprintf(rpath, sizeof(rpath), "%s/%s",
1166 : : mi->bind->mountpoint, mi->root + tok);
1167 : 0 : pr_info("\tBind %s to %s\n", rpath, mi->mountpoint);
1168 : :
1169 [ # # ]: 0 : if (mount(rpath, mi->mountpoint, NULL,
1170 : : MS_BIND, NULL) < 0) {
1171 : 0 : pr_perror("Can't mount at %s", mi->mountpoint);
1172 : 0 : return -1;
1173 : : }
1174 : : } else {
1175 [ # # ]: 0 : if (restore_ext_mount(mi))
1176 : : return -1;
1177 : : }
1178 : :
1179 : : /*
1180 : : * shared - the mount is in the same shared group with mi->bind
1181 : : * mi->shared_id && !shared - create a new shared group
1182 : : */
1183 [ # # ][ # # ]: 0 : if (restore_shared_options(mi, !shared && !mi->master_id,
[ # # ]
1184 [ # # ][ # # ]: 0 : mi->shared_id && !shared,
1185 : 0 : mi->master_id))
1186 : : return -1;
1187 : :
1188 : 0 : mi->mounted = true;
1189 : :
1190 : 0 : return 0;
1191 : : }
1192 : :
1193 : 8 : static bool can_mount_now(struct mount_info *mi)
1194 : : {
1195 : : /* The root mount */
1196 [ + + ]: 8 : if (!mi->parent)
1197 : : return true;
1198 : :
1199 : : /*
1200 : : * Private root mounts can be mounted at any time
1201 : : */
1202 [ + - ][ - + ]: 12 : if (!mi->master_id && fsroot_mounted(mi))
1203 : : return true;
1204 : :
1205 : : /*
1206 : : * Other mounts can be mounted only if they have
1207 : : * the master mount (see propagate_mount) or if we
1208 : : * expect a plugin to help us.
1209 : : */
1210 [ # # ][ # # ]: 0 : if (mi->bind || mi->need_plugin)
1211 : : return true;
1212 : :
1213 : 0 : return false;
1214 : : }
1215 : :
1216 : 2 : static int do_mount_root(struct mount_info *mi)
1217 : : {
1218 [ + - ][ - + ]: 2 : if (restore_shared_options(mi, !mi->shared_id && !mi->master_id,
[ + - ]
1219 : 4 : mi->shared_id, mi->master_id))
1220 : : return -1;
1221 : :
1222 : 2 : mi->mounted = true;
1223 : :
1224 : 2 : return 0;
1225 : : }
1226 : :
1227 : 8 : static int do_mount_one(struct mount_info *mi)
1228 : : {
1229 : : int ret;
1230 : :
1231 [ + - ]: 8 : if (mi->mounted)
1232 : : return 0;
1233 : :
1234 [ - + ]: 8 : if (!can_mount_now(mi)) {
1235 : 0 : pr_debug("Postpone slave %s\n", mi->mountpoint);
1236 : 0 : return 1;
1237 : : }
1238 : :
1239 : 8 : pr_debug("\tMounting %s @%s (%d)\n", mi->fstype->name, mi->mountpoint, mi->need_plugin);
1240 : :
1241 [ + + ]: 8 : if (!mi->parent)
1242 : 2 : ret = do_mount_root(mi);
1243 [ + - ][ + - ]: 6 : else if (!mi->bind && !mi->need_plugin)
1244 : 6 : ret = do_new_mount(mi);
1245 : : else
1246 : 0 : ret = do_bind_mount(mi);
1247 : :
1248 [ + - ][ + - ]: 6 : if (ret == 0 && propagate_mount(mi))
1249 : : return -1;
1250 : :
1251 [ + + ]: 6 : if (mi->fstype->code == FSTYPE__UNSUPPORTED) {
1252 : : struct statfs st;
1253 : :
1254 [ - + ]: 2 : if (statfs(mi->mountpoint, &st)) {
1255 : 0 : pr_perror("Unable to statfs %s", mi->mountpoint);
1256 : 0 : return -1;
1257 : : }
1258 [ - + ]: 2 : if (st.f_type == BTRFS_SUPER_MAGIC)
1259 : 2 : mi->fstype = find_fstype_by_name("btrfs");
1260 : : }
1261 : :
1262 : 6 : return ret;
1263 : : }
1264 : :
1265 : 0 : static int do_umount_one(struct mount_info *mi)
1266 : : {
1267 [ # # ]: 0 : if (!mi->parent)
1268 : : return 0;
1269 : :
1270 [ # # ]: 0 : if (mount("none", mi->parent->mountpoint, "none", MS_REC|MS_PRIVATE, NULL)) {
1271 : 0 : pr_perror("Can't mark %s as private", mi->parent->mountpoint);
1272 : 0 : return -1;
1273 : : }
1274 : :
1275 [ # # ]: 0 : if (umount(mi->mountpoint)) {
1276 : 0 : pr_perror("Can't umount at %s", mi->mountpoint);
1277 : 0 : return -1;
1278 : : }
1279 : :
1280 : 0 : pr_info("Umounted at %s\n", mi->mountpoint);
1281 : 0 : return 0;
1282 : : }
1283 : :
1284 : 0 : static int clean_mnt_ns(struct mount_info *mntinfo_tree)
1285 : : {
1286 : 0 : pr_info("Cleaning mount namespace\n");
1287 : :
1288 : : /*
1289 : : * Mountinfos were collected at prepare stage
1290 : : */
1291 : :
1292 : 0 : return mnt_tree_for_each_reverse(mntinfo_tree, do_umount_one);
1293 : : }
1294 : :
1295 : 0 : static int cr_pivot_root(char *root)
1296 : : {
1297 : 0 : char put_root[] = "crtools-put-root.XXXXXX";
1298 : :
1299 [ # # ]: 0 : pr_info("Move the root to %s\n", root ? : ".");
1300 : :
1301 [ # # ]: 0 : if (root) {
1302 [ # # ]: 0 : if (chdir(root)) {
1303 : 0 : pr_perror("chdir(%s) failed", root);
1304 : 0 : return -1;
1305 : : }
1306 : : }
1307 : :
1308 [ # # ]: 0 : if (mkdtemp(put_root) == NULL) {
1309 : 0 : pr_perror("Can't create a temporary directory");
1310 : 0 : return -1;
1311 : : }
1312 : :
1313 [ # # ]: 0 : if (pivot_root(".", put_root)) {
1314 : 0 : pr_perror("pivot_root(., %s) failed", put_root);
1315 [ # # ]: 0 : if (rmdir(put_root))
1316 : 0 : pr_perror("Can't remove the directory %s", put_root);
1317 : : return -1;
1318 : : }
1319 : :
1320 [ # # ]: 0 : if (mount("none", put_root, "none", MS_REC|MS_PRIVATE, NULL)) {
1321 : 0 : pr_perror("Can't remount root with MS_PRIVATE");
1322 : 0 : return -1;
1323 : : }
1324 : :
1325 [ # # ]: 0 : if (mount("none", put_root, "none", MS_REC|MS_PRIVATE, NULL)) {
1326 : 0 : pr_perror("Can't remount root with MS_PRIVATE");
1327 : 0 : return -1;
1328 : : }
1329 : :
1330 [ # # ]: 0 : if (umount2(put_root, MNT_DETACH)) {
1331 : 0 : pr_perror("Can't umount %s", put_root);
1332 : 0 : return -1;
1333 : : }
1334 [ # # ]: 0 : if (rmdir(put_root)) {
1335 : 0 : pr_perror("Can't remove the directory %s", put_root);
1336 : 0 : return -1;
1337 : : }
1338 : :
1339 : : return 0;
1340 : : }
1341 : :
1342 : 73012 : struct mount_info *mnt_entry_alloc()
1343 : : {
1344 : : struct mount_info *new;
1345 : :
1346 [ - + ]: 73012 : new = xzalloc(sizeof(struct mount_info));
1347 [ + - ]: 73012 : if (new) {
1348 : 73012 : INIT_LIST_HEAD(&new->children);
1349 : 73012 : INIT_LIST_HEAD(&new->siblings);
1350 : 73012 : INIT_LIST_HEAD(&new->mnt_slave_list);
1351 : 73012 : INIT_LIST_HEAD(&new->mnt_share);
1352 : 73012 : INIT_LIST_HEAD(&new->mnt_bind);
1353 : 73012 : INIT_LIST_HEAD(&new->postpone);
1354 : : }
1355 : 73012 : return new;
1356 : : }
1357 : :
1358 : 64 : void mnt_entry_free(struct mount_info *mi)
1359 : : {
1360 [ + - ]: 64 : if (mi == NULL)
1361 : 64 : return;
1362 : :
1363 [ + - ]: 64 : xfree(mi->root);
1364 [ + - ]: 64 : xfree(mi->mountpoint);
1365 [ + - ]: 64 : xfree(mi->source);
1366 [ + - ]: 64 : xfree(mi->options);
1367 [ + - ]: 64 : xfree(mi);
1368 : : }
1369 : :
1370 : : static void free_mntinfo(struct mount_info *pms)
1371 : : {
1372 [ + + ]: 66 : while (pms) {
1373 : : struct mount_info *pm;
1374 : :
1375 : 64 : pm = pms->next;
1376 : 64 : mnt_entry_free(pms);
1377 : : pms = pm;
1378 : : }
1379 : : }
1380 : :
1381 : : /*
1382 : : * mnt_roots is a temporary directory for restoring sub-trees of
1383 : : * non-root namespaces.
1384 : : */
1385 : : static char *mnt_roots;
1386 : :
1387 : 0 : static int create_mnt_roots()
1388 : : {
1389 [ # # ]: 0 : if (mnt_roots)
1390 : : return 0;
1391 : :
1392 [ # # ][ # # ]: 0 : if (chdir(opts.root ? : "/")) {
1393 : 0 : pr_perror("Unable to change working directory on %s", opts.root);
1394 : 0 : return -1;
1395 : : }
1396 : :
1397 [ # # ]: 0 : mnt_roots = strdup(".criu.mntns.XXXXXX");
1398 [ # # ]: 0 : if (mnt_roots == NULL) {
1399 : 0 : pr_perror("Can't allocate memory");
1400 : 0 : return -1;
1401 : : }
1402 : :
1403 [ # # ]: 0 : if (mkdtemp(mnt_roots) == NULL) {
1404 : 0 : pr_perror("Unable to create a temporary directory");
1405 : 0 : mnt_roots = NULL;
1406 : 0 : return -1;
1407 : : }
1408 : :
1409 : : return 0;
1410 : : }
1411 : :
1412 : 354 : int rst_collect_local_mntns()
1413 : : {
1414 : : struct ns_id *nsid;
1415 : :
1416 : 354 : nsid = shmalloc(sizeof(struct ns_id));
1417 [ + - ]: 354 : if (nsid == NULL)
1418 : : return -1;
1419 : :
1420 : 354 : nsid->nd = &mnt_ns_desc;
1421 : 354 : nsid->id = 0;
1422 : 354 : nsid->pid = getpid();
1423 : : futex_set(&nsid->created, 1);
1424 : :
1425 : 354 : mntinfo = collect_mntinfo(nsid);
1426 [ + - ]: 354 : if (mntinfo == NULL)
1427 : : return -1;
1428 : :
1429 : 354 : nsid->next = ns_ids;
1430 : 354 : ns_ids = nsid;
1431 : :
1432 : 354 : pr_info("Add namespace %d pid %d\n", nsid->id, nsid->pid);
1433 : :
1434 : 354 : return 0;
1435 : : }
1436 : :
1437 : 2 : static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid)
1438 : : {
1439 : 2 : MntEntry *me = NULL;
1440 : : int img, ret;
1441 : :
1442 : 2 : img = open_image(CR_FD_MNTS, O_RSTR, nsid->id);
1443 [ + - ]: 2 : if (img < 0)
1444 : : return -1;
1445 : :
1446 : 2 : pr_debug("Reading mountpoint images\n");
1447 : :
1448 : : while (1) {
1449 : : struct mount_info *pm;
1450 : 12 : char root[PATH_MAX] = ".";
1451 : : int len, root_len = 1;
1452 : :
1453 : 12 : ret = pb_read_one_eof(img, &me, PB_MNT);
1454 [ + + ]: 12 : if (ret <= 0)
1455 : : break;
1456 : :
1457 : 10 : pm = mnt_entry_alloc();
1458 [ + - ]: 10 : if (!pm)
1459 : : goto err;
1460 : :
1461 : 10 : pm->nsid = nsid;
1462 : 10 : pm->next = *pms;
1463 : 10 : *pms = pm;
1464 : :
1465 : 10 : pm->mnt_id = me->mnt_id;
1466 : 10 : pm->parent_mnt_id = me->parent_mnt_id;
1467 : 10 : pm->s_dev = me->root_dev;
1468 : 10 : pm->flags = me->flags;
1469 : 10 : pm->shared_id = me->shared_id;
1470 : 10 : pm->master_id = me->master_id;
1471 : 10 : pm->need_plugin = me->with_plugin;
1472 : 20 : pm->is_ns_root = is_root(me->mountpoint);
1473 : :
1474 : : /* FIXME: abort unsupported early */
1475 : 20 : pm->fstype = decode_fstype(me->fstype);
1476 : :
1477 : 10 : pr_debug("\t\tGetting root for %d\n", pm->mnt_id);
1478 [ - + ]: 10 : pm->root = xstrdup(me->root);
1479 [ + - ]: 10 : if (!pm->root)
1480 : : goto err;
1481 : :
1482 [ - + ]: 10 : if (nsid->id != root_item->ids->mnt_ns_id)
1483 : 0 : root_len = snprintf(root, sizeof(root), "%s/%d/",
1484 : : mnt_roots, nsid->id);
1485 : 10 : len = strlen(me->mountpoint) + root_len + 1;
1486 [ - + ]: 10 : pm->mountpoint = xmalloc(len);
1487 [ + - ]: 10 : if (!pm->mountpoint)
1488 : : goto err;
1489 : : /*
1490 : : * For bind-mounts we would also fix the root here
1491 : : * too, but bind-mounts restore merges mountpoint
1492 : : * and root paths together, so there's no need in
1493 : : * that.
1494 : : */
1495 : :
1496 : : strcpy(pm->mountpoint, root);
1497 : 10 : strcpy(pm->mountpoint + root_len, me->mountpoint);
1498 : :
1499 : 10 : pr_debug("\t\tGetting mpt for %d %s\n", pm->mnt_id, pm->mountpoint);
1500 : :
1501 : 10 : pr_debug("\t\tGetting source for %d\n", pm->mnt_id);
1502 [ - + ]: 10 : pm->source = xstrdup(me->source);
1503 [ + - ]: 10 : if (!pm->source)
1504 : : goto err;
1505 : :
1506 : 10 : pr_debug("\t\tGetting opts for %d\n", pm->mnt_id);
1507 [ - + ]: 10 : pm->options = xstrdup(me->options);
1508 [ + - ]: 10 : if (!pm->options)
1509 : : goto err;
1510 : :
1511 : 10 : pr_debug("\tRead %d mp @ %s\n", pm->mnt_id, pm->mountpoint);
1512 : 10 : }
1513 : :
1514 [ - + ]: 2 : if (me)
1515 : 0 : mnt_entry__free_unpacked(me, NULL);
1516 : :
1517 : 2 : close(img);
1518 : :
1519 : 2 : return 0;
1520 : : err:
1521 : 0 : close_safe(&img);
1522 : 0 : return -1;
1523 : : }
1524 : :
1525 : 2 : static struct mount_info *read_mnt_ns_img()
1526 : : {
1527 : 2 : struct mount_info *pms = NULL;
1528 : : struct ns_id *nsid;
1529 : :
1530 : 2 : nsid = ns_ids;
1531 [ + + ]: 4 : while (nsid) {
1532 [ - + ]: 2 : if (nsid->nd != &mnt_ns_desc) {
1533 : 0 : nsid = nsid->next;
1534 : 0 : continue;
1535 : : }
1536 : :
1537 [ - + ]: 2 : if (nsid->id != root_item->ids->mnt_ns_id)
1538 [ # # ]: 0 : if (create_mnt_roots(true))
1539 : : return NULL;
1540 : :
1541 [ + - ]: 2 : if (collect_mnt_from_image(&pms, nsid))
1542 : : goto err;
1543 : :
1544 : 2 : nsid = nsid->next;
1545 : : }
1546 : :
1547 : : /* Here is not matter where the mount list is saved */
1548 : 2 : mntinfo = pms;
1549 : :
1550 : 2 : return pms;
1551 : : err:
1552 : : return NULL;
1553 : : }
1554 : :
1555 : 18 : char *rst_get_mnt_root(int mnt_id)
1556 : : {
1557 : : struct mount_info *m;
1558 : : static char path[PATH_MAX] = "/";
1559 : :
1560 [ - + ]: 18 : if (!(root_ns_mask & CLONE_NEWNS))
1561 : : return path;
1562 : :
1563 [ # # ]: 0 : if (mnt_id == -1)
1564 : : return path;
1565 : :
1566 : : m = lookup_mnt_id(mnt_id);
1567 [ # # ]: 0 : if (m == NULL)
1568 : : return NULL;
1569 : :
1570 [ # # ]: 0 : if (m->nsid->pid == getpid())
1571 : : return path;
1572 : :
1573 : 0 : snprintf(path, sizeof(path), "%s/%d/",
1574 : 0 : mnt_roots, m->nsid->id);
1575 : :
1576 : 0 : return path;
1577 : : }
1578 : :
1579 : 347 : int restore_task_mnt_ns(struct ns_id *nsid, pid_t pid)
1580 : : {
1581 : : char path[PATH_MAX];
1582 : :
1583 [ - + ]: 347 : if (root_item->ids->mnt_ns_id == nsid->id)
1584 : : return 0;
1585 : :
1586 [ # # ]: 0 : if (nsid->pid != getpid()) {
1587 : : int fd;
1588 : :
1589 : 0 : futex_wait_while_eq(&nsid->created, 0);
1590 [ # # ]: 0 : fd = open_proc(nsid->pid, "ns/mnt");
1591 [ # # ]: 0 : if (fd < 0)
1592 : : return -1;
1593 : :
1594 [ # # ]: 0 : if (setns(fd, CLONE_NEWNS)) {
1595 : 0 : pr_perror("Unable to change mount namespace");
1596 : 0 : return -1;
1597 : : }
1598 : : return 0;
1599 : : }
1600 : :
1601 [ # # ]: 0 : if (unshare(CLONE_NEWNS)) {
1602 : 0 : pr_perror("Unable to unshare mount namespace");
1603 : 0 : return -1;
1604 : : }
1605 : :
1606 : 0 : snprintf(path, sizeof(path), "%s/%d/", mnt_roots, nsid->id);
1607 : :
1608 [ # # ]: 0 : if (cr_pivot_root(path))
1609 : : return -1;
1610 : :
1611 : 0 : futex_set_and_wake(&nsid->created, 1);
1612 : :
1613 : 0 : return 0;
1614 : : }
1615 : :
1616 : : /*
1617 : : * All nested mount namespaces are restore as sub-trees of the root namespace.
1618 : : */
1619 : 2 : static int prepare_roots_yard(void)
1620 : : {
1621 : : char path[PATH_MAX];
1622 : : struct ns_id *nsid;
1623 : :
1624 [ - + ]: 2 : if (mnt_roots == NULL)
1625 : : return 0;
1626 : :
1627 [ # # ]: 0 : if (mount("none", mnt_roots, "tmpfs", 0, NULL)) {
1628 : 0 : pr_perror("Unable to mount tmpfs in %s", mnt_roots);
1629 : 0 : return -1;
1630 : : }
1631 [ # # ]: 0 : if (mount("none", mnt_roots, NULL, MS_PRIVATE, NULL))
1632 : : return -1;
1633 : :
1634 : 0 : nsid = ns_ids;
1635 [ # # ]: 0 : while (nsid) {
1636 [ # # ]: 0 : if (nsid->nd != &mnt_ns_desc) {
1637 : 0 : nsid = nsid->next;
1638 : 0 : continue;
1639 : : }
1640 : :
1641 : 0 : snprintf(path, sizeof(path), "%s/%d",
1642 : : mnt_roots, nsid->id);
1643 : :
1644 [ # # ]: 0 : if (mkdir(path, 0600)) {
1645 : 0 : pr_perror("Unable to create %s", path);
1646 : 0 : return -1;
1647 : : }
1648 : 0 : nsid = nsid->next;
1649 : : }
1650 : :
1651 : : return 0;
1652 : : }
1653 : :
1654 : 4 : static int populate_mnt_ns(int ns_pid, struct mount_info *mis)
1655 : : {
1656 : : struct mount_info *pms;
1657 : : struct ns_id *nsid;
1658 : :
1659 [ + - ]: 2 : if (prepare_roots_yard())
1660 : : return -1;
1661 : :
1662 : 2 : pms = mnt_build_tree(mis);
1663 [ + - ]: 2 : if (!pms)
1664 : : return -1;
1665 : :
1666 [ + + ]: 4 : for (nsid = ns_ids; nsid; nsid = nsid->next) {
1667 [ - + ]: 2 : if (nsid->nd != &mnt_ns_desc)
1668 : 0 : continue;
1669 : :
1670 : 2 : nsid->mnt.mntinfo_tree = pms;
1671 : : }
1672 : :
1673 [ + - ]: 2 : if (validate_mounts(mis, false))
1674 : : return -1;
1675 : :
1676 : 2 : return mnt_tree_for_each(pms, do_mount_one);
1677 : : }
1678 : :
1679 : 237 : int fini_mnt_ns()
1680 : : {
1681 : : int ret = 0;
1682 : :
1683 [ - + ]: 237 : if (mnt_roots == NULL)
1684 : : return 0;
1685 : :
1686 [ # # ]: 0 : if (mount("none", mnt_roots, "none", MS_REC|MS_PRIVATE, NULL)) {
1687 : 0 : pr_perror("Can't remount root with MS_PRIVATE");
1688 : : ret = 1;
1689 : : }
1690 : : /*
1691 : : * Don't exit after a first error, becuase this function
1692 : : * can be used to rollback in a error case.
1693 : : * Don't worry about MNT_DETACH, because files are restored after this
1694 : : * and nobody will not be restored from a wrong mount namespace.
1695 : : */
1696 [ # # ]: 0 : if (umount2(mnt_roots, MNT_DETACH)) {
1697 : 0 : pr_perror("Can't unmount %s", mnt_roots);
1698 : : ret = 1;
1699 : : }
1700 [ # # ]: 0 : if (rmdir(mnt_roots)) {
1701 : 0 : pr_perror("Can't remove the directory %s", mnt_roots);
1702 : : ret = 1;
1703 : : }
1704 : :
1705 : 0 : return ret;
1706 : : }
1707 : :
1708 : 2 : int prepare_mnt_ns(int ns_pid)
1709 : : {
1710 : : int ret = -1;
1711 : : struct mount_info *mis, *old;
1712 : 2 : struct ns_id ns = { .pid = getpid(), .nd = &mnt_ns_desc };
1713 : :
1714 : 2 : pr_info("Restoring mount namespace\n");
1715 : :
1716 : 2 : old = collect_mntinfo(&ns);
1717 [ + - ]: 2 : if (old == NULL)
1718 : : return -1;
1719 : :
1720 : 2 : close_proc();
1721 : :
1722 : 2 : mis = read_mnt_ns_img(ns_pid);
1723 [ + - ]: 2 : if (!mis)
1724 : : goto out;
1725 : :
1726 [ + - ][ - + ]: 2 : if (chdir(opts.root ? : "/")) {
1727 [ # # ]: 0 : pr_perror("chdir(%s) failed", opts.root ? : "/");
1728 : 0 : return -1;
1729 : : }
1730 : :
1731 : : /*
1732 : : * The new mount namespace is filled with the mountpoint
1733 : : * clones from the original one. We have to umount them
1734 : : * prior to recreating new ones.
1735 : : */
1736 [ - + ]: 2 : if (!opts.root) {
1737 [ # # ]: 0 : if (clean_mnt_ns(ns.mnt.mntinfo_tree))
1738 : : return -1;
1739 : : } else {
1740 : : struct mount_info *mi;
1741 : :
1742 : : /* moving a mount residing under a shared mount is invalid. */
1743 : 2 : mi = mount_resolve_path(ns.mnt.mntinfo_tree, opts.root);
1744 [ - + ]: 2 : if (mi == NULL) {
1745 : 0 : pr_err("Unable to find mount point for %s\n", opts.root);
1746 : 0 : return -1;
1747 : : }
1748 [ - + ]: 2 : if (mi->parent == NULL) {
1749 : 0 : pr_err("New root and old root are the same\n");
1750 : 0 : return -1;
1751 : : }
1752 : :
1753 : : /* Our root is mounted over the parent (in the same directory) */
1754 [ - + ]: 2 : if (!strcmp(mi->parent->mountpoint, mi->mountpoint)) {
1755 : 0 : pr_err("The parent of the new root is unreachable\n");
1756 : 0 : return -1;
1757 : : }
1758 : :
1759 [ + - ]: 2 : if (mount("none", mi->parent->mountpoint + 1, "none", MS_SLAVE, NULL)) {
1760 : 0 : pr_perror("Can't remount the parent of the new root with MS_SLAVE");
1761 : 0 : return -1;
1762 : : }
1763 : : }
1764 : :
1765 : : free_mntinfo(old);
1766 : :
1767 : 2 : ret = populate_mnt_ns(ns_pid, mis);
1768 [ # # ]: 0 : if (ret)
1769 : : goto out;
1770 : :
1771 [ # # ]: 0 : if (opts.root)
1772 : 0 : ret = cr_pivot_root(NULL);
1773 : : out:
1774 : 0 : return ret;
1775 : : }
1776 : :
1777 : 147939 : int mntns_collect_root(pid_t pid)
1778 : : {
1779 : : static int mntns_root_pid = -1;
1780 : :
1781 : : int fd, pfd;
1782 : : int ret;
1783 : : char path[PATH_MAX + 1];
1784 : :
1785 [ + + ]: 147939 : if (mntns_root_pid == pid) /* The required root is already opened */
1786 : 145789 : return get_service_fd(ROOT_FD_OFF);
1787 : :
1788 : 2150 : close_service_fd(ROOT_FD_OFF);
1789 : :
1790 [ + + ]: 2150 : if (!(root_ns_mask & CLONE_NEWNS)) {
1791 : : /*
1792 : : * If criu and tasks we dump live in the same mount
1793 : : * namespace, we can just open the root directory.
1794 : : * All paths resolution would occur relative to criu's
1795 : : * root. Even if it is not namespace's root, provided
1796 : : * file paths are resolved, we'd get consistent dump.
1797 : : */
1798 : : fd = open("/", O_RDONLY | O_DIRECTORY);
1799 [ - + ]: 1308 : if (fd < 0) {
1800 : 0 : pr_perror("Can't open root\n");
1801 : 0 : return -1;
1802 : : }
1803 : :
1804 : : goto set_root;
1805 : : }
1806 : :
1807 : : /*
1808 : : * If /proc/pid/root links on '/', it signs that a root of the task
1809 : : * and a root of mntns is the same.
1810 : : */
1811 : :
1812 : 842 : pfd = open_pid_proc(pid);
1813 : 842 : ret = readlinkat(pfd, "root", path, sizeof(path) - 1);
1814 [ - + ]: 842 : if (ret < 0) {
1815 : 0 : close_pid_proc();
1816 : 0 : return ret;
1817 : : }
1818 : :
1819 : 842 : path[ret] = '\0';
1820 : :
1821 [ + - ][ - + ]: 842 : if (ret != 1 || path[0] != '/') {
1822 : 0 : pr_err("The root task has another root than mntns: %s\n", path);
1823 : 0 : close_pid_proc();
1824 : 0 : return -1;
1825 : : }
1826 : :
1827 : : fd = openat(pfd, "root", O_RDONLY | O_DIRECTORY, 0);
1828 : 842 : close_pid_proc();
1829 [ - + ]: 842 : if (fd < 0) {
1830 : 0 : pr_perror("Can't open the task root");
1831 : 0 : return -1;
1832 : : }
1833 : :
1834 : : set_root:
1835 : 2150 : ret = install_service_fd(ROOT_FD_OFF, fd);
1836 [ + - ]: 2150 : if (ret >= 0)
1837 : 2150 : mntns_root_pid = pid;
1838 : 2150 : close(fd);
1839 : 2150 : return ret;
1840 : : }
1841 : :
1842 : 10733 : struct ns_id *lookup_nsid_by_mnt_id(int mnt_id)
1843 : : {
1844 : : struct mount_info *mi;
1845 : :
1846 : : /*
1847 : : * Kernel before 3.15 doesn't show mnt_id for file descriptors.
1848 : : * mnt_id isn't saved for files, if mntns isn't dumped.
1849 : : * In both these cases we have only one root, so here
1850 : : * is not matter which mount will be restured.
1851 : : */
1852 [ + - ]: 10733 : if (mnt_id == -1)
1853 : 10733 : mi = mntinfo;
1854 : : else
1855 : : mi = lookup_mnt_id(mnt_id);
1856 : :
1857 [ + - ]: 10733 : if (mi == NULL)
1858 : : return NULL;
1859 : :
1860 : 10733 : return mi->nsid;
1861 : : }
1862 : :
1863 : 1344 : int collect_mnt_namespaces(void)
1864 : : {
1865 : : struct mount_info *pm, *pms;
1866 : : struct ns_id *ns;
1867 : : int ret = -1;
1868 : :
1869 [ + + ]: 3318 : for (ns = ns_ids; ns; ns = ns->next) {
1870 [ + + ]: 1974 : if (ns->pid == getpid()) {
1871 [ + + ]: 1344 : if (!(root_ns_mask & CLONE_NEWNS)) {
1872 : 714 : mntinfo = collect_mntinfo(ns);
1873 [ + - ]: 714 : if (mntinfo == NULL)
1874 : : return -1;
1875 : : }
1876 : : /* Skip current namespaces, which are in the list too */
1877 : 1344 : continue;
1878 : : }
1879 : :
1880 [ - + ]: 630 : if (!(ns->nd->cflag & CLONE_NEWNS))
1881 : 0 : continue;
1882 : :
1883 : 630 : pr_info("Dump MNT namespace (mountpoints) %d via %d\n",
1884 : : ns->id, ns->pid);
1885 : 630 : pms = collect_mntinfo(ns);
1886 [ + - ]: 630 : if (pms == NULL)
1887 : : goto err;
1888 : :
1889 [ + - ]: 630 : if (mntinfo == NULL)
1890 : 630 : mntinfo = pms;
1891 : : else {
1892 [ # # ]: 0 : for (pm = mntinfo; pm->next != NULL; pm = pm->next);
1893 : :
1894 : 0 : pm->next = pms;
1895 : : }
1896 : : }
1897 : : ret = 0;
1898 : : err:
1899 : 1344 : return ret;
1900 : : }
1901 : :
1902 : 448 : int dump_mnt_namespaces(void)
1903 : : {
1904 : : struct ns_id *ns;
1905 : : int ret = 0, n = 0;
1906 : :
1907 [ + + ]: 3754 : for (ns = ns_ids; ns; ns = ns->next) {
1908 : : /* Skip current namespaces, which are in the list too */
1909 [ + + ]: 3306 : if (ns->pid == getpid()) {
1910 [ + + ]: 2240 : if (!(root_ns_mask & CLONE_NEWNS))
1911 : 1190 : mntinfo = collect_mntinfo(ns);
1912 [ + - ]: 2240 : if (mntinfo == NULL)
1913 : : return -1;
1914 : 2240 : continue;
1915 : : }
1916 : :
1917 [ + + ]: 1066 : if (!(ns->nd->cflag & CLONE_NEWNS))
1918 : 856 : continue;
1919 : :
1920 : 210 : n++;
1921 : :
1922 [ - + ][ # # ]: 210 : if (n == 2 && check_mnt_id()) {
1923 : 0 : pr_err("Nested mount namespaces are not supported "
1924 : : "without mnt_id in fdinfo\n");
1925 : 0 : return -1;
1926 : : }
1927 : 210 : pr_info("Dump MNT namespace (mountpoints) %d via %d\n",
1928 : : ns->id, ns->pid);
1929 : 210 : ret = dump_mnt_ns(ns);
1930 [ + - ]: 210 : if (ret)
1931 : : break;
1932 : : }
1933 : :
1934 : 448 : return ret;
1935 : : }
1936 : :
1937 : : struct ns_desc mnt_ns_desc = NS_DESC_ENTRY(CLONE_NEWNS, "mnt");
|