Branch data Line data Source code
1 : : #include <stdlib.h>
2 : : #include <unistd.h>
3 : : #include <errno.h>
4 : : #include <string.h>
5 : : #include <sys/mman.h>
6 : : #include <sys/types.h>
7 : : #include <sys/stat.h>
8 : : #include <sys/vfs.h>
9 : : #include <ctype.h>
10 : :
11 : : /* Stolen from kernel/fs/nfs/unlink.c */
12 : : #define SILLYNAME_PREF ".nfs"
13 : : #define SILLYNAME_SUFF_LEN (((unsigned)sizeof(u64) << 1) + ((unsigned)sizeof(unsigned int) << 1))
14 : :
15 : : #include "cr_options.h"
16 : : #include "fdset.h"
17 : : #include "file-ids.h"
18 : : #include "mount.h"
19 : : #include "files.h"
20 : : #include "image.h"
21 : : #include "list.h"
22 : : #include "util.h"
23 : : #include "fs-magic.h"
24 : : #include "asm/atomic.h"
25 : : #include "namespaces.h"
26 : : #include "proc_parse.h"
27 : :
28 : : #include "protobuf.h"
29 : : #include "protobuf/regfile.pb-c.h"
30 : : #include "protobuf/remap-file-path.pb-c.h"
31 : :
32 : : #include "files-reg.h"
33 : : #include "plugin.h"
34 : :
35 : : /*
36 : : * Ghost files are those not visible from the FS. Dumping them is
37 : : * nasty and the only way we have -- just carry its contents with
38 : : * us. Any brave soul to implement link unlinked file back?
39 : : */
40 : : struct ghost_file {
41 : : struct list_head list;
42 : : u32 id;
43 : :
44 : : u32 dev;
45 : : u32 ino;
46 : :
47 : : struct file_remap remap;
48 : : };
49 : :
50 : : static u32 ghost_file_ids = 1;
51 : : static LIST_HEAD(ghost_files);
52 : :
53 : : static mutex_t *ghost_file_mutex;
54 : :
55 : : /*
56 : : * To rollback link remaps.
57 : : */
58 : : struct link_remap_rlb {
59 : : struct list_head list;
60 : : pid_t pid;
61 : : char *path;
62 : : };
63 : : static LIST_HEAD(link_remaps);
64 : :
65 : : /*
66 : : * This constant is selected without any calculations. Just do not
67 : : * want to pick up too big files with us in the image.
68 : : */
69 : : #define MAX_GHOST_FILE_SIZE (1 * 1024 * 1024)
70 : :
71 : 24 : static int open_remap_ghost(struct reg_file_info *rfi,
72 : : RemapFilePathEntry *rfe)
73 : : {
74 : : struct ghost_file *gf;
75 : 24 : GhostFileEntry *gfe = NULL;
76 : : int gfd, ifd, ghost_flags;
77 : : char *root, path[PATH_MAX];
78 : :
79 : 24 : rfe->remap_id &= ~REMAP_GHOST;
80 [ + + ]: 24 : list_for_each_entry(gf, &ghost_files, list)
81 [ - + ]: 6 : if (gf->id == rfe->remap_id)
82 : : goto gf_found;
83 : :
84 : : /*
85 : : * Ghost not found. We will create one in the same dir
86 : : * as the very first client of it thus resolving any
87 : : * issues with cross-device links.
88 : : */
89 : :
90 : 18 : pr_info("Opening ghost file %#x for %s\n", rfe->remap_id, rfi->path);
91 : :
92 : 18 : root = rst_get_mnt_root(rfi->rfe->mnt_id);
93 [ - + ]: 18 : if (root == NULL) {
94 : 0 : pr_err("The %d mount is not found\n", rfi->rfe->mnt_id);
95 : : return -1;
96 : : }
97 : :
98 : 18 : gf = shmalloc(sizeof(*gf));
99 [ + - ]: 18 : if (!gf)
100 : : return -1;
101 [ - + ]: 18 : gf->remap.path = xmalloc(PATH_MAX);
102 [ + - ]: 18 : if (!gf->remap.path)
103 : : goto err;
104 : :
105 : 18 : ifd = open_image(CR_FD_GHOST_FILE, O_RSTR, rfe->remap_id);
106 [ + - ]: 18 : if (ifd < 0)
107 : : goto err;
108 : :
109 [ + - ]: 18 : if (pb_read_one(ifd, &gfe, PB_GHOST_FILE) < 0)
110 : : goto close_ifd;
111 : :
112 : : /*
113 : : * For old formats where optional has_[dev|ino] is
114 : : * not present we will have zeros here which is quite
115 : : * a sign for "absent" fields.
116 : : */
117 : 18 : gf->dev = gfe->dev;
118 : 18 : gf->ino = gfe->ino;
119 : :
120 : 18 : snprintf(gf->remap.path, PATH_MAX, "%s.cr.%x.ghost", rfi->path, rfe->remap_id);
121 : :
122 [ + + ]: 18 : if (S_ISFIFO(gfe->mode)) {
123 [ - + ]: 2 : if (mknod(gf->remap.path, gfe->mode, 0)) {
124 : 0 : pr_perror("Can't create node for ghost file");
125 : : goto close_ifd;
126 : : }
127 : : ghost_flags = O_RDWR; /* To not block */
128 : : } else
129 : : ghost_flags = O_WRONLY | O_CREAT | O_EXCL;
130 : :
131 : 18 : snprintf(path, sizeof(path), "%s/%s", root, gf->remap.path);
132 : 36 : gfd = open(path, ghost_flags, gfe->mode);
133 [ - + ]: 18 : if (gfd < 0) {
134 : 0 : pr_perror("Can't open ghost file %s", path);
135 : : goto close_ifd;
136 : : }
137 : :
138 [ - + ]: 18 : if (fchown(gfd, gfe->uid, gfe->gid) < 0) {
139 : 0 : pr_perror("Can't reset user/group on ghost %#x", rfe->remap_id);
140 : : goto close_all;
141 : : }
142 : :
143 [ + + ]: 18 : if (S_ISREG(gfe->mode)) {
144 [ + - ]: 16 : if (copy_file(ifd, gfd, 0) < 0)
145 : : goto close_all;
146 : : }
147 : :
148 : 18 : ghost_file_entry__free_unpacked(gfe, NULL);
149 : 18 : close(ifd);
150 : 18 : close(gfd);
151 : :
152 : 18 : gf->id = rfe->remap_id;
153 : 18 : gf->remap.users = 0;
154 : 18 : list_add_tail(&gf->list, &ghost_files);
155 : : gf_found:
156 : 24 : rfi->remap = &gf->remap;
157 : : return 0;
158 : :
159 : : close_all:
160 : 0 : close_safe(&gfd);
161 : : close_ifd:
162 : 0 : close_safe(&ifd);
163 : : err:
164 [ # # ]: 0 : if (gfe)
165 : 0 : ghost_file_entry__free_unpacked(gfe, NULL);
166 [ # # ]: 0 : xfree(gf->remap.path);
167 : 0 : shfree_last(gf);
168 : : return -1;
169 : : }
170 : :
171 : 4 : static int open_remap_linked(struct reg_file_info *rfi,
172 : : RemapFilePathEntry *rfe)
173 : : {
174 : : struct file_remap *rm;
175 : : struct file_desc *rdesc;
176 : : struct reg_file_info *rrfi;
177 : :
178 : 2 : rdesc = find_file_desc_raw(FD_TYPES__REG, rfe->remap_id);
179 [ - + ]: 2 : if (!rdesc) {
180 : 0 : pr_err("Can't find target file %x\n", rfe->remap_id);
181 : : return -1;
182 : : }
183 : :
184 [ - + ]: 2 : rm = xmalloc(sizeof(*rm));
185 [ + - ]: 2 : if (!rm)
186 : : return -1;
187 : :
188 : : rrfi = container_of(rdesc, struct reg_file_info, d);
189 : 2 : pr_info("Remapped %s -> %s\n", rfi->path, rrfi->path);
190 : :
191 : 2 : rm->path = rrfi->path;
192 : 2 : rm->users = 0;
193 : 2 : rfi->remap = rm;
194 : : return 0;
195 : : }
196 : :
197 : 26 : static int collect_one_remap(void *obj, ProtobufCMessage *msg)
198 : : {
199 : : int ret = -1;
200 : : RemapFilePathEntry *rfe;
201 : : struct file_desc *fdesc;
202 : : struct reg_file_info *rfi;
203 : :
204 : : rfe = pb_msg(msg, RemapFilePathEntry);
205 : :
206 : 26 : fdesc = find_file_desc_raw(FD_TYPES__REG, rfe->orig_id);
207 [ - + ]: 26 : if (fdesc == NULL) {
208 : 0 : pr_err("Remap for non existing file %#x\n",
209 : : rfe->orig_id);
210 : 0 : goto out;
211 : : }
212 : :
213 : : rfi = container_of(fdesc, struct reg_file_info, d);
214 : 26 : pr_info("Configuring remap %#x -> %#x\n", rfi->rfe->id, rfe->remap_id);
215 : :
216 [ + + ]: 26 : if (rfe->remap_id & REMAP_GHOST)
217 : 24 : ret = open_remap_ghost(rfi, rfe);
218 : : else
219 : 2 : ret = open_remap_linked(rfi, rfe);
220 : : out:
221 : 26 : return ret;
222 : : }
223 : :
224 : : struct collect_image_info remap_cinfo = {
225 : : .fd_type = CR_FD_REMAP_FPATH,
226 : : .pb_type = PB_REMAP_FPATH,
227 : : .collect = collect_one_remap,
228 : : };
229 : :
230 : 32 : static int dump_ghost_file(int _fd, u32 id, const struct stat *st, dev_t phys_dev)
231 : : {
232 : : int img;
233 : 32 : GhostFileEntry gfe = GHOST_FILE_ENTRY__INIT;
234 : :
235 : 32 : pr_info("Dumping ghost file contents (id %#x)\n", id);
236 : :
237 : 32 : img = open_image(CR_FD_GHOST_FILE, O_DUMP, id);
238 [ + - ]: 32 : if (img < 0)
239 : : return -1;
240 : :
241 : 32 : gfe.uid = st->st_uid;
242 : 32 : gfe.gid = st->st_gid;
243 : 32 : gfe.mode = st->st_mode;
244 : :
245 : 32 : gfe.has_dev = gfe.has_ino = true;
246 : 32 : gfe.dev = phys_dev;
247 : 32 : gfe.ino = st->st_ino;
248 : :
249 [ + - ]: 32 : if (pb_write_one(img, &gfe, PB_GHOST_FILE))
250 : : return -1;
251 : :
252 [ + + ]: 32 : if (S_ISREG(st->st_mode)) {
253 : : int fd, ret;
254 : : char lpath[PSFDS];
255 : :
256 : : /*
257 : : * Reopen file locally since it may have no read
258 : : * permissions when drained
259 : : */
260 : : sprintf(lpath, "/proc/self/fd/%d", _fd);
261 : : fd = open(lpath, O_RDONLY);
262 [ - + ]: 28 : if (fd < 0) {
263 : 0 : pr_perror("Can't open ghost original file");
264 : 0 : return -1;
265 : : }
266 : 28 : ret = copy_file(fd, img, st->st_size);
267 : 28 : close(fd);
268 [ + - ]: 28 : if (ret)
269 : : return -1;
270 : : }
271 : :
272 : 32 : close(img);
273 : 32 : return 0;
274 : : }
275 : :
276 : 2 : void remap_put(struct file_remap *remap)
277 : : {
278 : 2 : mutex_lock(ghost_file_mutex);
279 [ - + ]: 2 : if (--remap->users == 0) {
280 : 0 : pr_info("Unlink the ghost %s\n", remap->path);
281 : 0 : unlink(remap->path);
282 : : }
283 : 2 : mutex_unlock(ghost_file_mutex);
284 : 2 : }
285 : :
286 : 6 : struct file_remap *lookup_ghost_remap(u32 dev, u32 ino)
287 : : {
288 : : struct ghost_file *gf;
289 : :
290 : 6 : mutex_lock(ghost_file_mutex);
291 [ + + ]: 8 : list_for_each_entry(gf, &ghost_files, list) {
292 [ + + ][ + - ]: 4 : if (gf->ino == ino && (gf->dev == dev)) {
293 : 2 : gf->remap.users++;
294 : 2 : mutex_unlock(ghost_file_mutex);
295 : 2 : return &gf->remap;
296 : : }
297 : : }
298 : 4 : mutex_unlock(ghost_file_mutex);
299 : :
300 : 4 : return NULL;
301 : : }
302 : :
303 : 80 : static int dump_ghost_remap(char *path, const struct stat *st,
304 : : int lfd, u32 id, struct ns_id *nsid)
305 : : {
306 : : struct ghost_file *gf;
307 : 40 : RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT;
308 : : dev_t phys_dev;
309 : :
310 : 40 : pr_info("Dumping ghost file for fd %d id %#x\n", lfd, id);
311 : :
312 [ - + ]: 40 : if (st->st_size > MAX_GHOST_FILE_SIZE) {
313 : 0 : pr_err("Can't dump ghost file %s of %"PRIu64" size\n",
314 : : path, st->st_size);
315 : : return -1;
316 : : }
317 : :
318 : 40 : phys_dev = phys_stat_resolve_dev(nsid->mnt.mntinfo_tree, st->st_dev, path);
319 [ + + ]: 40 : list_for_each_entry(gf, &ghost_files, list)
320 [ + - ][ - + ]: 8 : if ((gf->dev == phys_dev) && (gf->ino == st->st_ino))
321 : : goto dump_entry;
322 : :
323 [ - + ]: 32 : gf = xmalloc(sizeof(*gf));
324 [ + - ]: 32 : if (gf == NULL)
325 : : return -1;
326 : :
327 : 32 : gf->dev = phys_dev;
328 : 32 : gf->ino = st->st_ino;
329 : 32 : gf->id = ghost_file_ids++;
330 : 32 : list_add_tail(&gf->list, &ghost_files);
331 : :
332 [ + - ]: 32 : if (dump_ghost_file(lfd, gf->id, st, phys_dev))
333 : : return -1;
334 : :
335 : : dump_entry:
336 [ - + ]: 40 : BUG_ON(gf->id & REMAP_GHOST);
337 : :
338 : 40 : rpe.orig_id = id;
339 : 40 : rpe.remap_id = gf->id | REMAP_GHOST;
340 : :
341 : 40 : return pb_write_one(fdset_fd(glob_fdset, CR_FD_REMAP_FPATH),
342 : : &rpe, PB_REMAP_FPATH);
343 : : }
344 : :
345 : 448 : static void __rollback_link_remaps(bool do_unlink)
346 : : {
347 : : struct link_remap_rlb *rlb, *tmp;
348 : : int mntns_root;
349 : :
350 [ + + ]: 448 : if (!opts.link_remap_ok)
351 : : return;
352 : :
353 [ + + ]: 32 : list_for_each_entry_safe(rlb, tmp, &link_remaps, list) {
354 : 4 : mntns_root = mntns_collect_root(rlb->pid);
355 [ + - ]: 4 : if (mntns_root < 0)
356 : : return;
357 : : list_del(&rlb->list);
358 [ - + ]: 4 : if (do_unlink)
359 : 0 : unlinkat(mntns_root, rlb->path, 0);
360 [ + - ]: 4 : xfree(rlb->path);
361 [ + - ]: 4 : xfree(rlb);
362 : : }
363 : : }
364 : :
365 : 0 : void delete_link_remaps(void) { __rollback_link_remaps(true); }
366 : 896 : void free_link_remaps(void) { __rollback_link_remaps(false); }
367 : :
368 : 4 : static int create_link_remap(char *path, int len, int lfd,
369 : : u32 *idp, struct ns_id *nsid)
370 : : {
371 : : char link_name[PATH_MAX], *tmp;
372 : 4 : RegFileEntry rfe = REG_FILE_ENTRY__INIT;
373 : 4 : FownEntry fwn = FOWN_ENTRY__INIT;
374 : : struct link_remap_rlb *rlb;
375 : : int mntns_root;
376 : :
377 [ - + ]: 4 : if (!opts.link_remap_ok) {
378 : 0 : pr_err("Can't create link remap for %s. "
379 : : "Use " LREMAP_PARAM " option.\n", path);
380 : : return -1;
381 : : }
382 : :
383 : : /*
384 : : * Linked remapping -- we create a hard link on a removed file
385 : : * in the directory original file used to sit.
386 : : *
387 : : * Bad news is than we can't easily open lfd's parent dir. Thus
388 : : * we have to just generate an absolute path and use it. The linkat
389 : : * will fail if we chose the bad one.
390 : : */
391 : :
392 : 4 : link_name[0] = '.';
393 : 4 : memcpy(link_name + 1, path, len);
394 : 4 : tmp = link_name + len + 1;
395 [ + + ]: 124 : while (*tmp != '/') {
396 [ - + ]: 120 : BUG_ON(tmp == link_name);
397 : 120 : tmp--;
398 : : }
399 : :
400 : 4 : fd_id_generate_special(NULL, idp);
401 : 4 : rfe.id = *idp;
402 : 4 : rfe.flags = 0;
403 : 4 : rfe.pos = 0;
404 : 4 : rfe.fown = &fwn;
405 : 4 : rfe.name = link_name + 1;
406 : :
407 : : /* Any 'unique' name works here actually. Remap works by reg-file ids. */
408 : 4 : snprintf(tmp + 1, sizeof(link_name) - (size_t)(tmp - link_name - 1), "link_remap.%d", rfe.id);
409 : :
410 : 4 : mntns_root = mntns_collect_root(nsid->pid);
411 : :
412 [ - + ]: 4 : if (linkat(lfd, "", mntns_root, link_name, AT_EMPTY_PATH) < 0) {
413 : 0 : pr_perror("Can't link remap to %s", path);
414 : : return -1;
415 : : }
416 : :
417 : : /*
418 : : * Remember the name to delete it if needed on error or
419 : : * rollback action. Note we don't expect that there will
420 : : * be a HUGE number of link remaps, so in a sake of speed
421 : : * we keep all data in memory.
422 : : */
423 [ - + ]: 4 : rlb = xmalloc(sizeof(*rlb));
424 [ + - ]: 4 : if (rlb)
425 : 4 : rlb->path = strdup(link_name);
426 : :
427 : 4 : rlb->pid = nsid->pid;
428 : :
429 [ + - ][ - + ]: 4 : if (!rlb || !rlb->path) {
430 : 0 : pr_perror("Can't register rollback for %s", path);
431 [ # # ][ # # ]: 0 : xfree(rlb ? rlb->path : NULL);
[ # # ]
432 [ # # ]: 0 : xfree(rlb);
433 : : return -1;
434 : : }
435 : 4 : list_add(&rlb->list, &link_remaps);
436 : :
437 : 4 : return pb_write_one(fdset_fd(glob_fdset, CR_FD_REG_FILES), &rfe, PB_REG_FILE);
438 : : }
439 : :
440 : 8 : static int dump_linked_remap(char *path, int len, const struct stat *ost,
441 : : int lfd, u32 id, struct ns_id *nsid)
442 : : {
443 : : u32 lid;
444 : 4 : RemapFilePathEntry rpe = REMAP_FILE_PATH_ENTRY__INIT;
445 : :
446 [ + - ]: 4 : if (create_link_remap(path, len, lfd, &lid, nsid))
447 : : return -1;
448 : :
449 : 4 : rpe.orig_id = id;
450 : 4 : rpe.remap_id = lid;
451 : :
452 : 4 : return pb_write_one(fdset_fd(glob_fdset, CR_FD_REMAP_FPATH),
453 : : &rpe, PB_REMAP_FPATH);
454 : : }
455 : :
456 : 0 : static bool is_sillyrename_name(char *name)
457 : : {
458 : : int i;
459 : :
460 : 0 : name = strrchr(name, '/');
461 [ # # ]: 0 : BUG_ON(name == NULL); /* see check in dump_one_reg_file */
462 : 0 : name++;
463 : :
464 : : /*
465 : : * Strictly speaking this check is not bullet-proof. User
466 : : * can create file with this name by hands and we have no
467 : : * API to distinguish really-silly-renamed files from those
468 : : * fake names :(
469 : : *
470 : : * But since NFS people expect .nfsXXX files to be unstable,
471 : : * we treat them as such too.
472 : : */
473 : :
474 [ # # ]: 0 : if (strncmp(name, SILLYNAME_PREF, sizeof(SILLYNAME_PREF) - 1))
475 : : return false;
476 : :
477 : 0 : name += sizeof(SILLYNAME_PREF) - 1;
478 [ # # ]: 0 : for (i = 0; i < SILLYNAME_SUFF_LEN; i++)
479 [ # # ]: 0 : if (!isxdigit(name[i]))
480 : : return false;
481 : :
482 : : return true;
483 : : }
484 : :
485 : : static inline bool nfs_silly_rename(char *rpath, const struct fd_parms *parms)
486 : : {
487 [ - + ][ # # ]: 3844 : return (parms->fs_type == NFS_SUPER_MAGIC) && is_sillyrename_name(rpath);
488 : : }
489 : :
490 : 3884 : static int check_path_remap(char *rpath, int plen, const struct fd_parms *parms,
491 : : int lfd, u32 id, struct ns_id *nsid)
492 : : {
493 : : int ret, mntns_root;
494 : : struct stat pst;
495 : 3884 : const struct stat *ost = &parms->stat;
496 : :
497 [ + + ]: 3884 : if (ost->st_nlink == 0)
498 : : /*
499 : : * Unpleasant, but easy case. File is completely invisible
500 : : * from the FS. Just dump its contents and that's it. But
501 : : * be careful whether anybody still has any of its hardlinks
502 : : * also open.
503 : : */
504 : 40 : return dump_ghost_remap(rpath + 1, ost, lfd, id, nsid);
505 : :
506 [ - + ]: 3844 : if (nfs_silly_rename(rpath, parms)) {
507 : : /*
508 : : * If this is NFS silly-rename file the path we have at hands
509 : : * will be accessible by fstat(), but once we kill the dumping
510 : : * tasks it will disappear. So we just go ahead an dump it as
511 : : * linked-remap file (NFS will allow us to create more hard
512 : : * links on it) to have some persistent name at hands.
513 : : */
514 : 0 : pr_debug("Dump silly-rename linked remap for %x\n", id);
515 : 0 : return dump_linked_remap(rpath + 1, plen - 1, ost, lfd, id, nsid);
516 : : }
517 : :
518 : 3844 : mntns_root = mntns_collect_root(nsid->pid);
519 [ + - ]: 3844 : if (mntns_root < 0)
520 : : return -1;
521 : :
522 : : ret = fstatat(mntns_root, rpath, &pst, 0);
523 [ + + ]: 3844 : if (ret < 0) {
524 : : /*
525 : : * Linked file, but path is not accessible (unless any
526 : : * other error occurred). We can create a temporary link to it
527 : : * uning linkat with AT_EMPTY_PATH flag and remap it to this
528 : : * name.
529 : : */
530 : :
531 [ + - ]: 4 : if (errno == ENOENT)
532 : 4 : return dump_linked_remap(rpath + 1, plen - 1,
533 : : ost, lfd, id, nsid);
534 : :
535 : 0 : pr_perror("Can't stat path");
536 : 0 : return -1;
537 : : }
538 : :
539 [ + - ][ - + ]: 3840 : if ((pst.st_ino != ost->st_ino) || (pst.st_dev != ost->st_dev)) {
540 [ # # ][ # # ]: 0 : if (opts.evasive_devices &&
541 [ # # ]: 0 : (S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
542 : 0 : pst.st_rdev == ost->st_rdev)
543 : : return 0;
544 : : /*
545 : : * FIXME linked file, but the name we see it by is reused
546 : : * by somebody else. We can dump it with linked remaps, but
547 : : * we'll have difficulties on restore -- we will have to
548 : : * move the exisint file aside, then restore this one,
549 : : * unlink, then move the original file back. It's fairly
550 : : * easy to do, but we don't do it now, since unlinked files
551 : : * have the "(deleted)" suffix in proc and name conflict
552 : : * is unlikely :)
553 : : */
554 : 0 : pr_err("Unaccessible path opened %u:%u, need %u:%u\n",
555 : : (int)pst.st_dev, (int)pst.st_ino,
556 : : (int)ost->st_dev, (int)ost->st_ino);
557 : 0 : return -1;
558 : : }
559 : :
560 : : /*
561 : : * File is linked and visible by the name it is opened by
562 : : * this task. Go ahead and dump it.
563 : : */
564 : : return 0;
565 : : }
566 : :
567 : 3884 : int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p)
568 : : {
569 : : struct fd_link _link, *link;
570 : : struct ns_id *nsid;
571 : : int rfd;
572 : :
573 : 3884 : RegFileEntry rfe = REG_FILE_ENTRY__INIT;
574 : :
575 [ + + ]: 3884 : if (!p->link) {
576 [ + - ]: 3040 : if (fill_fdlink(lfd, p, &_link))
577 : : return -1;
578 : : link = &_link;
579 : : } else
580 : : link = p->link;
581 : :
582 [ - + ][ # # ]: 3884 : if (p->mnt_id >= 0 && (root_ns_mask & CLONE_NEWNS)) {
583 [ # # ]: 0 : if (lookup_mnt_id(p->mnt_id) == NULL) {
584 : 0 : pr_err("No mount for the %d file in the namespaces\n", p->mnt_id);
585 : 0 : return -1;
586 : : }
587 : :
588 : 0 : rfe.mnt_id = p->mnt_id;
589 : 0 : rfe.has_mnt_id = true;
590 : : }
591 : :
592 : 3884 : nsid = lookup_nsid_by_mnt_id(p->mnt_id);
593 [ - + ]: 3884 : if (nsid == NULL) {
594 : 0 : pr_err("Unable to look up the %d mount\n", p->mnt_id);
595 : 0 : return -1;
596 : : }
597 : :
598 : 3884 : pr_info("Dumping path for %d fd via self %d [%s]\n",
599 : : p->fd, lfd, &link->name[1]);
600 : :
601 : : /*
602 : : * The regular path we can handle should start with slash.
603 : : */
604 [ - + ]: 3884 : if (link->name[1] != '/') {
605 : 0 : pr_err("The path [%s] is not supported\n", &link->name[1]);
606 : 0 : return -1;
607 : : }
608 : :
609 [ + - ]: 3884 : if (check_path_remap(link->name, link->len, p, lfd, id, nsid))
610 : : return -1;
611 : :
612 : 3884 : rfe.id = id;
613 : 3884 : rfe.flags = p->flags;
614 : 3884 : rfe.pos = p->pos;
615 : 3884 : rfe.fown = (FownEntry *)&p->fown;
616 : 3884 : rfe.name = &link->name[1];
617 : :
618 : 3884 : rfd = fdset_fd(glob_fdset, CR_FD_REG_FILES);
619 : :
620 : 3884 : return pb_write_one(rfd, &rfe, PB_REG_FILE);
621 : : }
622 : :
623 : : const struct fdtype_ops regfile_dump_ops = {
624 : : .type = FD_TYPES__REG,
625 : : .dump = dump_one_reg_file,
626 : : };
627 : :
628 : : /*
629 : : * This routine properly resolves d's path handling ghost/link-remaps.
630 : : * The open_cb is a routine that does actual open, it differs for
631 : : * files, directories, fifos, etc.
632 : : */
633 : :
634 : : static inline int rfi_remap(struct reg_file_info *rfi)
635 : : {
636 : 30 : return link(rfi->remap->path, rfi->path);
637 : : }
638 : :
639 : 6886 : int open_path(struct file_desc *d,
640 : : int(*open_cb)(struct reg_file_info *, void *), void *arg)
641 : : {
642 : 30 : struct reg_file_info *rfi;
643 : : int tmp;
644 : : char *orig_path = NULL;
645 : :
646 : : rfi = container_of(d, struct reg_file_info, d);
647 : :
648 [ + + ]: 6886 : if (rfi->remap) {
649 : 30 : mutex_lock(ghost_file_mutex);
650 [ - + ]: 30 : if (rfi_remap(rfi) < 0) {
651 : : static char tmp_path[PATH_MAX];
652 : :
653 [ # # ]: 0 : if (errno != EEXIST) {
654 : 0 : pr_perror("Can't link %s -> %s", rfi->path,
655 : : rfi->remap->path);
656 : 0 : return -1;
657 : : }
658 : :
659 : : /*
660 : : * The file whose name we're trying to create
661 : : * exists. Need to pick some other one, we're
662 : : * going to remove it anyway.
663 : : *
664 : : * Strictly speaking, this is cheating, file
665 : : * name shouldn't change. But since NFS with
666 : : * its silly-rename doesn't care, why should we?
667 : : */
668 : :
669 : 0 : orig_path = rfi->path;
670 : 0 : rfi->path = tmp_path;
671 : : snprintf(tmp_path, sizeof(tmp_path), "%s.cr_link", orig_path);
672 : 0 : pr_debug("Fake %s -> %s link\n", rfi->path, rfi->remap->path);
673 : :
674 [ # # ]: 0 : if (rfi_remap(rfi) < 0) {
675 : 0 : pr_perror("Can't create even fake link!");
676 : 0 : return -1;
677 : : }
678 : : }
679 : : }
680 : :
681 : 6886 : tmp = open_cb(rfi, arg);
682 [ - + ]: 6886 : if (tmp < 0) {
683 : 0 : pr_perror("Can't open file %s", rfi->path);
684 : 0 : return -1;
685 : : }
686 : :
687 [ + + ]: 6886 : if (rfi->remap) {
688 : 30 : unlink(rfi->path);
689 [ - + ]: 30 : BUG_ON(!rfi->remap->users);
690 [ + + ]: 30 : if (--rfi->remap->users == 0) {
691 : 18 : pr_info("Unlink the ghost %s\n", rfi->remap->path);
692 : 18 : unlink(rfi->remap->path);
693 : : }
694 : :
695 [ - + ]: 30 : if (orig_path)
696 : 0 : rfi->path = orig_path;
697 : 30 : mutex_unlock(ghost_file_mutex);
698 : : }
699 : :
700 [ + - ]: 6886 : if (restore_fown(tmp, rfi->rfe->fown))
701 : : return -1;
702 : :
703 : 6886 : return tmp;
704 : : }
705 : :
706 : 6872 : static int do_open_reg_noseek_flags(struct reg_file_info *rfi, void *arg)
707 : : {
708 : 6872 : u32 flags = *(u32 *)arg;
709 : : int fd, mntns_root;
710 : : struct ns_id *nsid;
711 : :
712 : 6872 : nsid = lookup_nsid_by_mnt_id(rfi->rfe->mnt_id);
713 [ + - ]: 6872 : if (nsid == NULL)
714 : : return -1;
715 : :
716 : 6872 : mntns_root = mntns_collect_root(nsid->pid);
717 : :
718 : 6872 : fd = openat(mntns_root, rfi->path, flags);
719 [ - + ]: 6872 : if (fd < 0) {
720 : 0 : pr_perror("Can't open file %s on restore", rfi->path);
721 : 0 : return fd;
722 : : }
723 : :
724 : : return fd;
725 : : }
726 : :
727 : 1044 : static int do_open_reg_noseek(struct reg_file_info *rfi, void *arg)
728 : : {
729 : 1606 : return do_open_reg_noseek_flags(rfi, &rfi->rfe->flags);
730 : : }
731 : :
732 : 562 : static int do_open_reg(struct reg_file_info *rfi, void *arg)
733 : : {
734 : : int fd;
735 : :
736 : : fd = do_open_reg_noseek(rfi, arg);
737 [ + - ]: 562 : if (fd < 0)
738 : : return fd;
739 : :
740 [ + - - + ]: 1124 : if ((rfi->rfe->pos != -1ULL) &&
741 : 562 : lseek(fd, rfi->rfe->pos, SEEK_SET) < 0) {
742 : 0 : pr_perror("Can't restore file pos");
743 : 0 : close(fd);
744 : 0 : return -1;
745 : : }
746 : :
747 : 562 : return fd;
748 : : }
749 : :
750 : 1044 : int open_reg_by_id(u32 id)
751 : : {
752 : : struct file_desc *fd;
753 : :
754 : : /*
755 : : * This one gets called by exe link, chroot and cwd
756 : : * restoring code. No need in calling lseek on either
757 : : * of them.
758 : : */
759 : :
760 : 1044 : fd = find_file_desc_raw(FD_TYPES__REG, id);
761 [ - + ]: 1044 : if (fd == NULL) {
762 : 0 : pr_err("Can't find regfile for %#x\n", id);
763 : 0 : return -1;
764 : : }
765 : :
766 : 1044 : return open_path(fd, do_open_reg_noseek, NULL);
767 : : }
768 : :
769 : 5266 : int get_filemap_fd(struct vma_area *vma)
770 : : {
771 : : u32 flags;
772 : :
773 : : /*
774 : : * Thevma->fd should have been assigned in collect_filemap
775 : : *
776 : : * We open file w/o lseek, as mappings don't care about it
777 : : */
778 : :
779 [ - + ]: 5266 : BUG_ON(vma->fd == NULL);
780 [ + - ]: 5266 : if (vma->e->has_fdflags)
781 : 5266 : flags = vma->e->fdflags;
782 [ # # ][ # # ]: 0 : else if ((vma->e->prot & PROT_WRITE) &&
783 : 0 : vma_area_is(vma, VMA_FILE_SHARED))
784 : 0 : flags = O_RDWR;
785 : : else
786 : 0 : flags = O_RDONLY;
787 : :
788 : 5266 : return open_path(vma->fd, do_open_reg_noseek_flags, &flags);
789 : : }
790 : :
791 : 12669 : static void remap_get(struct file_desc *fdesc, char typ)
792 : : {
793 : : struct reg_file_info *rfi;
794 : :
795 : : rfi = container_of(fdesc, struct reg_file_info, d);
796 [ + + ]: 12669 : if (rfi->remap) {
797 : 34 : pr_debug("One more remap user (%c) for %s\n",
798 : : typ, rfi->remap->path);
799 : : /* No lock, we're still sngle-process here */
800 : 34 : rfi->remap->users++;
801 : : }
802 : 12669 : }
803 : :
804 : 3330 : static void collect_reg_fd(struct file_desc *fdesc,
805 : : struct fdinfo_list_entry *fle, struct rst_info *ri)
806 : : {
807 [ + + ]: 3330 : if (list_empty(&fdesc->fd_info_head))
808 : 1154 : remap_get(fdesc, 'f');
809 : :
810 : : collect_gen_fd(fle, ri);
811 : 3330 : }
812 : :
813 : 562 : static int open_fe_fd(struct file_desc *fd)
814 : : {
815 : 562 : return open_path(fd, do_open_reg, NULL);
816 : : }
817 : :
818 : : static struct file_desc_ops reg_desc_ops = {
819 : : .type = FD_TYPES__REG,
820 : : .open = open_fe_fd,
821 : : .collect_fd = collect_reg_fd,
822 : : };
823 : :
824 : 11515 : struct file_desc *collect_special_file(u32 id)
825 : : {
826 : : struct file_desc *fdesc;
827 : :
828 : : /*
829 : : * Files dumped for vmas/exe links can have remaps
830 : : * configured. Need to bump-up users for them, otherwise
831 : : * the open_path() would unlink the remap file after
832 : : * the very first open.
833 : : */
834 : :
835 : 11515 : fdesc = find_file_desc_raw(FD_TYPES__REG, id);
836 [ - + ]: 11515 : if (fdesc == NULL) {
837 : 0 : pr_err("No entry for reg-file-ID %#x\n", id);
838 : 0 : return NULL;
839 : : }
840 : :
841 : 11515 : remap_get(fdesc, 's');
842 : 11515 : return fdesc;
843 : : }
844 : :
845 : 3061 : static int collect_one_regfile(void *o, ProtobufCMessage *base)
846 : : {
847 : : struct reg_file_info *rfi = o;
848 : :
849 : 3061 : rfi->rfe = pb_msg(base, RegFileEntry);
850 : 3061 : rfi->path = rfi->rfe->name;
851 : 3061 : rfi->remap = NULL;
852 : :
853 : 3061 : pr_info("Collected [%s] ID %#x\n", rfi->path, rfi->rfe->id);
854 : 3061 : return file_desc_add(&rfi->d, rfi->rfe->id, ®_desc_ops);
855 : : }
856 : :
857 : : struct collect_image_info reg_file_cinfo = {
858 : : .fd_type = CR_FD_REG_FILES,
859 : : .pb_type = PB_REG_FILE,
860 : : .priv_size = sizeof(struct reg_file_info),
861 : : .collect = collect_one_regfile,
862 : : };
863 : :
864 : 355 : int prepare_shared_reg_files(void)
865 : : {
866 : 355 : ghost_file_mutex = shmalloc(sizeof(*ghost_file_mutex));
867 [ + - ]: 355 : if (!ghost_file_mutex)
868 : : return -1;
869 : :
870 : : mutex_init(ghost_file_mutex);
871 : 355 : return 0;
872 : : }
|